- Workshop is only about the streaming part, not the transcoding part. We assume the transcoding has already been done. If interested look at active-encode or connect2018-workshop
- Clone repo
git clone https://github.com/avalonmediasystem/connect2020-workshop.git
- Build Docker image
docker-compose build
- Show docker-compose.yml, this is a standard Rails setup, with DB
- Explain what has been scaffolded: Item, Devise for login
- Start the stack
docker-compose up
- Show Items view, login
streaming:
build: ./nginx
volumes:
- ./streams:/data
ports:
- "3333:80"
- Explain mount volume, streaming port
- Explain nginx build.sh, vod module, config
- Build service:
docker-compose build streaming
- Bring it up:
docker-compose up -d streaming
<p>
<video
id="my-video"
class="video-js"
width="640"
height="480"
controls
preload="auto"
>
<% @item.streams.each do |stream| %>
<source src="<%= stream["url"] %>" type="application/x-mpegURL" label="<%= stream["label"] %>"/>
<% end %>
</video>
</p>
Explain multiple sources in 1 video
<link href="https://vjs.zencdn.net/7.8.4/video-js.css" rel="stylesheet" />
<link href="https://unpkg.com/@silvermine/videojs-quality-selector/dist/css/quality-selector.css" rel="stylesheet">
<script src="https://vjs.zencdn.net/7.8.4/video.js"></script>
<script src="https://unpkg.com/@silvermine/videojs-quality-selector/dist/js/silvermine-videojs-quality-selector.min.js"></script>
<script>
var options, player;
options = {
controlBar: {
children: [
'playToggle',
'progressControl',
'volumePanel',
'qualitySelector',
'fullscreenToggle',
],
},
};
player = videojs('my-video', options);
</script>
- Check player working
- Show quality selector
- Item is protected but the stream is not. Someone can guess the URL and stream it.
How token-based auth works
- Uncomment
auth_request /auth;
- Explain how nginx get token and call auth
- Rebuild
docker-compose build streaming
- Recreate
docker-compose up -d streaming
- Shift-reload verify streaming not working
- Look at web log to see the authorize call
- in
show
action
session[:token] ||= SecureRandom.hex(16)
Rails.cache.write(session[:token],
@item.streams.collect { |s| s["url"] },
expires_in: 1.hours)
- in
show
view
<source src="<%= stream["url"] %>?token=<%= session[:token] %>" type="application/x-mpegURL" label="<%= stream["label"] %>"/>
- Enable cache store in
config/environments/development.rb
config.cache_store = :memory_store
- Add
authorize
action initems_controller.rb
def authorize
authorized_streams = Rails.cache.read(params[:token])
if params[:name] and not authorized_streams.any? { |valid| valid.index(params[:name]).present? }
return head :forbidden
else
return head :ok
end
end
This code looks at authorized streams associated with this token and see if the requested stream matches any of them
Make it publicly available so streaming service can reach it
before_action :require_login, except: [:index, :authorize]
- Add route
resources :items do
collection do
get :authorize
end
end
- Check auth call returns 200
- Check auth streaming working
-
Show example of adaptive HLS manifest
-
Add m3u8 view template
adaptive.erb
#EXTM3U
<% @streams.each do |stream| %>
#EXT-X-STREAM-INF:BANDWIDTH=<%= stream["bitrate"] %>
<%= stream["url"] + "?token=" + session[:token]%>
<% end %>
- Add route
items_controller.rb
member do
get :adaptive
end
- Add action
# GET /items/1/adaptive.m3u8
def adaptive
@streams = @item.streams
render layout: false, content_type: 'text/plain'
end
before_action :set_item, only: [:show, :edit, :update, :destroy, :adaptive]
Explain format, how player will choose which stream based on bandwidth
- Add source to
show.html.erb
<source src="<%= adaptive_item_path(@item, format: "m3u8") %>" type="application/x-mpegURL" label="auto"/>