opentok 4.1.0 → 4.5.1
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +30 -0
- data/.github/workflows/metrics.yml +17 -0
- data/CHANGES.md +171 -0
- data/README.md +62 -38
- data/lib/opentok/archive.rb +54 -4
- data/lib/opentok/archives.rb +115 -11
- data/lib/opentok/broadcast.rb +50 -3
- data/lib/opentok/broadcast_list.rb +14 -0
- data/lib/opentok/broadcasts.rb +178 -19
- data/lib/opentok/client.rb +251 -0
- data/lib/opentok/connections.rb +1 -1
- data/lib/opentok/constants.rb +1 -0
- data/lib/opentok/exceptions.rb +3 -1
- data/lib/opentok/opentok.rb +16 -10
- data/lib/opentok/render.rb +78 -0
- data/lib/opentok/render_list.rb +14 -0
- data/lib/opentok/renders.rb +101 -0
- data/lib/opentok/session.rb +4 -4
- data/lib/opentok/sip.rb +40 -2
- data/lib/opentok/streams.rb +49 -2
- data/lib/opentok/token_generator.rb +1 -0
- data/lib/opentok/version.rb +1 -1
- data/opentok.gemspec +2 -1
- data/sample/Broadcast/README.md +42 -0
- data/sample/Broadcast/broadcast_sample.rb +15 -0
- data/sample/Broadcast/views/all.erb +46 -0
- data/sample/Broadcast/views/index.erb +16 -1
- data/spec/cassettes/OpenTok_Archives/adds_a_stream_to_an_archive.yml +37 -0
- data/spec/cassettes/OpenTok_Archives/removes_a_stream_from_an_archive.yml +37 -0
- data/spec/cassettes/OpenTok_Archives/should_create_an_archive_with_matching_multi_archive_tag_when_multiArchiveTag_is_specified.yml +50 -0
- data/spec/cassettes/OpenTok_Archives/should_create_an_archive_with_multi_archive_tag_value_of_nil_when_multiArchiveTag_not_specified.yml +49 -0
- data/spec/cassettes/OpenTok_Archives/should_create_an_archives_with_a_specified_multiArchiveTag.yml +52 -0
- data/spec/cassettes/OpenTok_Archives/should_create_layout_archives_with_screenshare_layout_types.yml +50 -0
- data/spec/cassettes/OpenTok_Broadcasts/adds_a_stream_to_a_broadcast.yml +37 -0
- data/spec/cassettes/OpenTok_Broadcasts/for_many_broadcasts/should_return_all_broadcasts.yml +192 -0
- data/spec/cassettes/OpenTok_Broadcasts/for_many_broadcasts/should_return_broadcasts_with_an_offset.yml +117 -0
- data/spec/cassettes/OpenTok_Broadcasts/for_many_broadcasts/should_return_count_number_of_broadcasts.yml +92 -0
- data/spec/cassettes/OpenTok_Broadcasts/for_many_broadcasts/should_return_part_of_the_broadcasts_when_using_offset_and_count.yml +142 -0
- data/spec/cassettes/OpenTok_Broadcasts/for_many_broadcasts/should_return_session_broadcasts.yml +117 -0
- data/spec/cassettes/OpenTok_Broadcasts/removes_a_stream_from_a_broadcast.yml +37 -0
- data/spec/cassettes/OpenTok_Broadcasts/starts_a_broadcast_with_a_matching_multi_broadcast_tag_value_when_multiBroadcastTag_is_specified.yml +54 -0
- data/spec/cassettes/OpenTok_Broadcasts/starts_a_broadcast_with_a_multi_broadcast_tag_value_of_nil_when_multiBroadcastTag_not_specified.yml +53 -0
- data/spec/cassettes/OpenTok_Broadcasts/starts_a_broadcast_with_a_specified_multiBroadcastTag.yml +54 -0
- data/spec/cassettes/OpenTok_Renders/finds_an_Experience_Composer_render.yml +46 -0
- data/spec/cassettes/OpenTok_Renders/for_many_renders/should_return_all_renders.yml +108 -0
- data/spec/cassettes/OpenTok_Renders/for_many_renders/should_return_count_number_of_renders.yml +63 -0
- data/spec/cassettes/OpenTok_Renders/for_many_renders/should_return_part_of_the_renders_when_using_offset_and_count.yml +63 -0
- data/spec/cassettes/OpenTok_Renders/for_many_renders/should_return_renders_with_an_offset.yml +74 -0
- data/spec/cassettes/OpenTok_Renders/starts_an_Experience_Composer_render.yml +48 -0
- data/spec/cassettes/OpenTok_Renders/stops_an_Experience_Composer_render.yml +28 -0
- data/spec/cassettes/OpenTok_Sip/_play_dtmf_to_connection/returns_a_200_response_code_when_passed_a_valid_dtmf_digit_string.yml +39 -0
- data/spec/cassettes/OpenTok_Sip/_play_dtmf_to_session/returns_a_200_response_code_when_passed_a_valid_dtmf_digit_string.yml +39 -0
- data/spec/cassettes/OpenTok_Sip/receives_a_valid_response.yml +2 -2
- data/spec/cassettes/OpenTok_Streams/disables_the_mute_state_of_a_session.yml +37 -0
- data/spec/cassettes/OpenTok_Streams/forces_all_current_and_future_streams_in_a_session_to_be_muted.yml +39 -0
- data/spec/cassettes/OpenTok_Streams/forces_all_current_and_future_streams_in_a_session_to_be_muted_except_specified_excluded_streams.yml +39 -0
- data/spec/cassettes/OpenTok_Streams/forces_the_specified_stream_to_be_muted.yml +39 -0
- data/spec/opentok/archives_spec.rb +61 -0
- data/spec/opentok/broadcasts_spec.rb +157 -1
- data/spec/opentok/connection_spec.rb +1 -1
- data/spec/opentok/opentok_spec.rb +6 -0
- data/spec/opentok/renders_spec.rb +142 -0
- data/spec/opentok/sip_spec.rb +32 -1
- data/spec/opentok/streams_spec.rb +21 -1
- metadata +75 -7
- data/.travis.yml +0 -17
data/lib/opentok/client.rb
CHANGED
@@ -188,6 +188,33 @@ module OpenTok
|
|
188
188
|
raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
|
189
189
|
end
|
190
190
|
|
191
|
+
def select_streams_for_archive(archive_id, opts)
|
192
|
+
opts.extend(HashExtensions)
|
193
|
+
body = opts.camelize_keys!
|
194
|
+
response = self.class.patch("/v2/project/#{@api_key}/archive/#{archive_id}/streams", {
|
195
|
+
:body => body.to_json,
|
196
|
+
:headers => generate_headers("Content-Type" => "application/json")
|
197
|
+
})
|
198
|
+
case response.code
|
199
|
+
when 204
|
200
|
+
response
|
201
|
+
when 400
|
202
|
+
raise OpenTokArchiveError, "The request was invalid."
|
203
|
+
when 403
|
204
|
+
raise OpenTokAuthenticationError, "Authentication failed. API Key: #{@api_key}"
|
205
|
+
when 404
|
206
|
+
raise OpenTokArchiveError, "No matching archive found with the specified ID: #{archive_id}"
|
207
|
+
when 405
|
208
|
+
raise OpenTokArchiveError, "The archive was started with streamMode set to 'auto', which does not support stream manipulation."
|
209
|
+
when 500
|
210
|
+
raise OpenTokError, "OpenTok server error."
|
211
|
+
else
|
212
|
+
raise OpenTokArchiveError, "The archive streams could not be updated."
|
213
|
+
end
|
214
|
+
rescue StandardError => e
|
215
|
+
raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
|
216
|
+
end
|
217
|
+
|
191
218
|
def forceDisconnect(session_id, connection_id)
|
192
219
|
response = self.class.delete("/v2/project/#{@api_key}/session/#{session_id}/connection/#{connection_id}", {
|
193
220
|
:headers => generate_headers("Content-Type" => "application/json")
|
@@ -206,6 +233,45 @@ module OpenTok
|
|
206
233
|
raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
|
207
234
|
end
|
208
235
|
|
236
|
+
def force_mute_stream(session_id, stream_id)
|
237
|
+
response = self.class.post("/v2/project/#{@api_key}/session/#{session_id}/stream/#{stream_id}/mute", {
|
238
|
+
:headers => generate_headers("Content-Type" => "application/json")
|
239
|
+
})
|
240
|
+
case response.code
|
241
|
+
when 200
|
242
|
+
response
|
243
|
+
when 400
|
244
|
+
raise ArgumentError, "Force mute failed. Stream ID #{stream_id} or Session ID #{session_id} is invalid"
|
245
|
+
when 403
|
246
|
+
raise OpenTokAuthenticationError, "Authentication failed. API Key: #{@api_key}"
|
247
|
+
when 404
|
248
|
+
raise OpenTokConnectionError, "Either Stream ID #{stream_id} or Session ID #{session_id} is invalid"
|
249
|
+
end
|
250
|
+
rescue StandardError => e
|
251
|
+
raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
|
252
|
+
end
|
253
|
+
|
254
|
+
def force_mute_session(session_id, opts)
|
255
|
+
opts.extend(HashExtensions)
|
256
|
+
body = opts.camelize_keys!
|
257
|
+
response = self.class.post("/v2/project/#{@api_key}/session/#{session_id}/mute", {
|
258
|
+
:body => body.to_json,
|
259
|
+
:headers => generate_headers("Content-Type" => "application/json")
|
260
|
+
})
|
261
|
+
case response.code
|
262
|
+
when 200
|
263
|
+
response
|
264
|
+
when 400
|
265
|
+
raise ArgumentError, "Force mute failed. The request could not be processed due to a bad request"
|
266
|
+
when 403
|
267
|
+
raise OpenTokAuthenticationError, "Authentication failed. API Key: #{@api_key}"
|
268
|
+
when 404
|
269
|
+
raise OpenTokConnectionError, "Session ID #{session_id} is invalid"
|
270
|
+
end
|
271
|
+
rescue StandardError => e
|
272
|
+
raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
|
273
|
+
end
|
274
|
+
|
209
275
|
def signal(session_id, connection_id, opts)
|
210
276
|
opts.extend(HashExtensions)
|
211
277
|
connectionPath = connection_id.to_s.empty? ? "" : "/connection/#{connection_id}"
|
@@ -257,6 +323,52 @@ module OpenTok
|
|
257
323
|
raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
|
258
324
|
end
|
259
325
|
|
326
|
+
def play_dtmf_to_connection(session_id, connection_id, dtmf_digits)
|
327
|
+
body = { "digits" => dtmf_digits }
|
328
|
+
|
329
|
+
response = self.class.post("/v2/project/#{@api_key}/session/#{session_id}/connection/#{connection_id}/play-dtmf", {
|
330
|
+
:body => body.to_json,
|
331
|
+
:headers => generate_headers("Content-Type" => "application/json")
|
332
|
+
})
|
333
|
+
case response.code
|
334
|
+
when 200
|
335
|
+
response
|
336
|
+
when 400
|
337
|
+
raise ArgumentError, "One of the properties — dtmf_digits #{dtmf_digits} or session_id #{session_id} — is invalid."
|
338
|
+
when 403
|
339
|
+
raise OpenTokAuthenticationError, "Authentication failed. This can occur if you use an invalid OpenTok API key or an invalid JSON web token. API Key: #{@api_key}"
|
340
|
+
when 404
|
341
|
+
raise OpenTokError, "The specified session #{session_id} does not exist or the client specified by the #{connection_id} property is not connected to the session."
|
342
|
+
else
|
343
|
+
raise OpenTokError, "An error occurred when attempting to play DTMF digits to the session"
|
344
|
+
end
|
345
|
+
rescue StandardError => e
|
346
|
+
raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
|
347
|
+
end
|
348
|
+
|
349
|
+
def play_dtmf_to_session(session_id, dtmf_digits)
|
350
|
+
body = { "digits" => dtmf_digits }
|
351
|
+
|
352
|
+
response = self.class.post("/v2/project/#{@api_key}/session/#{session_id}/play-dtmf", {
|
353
|
+
:body => body.to_json,
|
354
|
+
:headers => generate_headers("Content-Type" => "application/json")
|
355
|
+
})
|
356
|
+
case response.code
|
357
|
+
when 200
|
358
|
+
response
|
359
|
+
when 400
|
360
|
+
raise ArgumentError, "One of the properties — dtmf_digits #{dtmf_digits} or session_id #{session_id} — is invalid."
|
361
|
+
when 403
|
362
|
+
raise OpenTokAuthenticationError, "Authentication failed. This can occur if you use an invalid OpenTok API key or an invalid JSON web token. API Key: #{@api_key}"
|
363
|
+
when 404
|
364
|
+
raise OpenTokError, "The specified session does not exist. Session ID: #{session_id}"
|
365
|
+
else
|
366
|
+
raise OpenTokError, "An error occurred when attempting to play DTMF digits to the session"
|
367
|
+
end
|
368
|
+
rescue StandardError => e
|
369
|
+
raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
|
370
|
+
end
|
371
|
+
|
260
372
|
def info_stream(session_id, stream_id)
|
261
373
|
streamId = stream_id.to_s.empty? ? '' : "/#{stream_id}"
|
262
374
|
url = "/v2/project/#{@api_key}/session/#{session_id}/stream#{streamId}"
|
@@ -371,6 +483,28 @@ module OpenTok
|
|
371
483
|
raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
|
372
484
|
end
|
373
485
|
|
486
|
+
def list_broadcasts(offset, count, session_id)
|
487
|
+
query = Hash.new
|
488
|
+
query[:offset] = offset unless offset.nil?
|
489
|
+
query[:count] = count unless count.nil?
|
490
|
+
query[:sessionId] = session_id unless session_id.nil?
|
491
|
+
response = self.class.get("/v2/project/#{@api_key}/broadcast", {
|
492
|
+
:query => query.empty? ? nil : query,
|
493
|
+
:headers => generate_headers,
|
494
|
+
})
|
495
|
+
case response.code
|
496
|
+
when 200
|
497
|
+
response
|
498
|
+
when 403
|
499
|
+
raise OpenTokAuthenticationError,
|
500
|
+
"Authentication failed while retrieving broadcasts. API Key: #{@api_key}"
|
501
|
+
else
|
502
|
+
raise OpenTokBroadcastError, "The broadcasts could not be retrieved."
|
503
|
+
end
|
504
|
+
rescue StandardError => e
|
505
|
+
raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
|
506
|
+
end
|
507
|
+
|
374
508
|
def layout_broadcast(broadcast_id, opts)
|
375
509
|
opts.extend(HashExtensions)
|
376
510
|
response = self.class.put("/v2/project/#{@api_key}/broadcast/#{broadcast_id}/layout", {
|
@@ -393,5 +527,122 @@ module OpenTok
|
|
393
527
|
raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
|
394
528
|
end
|
395
529
|
|
530
|
+
def select_streams_for_broadcast(broadcast_id, opts)
|
531
|
+
opts.extend(HashExtensions)
|
532
|
+
body = opts.camelize_keys!
|
533
|
+
response = self.class.patch("/v2/project/#{@api_key}/broadcast/#{broadcast_id}/streams", {
|
534
|
+
:body => body.to_json,
|
535
|
+
:headers => generate_headers("Content-Type" => "application/json")
|
536
|
+
})
|
537
|
+
case response.code
|
538
|
+
when 204
|
539
|
+
response
|
540
|
+
when 400
|
541
|
+
raise OpenTokBroadcastError, "The request was invalid."
|
542
|
+
when 403
|
543
|
+
raise OpenTokAuthenticationError, "Authentication failed. API Key: #{@api_key}"
|
544
|
+
when 404
|
545
|
+
raise OpenTokBroadcastError, "No matching broadcast found with the specified ID: #{broadcast_id}"
|
546
|
+
when 405
|
547
|
+
raise OpenTokBroadcastError, "The broadcast was started with streamMode set to 'auto', which does not support stream manipulation."
|
548
|
+
when 500
|
549
|
+
raise OpenTokError, "OpenTok server error."
|
550
|
+
else
|
551
|
+
raise OpenTokBroadcastError, "The broadcast streams could not be updated."
|
552
|
+
end
|
553
|
+
rescue StandardError => e
|
554
|
+
raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
|
555
|
+
end
|
556
|
+
|
557
|
+
def start_render(session_id, opts)
|
558
|
+
opts.extend(HashExtensions)
|
559
|
+
body = { :sessionId => session_id }.merge(opts.camelize_keys!)
|
560
|
+
response = self.class.post("/v2/project/#{@api_key}/render", {
|
561
|
+
:body => body.to_json,
|
562
|
+
:headers => generate_headers("Content-Type" => "application/json")
|
563
|
+
})
|
564
|
+
case response.code
|
565
|
+
when 202
|
566
|
+
response
|
567
|
+
when 400
|
568
|
+
raise OpenTokRenderError, "The render could not be started. The request was invalid."
|
569
|
+
when 403
|
570
|
+
raise OpenTokAuthenticationError, "Authentication failed while starting a render. API Key: #{@api_key}"
|
571
|
+
when 500
|
572
|
+
raise OpenTokError, "OpenTok server error."
|
573
|
+
else
|
574
|
+
raise OpenTokRenderError, "The render could not be started"
|
575
|
+
end
|
576
|
+
rescue StandardError => e
|
577
|
+
raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
|
578
|
+
end
|
579
|
+
|
580
|
+
def get_render(render_id)
|
581
|
+
response = self.class.get("/v2/project/#{@api_key}/render/#{render_id}", {
|
582
|
+
:headers => generate_headers
|
583
|
+
})
|
584
|
+
case response.code
|
585
|
+
when 200
|
586
|
+
response
|
587
|
+
when 400
|
588
|
+
raise OpenTokRenderError, "The request was invalid."
|
589
|
+
when 403
|
590
|
+
raise OpenTokAuthenticationError, "Authentication failed while getting a render. API Key: #{@api_key}"
|
591
|
+
when 404
|
592
|
+
raise OpenTokRenderError, "No matching render found (with the specified ID)"
|
593
|
+
when 500
|
594
|
+
raise OpenTokError, "OpenTok server error."
|
595
|
+
else
|
596
|
+
raise OpenTokRenderError, "Could not fetch render information."
|
597
|
+
end
|
598
|
+
rescue StandardError => e
|
599
|
+
raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
|
600
|
+
end
|
601
|
+
|
602
|
+
def stop_render(render_id)
|
603
|
+
response = self.class.delete("/v2/project/#{@api_key}/render/#{render_id}", {
|
604
|
+
:headers => generate_headers
|
605
|
+
})
|
606
|
+
case response.code
|
607
|
+
when 204
|
608
|
+
response
|
609
|
+
when 400
|
610
|
+
raise OpenTokRenderError, "The request was invalid."
|
611
|
+
when 403
|
612
|
+
raise OpenTokAuthenticationError, "Authentication failed while stopping a render. API Key: #{@api_key}"
|
613
|
+
when 404
|
614
|
+
raise OpenTokRenderError, "No matching render found (with the specified ID) or it is already stopped"
|
615
|
+
when 500
|
616
|
+
raise OpenTokError, "OpenTok server error."
|
617
|
+
else
|
618
|
+
raise OpenTokRenderError, "The render could not be stopped."
|
619
|
+
end
|
620
|
+
rescue StandardError => e
|
621
|
+
raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
|
622
|
+
end
|
623
|
+
|
624
|
+
def list_renders(offset, count)
|
625
|
+
query = Hash.new
|
626
|
+
query[:offset] = offset unless offset.nil?
|
627
|
+
query[:count] = count unless count.nil?
|
628
|
+
response = self.class.get("/v2/project/#{@api_key}/render", {
|
629
|
+
:query => query.empty? ? nil : query,
|
630
|
+
:headers => generate_headers,
|
631
|
+
})
|
632
|
+
case response.code
|
633
|
+
when 200
|
634
|
+
response
|
635
|
+
when 403
|
636
|
+
raise OpenTokAuthenticationError,
|
637
|
+
"Authentication failed while retrieving renders. API Key: #{@api_key}"
|
638
|
+
when 500
|
639
|
+
raise OpenTokError, "OpenTok server error."
|
640
|
+
else
|
641
|
+
raise OpenTokRenderError, "The renders could not be retrieved."
|
642
|
+
end
|
643
|
+
rescue StandardError => e
|
644
|
+
raise OpenTokError, "Failed to connect to OpenTok. Response code: #{e.message}"
|
645
|
+
end
|
646
|
+
|
396
647
|
end
|
397
648
|
end
|
data/lib/opentok/connections.rb
CHANGED
data/lib/opentok/constants.rb
CHANGED
data/lib/opentok/exceptions.rb
CHANGED
@@ -14,5 +14,7 @@ module OpenTok
|
|
14
14
|
class OpenTokStreamLayoutError < OpenTokError; end
|
15
15
|
# Defines errors raised when you perform Broadcast operations.
|
16
16
|
class OpenTokBroadcastError < OpenTokError; end
|
17
|
-
|
17
|
+
# Defines errors raised when you perform Experience Composer render operations.
|
18
|
+
class OpenTokRenderError < OpenTokError; end
|
19
|
+
|
18
20
|
end
|
data/lib/opentok/opentok.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require "resolv"
|
2
|
+
require "set"
|
3
|
+
|
1
4
|
require "opentok/constants"
|
2
5
|
require "opentok/session"
|
3
6
|
require "opentok/client"
|
@@ -8,9 +11,7 @@ require "opentok/sip"
|
|
8
11
|
require "opentok/streams"
|
9
12
|
require "opentok/signals"
|
10
13
|
require "opentok/broadcasts"
|
11
|
-
|
12
|
-
require "resolv"
|
13
|
-
require "set"
|
14
|
+
require "opentok/renders"
|
14
15
|
|
15
16
|
module OpenTok
|
16
17
|
# Contains methods for creating OpenTok sessions and generating tokens. It also includes
|
@@ -42,9 +43,9 @@ module OpenTok
|
|
42
43
|
# streams, and signal. (This is the default value if you do not specify a role.)
|
43
44
|
#
|
44
45
|
# * <code>:moderator</code> -- In addition to the privileges granted to a
|
45
|
-
# publisher,
|
46
|
-
#
|
47
|
-
#
|
46
|
+
# publisher, a moderator can perform moderation functions, such as forcing clients
|
47
|
+
# to disconnect, to stop publishing streams, or to mute audio in published streams. See the
|
48
|
+
# {https://tokbox.com/developer/guides/moderation/ Moderation developer guide}.
|
48
49
|
# @option options [integer] :expire_time The expiration time, in seconds since the UNIX epoch.
|
49
50
|
# Pass in 0 to use the default expiration time of 24 hours after the token creation time.
|
50
51
|
# The maximum expiration time is 30 days after the creation time.
|
@@ -77,8 +78,8 @@ module OpenTok
|
|
77
78
|
# @param [String] api_key The OpenTok API key for your
|
78
79
|
# {https://tokbox.com/account OpenTok project}.
|
79
80
|
# @param [String] api_secret Your OpenTok API key.
|
80
|
-
# @option opts [Symbol] :api_url Do not set this parameter. It is for internal use by
|
81
|
-
# @option opts [Symbol] :ua_addendum Do not set this parameter. It is for internal use by
|
81
|
+
# @option opts [Symbol] :api_url Do not set this parameter. It is for internal use by Vonage.
|
82
|
+
# @option opts [Symbol] :ua_addendum Do not set this parameter. It is for internal use by Vonage.
|
82
83
|
# @option opts [Symbol] :timeout_length Custom timeout in seconds. If not provided, defaults to 2 seconds.
|
83
84
|
def initialize(api_key, api_secret, opts={})
|
84
85
|
@api_key = api_key.to_s()
|
@@ -192,6 +193,11 @@ module OpenTok
|
|
192
193
|
@broadcasts ||= Broadcasts.new client
|
193
194
|
end
|
194
195
|
|
196
|
+
# A Renders object, which lets you work with OpenTok Experience Composer renders.
|
197
|
+
def renders
|
198
|
+
@renders ||= Renders.new client
|
199
|
+
end
|
200
|
+
|
195
201
|
# A Sip object, which lets you use the OpenTok SIP gateway.
|
196
202
|
def sip
|
197
203
|
@sip ||= Sip.new client
|
@@ -207,14 +213,14 @@ module OpenTok
|
|
207
213
|
@signals ||= Signals.new client
|
208
214
|
end
|
209
215
|
|
210
|
-
# A Connections object, which lets disconnect clients from an OpenTok session.
|
216
|
+
# A Connections object, which lets you disconnect clients from an OpenTok session.
|
211
217
|
def connections
|
212
218
|
@connections ||= Connections.new client
|
213
219
|
end
|
214
220
|
|
215
221
|
protected
|
216
222
|
def client
|
217
|
-
@client ||= Client.new api_key, api_secret, api_url, ua_addendum
|
223
|
+
@client ||= Client.new api_key, api_secret, api_url, ua_addendum, timeout_length: @timeout_length
|
218
224
|
end
|
219
225
|
|
220
226
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require "active_support/inflector"
|
2
|
+
|
3
|
+
module OpenTok
|
4
|
+
# Represents an Experience Composer render of an OpenTok session.
|
5
|
+
# See {https://tokbox.com/developer/guides/experience-composer/ Experience Composer}.
|
6
|
+
#
|
7
|
+
# @attr [string] id
|
8
|
+
# The unique ID for the Experience Composer.
|
9
|
+
#
|
10
|
+
# @attr [string] session_id
|
11
|
+
# The session ID of the OpenTok session associated with this render.
|
12
|
+
#
|
13
|
+
# @attr [string] project_id
|
14
|
+
# The API key associated with the render.
|
15
|
+
#
|
16
|
+
# @attr [int] created_at
|
17
|
+
# The time the Experience Composer started, expressed in milliseconds since the Unix epoch.
|
18
|
+
#
|
19
|
+
# @attr [int] updated_at
|
20
|
+
# The UNIX timestamp when the Experience Composer status was last updated.
|
21
|
+
#
|
22
|
+
# @attr [string] url
|
23
|
+
# A publicly reachable URL controlled by the customer and capable of generating the content to be rendered without user intervention.
|
24
|
+
#
|
25
|
+
# @attr [string] resolution
|
26
|
+
# The resolution of the Experience Composer (either "640x480", "480x640", "1280x720", "720x1280", "1920x1080", or "1080x1920").
|
27
|
+
#
|
28
|
+
# @attr [string] status
|
29
|
+
# The status of the Experience Composer. Poll frequently to check status updates. This property set to one of the following:
|
30
|
+
# - "starting" — The Vonage Video API platform is in the process of connecting to the remote application at the URL provided. This is the initial state.
|
31
|
+
# - "started" — The Vonage Video API platform has successfully connected to the remote application server, and is publishing the web view to an OpenTok stream.
|
32
|
+
# - "stopped" — The Experience Composer has stopped.
|
33
|
+
# - "failed" — An error occurred and the Experience Composer could not proceed. It may occur at startup if the OpenTok server cannot connect to the remote
|
34
|
+
# application server or republish the stream. It may also occur at any point during the process due to an error in the Vonage Video API platform.
|
35
|
+
#
|
36
|
+
# @attr [string] reason
|
37
|
+
# The reason field is only available when the status is either "stopped" or "failed". If the status is stopped, the reason field will contain either
|
38
|
+
# "Max Duration Exceeded" or "Stop Requested." If the status is failed, the reason will contain a more specific error message.
|
39
|
+
#
|
40
|
+
# @attr [string] streamId
|
41
|
+
# The ID of the composed stream being published. The streamId is not available when the status is "starting" and may not be available when the status is "failed".
|
42
|
+
class Render
|
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 Experience Composer render.
|
52
|
+
def to_json
|
53
|
+
@json.to_json
|
54
|
+
end
|
55
|
+
|
56
|
+
# Stops the OpenTok Experience Composer render.
|
57
|
+
def stop
|
58
|
+
# TODO: validate returned json fits schema
|
59
|
+
@json = @interface.stop @json['id']
|
60
|
+
end
|
61
|
+
|
62
|
+
# Gets info about the OpenTok Experience Composer render.
|
63
|
+
def info
|
64
|
+
# TODO: validate returned json fits schema
|
65
|
+
@json = @interface.find @json['id']
|
66
|
+
end
|
67
|
+
|
68
|
+
# @private ignore
|
69
|
+
def method_missing(method, *args, &block)
|
70
|
+
camelized_method = method.to_s.camelize(:lower)
|
71
|
+
if @json.has_key? camelized_method and args.empty?
|
72
|
+
@json[camelized_method]
|
73
|
+
else
|
74
|
+
super method, *args, &block
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "opentok/render"
|
2
|
+
|
3
|
+
module OpenTok
|
4
|
+
# A class for accessing an array of Experience Composer Render objects.
|
5
|
+
class RenderList < Array
|
6
|
+
# The total number of Experience Composer renders.
|
7
|
+
attr_reader :total
|
8
|
+
|
9
|
+
def initialize(interface, json)
|
10
|
+
@total = json["count"]
|
11
|
+
super json["items"].map { |item| ::OpenTok::Render.new interface, item }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require "opentok/client"
|
2
|
+
require "opentok/render"
|
3
|
+
require "opentok/render_list"
|
4
|
+
|
5
|
+
module OpenTok
|
6
|
+
# A class for working with OpenTok Experience Composer renders.
|
7
|
+
# See {https://tokbox.com/developer/guides/experience-composer/ Experience Composer}.
|
8
|
+
class Renders
|
9
|
+
|
10
|
+
# @private
|
11
|
+
def initialize(client)
|
12
|
+
@client = client
|
13
|
+
end
|
14
|
+
|
15
|
+
# Starts an Experience Composer render for an OpenTok session.
|
16
|
+
#
|
17
|
+
# @param [String] session_id (Required) The session ID of the OpenTok session that will include the Experience Composer stream.
|
18
|
+
#
|
19
|
+
# @param [Hash] options (Required) A hash defining options for the render.
|
20
|
+
#
|
21
|
+
# @option options [String] :token (Required) A valid OpenTok token with a Publisher role and (optionally) connection data to be associated with the output stream.
|
22
|
+
#
|
23
|
+
# @option options [String] :url (Required) A publicly reachable URL controlled by the customer and capable of generating the content to be rendered without user intervention.
|
24
|
+
# The minimum length of the URL is 15 characters and the maximum length is 2048 characters.
|
25
|
+
#
|
26
|
+
# @option options [Integer] :max_duration (Optional) The maximum time allowed for the Experience Composer, in seconds. After this time, it is stopped
|
27
|
+
# automatically, if it is still running. The maximum value is 36000 (10 hours), the minimum value is 60 (1 minute), and the default value is 7200 (2 hours).
|
28
|
+
# When the Experience Composer ends, its stream is unpublished and an event is posted to the callback URL, if configured in the Account Portal.
|
29
|
+
#
|
30
|
+
# @option options [String] :resolution The resolution of the Experience Composer, either "640x480" (SD landscape), "480x640" (SD portrait), "1280x720" (HD landscape),
|
31
|
+
# "720x1280" (HD portrait), "1920x1080" (FHD landscape), or "1080x1920" (FHD portrait). By default, this resolution is "1280x720" (HD landscape, the default).
|
32
|
+
#
|
33
|
+
# @option options [Hash] :properties (Optional) The initial configuration of Publisher properties for the composed output stream. The properties object contains
|
34
|
+
# the key <code>:name</code> (String) which serves as the name of the composed output stream which is published to the session. The name must have a minimum length of 1 and
|
35
|
+
# a maximum length of 200.
|
36
|
+
#
|
37
|
+
# @return [Render] The render object, which includes properties defining the render, including the render ID.
|
38
|
+
#
|
39
|
+
# @raise [OpenTokRenderError] The render could not be started. The request was invalid.
|
40
|
+
# @raise [OpenTokAuthenticationError] Authentication failed while starting a render. Invalid API key.
|
41
|
+
# @raise [OpenTokError] OpenTok server error.
|
42
|
+
def start(session_id, options = {})
|
43
|
+
raise ArgumentError, "session_id not provided" if session_id.to_s.empty?
|
44
|
+
raise ArgumentError, "options cannot be empty" if options.empty?
|
45
|
+
raise ArgumentError, "token property is required in options" unless options.has_key?(:token)
|
46
|
+
raise ArgumentError, "url property is required in options" unless options.has_key?(:url)
|
47
|
+
|
48
|
+
render_json = @client.start_render(session_id, options)
|
49
|
+
Render.new self, render_json
|
50
|
+
end
|
51
|
+
|
52
|
+
# Stops an OpenTok Experience Composer render.
|
53
|
+
#
|
54
|
+
# @param [String] render_id (Required) The render ID.
|
55
|
+
#
|
56
|
+
# @return [Render] The render object, which includes properties defining the render.
|
57
|
+
#
|
58
|
+
# @raise [OpenTokRenderError] The request was invalid.
|
59
|
+
# @raise [OpenTokAuthenticationError] Authentication failed while stopping a render. Invalid API key.
|
60
|
+
# @raise [OpenTokRenderError] No matching render found (with the specified ID) or it is already stopped
|
61
|
+
# @raise [OpenTokError] OpenTok server error.
|
62
|
+
def stop(render_id)
|
63
|
+
raise ArgumentError, "render_id not provided" if render_id.to_s.empty?
|
64
|
+
|
65
|
+
render_json = @client.stop_render(render_id)
|
66
|
+
Render.new self, render_json
|
67
|
+
end
|
68
|
+
|
69
|
+
# Gets a Render object for the given render ID.
|
70
|
+
#
|
71
|
+
# @param [String] render_id (Required) The render ID.
|
72
|
+
#
|
73
|
+
# @return [Render] The render object, which includes properties defining the render.
|
74
|
+
#
|
75
|
+
# @raise [OpenTokRenderError] The request was invalid.
|
76
|
+
# @raise [OpenTokAuthenticationError] Authentication failed while stopping a render. Invalid API key.
|
77
|
+
# @raise [OpenTokRenderError] No matching render found (with the specified ID) or it is already stopped
|
78
|
+
# @raise [OpenTokError] OpenTok server error.
|
79
|
+
def find(render_id)
|
80
|
+
raise ArgumentError, "render_id not provided" if render_id.to_s.empty?
|
81
|
+
|
82
|
+
render_json = @client.get_render(render_id.to_s)
|
83
|
+
Render.new self, render_json
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns a RenderList, which is an array of Experience Composers renders that are associated with a project.
|
87
|
+
#
|
88
|
+
# @param [Hash] options A hash with keys defining which range of renders to retrieve.
|
89
|
+
# @option options [integer] :offset (Optional). The start offset for the list of Experience Composer renders. The default is 0.
|
90
|
+
# @option options [integer] :count Optional. The number of Experience Composer renders to retrieve starting at the offset. The default value
|
91
|
+
# is 50 and the maximum is 1000.
|
92
|
+
#
|
93
|
+
# @return [RenderList] An RenderList object, which is an array of Render objects.
|
94
|
+
def list(options = {})
|
95
|
+
raise ArgumentError, "Limit is invalid" unless options[:count].nil? || (0..1000).include?(options[:count])
|
96
|
+
|
97
|
+
render_list_json = @client.list_renders(options[:offset], options[:count])
|
98
|
+
RenderList.new self, render_list_json
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/lib/opentok/session.rb
CHANGED
@@ -31,10 +31,10 @@ module OpenTok
|
|
31
31
|
# * <code>:publisher</code> -- A publisher can publish streams, subscribe to
|
32
32
|
# streams, and signal. (This is the default value if you do not specify a role.)
|
33
33
|
#
|
34
|
-
# * <code>:moderator</code> --
|
35
|
-
# publisher,
|
36
|
-
#
|
37
|
-
#
|
34
|
+
# * <code>:moderator</code> -- n addition to the privileges granted to a
|
35
|
+
# publisher, a moderator can perform moderation functions, such as forcing clients
|
36
|
+
# to disconnect, to stop publishing streams, or to mute audio in published streams. See the
|
37
|
+
# {https://tokbox.com/developer/guides/moderation/ Moderation developer guide}.
|
38
38
|
# @option options [integer] :expire_time The expiration time, in seconds since the UNIX epoch.
|
39
39
|
# Pass in 0 to use the default expiration time of 24 hours after the token creation time.
|
40
40
|
# The maximum expiration time is 30 days after the creation time.
|
data/lib/opentok/sip.rb
CHANGED
@@ -12,7 +12,9 @@ module OpenTok
|
|
12
12
|
# "password" => sip_password },
|
13
13
|
# "headers" => { "X-KEY1" => "value1",
|
14
14
|
# "X-KEY1" => "value2" },
|
15
|
-
# "secure" => "true"
|
15
|
+
# "secure" => "true",
|
16
|
+
# "video" => "true",
|
17
|
+
# "observe_force_mute" => "true"
|
16
18
|
# }
|
17
19
|
# response = opentok.sip.dial(session_id, token, "sip:+15128675309@acme.pstn.example.com;transport=tls", opts)
|
18
20
|
# @param [String] session_id The session ID corresponding to the session to which
|
@@ -33,14 +35,50 @@ module OpenTok
|
|
33
35
|
# @option opts [Hash] :auth This object contains the username and password
|
34
36
|
# to be used in the the SIP INVITE request for HTTP digest authentication,
|
35
37
|
# if it is required by your SIP platform.
|
36
|
-
# @option opts [true, false] :secure
|
38
|
+
# @option opts [true, false] :secure Whether the media must be transmitted
|
37
39
|
# encrypted (true) or not (false, the default).
|
40
|
+
# @option opts [true, false] :video Whether the SIP call will include
|
41
|
+
# video (true) or not (false, the default). With video included, the SIP
|
42
|
+
# client's video is included in the OpenTok stream that is sent to the
|
43
|
+
# OpenTok session. The SIP client will receive a single composed video of
|
44
|
+
# the published streams in the OpenTok session.
|
45
|
+
# @option opts [true, false] :observe_force_mute Whether the SIP end point
|
46
|
+
# observes {https://tokbox.com/developer/guides/moderation/#force_mute force mute moderation}
|
47
|
+
# (true) or not (false, the default).
|
38
48
|
def dial(session_id, token, sip_uri, opts)
|
39
49
|
response = @client.dial(session_id, token, sip_uri, opts)
|
40
50
|
end
|
41
51
|
|
52
|
+
# Sends DTMF digits to a specific client connected to an OpnTok session.
|
53
|
+
#
|
54
|
+
# @param [String] session_id The session ID.
|
55
|
+
# @param [String] connection_id The connection ID of the specific connection that
|
56
|
+
# the DTMF signal is being sent to.
|
57
|
+
# @param [String] dtmf_digits The DTMF digits to send. This can include 0-9, "*", "#", and "p".
|
58
|
+
# A p indicates a pause of 500ms (if you need to add a delay in sending the digits).
|
59
|
+
def play_dtmf_to_connection(session_id, connection_id, dtmf_digits)
|
60
|
+
raise ArgumentError, "invalid DTMF digits" unless dtmf_digits_valid?(dtmf_digits)
|
61
|
+
response = @client.play_dtmf_to_connection(session_id, connection_id, dtmf_digits)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Sends DTMF digits to all clients connected to an OpnTok session.
|
65
|
+
#
|
66
|
+
# @param [String] session_id The session ID.
|
67
|
+
# @param [String] dtmf_digits The DTMF digits to send. This can include 0-9, "*", "#", and "p".
|
68
|
+
# A p indicates a pause of 500ms (if you need to add a delay in sending the digits).
|
69
|
+
def play_dtmf_to_session(session_id, dtmf_digits)
|
70
|
+
raise ArgumentError, "invalid DTMF digits" unless dtmf_digits_valid?(dtmf_digits)
|
71
|
+
response = @client.play_dtmf_to_session(session_id, dtmf_digits)
|
72
|
+
end
|
73
|
+
|
42
74
|
def initialize(client)
|
43
75
|
@client = client
|
44
76
|
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def dtmf_digits_valid?(dtmf_digits)
|
81
|
+
dtmf_digits.match?(/^[0-9*#p]+$/)
|
82
|
+
end
|
45
83
|
end
|
46
84
|
end
|