opentok 3.0.3 → 3.1.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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +249 -14
  3. data/lib/opentok/archive.rb +45 -4
  4. data/lib/opentok/archives.rb +62 -5
  5. data/lib/opentok/broadcast.rb +118 -0
  6. data/lib/opentok/broadcasts.rb +149 -0
  7. data/lib/opentok/client.rb +206 -3
  8. data/lib/opentok/connections.rb +28 -0
  9. data/lib/opentok/exceptions.rb +6 -0
  10. data/lib/opentok/opentok.rb +40 -8
  11. data/lib/opentok/session.rb +5 -0
  12. data/lib/opentok/signals.rb +47 -0
  13. data/lib/opentok/sip.rb +35 -0
  14. data/lib/opentok/stream.rb +46 -0
  15. data/lib/opentok/stream_list.rb +18 -0
  16. data/lib/opentok/streams.rb +79 -0
  17. data/lib/opentok/version.rb +1 -1
  18. data/spec/cassettes/OpenTok_Archives/calls_layout_on_archive_object.yml +45 -0
  19. data/spec/cassettes/OpenTok_Archives/changes_the_layout_of_an_archive.yml +36 -0
  20. data/spec/cassettes/OpenTok_Archives/should_create_hd_archives.yml +52 -0
  21. data/spec/cassettes/OpenTok_Broadcasts/calls_layout_on_broadcast_object.yml +55 -0
  22. data/spec/cassettes/OpenTok_Broadcasts/changes_the_layout_of_a_broadcast.yml +36 -0
  23. data/spec/cassettes/OpenTok_Broadcasts/fetches_a_hls_broadcast_url.yml +50 -0
  24. data/spec/cassettes/OpenTok_Broadcasts/finds_a_broadcast.yml +55 -0
  25. data/spec/cassettes/OpenTok_Broadcasts/starts_a_rtmp_broadcast.yml +59 -0
  26. data/spec/cassettes/OpenTok_Broadcasts/stops_a_broadcast.yml +45 -0
  27. data/spec/cassettes/OpenTok_Connections/forces_a_connection_to_be_terminated.yml +36 -0
  28. data/spec/cassettes/OpenTok_Signals/receives_a_valid_response_for_a_connection.yml +37 -0
  29. data/spec/cassettes/OpenTok_Signals/receives_a_valid_response_for_all_connections.yml +37 -0
  30. data/spec/cassettes/OpenTok_Streams/get_all_streams_information.yml +53 -0
  31. data/spec/cassettes/OpenTok_Streams/get_specific_stream_information.yml +42 -0
  32. data/spec/cassettes/OpenTok_Streams/layout_working_on_two_stream_list.yml +36 -0
  33. data/spec/opentok/archives_spec.rb +73 -0
  34. data/spec/opentok/broadcasts_spec.rb +171 -0
  35. data/spec/opentok/connection_spec.rb +38 -0
  36. data/spec/opentok/signal_spec.rb +50 -0
  37. data/spec/opentok/streams_spec.rb +75 -0
  38. metadata +48 -3
@@ -0,0 +1,118 @@
1
+ require "active_support/inflector"
2
+
3
+ module OpenTok
4
+ # Represents a live streaming broadcast of an OpenTok session.
5
+ # See {https://tokbox.com/developer/guides/broadcast/live-streaming/ Live streaming broadcasts}.
6
+ #
7
+ # @attr [string] id
8
+ # The broadcast ID.
9
+ #
10
+ # @attr [string] session_id
11
+ # The session ID of the OpenTok session associated with this broadcast.
12
+ #
13
+ # @attr [string] project_id
14
+ # The API key associated with the broadcast.
15
+ #
16
+ # @attr [int] created_at
17
+ # The time at which the broadcast was created, in milliseconds since the UNIX epoch.
18
+ #
19
+ # @attr [int] updated_at
20
+ # For this start method, this timestamp matches the createdAt timestamp.
21
+ #
22
+ # @attr [string] resolution
23
+ # The resolution of the broadcast: either "640x480" (SD, the default) or "1280x720" (HD). This property is optional.
24
+ #
25
+ # @attr [Hash] broadcastUrls is defined as follows:
26
+ # This object defines the types of broadcast streams you want to start (both HLS and RTMP).
27
+ # You can include HLS, RTMP, or both as broadcast streams. If you include RTMP streaming,
28
+ # you can specify up to five target RTMP streams (or just one).
29
+ # The (<code>:hls</code>) property is set to an empty [Hash] object. The HLS URL is returned in the response.
30
+ # The (<code>:rtmp</code>) property is set to an [Array] of Rtmp [Hash] properties.
31
+ # For each RTMP stream, specify (<code>:serverUrl</code>) for the RTMP server URL,
32
+ # (<code>:streamName</code>) such as the YouTube Live stream name or the Facebook stream key),
33
+ # and (optionally) (<code>:id</code>), a unique ID for the stream.
34
+ #
35
+ # @attr [string] status The status of the RTMP stream.
36
+ # * "connecting" -- The OpenTok platform is in the process of connecting to the remote RTMP server.
37
+ # This is the initial state, and it is the status if you start when there are no streams published in the session.
38
+ # It changes to "live" when there are streams (or it changes to one of the other states).
39
+ # * "live -- The OpenTok platform has successfully connected to the remote RTMP server, and the media is streaming.
40
+ # * "offline" -- The OpenTok platform could not connect to the remote RTMP server. This is due to an unreachable server or an error in the RTMP handshake. Causes include rejected RTMP connections, non-existing RTMP applications, rejected stream names, authentication errors, etc. Check that the server is online, and that you have provided the correct server URL and stream name.
41
+ # * "error" -- There is an error in the OpenTok platform.
42
+ class Broadcast
43
+
44
+ # @private
45
+ def initialize(interface, json)
46
+ @interface = interface
47
+ # TODO: validate json fits schema
48
+ @json = json
49
+ end
50
+
51
+ # A JSON-encoded string representation of the broadcast.
52
+ def to_json
53
+ @json.to_json
54
+ end
55
+
56
+ # Stops the OpenTok broadcast.
57
+ def stop
58
+ # TODO: validate returned json fits schema
59
+ @json = @interface.stop @json['id']
60
+ end
61
+
62
+ # Sets the layout of the OpenTok broadcast.
63
+ #
64
+ # You can dynamically change the layout type of a broadcast while it is being broadcast.
65
+ # For more information, see
66
+ # {https://tokbox.com/developer/guides/broadcast/live-streaming/#configuring-video-layout-for-opentok-live-streaming-broadcasts Configuring video layout for OpenTok live streaming broadcasts}.
67
+ #
68
+ # @option options [String] :type
69
+ # The layout type. Set this to "bestFit", "pip", "verticalPresentation",
70
+ # "horizontalPresentation", "focus", or "custom".
71
+ #
72
+ # @option options [String] :stylesheet
73
+ # The stylesheet for a custom layout. Set this parameter
74
+ # if you set <code>type</code> to <code>"custom"</code>. Otherwise, leave it undefined.
75
+ #
76
+ # @raise [OpenTokBroadcastError]
77
+ # The broadcast layout could not be updated.
78
+ #
79
+ # @raise [OpenTokAuthenticationError]
80
+ # Authentication failed. Invalid API key or secret.
81
+ #
82
+ # @raise [OpenTokError]
83
+ # OpenTok server error.
84
+ #
85
+ # @raise [ArgumentError]
86
+ # The broadcast_id or options parameter is empty.
87
+ #
88
+ # @raise [ArgumentError]
89
+ # The "custom" type was specified without a stylesheet option.
90
+ #
91
+ # @raise [ArgumentError]
92
+ # A stylesheet was passed in for a type other than custom. Or an invalid type was passed in.
93
+ #
94
+ # @raise [ArgumentError]
95
+ # An invalid layout type was passed in.
96
+ # Refer to {https://tokbox.com/developer/rest/#change_composed_archive_layout}
97
+
98
+ def layout(opts = {})
99
+ # TODO: validate returned json fits schema
100
+ @json = @interface.layout(@json['id'], opts)
101
+ end
102
+
103
+ # @private ignore
104
+ def method_missing(method, *args, &block)
105
+ camelized_method = method.to_s.camelize(:lower)
106
+ if @json.has_key? camelized_method and args.empty?
107
+ # TODO: convert create_time method call to a Time object
108
+ if camelized_method == 'outputMode'
109
+ @json[camelized_method].to_sym
110
+ else
111
+ @json[camelized_method]
112
+ end
113
+ else
114
+ super method, *args, &block
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,149 @@
1
+ require "opentok/client"
2
+ require "opentok/broadcast"
3
+
4
+
5
+ module OpenTok
6
+ # A class for working with OpenTok live streaming broadcasts.
7
+ # See {https://tokbox.com/developer/guides/broadcast/live-streaming/ Live streaming broadcasts}.
8
+ class Broadcasts
9
+
10
+ # @private
11
+ def initialize(client)
12
+ @client = client
13
+ end
14
+
15
+ # Starts a live streaming broadcast of an OpenTok session.
16
+ #
17
+ # Clients must be actively connected to the OpenTok session for you to successfully start
18
+ # a broadcast.
19
+ #
20
+ # This broadcasts the session to an HLS (HTTP live streaming) or to RTMP streams.
21
+ #
22
+ # @param [String] session_id The session ID of the OpenTok session to broadcast.
23
+ #
24
+ # @param [Hash] options A hash defining options for the broadcast.
25
+ # @option options [Hash] :layout Specify this to assign the initial layout for the broadcast.
26
+ # Valid values for the layout (<code>:type</code>) property are "bestFit" (best fit), "custom" (custom),
27
+ # "horizontalPresentation" (horizontal presentation), "pip" (picture-in-picture), and
28
+ # "verticalPresentation" (vertical presentation)).
29
+ # If you specify a (<code>:custom</code>) layout type, set the (<code>:stylesheet</code>) property of the layout object
30
+ # to the stylesheet. (For other layout types, do not set a stylesheet property.)
31
+ # If you do not specify an initial layout type, the broadcast stream uses the Best Fit layout type.
32
+ #
33
+ # @option options [int] maxDuration
34
+ # The maximum duration for the broadcast, in seconds. The broadcast will automatically stop when
35
+ # the maximum duration is reached. You can set the maximum duration to a value from 60 (60 seconds) to 36000 (10 hours).
36
+ # The default maximum duration is 2 hours (7200 seconds).
37
+ #
38
+ # @option options [Hash] outputs
39
+ # This object defines the types of broadcast streams you want to start (both HLS and RTMP).
40
+ # You can include HLS, RTMP, or both as broadcast streams. If you include RTMP streaming,
41
+ # you can specify up to five target RTMP streams (or just one).
42
+ # The (<code>:hls</code>) property is set to an empty [Hash] object. The HLS URL is returned in the response.
43
+ # The (<code>:rtmp</code>) property is set to an [Array] of Rtmp [Hash] properties.
44
+ # For each RTMP , specify (<code>:serverUrl</code>) for the RTMP server URL,
45
+ # (<code>:streamName</code>) such as the YouTube Live stream name or the Facebook stream key),
46
+ # and (optionally) (<code>:id</code>), a unique ID for the stream.
47
+ #
48
+ # @option options [string] resolution
49
+ # The resolution of the broadcast: either "640x480" (SD, the default) or "1280x720" (HD).
50
+ #
51
+ # @return [Broadcast] The broadcast object, which includes properties defining the broadcast,
52
+ # including the broadcast ID.
53
+ #
54
+ # @raise [OpenTokBroadcastError] The broadcast could not be started. The request was invalid or broadcast already started
55
+ # @raise [OpenTokAuthenticationError] Authentication failed while starting an archive.
56
+ # Invalid API key.
57
+ # @raise [OpenTokError] OpenTok server error.
58
+ def create(session_id, options = {})
59
+ raise ArgumentError, "session_id not provided" if session_id.to_s.empty?
60
+ raise ArgumentError, "options cannot be empty" if options.empty?
61
+ broadcast_json = @client.start_broadcast(session_id, options)
62
+ Broadcast.new self, broadcast_json
63
+ end
64
+
65
+ # Gets a Broadcast object for the given broadcast ID.
66
+ #
67
+ # @param [String] broadcast_id The broadcast ID.
68
+ #
69
+ # @return [Broadcast] The broadcast object, which includes properties defining the broadcast.
70
+ #
71
+ # @raise [OpenTokBroadcastError] No matching broadcast found.
72
+ # @raise [OpenTokAuthenticationError] Authentication failed.
73
+ # Invalid API key.
74
+ # @raise [OpenTokError] OpenTok server error.
75
+ def find(broadcast_id)
76
+ raise ArgumentError, "broadcast_id not provided" if broadcast_id.to_s.empty?
77
+ broadcast_json = @client.get_broadcast(broadcast_id.to_s)
78
+ Broadcast.new self, broadcast_json
79
+ end
80
+
81
+
82
+ # Stops an OpenTok broadcast
83
+ #
84
+ # Note that broadcasts automatically stop after 120 minute
85
+ #
86
+ # @param [String] broadcast_id The broadcast ID.
87
+ #
88
+ # @return [Broadcast] The broadcast object, which includes properties defining the broadcast.
89
+ #
90
+ # @raise [OpenTokBroadcastError] The broadcast could not be stopped. The request was invalid.
91
+ # @raise [OpenTokAuthenticationError] Authentication failed.
92
+ # Invalid API key.
93
+ # @raise [OpenTokError] OpenTok server error.
94
+ def stop(broadcast_id)
95
+ raise ArgumentError, "broadcast_id not provided" if broadcast_id.to_s.empty?
96
+ broadcast_json = @client.stop_broadcast(broadcast_id)
97
+ Broadcast.new self, broadcast_json
98
+ end
99
+
100
+ # Dynamically alters the layout an OpenTok broadcast. For more information, see
101
+ # For more information, see
102
+ # {https://tokbox.com/developer/guides/broadcast/live-streaming/#configuring-video-layout-for-opentok-live-streaming-broadcasts Configuring video layout for OpenTok live streaming broadcasts}.
103
+ #
104
+ # @param [String] broadcast_id
105
+ # The broadcast ID.
106
+ #
107
+ # @option options [String] :type
108
+ # The layout type. Set this to "bestFit", "pip", "verticalPresentation",
109
+ # "horizontalPresentation", "focus", or "custom".
110
+ #
111
+ # @option options [String] :stylesheet
112
+ # The stylesheet for a custom layout. Set this parameter
113
+ # if you set <code>type</code> to <code>"custom"</code>. Otherwise, leave it undefined.
114
+ #
115
+ # @raise [OpenTokBroadcastError]
116
+ # The broadcast layout could not be updated.
117
+ #
118
+ # @raise [OpenTokAuthenticationError]
119
+ # Authentication failed. Invalid API key or secret.
120
+ #
121
+ # @raise [OpenTokError]
122
+ # OpenTok server error.
123
+ #
124
+ # @raise [ArgumentError]
125
+ # The broadcast_id or options parameter is empty.
126
+ #
127
+ # @raise [ArgumentError]
128
+ # The "custom" type was specified without a stylesheet option.
129
+ #
130
+ # @raise [ArgumentError]
131
+ # A stylesheet was passed in for a type other than custom. Or an invalid type was passed in.
132
+ #
133
+ # @raise [ArgumentError]
134
+ # An invalid layout type was passed in.
135
+ def layout(broadcast_id, options = {})
136
+ raise ArgumentError, "option parameter is empty" if options.empty?
137
+ raise ArgumentError, "broadcast_id not provided" if broadcast_id.to_s.empty?
138
+ type = options[:type]
139
+ raise ArgumentError, "custom type must have a stylesheet" if (type.eql? "custom") && (!options.key? :stylesheet)
140
+ valid_non_custom_type = ["bestFit","horizontalPresentation","pip", "verticalPresentation", ""].include? type
141
+ raise ArgumentError, "type is not valid" if !valid_non_custom_type
142
+ raise ArgumentError, "stylesheet not needed" if valid_non_custom_type and options.key? :stylesheet
143
+ response = @client.layout_broadcast(broadcast_id, options)
144
+ (200..300).include? response.code
145
+ end
146
+
147
+
148
+ end
149
+ end
@@ -164,6 +164,72 @@ module OpenTok
164
164
  raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
165
165
  end
166
166
 
167
+ def layout_archive(archive_id, opts)
168
+ opts.extend(HashExtensions)
169
+ response = self.class.put("/v2/project/#{@api_key}/archive/#{archive_id}/layout", {
170
+ :body => opts.camelize_keys!.to_json,
171
+ :headers => generate_headers("Content-Type" => "application/json")
172
+ })
173
+ case response.code
174
+ when 200
175
+ response
176
+ when 400
177
+ raise OpenTokArchiveError, "Setting the layout failed. The request was invalid or invalid layout options were given."
178
+ when 403
179
+ raise OpenTokAuthenticationError, "Authentication failed. API Key: #{@api_key}"
180
+ when 500
181
+ raise OpenTokError, "Setting the layout failed. OpenTok server error."
182
+ else
183
+ raise OpenTokArchiveError, "Setting the layout failed."
184
+ end
185
+ rescue StandardError => e
186
+ raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
187
+ end
188
+
189
+ def forceDisconnect(session_id, connection_id)
190
+ response = self.class.delete("/v2/project/#{@api_key}/session/#{session_id}/connection/#{connection_id}", {
191
+ :headers => generate_headers("Content-Type" => "application/json")
192
+ })
193
+ case response.code
194
+ when 204
195
+ response
196
+ when 400
197
+ raise ArgumentError, "Force disconnect failed. Connection ID #{connection_id} or Session ID #{session_id} is invalid"
198
+ when 403
199
+ raise OpenTokAuthenticationError, "You are not authorized to forceDisconnect, check your authentication credentials or token type is non-moderator"
200
+ when 404
201
+ raise OpenTokConnectionError, "The client specified by the connection ID: #{connection_id} is not connected to the session"
202
+ end
203
+ rescue StandardError => e
204
+ raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
205
+ end
206
+
207
+ def signal(session_id, connection_id, opts)
208
+ opts.extend(HashExtensions)
209
+ connectionPath = connection_id.to_s.empty? ? "" : "/connection/#{connection_id}"
210
+ url = "/v2/project/#{@api_key}/session/#{session_id}#{connectionPath}/signal"
211
+ response = self.class.post(url, {
212
+ :body => opts.camelize_keys!.to_json,
213
+ :headers => generate_headers("Content-Type" => "application/json")
214
+ })
215
+ case response.code
216
+ when 204
217
+ response
218
+ when 400
219
+ raise ArgumentError, "One of the signal properties — data, type, sessionId or connectionId — is invalid."
220
+ when 403
221
+ raise OpenTokAuthenticationError, "You are not authorized to send the signal. Check your authentication credentials."
222
+ when 404
223
+ raise OpenTokError, "The client specified by the connectionId property is not connected to the session."
224
+ when 413
225
+ raise OpenTokError, "The type string exceeds the maximum length (128 bytes), or the data string exceeds the maximum size (8 kB)."
226
+ else
227
+ raise OpenTokError, "The signal could not be send."
228
+ end
229
+ rescue StandardError => e
230
+ raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
231
+ end
232
+
167
233
  def dial(session_id, token, sip_uri, opts)
168
234
  opts.extend(HashExtensions)
169
235
  body = { "sessionId" => session_id,
@@ -179,14 +245,151 @@ module OpenTok
179
245
  when 200
180
246
  response
181
247
  when 403
182
- raise OpenTokAuthenticationError, "Authentication failed while dialing a sip session. API Key: #{@api_key}"
248
+ raise OpenTokAuthenticationError, "Authentication failed while dialing a SIP session. API Key: #{@api_key}"
183
249
  when 404
184
- raise OpenTokSipError, "The sip session could not be dialed. The Session ID does not exist: #{session_id}"
250
+ raise OpenTokSipError, "The SIP session could not be dialed. The Session ID does not exist: #{session_id}"
185
251
  else
186
- raise OpenTokSipError, "The sip session could not be dialed"
252
+ raise OpenTokSipError, "The SIP session could not be dialed"
187
253
  end
188
254
  rescue StandardError => e
189
255
  raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
190
256
  end
257
+
258
+ def info_stream(session_id, stream_id)
259
+ streamId = stream_id.to_s.empty? ? '' : "/#{stream_id}"
260
+ url = "/v2/project/#{@api_key}/session/#{session_id}/stream#{streamId}"
261
+ response = self.class.get(url,
262
+ headers: generate_headers('Content-Type' => 'application/json'))
263
+ case response.code
264
+ when 200
265
+ response
266
+ when 400
267
+ raise ArgumentError, 'Invalid request. You did not pass in a valid session ID or stream ID.'
268
+ when 403
269
+ raise OpenTokAuthenticationError, 'Check your authentication credentials. You passed in an invalid OpenTok API key.'
270
+ when 408
271
+ raise ArgumentError, 'You passed in an invalid stream ID.'
272
+ when 500
273
+ raise OpenTokError, 'OpenTok server error.'
274
+ else
275
+ raise OpenTokError, 'Could not fetch the stream information.'
276
+ end
277
+ rescue StandardError => e
278
+ raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
279
+ end
280
+
281
+ def layout_streams(session_id, opts)
282
+ opts.extend(HashExtensions)
283
+ response = self.class.put("/v2/project/#{@api_key}/session/#{session_id}/stream", {
284
+ :body => opts.camelize_keys!.to_json,
285
+ :headers => generate_headers("Content-Type" => "application/json")
286
+ })
287
+ case response.code
288
+ when 200
289
+ response
290
+ when 400
291
+ raise OpenTokStreamLayoutError, "Setting the layout failed. The request was invalid or invalid layout options were given."
292
+ when 403
293
+ raise OpenTokAuthenticationError, "Authentication failed. API Key: #{@api_key}"
294
+ when 500
295
+ raise OpenTokError, "Setting the layout failed. OpenTok server error."
296
+ else
297
+ raise OpenTokStreamLayoutError, "Setting the layout failed."
298
+ end
299
+ rescue StandardError => e
300
+ raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
301
+ end
302
+
303
+ def start_broadcast(session_id, opts)
304
+ opts.extend(HashExtensions)
305
+ body = { :sessionId => session_id }.merge(opts.camelize_keys!)
306
+ response = self.class.post("/v2/project/#{@api_key}/broadcast", {
307
+ :body => body.to_json,
308
+ :headers => generate_headers("Content-Type" => "application/json")
309
+ })
310
+ case response.code
311
+ when 200
312
+ response
313
+ when 400
314
+ raise OpenTokBroadcastError, "The broadcast could not be started. The request was invalid or invalid layout options or exceeded the limit of five simultaneous RTMP streams."
315
+ when 403
316
+ raise OpenTokAuthenticationError, "Authentication failed while starting a broadcast. API Key: #{@api_key}"
317
+ when 409
318
+ raise OpenTokBroadcastError, "The broadcast has already been started for this session."
319
+ when 500
320
+ raise OpenTokError, "OpenTok server error."
321
+ else
322
+ raise OpenTokBroadcastError, "The broadcast could not be started"
323
+ end
324
+ rescue StandardError => e
325
+ raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
326
+ end
327
+
328
+ def get_broadcast(broadcast_id)
329
+ response = self.class.get("/v2/project/#{@api_key}/broadcast/#{broadcast_id}", {
330
+ :headers => generate_headers
331
+ })
332
+ case response.code
333
+ when 200
334
+ response
335
+ when 400
336
+ raise OpenTokBroadcastError, "The request was invalid."
337
+ when 403
338
+ raise OpenTokAuthenticationError, "Authentication failed while getting a broadcast. API Key: #{@api_key}"
339
+ when 404
340
+ raise OpenTokBroadcastError, "No matching broadcast found (with the specified ID)"
341
+ when 500
342
+ raise OpenTokError, "OpenTok server error."
343
+ else
344
+ raise OpenTokBroadcastError, "Could not fetch broadcast information."
345
+ end
346
+ rescue StandardError => e
347
+ raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
348
+ end
349
+
350
+ def stop_broadcast(broadcast_id)
351
+ response = self.class.post("/v2/project/#{@api_key}/broadcast/#{broadcast_id}/stop", {
352
+ :headers => generate_headers
353
+ })
354
+ case response.code
355
+ when 200
356
+ response
357
+ when 400
358
+ raise OpenTokBroadcastError, "The request was invalid."
359
+ when 403
360
+ raise OpenTokAuthenticationError, "Authentication failed while stopping a broadcast. API Key: #{@api_key}"
361
+ when 404
362
+ raise OpenTokBroadcastError, "No matching broadcast found (with the specified ID) or it is already stopped"
363
+ when 500
364
+ raise OpenTokError, "OpenTok server error."
365
+ else
366
+ raise OpenTokBroadcastError, "The broadcast could not be stopped."
367
+ end
368
+ rescue StandardError => e
369
+ raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
370
+ end
371
+
372
+ def layout_broadcast(broadcast_id, opts)
373
+ opts.extend(HashExtensions)
374
+ response = self.class.put("/v2/project/#{@api_key}/broadcast/#{broadcast_id}/layout", {
375
+ :body => opts.camelize_keys!.to_json,
376
+ :headers => generate_headers("Content-Type" => "application/json")
377
+ })
378
+ case response.code
379
+ when 200
380
+ response
381
+ when 400
382
+ raise OpenTokBroadcastError, "The layout operation could not be performed. The request was invalid or invalid layout options."
383
+ when 403
384
+ raise OpenTokAuthenticationError, "Authentication failed for broadcast layout. API Key: #{@api_key}"
385
+ when 500
386
+ raise OpenTokError, "OpenTok server error."
387
+ else
388
+ raise OpenTokBroadcastError, "The broadcast layout could not be performed."
389
+ end
390
+ rescue StandardError => e
391
+ raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
392
+ end
393
+
191
394
  end
192
395
  end