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
@@ -0,0 +1,64 @@
1
+ /* Move down content because we have a fixed navbar that is 50px tall */
2
+ body {
3
+ padding-top: 50px;
4
+ padding-bottom: 20px;
5
+ background-color: #F2F2F2;
6
+ }
7
+
8
+ /* Responsive: Portrait tablets and up */
9
+ @media screen and (min-width: 768px) {
10
+ /* Remove padding from wrapping element since we kick in the grid classes here */
11
+ .body-content {
12
+ padding: 0;
13
+ }
14
+ }
15
+
16
+ #streams {
17
+ background-color: gray;
18
+ width: 320px;
19
+ height: 180px;
20
+ }
21
+
22
+ #streams > div {
23
+ width: 20%;
24
+ height: 20%;
25
+ float: left;
26
+ position: relative;
27
+ cursor: pointer;
28
+ }
29
+
30
+ #streams.vertical > div {
31
+ left: 0px;
32
+ clear: left;
33
+ padding: 0px;
34
+ }
35
+
36
+ #streams .focus {
37
+ position: relative;
38
+ top: 0;
39
+ left: 0;
40
+ margin-top: 0;
41
+ height: 100%;
42
+ width: 100%;
43
+ }
44
+
45
+ #streams.vertical .focus {
46
+ padding: 0;
47
+ left: 0;
48
+ margin: 0;
49
+ left: 20%;
50
+ height: 100%;
51
+ width: 80%;
52
+ }
53
+
54
+ .stop {
55
+ display: none;
56
+ }
57
+
58
+ .bump-me {
59
+ padding-top: 40px;
60
+ }
61
+
62
+ .help-block {
63
+ font-weight: bold;
64
+ }
@@ -0,0 +1,185 @@
1
+ /* global OT, apiKey, sessionId, initialBroadcastId, token, $, initialLayout, focusStreamId */
2
+ /* eslint-disable no-console */
3
+
4
+ var session = OT.initSession(apiKey, sessionId);
5
+ var publisher = OT.initPublisher('publisher', {
6
+ insertMode: 'append',
7
+ width: '100%',
8
+ height: '100%',
9
+ resolution: '1280x720'
10
+ });
11
+ var broadcastId = initialBroadcastId;
12
+ var layout = initialLayout;
13
+
14
+ function disableForm() {
15
+ $('.broadcast-options-fields').attr('disabled', 'disabled');
16
+ $('.start').hide();
17
+ $('.stop').show();
18
+ }
19
+
20
+ function enableForm() {
21
+ $('.broadcast-options-fields').removeAttr('disabled');
22
+ $('.start').show();
23
+ $('.stop').hide();
24
+ }
25
+
26
+ function positionStreams() {
27
+ var $focusElement;
28
+ $focusElement = $('.focus');
29
+ if ($('#streams').hasClass('vertical')) {
30
+ $('#streams').children().css('top', '0');
31
+ $focusElement.appendTo('#streams');
32
+ $focusElement.css('top', (-20 * ($('#streams').children().size() - 1)) + '%');
33
+ }
34
+ else {
35
+ $focusElement.prependTo('#streams');
36
+ $focusElement.css('top', '0');
37
+ }
38
+ }
39
+
40
+ function setFocus(focusStreamId) {
41
+ var $focusElement;
42
+ var otherStreams = $.map($('#streams').children(), function (element) {
43
+ var streamId = (element.id === 'publisher' && publisher.stream) ? publisher.stream.streamId
44
+ : element.id;
45
+ if (streamId !== focusStreamId) {
46
+ $('#' + element.id).removeClass('focus');
47
+ return streamId;
48
+ }
49
+ return null;
50
+ });
51
+
52
+ $.post('/focus', {
53
+ focus: focusStreamId,
54
+ otherStreams: otherStreams
55
+ }).done(function () {
56
+ console.log('Focus changed.');
57
+ }).fail(function (jqXHR) {
58
+ console.error('Stream class list error:', jqXHR.responseText);
59
+ });
60
+
61
+ $('.focus').removeClass('focus');
62
+ $focusElement = (publisher.stream && publisher.stream.streamId === focusStreamId) ?
63
+ $('#publisher') : $('#' + focusStreamId);
64
+ $focusElement.addClass('focus');
65
+ session.signal({
66
+ type: 'focusStream',
67
+ data: focusStreamId
68
+ });
69
+ positionStreams();
70
+ }
71
+
72
+ function createFocusClick(elementId, focusStreamId) {
73
+ $('#' + elementId).click(function () {
74
+ setFocus(focusStreamId);
75
+ });
76
+ }
77
+
78
+ if (initialLayout === 'verticalPresentation') {
79
+ $('#streams').addClass('vertical');
80
+ }
81
+
82
+ if (initialLayout === 'verticalPresentation') {
83
+ $('.start').hide();
84
+ $('.stop').show();
85
+ }
86
+
87
+ session.connect(token, function (err) {
88
+ if (err) {
89
+ alert(err.message || err); // eslint-disable-line no-alert
90
+ }
91
+ session.publish(publisher);
92
+ });
93
+
94
+ publisher.on('streamCreated', function () {
95
+ createFocusClick(publisher.id, publisher.stream.streamId);
96
+ positionStreams();
97
+ });
98
+
99
+ session.on('streamCreated', function (event) {
100
+ var subscriber;
101
+ var streamId = event.stream.streamId;
102
+ var $streamContainer = $('<div></div>');
103
+ $streamContainer.attr('id', event.stream.id);
104
+ $('#streams').append($streamContainer);
105
+ subscriber = session.subscribe(event.stream, streamId, {
106
+ insertMode: 'append',
107
+ width: '100%',
108
+ height: '100%'
109
+ });
110
+
111
+ if (streamId === focusStreamId) {
112
+ setFocus(streamId);
113
+ }
114
+ createFocusClick(subscriber.id, streamId);
115
+ positionStreams();
116
+ });
117
+
118
+ session.on('streamDestroyed', function (event) {
119
+ var $streamElem = $('#' + event.stream.id);
120
+ if ($streamElem.hasClass('focus')) {
121
+ setFocus(publisher.stream.streamId);
122
+ }
123
+ $streamElem.remove();
124
+ positionStreams();
125
+ });
126
+
127
+ $(document).ready(function () {
128
+ $('.start').click(function () {
129
+ var options = {
130
+ maxDuration: $('input[name=maxDuration]').val() || undefined,
131
+ resolution: $('input[name=resolution]:checked').val(),
132
+ layout: {
133
+ type: layout
134
+ }
135
+ };
136
+ disableForm();
137
+ $.post('/start', options)
138
+ .done(function (response) {
139
+ console.log('start success.');
140
+ broadcastId = response.id;
141
+ setFocus(publisher.stream.streamId);
142
+ })
143
+ .fail(function (jqXHR) {
144
+ console.error(jqXHR.responseText);
145
+ enableForm();
146
+ });
147
+ }).prop('disabled', false);
148
+ $('.stop').click(function () {
149
+ $.get('stop/' + broadcastId)
150
+ .done(function () {
151
+ console.log('stop success.');
152
+ broadcastId = null;
153
+ enableForm();
154
+ })
155
+ .fail(function (jqXHR) {
156
+ console.error(jqXHR.responseText);
157
+ });
158
+ });
159
+ $('.toggle-layout').click(function () {
160
+ if ($('#streams').hasClass('vertical')) {
161
+ $('#streams').removeClass('vertical');
162
+ }
163
+ else {
164
+ $('#streams').addClass('vertical');
165
+ }
166
+
167
+ positionStreams();
168
+
169
+ layout = $('#streams').hasClass('vertical') ? 'verticalPresentation'
170
+ : 'horizontalPresentation';
171
+
172
+ $.post('broadcast/' + broadcastId + '/layout', {
173
+ type: layout
174
+ }).done(function () {
175
+ console.log('Broadcast layout updated.');
176
+ }).fail(function (jqXHR) {
177
+ console.error('Broadcast layout error:', jqXHR.responseText);
178
+ });
179
+
180
+ session.signal({
181
+ type: 'layoutClass',
182
+ data: layout
183
+ });
184
+ });
185
+ });
@@ -0,0 +1,85 @@
1
+ /* global OT, apiKey, sessionId, token, $, layout, focusStreamId */
2
+ var session = OT.initSession(apiKey, sessionId);
3
+ var publisher;
4
+
5
+ var container = $('<div id = "publisher"></div>');
6
+
7
+ if (layout === 'verticalPresentation') {
8
+ $('#streams').addClass('vertical');
9
+ }
10
+
11
+ container.addClass('focus');
12
+ $('#streams').append(container);
13
+
14
+ publisher = OT.initPublisher('publisher', {
15
+ insertMode: 'append',
16
+ width: '100%',
17
+ height: '100%',
18
+ resolution: '1280x720'
19
+ });
20
+
21
+ function positionStreams() {
22
+ var $focusElement = $('.focus');
23
+ if ($('#streams').hasClass('vertical')) {
24
+ $focusElement.appendTo('#streams');
25
+ $('#streams').children().css('top', '0');
26
+ $focusElement.css('top', (-20 * ($('#streams').children().size() - 1)) + '%');
27
+ }
28
+ else {
29
+ $focusElement.prependTo('#streams');
30
+ $focusElement.css('top', '0');
31
+ }
32
+ }
33
+
34
+ function focusStream(streamId) {
35
+ var focusStreamId = streamId;
36
+ var $focusElement = (publisher.stream && publisher.stream.id === focusStreamId) ? $('#publisher')
37
+ : $('#' + focusStreamId);
38
+ $('.focus').removeClass('focus');
39
+ $focusElement.addClass('focus');
40
+ positionStreams();
41
+ }
42
+
43
+ session.connect(token, function (err) {
44
+ if (err) {
45
+ alert(err.message || err); // eslint-disable-line no-alert
46
+ }
47
+ session.publish(publisher);
48
+ });
49
+
50
+ session.on('streamCreated', function (event) {
51
+ var streamId = event.stream.id;
52
+ container = document.createElement('div');
53
+ container.id = streamId;
54
+ $('#streams').append(container);
55
+ session.subscribe(event.stream, streamId, {
56
+ insertMode: 'append',
57
+ width: '100%',
58
+ height: '100%'
59
+ });
60
+ if (streamId === focusStreamId) {
61
+ focusStream(streamId);
62
+ }
63
+ positionStreams();
64
+ });
65
+
66
+ session.on('streamDestroyed', function (event) {
67
+ $('#' + event.stream.id).remove();
68
+ positionStreams();
69
+ });
70
+
71
+ session.on('signal:layoutClass', function (event) {
72
+ if (event.data === 'horizontalPresentation') {
73
+ $('#streams').removeClass('vertical');
74
+ $('.focus').prependTo('#streams');
75
+ }
76
+ else {
77
+ $('#streams').addClass('vertical');
78
+ $('.focus').appendTo('#streams');
79
+ }
80
+ positionStreams();
81
+ });
82
+
83
+ session.on('signal:focusStream', function (event) {
84
+ focusStream(event.data);
85
+ });
@@ -0,0 +1,82 @@
1
+
2
+ <script src="https://static.opentok.com/v2/js/opentok.min.js"></script>
3
+
4
+ <div class="container bump-me">
5
+
6
+ <div class="body-content">
7
+
8
+ <div class="panel panel-default">
9
+ <div class="panel-heading">
10
+ <h3 class="panel-title">Host</h3>
11
+ </div>
12
+ <div class="panel-body">
13
+ <div id="streams">
14
+ <div id="publisher" class="focus"></div>
15
+ </div>
16
+ </div>
17
+ <div class="panel-footer">
18
+ <form class="broadcast-options">
19
+ <fieldset class="broadcast-options-fields">
20
+ <div class="form-group">
21
+ <h4>Broadcast Options:</h4>
22
+ <label>
23
+ Maximum duration (seconds, minimum 60, maximum 36000):
24
+ <input type="number" step="30" min="60" max="36000" name="maxDuration">
25
+ </label>
26
+ </div>
27
+
28
+ <div class="form-group">
29
+ <p>
30
+ <label>Resolution:</label>
31
+ <label class="help-block">
32
+ <input type="radio" name="resolution" value="640x480"> 640x480
33
+ </label>
34
+ <label class="help-block">
35
+ <input type="radio" name="resolution" value="1280x720" checked> 1280x720
36
+ </label>
37
+ </p>
38
+ </div>
39
+ </fieldset>
40
+ </form>
41
+ <button class="btn btn-danger start" disabled>Start broadcast</button>
42
+ <button class="btn btn-success stop">Stop broadcast</button>
43
+ <button class="btn toggle-layout">Toggle layout</button>
44
+ </div>
45
+ </div>
46
+ </div>
47
+
48
+ <div class="panel panel-default">
49
+ <div class="panel-heading">
50
+ <h3 class="panel-title">Instructions</h3>
51
+ </div>
52
+ <div class="panel-body">
53
+ <p>
54
+ Click <strong>Start broadcast</strong> to start broadcasting this session.
55
+ All publishers in the session will be included, and all publishers that
56
+ join the session will be included as well.
57
+ </p>
58
+ <p>
59
+ Click <strong>Stop broadcast</strong> to stop broadcasting this session.
60
+ </p>
61
+ <p>
62
+ Click <strong>Toggle layout</strong> to toggle the layout
63
+ between a vertical and horizontal presentation. The layout changes in all clients
64
+ and in the broadcast.
65
+ <p>
66
+ Click any stream to set it to be the focus stream in the broadcast layout.
67
+ </div>
68
+ </div>
69
+ </div>
70
+
71
+ <script>
72
+ var sessionId = "<%= sessionId %>";
73
+ var initialBroadcastId = "<%= initialBroadcastId || '' %>";
74
+ var apiKey = "<%= apiKey %>";
75
+ var token = "<%= token %>";
76
+ var focusStreamId = "<%= focusStreamId || '' %>";
77
+ var initialLayout = "<%= initialLayout %>";
78
+ </script>
79
+ <script src="/js/host.js"></script>
80
+
81
+ </div>
82
+
@@ -0,0 +1,32 @@
1
+ <div class="container bump-me">
2
+
3
+
4
+ <div class="body-content">
5
+
6
+
7
+ <div class="row">
8
+ <div class="col-lg-6 col-offset-1">
9
+
10
+ <div class="panel panel-default">
11
+ <div class="panel-heading">Create a broadcast</div>
12
+ <div class="panel-body">
13
+ <p>
14
+ Everyone who joins either the Host View or Participant View
15
+ joins a single OpenTok session. The Host can click
16
+ Start Broadcast and Stop Broadcast to control the live streaming
17
+ broadcast of the entire session.
18
+ </p>
19
+ </div>
20
+ <div class="panel-footer">
21
+ <a class="btn btn-danger" href="host">Host View</a>
22
+ <a class="btn btn-danger" href="participant">Participant View</a>
23
+ <a class="btn btn-danger" href="broadcast">Broadcast URL</a>
24
+ </div>
25
+ </div>
26
+
27
+ </div>
28
+
29
+ </div>
30
+
31
+ </div>
32
+ </div>