opentok 3.1.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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