opentok 0.1.3 → 2.2.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.
- checksums.yaml +4 -4
- data/.gitignore +16 -2
- data/.travis.yml +6 -0
- data/.yardopts +1 -0
- data/CONTRIBUTING.md +47 -0
- data/DEVELOPING.md +91 -0
- data/LICENSE +19 -5
- data/README.md +170 -53
- data/Rakefile +10 -5
- data/doc/OpenTok.html +411 -0
- data/doc/OpenTok/Archive.html +1320 -0
- data/doc/OpenTok/ArchiveList.html +216 -0
- data/doc/OpenTok/Archives.html +1028 -0
- data/doc/OpenTok/Client.html +695 -0
- data/doc/OpenTok/OpenTok.html +1046 -0
- data/doc/OpenTok/OpenTokArchiveError.html +142 -0
- data/doc/OpenTok/OpenTokAuthenticationError.html +143 -0
- data/doc/OpenTok/OpenTokError.html +138 -0
- data/doc/OpenTok/Session.html +665 -0
- data/doc/OpenTok/TokenGenerator.html +204 -0
- data/doc/OpenTok/TokenGenerator/ClassMethods.html +187 -0
- data/doc/README.md +15 -0
- data/doc/_index.html +182 -0
- data/doc/class_list.html +54 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +57 -0
- data/doc/css/style.css +339 -0
- data/doc/file.README.html +87 -0
- data/doc/file_list.html +56 -0
- data/doc/frames.html +26 -0
- data/doc/index.html +87 -0
- data/doc/js/app.js +219 -0
- data/doc/js/full_list.js +178 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +227 -0
- data/doc/top-level-namespace.html +112 -0
- data/lib/opentok.rb +3 -14
- data/lib/opentok/archive.rb +92 -0
- data/lib/opentok/archive_list.rb +17 -0
- data/lib/opentok/archives.rb +120 -0
- data/lib/opentok/client.rb +125 -0
- data/lib/opentok/constants.rb +5 -0
- data/lib/opentok/exceptions.rb +10 -0
- data/lib/opentok/opentok.rb +174 -0
- data/lib/opentok/session.rb +76 -0
- data/lib/opentok/token_generator.rb +101 -0
- data/lib/opentok/version.rb +4 -0
- data/opentok.gemspec +29 -22
- data/sample/Archiving/Gemfile +4 -0
- data/sample/Archiving/README.md +212 -0
- data/sample/Archiving/archiving_sample.rb +80 -0
- data/sample/Archiving/public/css/sample.css +22 -0
- data/sample/Archiving/public/img/archiving-off.png +0 -0
- data/sample/Archiving/public/img/archiving-on-idle.png +0 -0
- data/sample/Archiving/public/img/archiving-on-message.png +0 -0
- data/sample/Archiving/public/js/host.js +37 -0
- data/sample/Archiving/public/js/participant.js +13 -0
- data/sample/Archiving/views/history.erb +65 -0
- data/sample/Archiving/views/host.erb +69 -0
- data/sample/Archiving/views/index.erb +48 -0
- data/sample/Archiving/views/layout.erb +29 -0
- data/sample/Archiving/views/participant.erb +55 -0
- data/sample/HelloWorld/Gemfile +4 -0
- data/sample/HelloWorld/README.md +123 -0
- data/sample/HelloWorld/hello_world.rb +27 -0
- data/sample/HelloWorld/public/js/helloworld.js +32 -0
- data/sample/HelloWorld/views/index.erb +21 -0
- data/spec/cassettes/OpenTok_Archives/should_create_archives.yml +48 -0
- data/spec/cassettes/OpenTok_Archives/should_create_named_archives.yml +49 -0
- data/spec/cassettes/OpenTok_Archives/should_delete_an_archive_by_id.yml +32 -0
- data/spec/cassettes/OpenTok_Archives/should_find_archives_by_id.yml +46 -0
- data/spec/cassettes/OpenTok_Archives/should_stop_archives.yml +48 -0
- data/spec/cassettes/OpenTok_Archives/when_many_archives_are_created/should_return_all_archives.yml +104 -0
- data/spec/cassettes/OpenTok_Archives/when_many_archives_are_created/should_return_archives_with_an_offset.yml +71 -0
- data/spec/cassettes/OpenTok_Archives/when_many_archives_are_created/should_return_count_number_of_archives.yml +60 -0
- data/spec/cassettes/OpenTok_Archives/when_many_archives_are_created/should_return_part_of_the_archives_when_using_offset_and_count.yml +82 -0
- data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_default_sessions.yml +39 -0
- data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_relayed_media_sessions.yml +39 -0
- data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_relayed_media_sessions_with_a_location_hint.yml +39 -0
- data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_routed_media_sessions.yml +39 -0
- data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_routed_media_sessions_for_invalid_media_modes.yml +39 -0
- data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_routed_media_sessions_with_a_location_hint.yml +39 -0
- data/spec/cassettes/OpenTok_OpenTok/when_initialized_properly/_create_session/creates_sessions_with_a_location_hint.yml +39 -0
- data/spec/matchers/token.rb +48 -0
- data/spec/opentok/archives_spec.rb +91 -0
- data/spec/opentok/opentok_spec.rb +144 -0
- data/spec/opentok/session_spec.rb +71 -0
- data/spec/shared/opentok_generates_tokens.rb +62 -0
- data/spec/shared/session_generates_tokens.rb +63 -0
- data/spec/spec_helper.rb +6 -7
- metadata +197 -59
- data/.rspec +0 -3
- data/CHANGES +0 -33
- data/doc/reference.md +0 -122
- data/lib/open_tok/archive.rb +0 -53
- data/lib/open_tok/archive_timeline_event.rb +0 -22
- data/lib/open_tok/archive_video_resource.rb +0 -28
- data/lib/open_tok/exception.rb +0 -50
- data/lib/open_tok/open_tok_sdk.rb +0 -198
- data/lib/open_tok/request.rb +0 -63
- data/lib/open_tok/role_constants.rb +0 -18
- data/lib/open_tok/session.rb +0 -25
- data/lib/open_tok/session_property_constants.rb +0 -30
- data/lib/open_tok/utils.rb +0 -10
- data/lib/open_tok/version.rb +0 -5
- data/sample/sample.rb +0 -26
- data/spec/cassettes/archives.yml +0 -83
- data/spec/cassettes/deleteArchive.yml +0 -91
- data/spec/cassettes/invalidSession.yml +0 -41
- data/spec/cassettes/session.yml +0 -46
- data/spec/cassettes/stitchArchive.yml +0 -42
- data/spec/opentok_exception_spec.rb +0 -38
- data/spec/opentok_spec.rb +0 -135
|
@@ -0,0 +1,80 @@
|
|
|
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 ArchivingSample < 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
|
|
11
|
+
set :erb, :layout => :layout
|
|
12
|
+
|
|
13
|
+
get '/' do
|
|
14
|
+
erb :index
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
get '/host' do
|
|
18
|
+
api_key = settings.api_key
|
|
19
|
+
session_id = settings.session.session_id
|
|
20
|
+
token = settings.opentok.generate_token(session_id, :role => :moderator)
|
|
21
|
+
|
|
22
|
+
erb :host, :locals => {
|
|
23
|
+
:api_key => api_key,
|
|
24
|
+
:session_id => session_id,
|
|
25
|
+
:token => token
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
get '/participant' do
|
|
30
|
+
api_key = settings.api_key
|
|
31
|
+
session_id = settings.session.session_id
|
|
32
|
+
token = settings.opentok.generate_token(session_id, :role => :moderator)
|
|
33
|
+
|
|
34
|
+
erb :participant, :locals => {
|
|
35
|
+
:api_key => api_key,
|
|
36
|
+
:session_id => session_id,
|
|
37
|
+
:token => token
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
get '/history' do
|
|
42
|
+
page = (params[:page] || "1").to_i
|
|
43
|
+
offset = (page - 1) * 5
|
|
44
|
+
archives = settings.opentok.archives.all(:offset => offset, :count => 5)
|
|
45
|
+
|
|
46
|
+
show_previous = page > 1 ? '/history?page=' + (page-1).to_s : nil
|
|
47
|
+
show_next = archives.total > (offset + 5) ? '/history?page=' + (page+1).to_s : nil
|
|
48
|
+
|
|
49
|
+
erb :history, :locals => {
|
|
50
|
+
:archives => archives,
|
|
51
|
+
:show_previous => show_previous,
|
|
52
|
+
:show_next => show_next
|
|
53
|
+
}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
get '/download/:archive_id' do
|
|
57
|
+
archive = settings.opentok.archives.find(params[:archive_id])
|
|
58
|
+
redirect archive.url
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
get '/start' do
|
|
62
|
+
archive = settings.opentok.archives.create settings.session.session_id, {
|
|
63
|
+
:name => "Ruby Archiving Sample App"
|
|
64
|
+
}
|
|
65
|
+
body archive.to_json
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
get '/stop/:archive_id' do
|
|
69
|
+
archive = settings.opentok.archives.stop_by_id(params[:archive_id])
|
|
70
|
+
body archive.to_json
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
get '/delete/:archive_id' do
|
|
74
|
+
settings.opentok.archives.delete_by_id(params[:archive_id])
|
|
75
|
+
redirect '/history'
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# start the server if ruby file executed directly
|
|
79
|
+
run! if app_file == $0
|
|
80
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
#subscribers div {
|
|
17
|
+
float: left;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.bump-me {
|
|
21
|
+
padding-top: 40px;
|
|
22
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
var session = OT.initSession(sessionId),
|
|
2
|
+
publisher = OT.initPublisher("publisher"),
|
|
3
|
+
archiveID = null;
|
|
4
|
+
|
|
5
|
+
session.connect(apiKey, token, function(err, info) {
|
|
6
|
+
if(err) {
|
|
7
|
+
alert(err.message || err);
|
|
8
|
+
}
|
|
9
|
+
session.publish(publisher);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
session.on('streamCreated', function(event) {
|
|
13
|
+
session.subscribe(event.stream, "subscribers", { insertMode: "append" });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
session.on('archiveStarted', function(event) {
|
|
17
|
+
archiveID = event.id;
|
|
18
|
+
console.log("ARCHIVE STARTED");
|
|
19
|
+
$(".start").hide();
|
|
20
|
+
$(".stop").show();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
session.on('archiveStopped', function(event) {
|
|
24
|
+
archiveID = null;
|
|
25
|
+
console.log("ARCHIVE STOPPED");
|
|
26
|
+
$(".start").show();
|
|
27
|
+
$(".stop").hide();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
$(document).ready(function() {
|
|
31
|
+
$(".start").click(function(event){
|
|
32
|
+
$.get("start");
|
|
33
|
+
}).show();
|
|
34
|
+
$(".stop").click(function(event){
|
|
35
|
+
$.get("stop/" + archiveID);
|
|
36
|
+
}).hide();
|
|
37
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
var session = OT.initSession(sessionId),
|
|
2
|
+
publisher = OT.initPublisher("publisher");
|
|
3
|
+
|
|
4
|
+
session.connect(apiKey, token, function(err, info) {
|
|
5
|
+
if(err) {
|
|
6
|
+
alert(err.message || err);
|
|
7
|
+
}
|
|
8
|
+
session.publish(publisher);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
session.on('streamCreated', function(event) {
|
|
12
|
+
session.subscribe(event.stream, "subscribers", { insertMode : "append" });
|
|
13
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<div class="container bump-me">
|
|
2
|
+
|
|
3
|
+
<div class="body-content">
|
|
4
|
+
|
|
5
|
+
<div class="panel panel-default">
|
|
6
|
+
<div class="panel-heading">
|
|
7
|
+
<h3 class="panel-title">Past Recordings</h3>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="panel-body">
|
|
10
|
+
<% if archives.count > 0 %>
|
|
11
|
+
<table class="table">
|
|
12
|
+
<thead>
|
|
13
|
+
<tr>
|
|
14
|
+
<th> </th>
|
|
15
|
+
<th>Created</th>
|
|
16
|
+
<th>Duration</th>
|
|
17
|
+
<th>Status</th>
|
|
18
|
+
</tr>
|
|
19
|
+
</thead>
|
|
20
|
+
<tbody>
|
|
21
|
+
<% for item in archives %>
|
|
22
|
+
|
|
23
|
+
<tr data-item-id="<%= item.id %>">
|
|
24
|
+
<td>
|
|
25
|
+
<% if (item.status == "available") && item.url && (item.url.length > 0) %>
|
|
26
|
+
<a href="/download/<%= item.id %>">
|
|
27
|
+
<% end %>
|
|
28
|
+
<%= item.name || "Untitled" %>
|
|
29
|
+
<% if (item.status == "available") && item.url && (item.url.length > 0) %>
|
|
30
|
+
</a>
|
|
31
|
+
<% end %>
|
|
32
|
+
</td>
|
|
33
|
+
<td><%= Time.at(item.created_at/1000).strftime("%B %e, %Y at %I:%M %p") %></td>
|
|
34
|
+
<td><%= item.duration %> seconds</td>
|
|
35
|
+
<td><%= item.status %></td>
|
|
36
|
+
<td>
|
|
37
|
+
<% if item.status == "available" %>
|
|
38
|
+
<a href="/delete/<%= item.id %>">Delete</a>
|
|
39
|
+
<% else %>
|
|
40
|
+
|
|
41
|
+
<% end %>
|
|
42
|
+
</td>
|
|
43
|
+
</tr>
|
|
44
|
+
|
|
45
|
+
<% end %>
|
|
46
|
+
</tbody>
|
|
47
|
+
</table>
|
|
48
|
+
<% else %>
|
|
49
|
+
<p>
|
|
50
|
+
There are no archives currently. Try making one in the <a href="/host">host view</a>.
|
|
51
|
+
</p>
|
|
52
|
+
<% end %>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="panel-footer">
|
|
55
|
+
<% if show_previous %>
|
|
56
|
+
<a href="<%= show_previous %>" class="pull-left">← Newer</a>
|
|
57
|
+
<% end %>
|
|
58
|
+
|
|
59
|
+
<% if show_next %>
|
|
60
|
+
<a href="<%= show_next %>" class="pull-right">Older →</a>
|
|
61
|
+
<% end %>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<script src="//static.opentok.com/webrtc/v2.2/js/opentok.min.js"></script>
|
|
2
|
+
|
|
3
|
+
<div class="container bump-me">
|
|
4
|
+
|
|
5
|
+
<div class="body-content">
|
|
6
|
+
|
|
7
|
+
<div class="panel panel-default">
|
|
8
|
+
<div class="panel-heading">
|
|
9
|
+
<h3 class="panel-title">Host</h3>
|
|
10
|
+
</div>
|
|
11
|
+
<div class="panel-body">
|
|
12
|
+
<div id="subscribers"><div id="publisher"></div></div>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="panel-footer">
|
|
15
|
+
<button class="btn btn-danger start">Start archiving</button>
|
|
16
|
+
<button class="btn btn-success stop">Stop archiving</button>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<div class="panel panel-default">
|
|
22
|
+
<div class="panel-heading">
|
|
23
|
+
<h3 class="panel-title">Instructions</h3>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="panel-body">
|
|
26
|
+
<p>
|
|
27
|
+
Click <strong>Start archiving</strong> to begin archiving this session.
|
|
28
|
+
All publishers in the session will be included, and all publishers that
|
|
29
|
+
join the session will be included as well.
|
|
30
|
+
</p>
|
|
31
|
+
<p>
|
|
32
|
+
Click <strong>Stop archiving</strong> to end archiving this session.
|
|
33
|
+
You can then go to <a href="/history">past archives</a> to
|
|
34
|
+
view your archive (once its status changes to available).
|
|
35
|
+
</p>
|
|
36
|
+
<table class="table">
|
|
37
|
+
<thead>
|
|
38
|
+
<tr>
|
|
39
|
+
<th>When</th>
|
|
40
|
+
<th>You will see</th>
|
|
41
|
+
</tr>
|
|
42
|
+
</thead>
|
|
43
|
+
<tbody>
|
|
44
|
+
<tr>
|
|
45
|
+
<td style="vertical-align: middle;">Archiving is started</td>
|
|
46
|
+
<td><img src="img/archiving-on-message.png"></td>
|
|
47
|
+
</tr>
|
|
48
|
+
<tr>
|
|
49
|
+
<td style="vertical-align: middle;">Archiving remains on</td>
|
|
50
|
+
<td><img src="img/archiving-on-idle.png"></td>
|
|
51
|
+
</tr>
|
|
52
|
+
<tr>
|
|
53
|
+
<td style="vertical-align: middle;">Archiving is stopped</td>
|
|
54
|
+
<td><img src="img/archiving-off.png"></td>
|
|
55
|
+
</tr>
|
|
56
|
+
</tbody>
|
|
57
|
+
</table>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<script>
|
|
63
|
+
var sessionId = "<%= session_id %>";
|
|
64
|
+
var apiKey = "<%= api_key %>";
|
|
65
|
+
var token = "<%= token %>";
|
|
66
|
+
</script>
|
|
67
|
+
<script src="/js/host.js"></script>
|
|
68
|
+
|
|
69
|
+
</div>
|
|
@@ -0,0 +1,48 @@
|
|
|
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 an archive</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. Anyone with the Host View
|
|
16
|
+
open can click Start Archive or Stop Archive to control
|
|
17
|
+
recording 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
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
</div>
|
|
27
|
+
<div class="col-lg-6 col-offset-1">
|
|
28
|
+
|
|
29
|
+
<div class="panel panel-default">
|
|
30
|
+
<div class="panel-heading">Play an archive</div>
|
|
31
|
+
<div class="panel-body">
|
|
32
|
+
<p>
|
|
33
|
+
Click through to Past Archives to see examples of using the
|
|
34
|
+
Archiving REST API to list archives showing status (started,
|
|
35
|
+
stopped, available) and playback (for available archives).
|
|
36
|
+
</p>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="panel-footer">
|
|
39
|
+
<a class="btn btn-success" href="history">Past Archives</a>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
</div>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
|
6
|
+
<title>Archiving Sample</title>
|
|
7
|
+
<meta name="description" content="">
|
|
8
|
+
<meta name="viewport" content="width=device-width">
|
|
9
|
+
|
|
10
|
+
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/css/bootstrap.min.css">
|
|
11
|
+
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/css/bootstrap-theme.min.css">
|
|
12
|
+
<link rel="stylesheet" href="css/sample.css">
|
|
13
|
+
|
|
14
|
+
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
|
|
15
|
+
</head>
|
|
16
|
+
<body>
|
|
17
|
+
|
|
18
|
+
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
|
|
19
|
+
<!-- Brand and toggle get grouped for better mobile display -->
|
|
20
|
+
<div class="navbar-header">
|
|
21
|
+
<a class="navbar-brand" href="./">Archiving Sample App</a>
|
|
22
|
+
</div>
|
|
23
|
+
</nav>
|
|
24
|
+
|
|
25
|
+
<%= yield %>
|
|
26
|
+
|
|
27
|
+
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/js/bootstrap.min.js"></script>
|
|
28
|
+
</body>
|
|
29
|
+
</html>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<script src="//static.opentok.com/webrtc/v2.2/js/opentok.min.js"></script>
|
|
2
|
+
|
|
3
|
+
<div class="container bump-me">
|
|
4
|
+
|
|
5
|
+
<div class="body-content">
|
|
6
|
+
|
|
7
|
+
<div class="panel panel-default">
|
|
8
|
+
<div class="panel-heading">
|
|
9
|
+
<h3 class="panel-title">Participant</h3>
|
|
10
|
+
</div>
|
|
11
|
+
<div class="panel-body">
|
|
12
|
+
<div id="subscribers"><div id="publisher"></div></div>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div class="panel panel-default">
|
|
18
|
+
<div class="panel-heading">
|
|
19
|
+
<h3 class="panel-title">Instructions</h3>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="panel-body">
|
|
22
|
+
<table class="table">
|
|
23
|
+
<thead>
|
|
24
|
+
<tr>
|
|
25
|
+
<th>When</th>
|
|
26
|
+
<th>You will see</th>
|
|
27
|
+
</tr>
|
|
28
|
+
</thead>
|
|
29
|
+
<tbody>
|
|
30
|
+
<tr>
|
|
31
|
+
<td style="vertical-align: middle;">Archiving is started</td>
|
|
32
|
+
<td><img src="img/archiving-on-message.png"></td>
|
|
33
|
+
</tr>
|
|
34
|
+
<tr>
|
|
35
|
+
<td style="vertical-align: middle;">Archiving remains on</td>
|
|
36
|
+
<td><img src="img/archiving-on-idle.png"></td>
|
|
37
|
+
</tr>
|
|
38
|
+
<tr>
|
|
39
|
+
<td style="vertical-align: middle;">Archiving is stopped</td>
|
|
40
|
+
<td><img src="img/archiving-off.png"></td>
|
|
41
|
+
</tr>
|
|
42
|
+
</tbody>
|
|
43
|
+
</table>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<script>
|
|
49
|
+
var sessionId = "<%= session_id %>";
|
|
50
|
+
var apiKey = "<%= api_key %>";
|
|
51
|
+
var token = "<%= token %>";
|
|
52
|
+
</script>
|
|
53
|
+
<script src="/js/participant.js"></script>
|
|
54
|
+
|
|
55
|
+
</div>
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# OpenTok Hello World Ruby
|
|
2
|
+
|
|
3
|
+
This is a simple demo app that shows how you can use the OpenTok-Ruby-SDK to create Sessions,
|
|
4
|
+
generate Tokens with those Sessions, and then pass these values to a JavaScript client that can
|
|
5
|
+
connect and conduct a group chat.
|
|
6
|
+
|
|
7
|
+
## Running the App
|
|
8
|
+
|
|
9
|
+
First, download the dependencies using [Bundler](http://bundler.io)
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
$ bundle install
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Next, add your own API Key and API Secret to the environment variables. There are a few ways to do
|
|
16
|
+
this but the simplest would be to do it right in your shell.
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
$ export API_KEY=0000000
|
|
20
|
+
$ export API_SECRET=abcdef1234567890abcdef01234567890abcdef
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Finally, start the server using Bundler to handle dependencies
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
$ bundle exec ruby hello_world.rb
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Visit <http://localhost:9393> in your browser. Open it again in a second window. Smile! You've just
|
|
30
|
+
set up a group chat.
|
|
31
|
+
|
|
32
|
+
## Walkthrough
|
|
33
|
+
|
|
34
|
+
This demo application uses the [Sinatra web framework](http://www.sinatrarb.com/). It is similar to
|
|
35
|
+
many other popular web frameworks, such as [Rails](http://rubyonrails.org/), but more light-weight.
|
|
36
|
+
We are only covering the very basics of the framework, but you can learn more by following the links
|
|
37
|
+
above.
|
|
38
|
+
|
|
39
|
+
### Main Application (hello_world.rb)
|
|
40
|
+
|
|
41
|
+
The first thing done in this file is to require the dependencies we will be using. In this case that
|
|
42
|
+
is the Sinatra web framework and most importantly the OpenTok SDK. By running the application with
|
|
43
|
+
the `bundle exec` command, we allow Bundler to select the right versions of these gems from the
|
|
44
|
+
right place.
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
require 'sinatra/base'
|
|
48
|
+
require 'opentok'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Next this file performs some basic checks on the environment. If it cannot find the `API_KEY`and
|
|
52
|
+
`API_SECRET` environment variables, there is no point in continuing.
|
|
53
|
+
|
|
54
|
+
The class `HelloWorld` is our application. The first thing it does is to initialize an instance of
|
|
55
|
+
OpenTok and also store it using Sinatra's `set` method so it can be accessed in other parts of the
|
|
56
|
+
application. At the same time, we also `set` the `api_key` separately so that we can access
|
|
57
|
+
it on its own.
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
set :api_key, ENV['API_KEY']
|
|
61
|
+
set :opentok, OpenTok::OpenTok.new(api_key, ENV['API_SECRET'])
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Now, lets discuss the Hello World application's functionality. We want to set up a group chat so
|
|
65
|
+
that any client that visits a page will connect to the same OpenTok Session. Once they are connected
|
|
66
|
+
they can Publish a Stream and Subscribe to all the other streams in that Session. So we just need
|
|
67
|
+
one Session object, and it needs to be accessible every time a request is made. The next line of our
|
|
68
|
+
application simply calls the `OpenTok` instance's `create_session` method and once again uses `set`
|
|
69
|
+
to store it. Alternatively, `session_id`s are commonly stored in databses for applications that have
|
|
70
|
+
many of them.
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
set :session, opentok.create_session
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
We only need one page, so we create one route handler for any HTTP GET requests to trigger.
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
get '\' do
|
|
80
|
+
# ...
|
|
81
|
+
end
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Now all we have to do is serve a page with the three values the client will need to connect to the
|
|
85
|
+
session: `api_key`, `session_id`, and `token`. The first two are right on the `settings` object
|
|
86
|
+
because we called `set` earlier. Note that the we call the `session_id` method to get just that
|
|
87
|
+
value from the `session` object. The `token` is generated freshly on this request by calling the
|
|
88
|
+
`generate_token` method of the `opentok` instance, and passing in the `session_id`. This is because
|
|
89
|
+
a Token is a piece of information that carries a specific client's permissions in a certain Session.
|
|
90
|
+
Ideally, as we've done here, you generate a unique token for each client that will connect.
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
api_key = settings.api_key
|
|
94
|
+
session_id = settings.session.session_id
|
|
95
|
+
token = settings.opentok.generate_token(session_id)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Now all we have to do is serve a page with those three values. Lets call our `erb` helper that will
|
|
99
|
+
pick up a template called `index.erb` from the `views/` directory in our application and pass in
|
|
100
|
+
the local variables for it to print using the `:locals` hash.
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
erb :index, :locals => {
|
|
104
|
+
:api_key => api_key,
|
|
105
|
+
:session_id => session_id,
|
|
106
|
+
:token => token
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Main Template (views/index.rb)
|
|
111
|
+
|
|
112
|
+
This file simply sets up the HTML page for the JavaScript application to run, imports the
|
|
113
|
+
JavaScript library, and passes the values created by the server into the JavaScript application
|
|
114
|
+
inside `public/js/helloworld.js`
|
|
115
|
+
|
|
116
|
+
### JavaScript Applicaton (public/js/helloworld.js)
|
|
117
|
+
|
|
118
|
+
The group chat is mostly implemented in this file. At a high level, we connect to the given
|
|
119
|
+
Session, publish a stream from our webcam, and listen for new streams from other clients to
|
|
120
|
+
subscribe to.
|
|
121
|
+
|
|
122
|
+
For more details, read the comments in the file or go to the
|
|
123
|
+
[JavaScript Client Library](http://tokbox.com/opentok/libraries/client/js/) for a full reference.
|