opentok 3.1.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +3 -1
  3. data/README.md +35 -4
  4. data/lib/opentok/archives.rb +12 -1
  5. data/lib/opentok/sip.rb +0 -2
  6. data/lib/opentok/version.rb +1 -1
  7. data/opentok.gemspec +9 -8
  8. data/sample/Broadcast/Gemfile +4 -0
  9. data/sample/Broadcast/README.md +201 -0
  10. data/sample/Broadcast/broadcast_sample.rb +97 -0
  11. data/sample/Broadcast/public/css/sample.css +64 -0
  12. data/sample/Broadcast/public/js/host.js +185 -0
  13. data/sample/Broadcast/public/js/participant.js +85 -0
  14. data/sample/Broadcast/views/host.erb +82 -0
  15. data/sample/Broadcast/views/index.erb +32 -0
  16. data/sample/Broadcast/views/layout.erb +29 -0
  17. data/sample/Broadcast/views/participant.erb +27 -0
  18. data/sample/HelloWorld/public/js/helloworld.js +4 -10
  19. data/sample/HelloWorld/views/index.erb +1 -3
  20. data/spec/cassettes/OpenTok_Archives/calls_layout_on_archive_object.yml +1 -1
  21. data/spec/cassettes/OpenTok_Archives/changes_the_layout_of_an_archive.yml +1 -1
  22. data/spec/cassettes/OpenTok_Archives/http_client_errors/.yml +34 -0
  23. data/spec/cassettes/OpenTok_Archives/should_create_archives.yml +1 -1
  24. data/spec/cassettes/OpenTok_Archives/should_create_audio_only_archives.yml +1 -1
  25. data/spec/cassettes/OpenTok_Archives/should_create_custom_layout_archives.yml +48 -0
  26. data/spec/cassettes/OpenTok_Archives/should_create_hd_archives.yml +1 -1
  27. data/spec/cassettes/OpenTok_Archives/should_create_individual_archives.yml +1 -1
  28. data/spec/cassettes/OpenTok_Archives/should_create_named_archives.yml +1 -1
  29. data/spec/cassettes/OpenTok_Archives/should_delete_an_archive_by_id.yml +1 -1
  30. data/spec/cassettes/OpenTok_Archives/should_find_archives_by_id.yml +1 -1
  31. data/spec/cassettes/OpenTok_Archives/should_find_archives_with_unknown_properties.yml +1 -1
  32. data/spec/cassettes/OpenTok_Archives/should_find_expired_archives.yml +1 -1
  33. data/spec/cassettes/OpenTok_Archives/should_find_paused_archives_by_id.yml +1 -1
  34. data/spec/cassettes/OpenTok_Archives/should_stop_archives.yml +1 -1
  35. data/spec/cassettes/OpenTok_Archives/when_many_archives_are_created/should_return_all_archives.yml +1 -1
  36. data/spec/cassettes/OpenTok_Archives/when_many_archives_are_created/should_return_archives_with_an_offset.yml +1 -1
  37. data/spec/cassettes/OpenTok_Archives/when_many_archives_are_created/should_return_count_number_of_archives.yml +1 -1
  38. data/spec/cassettes/OpenTok_Archives/when_many_archives_are_created/should_return_part_of_the_archives_when_using_offset_and_count.yml +1 -1
  39. data/spec/cassettes/OpenTok_Archives/when_many_archives_are_created/should_return_session_archives.yml +1 -1
  40. data/spec/cassettes/OpenTok_Broadcasts/calls_layout_on_broadcast_object.yml +1 -1
  41. data/spec/cassettes/OpenTok_Broadcasts/changes_the_layout_of_a_broadcast.yml +1 -1
  42. data/spec/cassettes/OpenTok_Broadcasts/fetches_a_hls_broadcast_url.yml +1 -1
  43. data/spec/cassettes/OpenTok_Broadcasts/finds_a_broadcast.yml +1 -1
  44. data/spec/cassettes/OpenTok_Broadcasts/starts_a_rtmp_broadcast.yml +1 -1
  45. data/spec/cassettes/OpenTok_Broadcasts/stops_a_broadcast.yml +1 -1
  46. data/spec/cassettes/OpenTok_Connections/forces_a_connection_to_be_terminated.yml +1 -1
  47. data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_always_archived_sessions.yml +1 -1
  48. data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_default_sessions.yml +1 -1
  49. data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_relayed_media_sessions.yml +1 -1
  50. data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_relayed_media_sessions_for_invalid_media_modes.yml +1 -1
  51. data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_relayed_media_sessions_with_a_location_hint.yml +1 -1
  52. data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_routed_media_sessions.yml +1 -1
  53. data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_routed_media_sessions_with_a_location_hint.yml +1 -1
  54. data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_sessions_with_a_location_hint.yml +1 -1
  55. data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/with_an_addendum_to_the_user_agent_string/should_append_the_addendum_to_the_user_agent_header.yml +1 -1
  56. data/spec/cassettes/OpenTok_Signals/receives_a_valid_response_for_a_connection.yml +1 -1
  57. data/spec/cassettes/OpenTok_Signals/receives_a_valid_response_for_all_connections.yml +1 -1
  58. data/spec/cassettes/OpenTok_Sip/receives_a_valid_response.yml +1 -1
  59. data/spec/cassettes/OpenTok_Streams/get_all_streams_information.yml +1 -1
  60. data/spec/cassettes/OpenTok_Streams/get_specific_stream_information.yml +1 -1
  61. data/spec/cassettes/OpenTok_Streams/layout_working_on_two_stream_list.yml +1 -1
  62. data/spec/opentok/archives_spec.rb +11 -1
  63. data/spec/spec_helper.rb +2 -0
  64. metadata +33 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 4baddcff5e72cad62caf5c0046c8a2eb3cc375b3
4
- data.tar.gz: 59b84a91a65d5841f76f4251a26ea99739386117
2
+ SHA256:
3
+ metadata.gz: 2d54c20aba3659203311b38260a883c4586590ebbeeeeea059a4f3bbaf53cd88
4
+ data.tar.gz: 14808a5dccb04fd42df4b1768fc1943b4620b2e2e753a123db244f9849e82e6a
5
5
  SHA512:
6
- metadata.gz: 5bdaf9b065a6e5449b9753d42e3fd906e9afa66635d71b74ae0f2965bc34e138de2a253f4707d0bbbe3fe972584db3f9f235129c55ec1dfb09b4669ef2de0eb1
7
- data.tar.gz: ad070ca9e3e516b96c9cbd8aff45ccd9b1f593f657688f8b1c90894c1b72bcb5c9dc53ccea0d19c7ef7d813951645709a6daa3855362625bd3e976be87118f80
6
+ metadata.gz: 9ee3bf5992a0c962099f5db88d8db4043699d596566256ff3256447f1658173610fdd76fa10c086620742d3dddb4fe45e56ab66b3724b749f336c1b748be7dcd
7
+ data.tar.gz: 9e39c51d175a273666d2af2e5cd8667d46b1c04531f10ca297dd9d3b19db2a3e080fb989480038d290e702c816ca790aa1baf39d051dbb2e438c87b9e00f61f2
@@ -5,11 +5,13 @@ language: ruby
5
5
  cache: bundler
6
6
  before_install: gem update bundler
7
7
  rvm:
8
- - 2.0
9
8
  - 2.1
10
9
  - 2.2
11
10
  - 2.3
12
11
  - 2.4
12
+ - 2.5
13
+ - 2.6
14
+ - 2.7
13
15
  notifications:
14
16
  slack:
15
17
  secure: agVll2R9PTPvJMcUgbvOh9eGt60zGDc8kPUwEsiQr828rCgXh/ZxD5irYDyKQg3ZsS8+f3MjFCwzU7uQALkia2pDrie9d8g8m1dt4Q5U7Qm6QecshvE0U9JwbB5Ngxaftbqyf0XEFrE7CKs7RI1BzFRpe8m+fdZgfwccX8Gb7pc=
data/README.md CHANGED
@@ -21,7 +21,7 @@ Bundler helps manage dependencies for Ruby projects. Find more info here: <http:
21
21
  Add this gem to your `Gemfile`:
22
22
 
23
23
  ```ruby
24
- gem "opentok", "~> 3.1.0"
24
+ gem "opentok", "~> 4.0.0"
25
25
  ```
26
26
 
27
27
  Allow bundler to install the change.
@@ -181,6 +181,30 @@ opts = {
181
181
  archive = opentok.archives.create session_id, opts
182
182
  ```
183
183
 
184
+ To customize the initial layout of composed archives, you can use the `:layout` option.
185
+ Set this to a hash containing two keys: `:type` and `:stylesheet`. Valid values for
186
+ `:type` are "bestFit" (best fit), "custom" (custom), "horizontalPresentation"
187
+ (horizontal presentation), "pip" (picture-in-picture), and "verticalPresentation"
188
+ (vertical presentation)). If you specify a "custom" layout type, set the `:stylesheet`
189
+ key to the stylesheet (CSS). (For other layout types, do not set the `:stylesheet` key.)
190
+
191
+ ```ruby
192
+ opts = {
193
+ :output_mode => :composed,
194
+ :resolution => "1280x720",
195
+ :layout => {
196
+ :type => "custom",
197
+ :stylesheet => "stream:last-child{display: block;margin: 0;top: 0;left: 0;width: 1px;height: 1px;}stream:first-child{display: block;margin: 0;top: 0;left: 0;width: 100%;height: 100%;}"
198
+ }
199
+ }
200
+
201
+ archive = opentok.archives.create session_id, opts
202
+ ```
203
+
204
+ If you do not specify an initial layout type, the archive uses the best fit
205
+ layout type. For more information, see [Customizing the video layout for composed
206
+ archives](https://tokbox.com/developer/guides/archiving/layout-control.html).
207
+
184
208
  You can stop the recording of a started Archive using the `opentok.archives.stop_by_id(archive_id)`
185
209
  method. You can also do this using the `Archive#stop()` method.
186
210
 
@@ -432,11 +456,12 @@ For more information on SIP Interconnect, see the
432
456
 
433
457
  # Samples
434
458
 
435
- There are two sample applications included in this repository. To get going as fast as possible, clone the whole
436
- repository and follow the Walkthroughs:
459
+ There are three sample applications included in this repository. To get going as fast as possible, clone the whole
460
+ repository and read the README in each of the sample directories:
437
461
 
438
462
  * [HelloWorld](sample/HelloWorld/README.md)
439
463
  * [Archiving](sample/Archiving/README.md)
464
+ * [Broadcast](sample/Broadcast/README.md)
440
465
 
441
466
  # Documentation
442
467
 
@@ -447,7 +472,7 @@ Reference documentation is available at <http://www.tokbox.com//opentok/librarie
447
472
  You need an OpenTok API key and API secret, which you can obtain by logging into your
448
473
  [TokBox account](https://tokbox.com/account).
449
474
 
450
- The OpenTok Ruby SDK requires Ruby 1.9.3 or greater.
475
+ The OpenTok Ruby SDK requires Ruby 2.1.0 or greater.
451
476
 
452
477
  # Release Notes
453
478
 
@@ -456,6 +481,12 @@ about each release.
456
481
 
457
482
  ## Important changes since v2.2.0
458
483
 
484
+ **Changes in v4.0.0:**
485
+
486
+ The SDK adds support for Ruby v2.7 and now requires Ruby v2.1.0 or higher.
487
+ For Ruby v2.0.0 please continue to use the OpenTok Ruby SDK v3.0.0.
488
+ For Ruby v1.9.3 please continue to use the OpenTok Ruby SDK v2.5.0.
489
+
459
490
  **Changes in v3.0.0:**
460
491
 
461
492
  The SDK now now requires Ruby v2.0.0 or higher. For Ruby v1.9.3 please continue to use the
@@ -48,6 +48,17 @@ module OpenTok
48
48
  # default) or "1280x720" (HD). This property only applies to composed archives. If you set
49
49
  # this property and set the outputMode property to "individual", the call the method
50
50
  # results in an error.
51
+ # @option options [Hash] :layout Specify this to assign the initial layout type for
52
+ # the archive. This applies only to composed archives. This is a hash containing two keys:
53
+ # <code>:type</code> and <code>:stylesheet<code>. Valid values for <code>:type</code> are
54
+ # "bestFit" (best fit), "custom" (custom), "horizontalPresentation" (horizontal presentation),
55
+ # "pip" (picture-in-picture), and "verticalPresentation" (vertical presentation)).
56
+ # If you specify a "custom" layout type, set the <code>:stylesheet</code> key to the
57
+ # stylesheet (CSS). (For other layout types, do not set the <code>:stylesheet</code> key.)
58
+ # If you do not specify an initial layout type, the archive uses the best fit
59
+ # layout type. For more information, see
60
+ # {https://tokbox.com/developer/guides/archiving/layout-control.html Customizing
61
+ # the video layout for composed archives}.
51
62
  #
52
63
  # @return [Archive] The Archive object, which includes properties defining the archive,
53
64
  # including the archive ID.
@@ -66,7 +77,7 @@ module OpenTok
66
77
  "Resolution cannot be supplied for individual output mode" if options.key?(:resolution) and options[:output_mode] == :individual
67
78
 
68
79
  # normalize opts so all keys are symbols and only include valid_opts
69
- valid_opts = [ :name, :has_audio, :has_video, :output_mode, :resolution ]
80
+ valid_opts = [ :name, :has_audio, :has_video, :output_mode, :resolution, :layout ]
70
81
  opts = options.inject({}) do |m,(k,v)|
71
82
  if valid_opts.include? k.to_sym
72
83
  m[k.to_sym] = v
@@ -30,8 +30,6 @@ module OpenTok
30
30
  # PSTN phones.
31
31
  # @option opts [Hash] :headers This hash defines custom headers to be added
32
32
  # to the SIP ​INVITE​ request initiated from OpenTok to the your SIP platform.
33
- # Each of the custom headers must start with the ​"X-"​ prefix, or the call
34
- # will result in a Bad Request (400) response.
35
33
  # @option opts [Hash] :auth This object contains the username and password
36
34
  # to be used in the the SIP INVITE​ request for HTTP digest authentication,
37
35
  # if it is required by your SIP platform.
@@ -1,4 +1,4 @@
1
1
  module OpenTok
2
2
  # @private
3
- VERSION = '3.1.0'
3
+ VERSION = '4.0.0'
4
4
  end
@@ -16,17 +16,18 @@ Gem::Specification.new do |spec|
16
16
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
 
19
- spec.add_development_dependency "bundler", "~> 1.5"
20
- spec.add_development_dependency "rake", "~> 10.1.1"
21
- spec.add_development_dependency "rspec", "~> 2.14.1"
22
- spec.add_development_dependency "webmock", "~> 2.3.2"
23
- spec.add_development_dependency "vcr", "~> 2.8.0"
24
- spec.add_development_dependency "yard", "~> 0.9.11"
19
+ bundler_version = RUBY_VERSION < '2.1' ? '~> 1.5' : '>= 1.5'
20
+ spec.add_development_dependency "bundler", bundler_version
21
+ spec.add_development_dependency "rake", "~> 12.0.0"
22
+ spec.add_development_dependency "rspec", "~> 3.9.0"
23
+ spec.add_development_dependency "webmock", ">= 2.3.2"
24
+ spec.add_development_dependency "vcr", ">= 2.8.0"
25
+ spec.add_development_dependency "yard", ">= 0.9.11"
25
26
  # TODO: exclude this for compatibility with rbx
26
27
  # spec.add_development_dependency "debugger", "~> 1.6.6"
27
28
 
28
29
  spec.add_dependency "addressable", "~> 2.3" # 2.3.0 <= version < 3.0.0
29
- spec.add_dependency "httparty", "~> 0.15.5"
30
+ spec.add_dependency "httparty", ">= 0.15.5"
30
31
  spec.add_dependency "activesupport", ">= 2.0"
31
- spec.add_dependency "jwt", "~> 1.5.6"
32
+ spec.add_dependency "jwt", ">= 1.5.6"
32
33
  end
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "sinatra", "~> 1.4.4"
4
+ gem "opentok", :path => "../../"
@@ -0,0 +1,201 @@
1
+ # OpenTok Broadcasting Sample for Ruby
2
+
3
+ This is a simple demo app that shows how you can use the OpenTok Ruby SDK to broadcast
4
+ sessions and how to stop them, change the layout of the broadcast and/or the streams within.
5
+
6
+ ## Running the App
7
+
8
+ First, download the dependencies using [Bundler](http://bundler.io)
9
+
10
+ ```
11
+ $ bundle install
12
+ ```
13
+
14
+ Next, add your OpenTok API key and API secret to the environment variables. There are a few ways to do
15
+ this but the simplest would be to do it right in your shell.
16
+
17
+ ```
18
+ $ export API_KEY=0000000
19
+ $ export API_SECRET=abcdef1234567890abcdef01234567890abcdef
20
+ ```
21
+
22
+ Finally, start the server using Bundler to handle dependencies
23
+
24
+ ```
25
+ $ bundle exec ruby broadcast_sample.rb
26
+ ```
27
+
28
+ Visit <http://localhost:4567> in your browser. You can now create new broadcast (with a host and
29
+ as a participant) and also view those broadcasts.
30
+
31
+ ## Walkthrough
32
+
33
+ This demo application uses the same frameworks and libraries as the HelloWorld sample. If you have
34
+ not already gotten familiar with the code in that project, consider doing so before continuing.
35
+
36
+ The explanations below are separated by page. Each section will focus on a route handler within the
37
+ main application (broadcast_sample.rb).
38
+
39
+ ### Creating Broadcasts – Host View
40
+
41
+ The Host view manages the broadcasting process. Visit the host page at <http://localhost:4567/host>.
42
+ Your browser will first ask you to approve permission to use the camera and microphone.
43
+ Once you've accepted, your image will appear inside the section titled 'Host'. To start broadcasting
44
+ the video stream, press the 'Start Broadcast' button. You can specify the maximum duration,
45
+ resolution, and layout of the broadcast. Once broadcasting has begun the button will turn
46
+ green and change to 'Stop Broadcast'. Click this button when you are done broadcasting.
47
+
48
+ The host page basically sets up the OpenTok session with the API key and secret you provided.
49
+ If a previously started broadcast exists, it defaults to it, along with the layout and the stream
50
+ that has the focus:
51
+
52
+ ```ruby
53
+ get '/host' do
54
+ api_key = settings.api_key
55
+ session_id = settings.session.session_id
56
+ token = settings.opentok.generate_token(session_id, role: :publisher, initialLayoutClassList: ['focus'])
57
+
58
+ erb :host, locals: {
59
+ apiKey: api_key,
60
+ sessionId: session_id,
61
+ token: token,
62
+ initialBroadcastId: settings.broadcast_id,
63
+ focusStreamId: settings.focus_stream_id,
64
+ initialLayout: settings.broadcast_layout
65
+ }
66
+ end
67
+ ```
68
+
69
+ This handler generates the three strings that the client (JavaScript) needs to connect
70
+ to the session: `apiKey`, `sessionId`, and `token`. The `initialBroadcastId` is the broadcast ID,
71
+ `focusStreamId` is the stream ID that has the current focus (if there is one), and
72
+ `initialLayout` is the initial layout for the current broadcast in progress (if there is one).
73
+ (We will discuss focus stream and broadcast layout below.)
74
+
75
+ In the host page, the user presses the 'Start Broadcast' button, which sends an XHR (or Ajax)
76
+ request to the <http://localhost:4567/start> URL. The route handler for this URL is shown below:
77
+
78
+ ```ruby
79
+ post '/start' do
80
+ opts = {
81
+ :maxDuration => params.key?("maxDuration") ? params[:maxDuration] : 7200,
82
+ :resolution => params[:resolution],
83
+ :layout => params[:layout],
84
+ :outputs => {
85
+ :hls => {}
86
+ }
87
+ }
88
+ broadcast = settings.opentok.broadcasts.create(settings.session.session_id, opts)
89
+ settings.broadcast_id = broadcast.id
90
+ body broadcast.to_json
91
+ end
92
+ ```
93
+
94
+ In this handler, `opentok.broadcasts.create` is called with the `session_id` for
95
+ the OpenTok session to broadcast. The optional second argument is a hash which defines
96
+ optional properties for the broadcast. It consists of `maxDuration` of the broadcast,
97
+ `resolution`, and broadcast `layout`. This sample app starts an HLS broadcast (not RTMP),
98
+ so it only specifies an `hls` property of the `outputs` property. See the
99
+ [Ruby SDK documentation](https://github.com/opentok/OpenTok-Ruby-SDK) for information
100
+ on adding RTMP broadcast streams. In this case, as in the HelloWorld sample app, there is
101
+ only one session created and it is used here and for the participant view.
102
+ This will trigger the broadcasting to begin. The response sent back to the client’s XHR request
103
+ will be the JSON representation of the broadcast, which is returned from the `to_json()` method.
104
+
105
+ You can view the HLS broadcast by opening the root URL (<http://localhost:4567/>) in
106
+ a different tab and clicking the `Broadcast URL` button. The code for handling this is as follows:
107
+
108
+ ```ruby
109
+ get '/broadcast' do
110
+ return 'No broadcast id exists' if settings.broadcast_id.nil? || settings.broadcast_id.empty?
111
+ broadcast = settings.opentok.broadcasts.find settings.broadcast_id
112
+ redirect broadcast.broadcastUrls['hls'] if broadcast.status == 'started'
113
+ end
114
+ ```
115
+
116
+ The route for Stop Broadcast has the following code:
117
+
118
+ ```ruby
119
+ get '/stop/:broadcastId' do
120
+ broadcast = settings.opentok.broadcasts.stop settings.broadcast_id
121
+ settings.broadcast_id = nil
122
+ settings.focus_stream_id = ''
123
+ settings.broadcast_layout = 'horizontalPresentation'
124
+ body broadcast.to_json
125
+ end
126
+ ```
127
+
128
+ The settings revert backs to the settings when you start the app.
129
+
130
+ The host page includes a `Toggle Layout` button, which toggles between
131
+ `verticalPresentation` and `horizontalPresentation`.
132
+
133
+ The route for `Toggle Layout` has the following code:
134
+
135
+ ```ruby
136
+ post '/broadcast/:broadcastId/layout' do
137
+ layoutType = params[:type]
138
+ settings.opentok.broadcasts.layout(settings.broadcast_id, type: layoutType)
139
+ settings.broadcast_layout = layoutType
140
+ end
141
+ ```
142
+
143
+ This calls the `opentok.broadcasts.layout()` method, setting the broadcast layout to
144
+ the layout type defined in the POST request's body. In this app, the layout type is
145
+ set to `horizontalPresentation` or `verticalPresentation`, two of the [predefined layout
146
+ types](https://tokbox.com/developer/guides/broadcast/live-streaming/#predefined-layout-types)
147
+ available to live streaming broadcasts.
148
+
149
+ ### Creating Broadcast - Participant View
150
+
151
+ With the host view still open and publishing, open an additional tab and navigate to
152
+ <http://localhost:4567/participant> and allow the browser to use your camera and microphone.
153
+ You will now see the participant in the broadcast.
154
+
155
+ ```ruby
156
+ get '/participant' do
157
+ api_key = settings.api_key
158
+ session_id = settings.session.session_id
159
+ token = settings.opentok.generate_token(session_id, role: :publisher)
160
+
161
+ erb :participant, locals: {
162
+ apiKey: api_key,
163
+ sessionId: session_id,
164
+ token: token,
165
+ focusStreamId: settings.focus_stream_id,
166
+ layout: settings.broadcast_layout
167
+ }
168
+ end
169
+ ```
170
+
171
+ ### Changing the layout classes for streams
172
+
173
+ In the host page, if you click on either the host or a participant video, that video gets
174
+ the `focus` layout in the broadcast. The host page sends the `focus` stream ID and
175
+ the other streams' layout class lists can be cleared, as shown below:
176
+
177
+ ```ruby
178
+ post '/focus' do
179
+ hash = { items: [] }
180
+ hash[:items] << { id: params[:focus], layoutClassList: ['focus'] }
181
+ settings.focus_stream_id = params[:focus]
182
+ if params.key?('otherStreams')
183
+ params[:otherStreams].each do |stream|
184
+ hash[:items] << { id: stream, layoutClassList: [] }
185
+ end
186
+ end
187
+ settings.opentok.streams.layout(settings.session.session_id, hash)
188
+ end
189
+ ```
190
+
191
+ The host client page also uses OpenTok signaling to notify other clients when the layout type and
192
+ focus stream changes, and they then update the local display of streams in the HTML DOM accordingly.
193
+ However, this is not necessary. The layout of the broadcast is unrelated to the layout of
194
+ streams in the web clients.
195
+
196
+ When you view the broadcast stream, the layout type and focus stream changes, based on calls
197
+ to the `OpenTok.setBroadcastLayout()` and `OpenTok.setStreamClassLists()` methods during
198
+ the broadcast.
199
+
200
+ For more information, see [Configuring video layout for OpenTok live streaming
201
+ broadcasts](https://tokbox.com/developer/guides/broadcast/live-streaming/#configuring-video-layout-for-opentok-live-streaming-broadcasts).
@@ -0,0 +1,97 @@
1
+ require 'sinatra/base'
2
+ require 'opentok'
3
+
4
+ raise "You must define API_KEY and API_SECRET environment variables" unless ENV.has_key?("API_KEY") && ENV.has_key?("API_SECRET")
5
+
6
+ class BroadcastSample < Sinatra::Base
7
+
8
+ set :api_key, ENV['API_KEY']
9
+ set :opentok, OpenTok::OpenTok.new(api_key, ENV['API_SECRET'])
10
+ set :session, opentok.create_session(:media_mode => :routed)
11
+ set :erb, :layout => :layout
12
+ set :broadcast_id, nil
13
+ set :focus_stream_id, ''
14
+ set :broadcast_layout, 'horizontalPresentation'
15
+
16
+ get '/' do
17
+ erb :index
18
+ end
19
+
20
+ get '/host' do
21
+ api_key = settings.api_key
22
+ session_id = settings.session.session_id
23
+ token = settings.opentok.generate_token(session_id, role: :publisher, initialLayoutClassList: ['focus'])
24
+
25
+ erb :host, locals: {
26
+ apiKey: api_key,
27
+ sessionId: session_id,
28
+ token: token,
29
+ initialBroadcastId: settings.broadcast_id,
30
+ focusStreamId: settings.focus_stream_id,
31
+ initialLayout: settings.broadcast_layout
32
+ }
33
+ end
34
+
35
+ get '/participant' do
36
+ api_key = settings.api_key
37
+ session_id = settings.session.session_id
38
+ token = settings.opentok.generate_token(session_id, role: :publisher)
39
+
40
+ erb :participant, locals: {
41
+ apiKey: api_key,
42
+ sessionId: session_id,
43
+ token: token,
44
+ focusStreamId: settings.focus_stream_id,
45
+ layout: settings.broadcast_layout
46
+ }
47
+ end
48
+
49
+ post '/start' do
50
+ opts = {
51
+ :maxDuration => params.key?("maxDuration") ? params[:maxDuration] : 7200,
52
+ :resolution => params[:resolution],
53
+ :layout => params[:layout],
54
+ :outputs => {
55
+ :hls => {}
56
+ }
57
+ }
58
+ broadcast = settings.opentok.broadcasts.create(settings.session.session_id, opts)
59
+ settings.broadcast_id = broadcast.id
60
+ body broadcast.to_json
61
+ end
62
+
63
+ get '/broadcast' do
64
+ return 'No broadcast id exists' if settings.broadcast_id.nil? || settings.broadcast_id.empty?
65
+ broadcast = settings.opentok.broadcasts.find settings.broadcast_id
66
+ redirect broadcast.broadcastUrls['hls'] if broadcast.status == 'started'
67
+ end
68
+
69
+ get '/stop/:broadcastId' do
70
+ broadcast = settings.opentok.broadcasts.stop settings.broadcast_id
71
+ settings.broadcast_id = nil
72
+ settings.focus_stream_id = ''
73
+ settings.broadcast_layout = 'horizontalPresentation'
74
+ body broadcast.to_json
75
+ end
76
+
77
+ post '/broadcast/:broadcastId/layout' do
78
+ layoutType = params[:type]
79
+ settings.opentok.broadcasts.layout(settings.broadcast_id, type: layoutType)
80
+ settings.broadcast_layout = layoutType
81
+ end
82
+
83
+ post '/focus' do
84
+ hash = { items: [] }
85
+ hash[:items] << { id: params[:focus], layoutClassList: ['focus'] }
86
+ settings.focus_stream_id = params[:focus]
87
+ if params.key?('otherStreams')
88
+ params[:otherStreams].each do |stream|
89
+ hash[:items] << { id: stream, layoutClassList: [] }
90
+ end
91
+ end
92
+ settings.opentok.streams.layout(settings.session.session_id, hash)
93
+ end
94
+
95
+ # start the server if ruby file executed directly
96
+ run! if app_file == $0
97
+ end