social_stream 0.21.4 → 0.22.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.
- data/README.rdoc +11 -5
- data/base/app/assets/stylesheets/cheesecake.css.scss +1 -0
- data/base/app/views/cheesecake/_cheesecake.html.erb +3 -0
- data/base/app/views/cheesecake/_index.html.erb +88 -41
- data/base/app/views/cheesecake/_sector_form.html.erb +12 -12
- data/base/lib/social_stream/base/version.rb +1 -1
- data/base/lib/social_stream/test_helpers/controllers.rb +19 -2
- data/base/lib/tasks/db/populate.rake +190 -165
- data/base/social_stream-base.gemspec +1 -1
- data/base/spec/controllers/posts_controller_spec.rb +19 -1
- data/lib/social_stream/version.rb +1 -1
- data/presence/app/assets/images/status/chat.png +0 -0
- data/presence/app/assets/javascripts/chat_interface_manager.js.erb +42 -45
- data/presence/app/assets/javascripts/chat_parser.js +5 -5
- data/presence/app/assets/javascripts/chat_persistence.js +25 -26
- data/presence/app/assets/javascripts/chat_utilities.js +15 -11
- data/presence/app/assets/javascripts/chat_window_manager.js +129 -26
- data/presence/app/assets/javascripts/jquery.ui.chatbox.sstreampresence.js +22 -3
- data/presence/app/assets/javascripts/social_stream-presence.js +1 -0
- data/presence/app/assets/javascripts/videochat.js.erb +459 -0
- data/presence/app/assets/javascripts/xmpp_client_management.js.erb +303 -65
- data/presence/app/assets/stylesheets/chat.css.scss +42 -1
- data/presence/app/controllers/xmpp_controller.rb +20 -3
- data/presence/app/views/chat/_index.html.erb +7 -2
- data/presence/app/views/xmpp/getOpenTokSessionIDAndToken.xml.builder +6 -0
- data/presence/config/locales/en.yml +22 -1
- data/presence/config/locales/es.yml +23 -2
- data/presence/config/routes.rb +2 -0
- data/presence/ejabberd/conf/ssconfig_example.cfg +4 -3
- data/presence/ejabberd/ejabberd_files.zip +0 -0
- data/presence/ejabberd/ejabberd_scripts/authentication_script +22 -12
- data/presence/ejabberd/ejabberd_scripts/development_scripts/show_config.sh +9 -10
- data/presence/ejabberd/ejabberd_scripts/emanagement +275 -178
- data/presence/ejabberd/ejabberd_scripts/manageWebDomains +164 -0
- data/presence/ejabberd/ejabberd_scripts/rest_api_client_script +75 -32
- data/presence/ejabberd/ejabberd_scripts/synchronize_presence_script +81 -34
- data/presence/ejabberd/mod_sspresence/mod_sspresence.beam +0 -0
- data/presence/ejabberd/mod_sspresence/mod_sspresence.erl +27 -23
- data/presence/lib/OpenTok/Exceptions.rb +11 -0
- data/presence/lib/OpenTok/OpenTokSDK.rb +184 -0
- data/presence/lib/OpenTok/Session.rb +27 -0
- data/presence/lib/generators/social_stream/presence/templates/initializer.rb +8 -2
- data/presence/lib/open_tok.rb +31 -0
- data/presence/lib/opentok.rb +29 -0
- data/presence/lib/social_stream-presence.rb +4 -0
- data/presence/lib/social_stream/presence/models/buddy_manager.rb +1 -1
- data/presence/lib/social_stream/presence/version.rb +1 -1
- data/presence/lib/social_stream/presence/xmpp_server_order.rb +96 -76
- data/presence/lib/social_stream/presence/xmpp_ssclient.rb +54 -0
- data/presence/lib/tasks/presence/multidomain.rake +45 -0
- data/presence/lib/tasks/presence/synchronize.rake +18 -4
- data/presence/vendor/assets/javascripts/TB.min.js +4329 -0
- data/social_stream.gemspec +2 -2
- metadata +40 -30
- data/presence/ejabberd/ejabberd_scripts/reset_connection_script +0 -300
- data/presence/ejabberd/ejabberd_scripts/set_script_header.sh +0 -112
@@ -1,8 +1,3 @@
|
|
1
|
-
require 'xmpp4r'
|
2
|
-
require 'xmpp4r/muc'
|
3
|
-
require 'xmpp4r/roster'
|
4
|
-
require 'xmpp4r/client'
|
5
|
-
require 'xmpp4r/message'
|
6
1
|
require 'net/ssh'
|
7
2
|
require 'net/sftp'
|
8
3
|
|
@@ -32,54 +27,53 @@ module SocialStream
|
|
32
27
|
executeEmanagementCommand("removeBuddyFromRoster",[userSid,buddySid])
|
33
28
|
end
|
34
29
|
|
35
|
-
|
36
|
-
|
37
|
-
def synchronizePresence
|
30
|
+
|
31
|
+
# Presence synchronization
|
32
|
+
def synchronizePresence(webDomain)
|
38
33
|
if isEjabberdNodeUp
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
if (webDomain=="all")
|
35
|
+
output = executeEmanagementCommand("getConnectedJids",[])
|
36
|
+
else
|
37
|
+
output = executeEmanagementCommand("getConnectedJidsByDomain",[webDomain])
|
38
|
+
end
|
39
|
+
user_jids = output.split("\n")
|
40
|
+
synchronizePresenceForJids(user_jids)
|
42
41
|
else
|
43
42
|
resetPresence
|
44
43
|
return "Xmpp Server Down: Reset Connected Users"
|
45
44
|
end
|
46
45
|
end
|
47
46
|
|
48
|
-
|
49
|
-
|
50
|
-
|
47
|
+
def synchronizePresenceForJids(user_jids)
|
48
|
+
domains = getDomainsFromJids(user_jids)
|
49
|
+
domains.each do |domain|
|
50
|
+
user_slugs = getSlugsFromJids(user_jids,domain)
|
51
|
+
synchronizePresenceForSlugs(user_slugs,domain)
|
52
|
+
end
|
51
53
|
end
|
52
|
-
|
53
|
-
|
54
|
-
def synchronizeRosters
|
55
|
-
commands = []
|
56
|
-
|
57
|
-
#"Remove all rosters"
|
58
|
-
commands << buildCommand("emanagement","removeAllRosters",[])
|
59
54
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
users.each do |user|
|
66
|
-
checkedUsers << user.slug
|
67
|
-
contacts = user.contact_actors(:type=>:user)
|
68
|
-
contacts.each do |contact|
|
69
|
-
unless checkedUsers.include?(contact.slug)
|
70
|
-
domain = SocialStream::Presence.domain
|
71
|
-
user_sid = user.slug + "@" + domain
|
72
|
-
contact_sid = contact.slug + "@" + domain
|
73
|
-
commands << buildCommand("emanagement","setBidireccionalBuddys",[user_sid,contact_sid,user.name,contact.name,site_name,site_name])
|
55
|
+
def getSlugsFromJids(user_jids,domain)
|
56
|
+
user_slugs = []
|
57
|
+
user_jids.each do |user_jid|
|
58
|
+
if(user_jid.split("@")[1]==domain)
|
59
|
+
user_slugs << user_jid.split("@")[0]
|
74
60
|
end
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
executeCommands(commands)
|
61
|
+
end
|
62
|
+
return user_slugs
|
79
63
|
end
|
80
64
|
|
81
|
-
|
82
|
-
|
65
|
+
def getDomainsFromJids(user_jids)
|
66
|
+
domains = []
|
67
|
+
user_jids.each do |user_jid|
|
68
|
+
domain=user_jid.split("@")[1]
|
69
|
+
if !domains.include?(domain)
|
70
|
+
domains << domain
|
71
|
+
end
|
72
|
+
end
|
73
|
+
return domains
|
74
|
+
end
|
75
|
+
|
76
|
+
def synchronizePresenceForSlugs(user_slugs,domain)
|
83
77
|
|
84
78
|
#Check connected users
|
85
79
|
users = User.find_all_by_connected(true)
|
@@ -101,6 +95,7 @@ module SocialStream
|
|
101
95
|
end
|
102
96
|
|
103
97
|
|
98
|
+
#Reset presence for all domains
|
104
99
|
def resetPresence
|
105
100
|
users = User.find_all_by_connected(true)
|
106
101
|
|
@@ -111,6 +106,40 @@ module SocialStream
|
|
111
106
|
end
|
112
107
|
|
113
108
|
|
109
|
+
|
110
|
+
# Rosters synchronization
|
111
|
+
def removeAllRosters(webDomain)
|
112
|
+
executeEmanagementCommand("removeAllRostersByDomain",[webDomain])
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
def synchronizeRosters(webDomain)
|
117
|
+
commands = []
|
118
|
+
|
119
|
+
#"Remove all rosters"
|
120
|
+
commands << buildCommand("emanagement","removeAllRostersByDomain",[webDomain])
|
121
|
+
|
122
|
+
#"Populate rosters"
|
123
|
+
users = User.all
|
124
|
+
checkedUsers = []
|
125
|
+
site_name = I18n.t('site.name').delete(' ')
|
126
|
+
|
127
|
+
users.each do |user|
|
128
|
+
checkedUsers << user.slug
|
129
|
+
contacts = user.contact_actors(:type=>:user)
|
130
|
+
contacts.each do |contact|
|
131
|
+
unless checkedUsers.include?(contact.slug)
|
132
|
+
user_sid = user.slug + "@" + webDomain
|
133
|
+
contact_sid = contact.slug + "@" + webDomain
|
134
|
+
commands << buildCommand("emanagement","setBidireccionalBuddys",[user_sid,contact_sid,user.name,contact.name,site_name,site_name])
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
executeCommands(commands)
|
140
|
+
end
|
141
|
+
|
142
|
+
|
114
143
|
#Installation methods
|
115
144
|
|
116
145
|
def copyFolderToXmppServer(oPath,dPath)
|
@@ -183,8 +212,8 @@ module SocialStream
|
|
183
212
|
autoconf.push("scripts_path=" + SocialStream::Presence.scripts_path)
|
184
213
|
autoconf.push("ejabberd_password=" + SocialStream::Presence.xmpp_server_password)
|
185
214
|
autoconf.push("secure_rest_api=" + SocialStream::Presence.secure_rest_api.to_s)
|
186
|
-
autoconf.push("server_domain=" + SocialStream::Presence.domain)
|
187
215
|
autoconf.push("cookie_name=" + Rails.application.config.session_options[:key])
|
216
|
+
autoconf.push("web_domains=[" + SocialStream::Presence.domain + "]")
|
188
217
|
|
189
218
|
#Param options
|
190
219
|
if options
|
@@ -337,7 +366,7 @@ module SocialStream
|
|
337
366
|
output=""
|
338
367
|
commands.each do |command|
|
339
368
|
response = %x[#{command}]
|
340
|
-
output = output + "\n"
|
369
|
+
output = output + response + "\n";
|
341
370
|
end
|
342
371
|
return output
|
343
372
|
end
|
@@ -354,7 +383,7 @@ module SocialStream
|
|
354
383
|
commands.each do |command|
|
355
384
|
response = session.exec!(command)
|
356
385
|
if response != nil
|
357
|
-
output = output + "\n"
|
386
|
+
output = output + response + "\n";
|
358
387
|
end
|
359
388
|
end
|
360
389
|
end
|
@@ -506,43 +535,34 @@ module SocialStream
|
|
506
535
|
return hash
|
507
536
|
end
|
508
537
|
|
509
|
-
#Xmpp client manage methods
|
510
538
|
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
def openXmppClientForSocialStreamUser
|
521
|
-
begin
|
522
|
-
password= SocialStream::Presence.password
|
523
|
-
client = Jabber::Client.new(Jabber::JID.new(getSocialStreamUserSid))
|
524
|
-
client.connect
|
525
|
-
client.auth(password)
|
526
|
-
return client
|
527
|
-
rescue Exception => e
|
528
|
-
case e
|
529
|
-
when Errno::ECONNREFUSED
|
530
|
-
puts "Connection to XMPP Server refused"
|
531
|
-
return nil
|
532
|
-
else
|
533
|
-
puts "Unknown exception: #{e.to_s}"
|
534
|
-
return nil
|
535
|
-
end
|
539
|
+
#Multidomain tasks
|
540
|
+
def addWebDomain(domain,url)
|
541
|
+
commands = []
|
542
|
+
if url
|
543
|
+
commands << buildCommand("manageWebDomains","add",[domain,url])
|
544
|
+
else
|
545
|
+
commands << buildCommand("manageWebDomains","add",[domain])
|
536
546
|
end
|
547
|
+
return executeCommands(commands)
|
537
548
|
end
|
538
549
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
client.send(msg)
|
550
|
+
def removeWebDomain(domain)
|
551
|
+
commands = []
|
552
|
+
commands << buildCommand("manageWebDomains","remove",[domain])
|
553
|
+
return executeCommands(commands)
|
544
554
|
end
|
545
|
-
|
555
|
+
|
556
|
+
def updateWebDomain(domain,url)
|
557
|
+
commands = []
|
558
|
+
if url
|
559
|
+
commands << buildCommand("manageWebDomains","update",[domain,url])
|
560
|
+
else
|
561
|
+
commands << buildCommand("manageWebDomains","update",[domain])
|
562
|
+
end
|
563
|
+
return executeCommands(commands)
|
564
|
+
end
|
565
|
+
|
546
566
|
end
|
547
567
|
end
|
548
568
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'xmpp4r'
|
2
|
+
require 'xmpp4r/muc'
|
3
|
+
require 'xmpp4r/roster'
|
4
|
+
require 'xmpp4r/client'
|
5
|
+
require 'xmpp4r/message'
|
6
|
+
|
7
|
+
|
8
|
+
module SocialStream
|
9
|
+
module Presence
|
10
|
+
class XmppSsclient
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
#Xmpp client manage methods
|
15
|
+
|
16
|
+
def getSocialStreamUserSid
|
17
|
+
#WEB DOMAIN
|
18
|
+
domain = SocialStream::Presence.domain
|
19
|
+
#SS Username
|
20
|
+
ss_name = SocialStream::Presence.social_stream_presence_username
|
21
|
+
return ss_name + "@" + domain
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def openXmppClientForSocialStreamUser
|
26
|
+
begin
|
27
|
+
password= SocialStream::Presence.password
|
28
|
+
client = Jabber::Client.new(Jabber::JID.new(getSocialStreamUserSid))
|
29
|
+
client.connect
|
30
|
+
client.auth(password)
|
31
|
+
return client
|
32
|
+
rescue Exception => e
|
33
|
+
case e
|
34
|
+
when Errno::ECONNREFUSED
|
35
|
+
puts "Connection to XMPP Server refused"
|
36
|
+
return nil
|
37
|
+
else
|
38
|
+
puts "Unknown exception: #{e.to_s}"
|
39
|
+
return nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def sendXmppChatMessage(client,dest_sid,body)
|
46
|
+
msg = Jabber::Message::new(dest_sid, body)
|
47
|
+
msg.type=:chat
|
48
|
+
client.send(msg)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
namespace :presence do
|
2
|
+
desc 'Add web domains to Xmpp Server'
|
3
|
+
task :multidomain => [ 'presence:multidomain:add', 'presence:multidomain:remove' ,
|
4
|
+
'presence:multidomain:update']
|
5
|
+
|
6
|
+
namespace :multidomain do
|
7
|
+
|
8
|
+
desc "Add new web domain to XMPP Server"
|
9
|
+
task :add, [:domain, :url] => :environment do |t, args|
|
10
|
+
puts "Starting presence:multidomain:add"
|
11
|
+
unless args[:domain]
|
12
|
+
puts "Please specify a web domain"
|
13
|
+
puts "Syntax: rake presence:multidomain:add[domain,[url]]"
|
14
|
+
return
|
15
|
+
end
|
16
|
+
response = SocialStream::Presence::XmppServerOrder::addWebDomain(args[:domain],args[:url])
|
17
|
+
puts response
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "Remove web domain from the XMPP Server"
|
21
|
+
task :remove, [:domain] => :environment do |t, args|
|
22
|
+
puts "Starting presence:multidomain:remove"
|
23
|
+
unless args[:domain]
|
24
|
+
puts "Please specify a web domain"
|
25
|
+
puts "Syntax: rake presence:multidomain:remove[domain]"
|
26
|
+
return
|
27
|
+
end
|
28
|
+
response = SocialStream::Presence::XmppServerOrder::removeWebDomain(args[:domain])
|
29
|
+
puts response
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "Update web domain of XMPP Server"
|
33
|
+
task :update, [:domain, :url] => :environment do |t, args|
|
34
|
+
puts "Starting presence:multidomain:update"
|
35
|
+
unless args[:domain]
|
36
|
+
puts "Please specify a web domain"
|
37
|
+
puts "Syntax: rake presence:multidomain:update[domain,[url]]"
|
38
|
+
return
|
39
|
+
end
|
40
|
+
response = SocialStream::Presence::XmppServerOrder::updateWebDomain(args[:domain],args[:url])
|
41
|
+
puts response
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -5,17 +5,31 @@ namespace :presence do
|
|
5
5
|
namespace :synchronize do
|
6
6
|
|
7
7
|
desc "Synchronize user presence"
|
8
|
-
task :connections => :environment do
|
8
|
+
task :connections, [:domain] => :environment do |t, args|
|
9
9
|
puts "Starting presence:synchronize:connections"
|
10
|
-
|
10
|
+
unless args[:domain]
|
11
|
+
puts "No web domain specified"
|
12
|
+
domain = SocialStream::Presence.domain
|
13
|
+
puts "Executing rake presence:synchronize:connections[" + domain + "]"
|
14
|
+
else
|
15
|
+
domain = args[:domain]
|
16
|
+
end
|
17
|
+
SocialStream::Presence::XmppServerOrder::synchronizePresence(domain)
|
11
18
|
puts "Synchronization complete"
|
12
19
|
end
|
13
20
|
|
14
21
|
desc "Synchronize Xmpp Server database with Social Stream Rails Application database"
|
15
22
|
desc "Remove all rosters and populate rosters from Social Stream data."
|
16
|
-
task :rosters => :environment do
|
23
|
+
task :rosters, [:domain] => :environment do |t, args|
|
17
24
|
puts "Starting presence:synchronize:rosters"
|
18
|
-
|
25
|
+
unless args[:domain]
|
26
|
+
puts "No web domain specified"
|
27
|
+
domain = SocialStream::Presence.domain
|
28
|
+
puts "Executing rake presence:synchronize:rosters[" + domain + "]"
|
29
|
+
else
|
30
|
+
domain = args[:domain]
|
31
|
+
end
|
32
|
+
SocialStream::Presence::XmppServerOrder::synchronizeRosters(domain)
|
19
33
|
puts "Rosters Synchronization complete"
|
20
34
|
end
|
21
35
|
end
|
@@ -0,0 +1,4329 @@
|
|
1
|
+
/*!
|
2
|
+
* OpenTok JavaScript Library v0.91.46
|
3
|
+
* http://www.tokbox.com/
|
4
|
+
*
|
5
|
+
* Copyright (c) 2011 TokBox, Inc.
|
6
|
+
*
|
7
|
+
* Date: February 16 18:15:10 2012
|
8
|
+
*/
|
9
|
+
|
10
|
+
function getHostname() {
|
11
|
+
return window.location.hostname;
|
12
|
+
}
|
13
|
+
|
14
|
+
// Instrumentation
|
15
|
+
|
16
|
+
TB = function() {
|
17
|
+
|
18
|
+
//--------------------------------------
|
19
|
+
// EVENT CLASSES
|
20
|
+
//--------------------------------------
|
21
|
+
|
22
|
+
function EventDispatcher() {
|
23
|
+
this._listeners = {};
|
24
|
+
|
25
|
+
this.addEventListener = function(type, listener) {
|
26
|
+
if (!type) {
|
27
|
+
throw new Error("EventDispatcher.addEventListener :: No type specified");
|
28
|
+
}
|
29
|
+
if (!listener) {
|
30
|
+
throw new Error("EventDispatcher.addEventListener :: No listener function specified");
|
31
|
+
}
|
32
|
+
|
33
|
+
|
34
|
+
if (!this._listeners.hasOwnProperty(type)) {
|
35
|
+
this._listeners[type] = new Array();
|
36
|
+
}
|
37
|
+
this.removeEventListener(type, listener); // You cannot have the same listener for the same type multiple times
|
38
|
+
debug("TB.addEventListener(" + type + ")");
|
39
|
+
this._listeners[type].push(listener);
|
40
|
+
};
|
41
|
+
|
42
|
+
this.removeEventListener = function(type, listener) {
|
43
|
+
if (!type) {
|
44
|
+
throw new Error("EventDispatcher.removeEventListener :: No type specified");
|
45
|
+
}
|
46
|
+
if (!listener) {
|
47
|
+
throw new Error("EventDispatcher.removeEventListener :: No listener function specified");
|
48
|
+
}
|
49
|
+
|
50
|
+
debug("TB.removeEventListener(" + type + ")");
|
51
|
+
if (this._listeners.hasOwnProperty(type)) {
|
52
|
+
for (var i=0; i < this._listeners[type].length; i++) {
|
53
|
+
if (this._listeners[type][i] == listener) {
|
54
|
+
this._listeners[type].splice(i, 1);
|
55
|
+
break;
|
56
|
+
}
|
57
|
+
};
|
58
|
+
}
|
59
|
+
};
|
60
|
+
|
61
|
+
this.dispatchEvent = function(event) {
|
62
|
+
if (!event) {
|
63
|
+
throw new Error("EventDispatcher.dispatchEvent :: No event specified");
|
64
|
+
}
|
65
|
+
if (!event.type) {
|
66
|
+
throw new Error("EventDispatcher.dispatchEvent :: Event has no type");
|
67
|
+
}
|
68
|
+
if (!event.target) {
|
69
|
+
event.target = this;
|
70
|
+
}
|
71
|
+
|
72
|
+
if (this._listeners.hasOwnProperty(event.type)) {
|
73
|
+
var listeners = this._listeners[event.type];
|
74
|
+
|
75
|
+
if (listeners instanceof Array) {
|
76
|
+
for (var i=0; i < listeners.length; i++) {
|
77
|
+
var handler = createHandler(listeners[i], event);
|
78
|
+
// We run this asynchronously so that it doesn't interfere with execution if an error happens
|
79
|
+
// eg. multiple event handlers are added one has an error so the subsequent ones fail
|
80
|
+
setTimeout(handler, 1);
|
81
|
+
};
|
82
|
+
} else {
|
83
|
+
throw new Error("EventDispatcher.dispatchEvent :: Invalid object type in listeners");
|
84
|
+
}
|
85
|
+
}
|
86
|
+
};
|
87
|
+
}
|
88
|
+
|
89
|
+
function Event (type, cancelable) {
|
90
|
+
this.type = type;
|
91
|
+
this.cancelable = cancelable ? cancelable : false;
|
92
|
+
this.target;
|
93
|
+
|
94
|
+
var defaultPrevented = false;
|
95
|
+
|
96
|
+
this.preventDefault = function() {
|
97
|
+
if (this.cancelable) {
|
98
|
+
defaultPrevented = true;
|
99
|
+
} else {
|
100
|
+
warn("Event.preventDefault :: Trying to preventDefault on an Event that isn't cancelable");
|
101
|
+
}
|
102
|
+
};
|
103
|
+
|
104
|
+
this.isDefaultPrevented = function() {
|
105
|
+
return defaultPrevented;
|
106
|
+
};
|
107
|
+
}
|
108
|
+
|
109
|
+
function ExceptionEvent (type, message, title, code) {
|
110
|
+
this.superClass = Event;
|
111
|
+
this.superClass(type);
|
112
|
+
|
113
|
+
this.message = message;
|
114
|
+
this.title = title;
|
115
|
+
this.code = code;
|
116
|
+
}
|
117
|
+
|
118
|
+
function ConnectionEvent (type, connections, reason) {
|
119
|
+
this.superClass = Event;
|
120
|
+
this.superClass(type);
|
121
|
+
|
122
|
+
this.connections = connections;
|
123
|
+
this.reason = reason;
|
124
|
+
}
|
125
|
+
|
126
|
+
function StreamEvent (type, streams, reason, cancelable) {
|
127
|
+
this.superClass = Event;
|
128
|
+
this.superClass(type, cancelable);
|
129
|
+
|
130
|
+
this.streams = streams;
|
131
|
+
this.reason = reason;
|
132
|
+
}
|
133
|
+
|
134
|
+
function SessionConnectEvent (type, connections, streams, groups, archives) {
|
135
|
+
this.superClass = Event;
|
136
|
+
this.superClass(type);
|
137
|
+
|
138
|
+
this.connections = connections;
|
139
|
+
this.streams = streams;
|
140
|
+
this.groups = groups;
|
141
|
+
this.archives = archives;
|
142
|
+
}
|
143
|
+
|
144
|
+
function SessionDisconnectEvent (type, reason, cancelable) {
|
145
|
+
this.superClass = Event;
|
146
|
+
this.superClass(type, cancelable);
|
147
|
+
|
148
|
+
this.reason = reason;
|
149
|
+
}
|
150
|
+
|
151
|
+
function SignalEvent (type, fromConnection) {
|
152
|
+
this.superClass = Event;
|
153
|
+
this.superClass(type);
|
154
|
+
|
155
|
+
this.fromConnection = fromConnection;
|
156
|
+
}
|
157
|
+
|
158
|
+
function VolumeEvent(type, streamId, volume) {
|
159
|
+
this.superClass = Event;
|
160
|
+
this.superClass(type);
|
161
|
+
|
162
|
+
this.streamId = streamId;
|
163
|
+
this.volume = volume;
|
164
|
+
}
|
165
|
+
|
166
|
+
|
167
|
+
function DeviceEvent (type, camera, microphone) {
|
168
|
+
this.superClass = Event;
|
169
|
+
this.superClass(type);
|
170
|
+
|
171
|
+
this.camera = camera;
|
172
|
+
this.microphone = microphone;
|
173
|
+
}
|
174
|
+
|
175
|
+
function GroupEvent (type, group, reason) {
|
176
|
+
this.superClass = Event;
|
177
|
+
this.superClass(type);
|
178
|
+
|
179
|
+
this.group = group;
|
180
|
+
this.reason = reason;
|
181
|
+
}
|
182
|
+
|
183
|
+
function DeviceStatusEvent (type, cameras, microphones, selectedCamera, selectedMicrophone) {
|
184
|
+
this.superClass = Event;
|
185
|
+
this.superClass(type);
|
186
|
+
|
187
|
+
this.cameras = cameras;
|
188
|
+
this.microphones = microphones;
|
189
|
+
this.selectedCamera = selectedCamera;
|
190
|
+
this.selectedMicrophone = selectedMicrophone;
|
191
|
+
}
|
192
|
+
|
193
|
+
function ResizeEvent (type, widthFrom, widthTo, heightFrom, heightTo) {
|
194
|
+
this.superClass = Event;
|
195
|
+
this.superClass(type);
|
196
|
+
|
197
|
+
this.widthFrom = widthFrom;
|
198
|
+
this.widthTo = widthTo;
|
199
|
+
this.heightFrom = heightFrom;
|
200
|
+
this.heightTo = heightTo;
|
201
|
+
}
|
202
|
+
|
203
|
+
function StreamPropertyChangedEvent(type, stream, changedProperty, oldValue, newValue) {
|
204
|
+
this.superClass = Event;
|
205
|
+
this.superClass(type);
|
206
|
+
|
207
|
+
this.type = type;
|
208
|
+
this.stream = stream;
|
209
|
+
this.changedProperty = changedProperty;
|
210
|
+
this.oldValue = oldValue;
|
211
|
+
this.newValue = newValue;
|
212
|
+
}
|
213
|
+
|
214
|
+
function ArchiveEvent (type, archives) {
|
215
|
+
this.superClass = Event;
|
216
|
+
this.superClass(type);
|
217
|
+
|
218
|
+
this.archives = archives;
|
219
|
+
}
|
220
|
+
|
221
|
+
function ArchiveStreamEvent (type, archive, streams) {
|
222
|
+
this.superClass = Event;
|
223
|
+
this.superClass(type);
|
224
|
+
|
225
|
+
this.archive = archive;
|
226
|
+
this.streams = streams;
|
227
|
+
}
|
228
|
+
|
229
|
+
function StateChangedEvent(type, changedValues) {
|
230
|
+
this.superClass = Event;
|
231
|
+
this.superClass(type);
|
232
|
+
this.changedValues = changedValues;
|
233
|
+
}
|
234
|
+
|
235
|
+
function ChangeFailedEvent(type, reasonCode, reason, failedValues) {
|
236
|
+
this.superClass = Event;
|
237
|
+
this.superClass(type);
|
238
|
+
|
239
|
+
this.reasonCode = reasonCode;
|
240
|
+
this.reason = reason;
|
241
|
+
this.failedValues = failedValues;
|
242
|
+
}
|
243
|
+
|
244
|
+
//--------------------------------------
|
245
|
+
// CLASSES
|
246
|
+
//--------------------------------------
|
247
|
+
|
248
|
+
function Connection (connectionId, creationTime, data) {
|
249
|
+
this.connectionId = connectionId;
|
250
|
+
this.creationTime = Number(creationTime);
|
251
|
+
this.data = data;
|
252
|
+
|
253
|
+
this.quality;
|
254
|
+
}
|
255
|
+
|
256
|
+
|
257
|
+
function Stream (streamId, connection, name, data, type, creationTime, hasAudio, hasVideo, orientation, sessionId, peerId, quality) {
|
258
|
+
//INSTANCE VARIABLES
|
259
|
+
this.streamId = streamId;
|
260
|
+
this.connection = connection;
|
261
|
+
this.name = name;
|
262
|
+
this.data = data;
|
263
|
+
this.type = type;
|
264
|
+
this.creationTime = creationTime;
|
265
|
+
this.hasAudio = hasAudio;
|
266
|
+
this.hasVideo = hasVideo;
|
267
|
+
this.orientation = orientation;
|
268
|
+
this.peerId = peerId;
|
269
|
+
this.quality = quality;
|
270
|
+
|
271
|
+
this.startRecording = function(archive) {
|
272
|
+
debug("Stream.startRecording()");
|
273
|
+
var controllerId = "controller_" + sessionId;
|
274
|
+
archive = createdArchives[sessionId][archive.archiveId];
|
275
|
+
if (!archive) {
|
276
|
+
var errorMsg = "Stream.startRecording :: Archive not created.";
|
277
|
+
error(errorMsg);
|
278
|
+
throw new Error(errorMsg);
|
279
|
+
}
|
280
|
+
if (archive.type != TB.PER_STREAM) {
|
281
|
+
errorMsg = "Stream.startRecording :: Trying to record per stream on a " + archive.type + " archive";
|
282
|
+
error(errorMsg);
|
283
|
+
throw new Error(errorMsg);
|
284
|
+
}
|
285
|
+
if (controllerId && this.connection && this.connection.connectionId) {
|
286
|
+
try {
|
287
|
+
var controller = document.getElementById(controllerId);
|
288
|
+
controller.startRecordingStream(this.streamId, archive.archiveId);
|
289
|
+
archive.recording = true;
|
290
|
+
} catch(err) {
|
291
|
+
errorMsg = "Stream.startRecording :: " + err;
|
292
|
+
error(errorMsg);
|
293
|
+
throw new Error(errorMsg);
|
294
|
+
}
|
295
|
+
} else {
|
296
|
+
errorMsg = "Stream.startRecording :: Connection required to record an archive.";
|
297
|
+
error(errorMsg);
|
298
|
+
throw new Error(errorMsg);
|
299
|
+
}
|
300
|
+
};
|
301
|
+
|
302
|
+
this.stopRecording = function(archive) {
|
303
|
+
debug("Stream.stopRecording()");
|
304
|
+
archive = createdArchives[sessionId][archive.archiveId];
|
305
|
+
if (!archive) {
|
306
|
+
var errorMsg = "Stream.stopRecording :: Archive not created.";
|
307
|
+
error(errorMsg);
|
308
|
+
throw new Error(errorMsg);
|
309
|
+
}
|
310
|
+
if (archive.type != TB.PER_STREAM) {
|
311
|
+
errorMsg = "Stream.stopRecording :: Trying to stop recording per stream on a " + archive.type + " archive";
|
312
|
+
error(errorMsg);
|
313
|
+
throw new Error(errorMsg);
|
314
|
+
}
|
315
|
+
var controllerId = "controller_" + sessionId;
|
316
|
+
if (controllerId && this.connection && this.connection.connectionId) {
|
317
|
+
try {
|
318
|
+
var controller = document.getElementById(controllerId);
|
319
|
+
controller.stopRecordingStream(this.streamId, archive.archiveId);
|
320
|
+
} catch(err) {
|
321
|
+
errorMsg = "Stream.stopRecording :: " + err;
|
322
|
+
error(errorMsg);
|
323
|
+
throw new Error(errorMsg);
|
324
|
+
}
|
325
|
+
} else {
|
326
|
+
errorMsg = "Stream.stopRecording :: Connection required to record an archive.";
|
327
|
+
error(errorMsg);
|
328
|
+
throw new Error(errorMsg);
|
329
|
+
}
|
330
|
+
};
|
331
|
+
}
|
332
|
+
|
333
|
+
function UIComponent (id, replacedDivId) {
|
334
|
+
this.id = id;
|
335
|
+
this.replacedDivId = replacedDivId;
|
336
|
+
this.parentClass = EventDispatcher;
|
337
|
+
this.parentClass();
|
338
|
+
}
|
339
|
+
|
340
|
+
function StylableComponent(id, replacedDivId) {
|
341
|
+
this.uberClass = UIComponent;
|
342
|
+
this.uberClass(id, replacedDivId);
|
343
|
+
|
344
|
+
var componentStyles = ["showMicButton", "showSpeakerButton", "showSettingsButton", "showCameraToggleButton", "nameDisplayMode", "buttonDisplayMode", "showSaveButton", "showRecordButton", "showRecordStopButton", "showReRecordButton", "showPauseButton", "showPlayButton", "showPlayStopButton", "showStopButton", "backgroundImageURI", "showControlPanel", "showRecordCounter", "showPlayCounter", "showControlBar"];
|
345
|
+
this.getStyle = function(key) {
|
346
|
+
var component = document.getElementById(this.id);
|
347
|
+
if (!this.loaded) {
|
348
|
+
if (key) {
|
349
|
+
return this._style[key];
|
350
|
+
} else {
|
351
|
+
return this._style;
|
352
|
+
}
|
353
|
+
} else if (component) {
|
354
|
+
try {
|
355
|
+
var style = component.getStyle(key);
|
356
|
+
if (typeof(style) == "string")
|
357
|
+
return style;
|
358
|
+
for (var i in style) {
|
359
|
+
if (style[i] == "false")
|
360
|
+
style[i] = false;
|
361
|
+
if (style[i] == "true")
|
362
|
+
style[i] = true;
|
363
|
+
if (componentStyles.indexOf(i) < 0) {
|
364
|
+
// Strip unnecessary properties out
|
365
|
+
delete style[i];
|
366
|
+
}
|
367
|
+
};
|
368
|
+
return style;
|
369
|
+
} catch (err) {
|
370
|
+
var errorMsg = "Publisher.getStyle:: Failed to call getStyle. " + err;
|
371
|
+
error(errorMsg);
|
372
|
+
throw new Error(errorMsg);
|
373
|
+
}
|
374
|
+
} else {
|
375
|
+
errorMsg = "Publisher.getStyle:: Publisher " + this.id + " does not exist.";
|
376
|
+
error(errorMsg);
|
377
|
+
throw new Error(errorMsg);
|
378
|
+
}
|
379
|
+
};
|
380
|
+
|
381
|
+
this._style = {};
|
382
|
+
var validStyleValues = {
|
383
|
+
buttonDisplayMode: ["auto", "off", "on"],
|
384
|
+
nameDisplayMode: ["auto", "off", "on"],
|
385
|
+
showSettingsButton: [true, false],
|
386
|
+
showMicButton: [true, false],
|
387
|
+
showCameraToggleButton: [true, false],
|
388
|
+
showSaveButton: [true, false],
|
389
|
+
backgroundImageURI: null,
|
390
|
+
showControlBar: [true, false],
|
391
|
+
showPlayCounter: [true, false],
|
392
|
+
showRecordCounter: [true, false]
|
393
|
+
};
|
394
|
+
this.setStyle = function(key, value) {
|
395
|
+
debug("Publisher.setStyle: " + key.toString());
|
396
|
+
var component = document.getElementById(this.id);
|
397
|
+
if (!this.loaded) {
|
398
|
+
if ((typeof(key) == "string") && value != null) {
|
399
|
+
if (this._style.hasOwnProperty(key) && (key == "backgroundImageURI" || (validStyleValues[key].indexOf(value) > -1)) ) {
|
400
|
+
debug("setStyle::Setting " + key + " to " + value);
|
401
|
+
this._style[key] = value;
|
402
|
+
} else {
|
403
|
+
warn("setStyle::Invalid style property passed " + key + " : " + value);
|
404
|
+
}
|
405
|
+
} else {
|
406
|
+
for (var i in key) {
|
407
|
+
this.setStyle(i, key[i]);
|
408
|
+
};
|
409
|
+
}
|
410
|
+
this.modified = true;
|
411
|
+
} else if (component) {
|
412
|
+
try {
|
413
|
+
component.setStyle(key, value);
|
414
|
+
} catch (err) {
|
415
|
+
var errorMsg = "Publisher.setStyle:: Failed to call setStyle. " + err;
|
416
|
+
error(errorMsg);
|
417
|
+
throw new Error(errorMsg);
|
418
|
+
}
|
419
|
+
} else {
|
420
|
+
errorMsg = "Publisher.setStyle:: Publisher " + this.id + " does not exist.";
|
421
|
+
error(errorMsg);
|
422
|
+
throw new Error(errorMsg);
|
423
|
+
}
|
424
|
+
|
425
|
+
return this;
|
426
|
+
};
|
427
|
+
}
|
428
|
+
|
429
|
+
function VideoComponent(id, replacedDivId) {
|
430
|
+
this.supClass = StylableComponent;
|
431
|
+
this.supClass(id, replacedDivId);
|
432
|
+
|
433
|
+
this.getImgData = function() {
|
434
|
+
debug("VideoComponent.getImgData");
|
435
|
+
|
436
|
+
var component = document.getElementById(this.id);
|
437
|
+
if (component) {
|
438
|
+
try {
|
439
|
+
return component.getImgData();
|
440
|
+
} catch(err) {
|
441
|
+
var errorMsg = "VideoComponent.getImgData:: Failed to call getImgData. " + err;
|
442
|
+
error(errorMsg);
|
443
|
+
throw new Error(errorMsg);
|
444
|
+
}
|
445
|
+
} else {
|
446
|
+
errorMsg = "VideoComponent.getImgData:: Component " + this.id + " does not exist.";
|
447
|
+
error(errorMsg);
|
448
|
+
throw new Error(errorMsg);
|
449
|
+
}
|
450
|
+
};
|
451
|
+
}
|
452
|
+
|
453
|
+
|
454
|
+
function Publisher (id, replacedDivId, properties) {
|
455
|
+
this.superClass = VideoComponent;
|
456
|
+
this.superClass(id, replacedDivId);
|
457
|
+
this._style = {
|
458
|
+
showMicButton: true,
|
459
|
+
showSettingsButton: true,
|
460
|
+
showCameraToggleButton: true,
|
461
|
+
nameDisplayMode: "auto",
|
462
|
+
buttonDisplayMode: "auto",
|
463
|
+
backgroundImageURI: null
|
464
|
+
};
|
465
|
+
|
466
|
+
this.modified = false;
|
467
|
+
|
468
|
+
if (properties && properties.hasOwnProperty("style")) {
|
469
|
+
this.setStyle(properties['style']);
|
470
|
+
this.modified = true;
|
471
|
+
}
|
472
|
+
|
473
|
+
this.properties = properties;
|
474
|
+
this.loaded = false;
|
475
|
+
this.panelId = null;
|
476
|
+
this.gain = 50;
|
477
|
+
|
478
|
+
if(properties && properties.hasOwnProperty("microphoneGain")) {
|
479
|
+
this.gain = parseInt(properties["microphoneGain"], 10);
|
480
|
+
}
|
481
|
+
|
482
|
+
this.enableMicrophone = function() {
|
483
|
+
this.publishAudio(true);
|
484
|
+
};
|
485
|
+
this.disableMicrophone = function() {
|
486
|
+
this.publishAudio(false);
|
487
|
+
};
|
488
|
+
this.setMicrophoneGain = function(value) {
|
489
|
+
var component = document.getElementById(this.id);
|
490
|
+
if (!this.loaded) {
|
491
|
+
this.gain = value;
|
492
|
+
this.modified = true;
|
493
|
+
} else if (component) {
|
494
|
+
try {
|
495
|
+
component.setMicGain(value);
|
496
|
+
} catch (err) {
|
497
|
+
var errorMsg = "Microphone gain adjustment on publisher "+this.id+" failed";
|
498
|
+
error(errorMsg);
|
499
|
+
throw new Error(errorMsg);
|
500
|
+
}
|
501
|
+
} else {
|
502
|
+
errorMsg = "Publisher "+ this.id + " does not exist.";
|
503
|
+
error(errorMsg);
|
504
|
+
throw new Error(errorMsg);
|
505
|
+
}
|
506
|
+
return this;
|
507
|
+
};
|
508
|
+
this.getMicrophoneGain = function() {
|
509
|
+
var component = document.getElementById(this.id);
|
510
|
+
if (!this.loaded) {
|
511
|
+
return this.gain;
|
512
|
+
} else if (component) {
|
513
|
+
try {
|
514
|
+
return component.getMicGain();
|
515
|
+
} catch (err) {
|
516
|
+
var errorMsg = "Microphone gain adjustment on publisher "+this.id+" failed";
|
517
|
+
error(errorMsg);
|
518
|
+
throw new Error(errorMsg);
|
519
|
+
}
|
520
|
+
} else {
|
521
|
+
errorMsg = "Publisher "+ this.id + " does not exist.";
|
522
|
+
error(errorMsg);
|
523
|
+
throw new Error(errorMsg);
|
524
|
+
}
|
525
|
+
};
|
526
|
+
this.getEchoCancellationMode = function() {
|
527
|
+
debug("Publisher.getEchoCancellationMode()");
|
528
|
+
|
529
|
+
var mode = "";
|
530
|
+
var component = document.getElementById(this.id);
|
531
|
+
if (!this.loaded) {
|
532
|
+
return "unknown";
|
533
|
+
} else if (component) {
|
534
|
+
try {
|
535
|
+
mode = component.getEchoCancellationMode();
|
536
|
+
} catch (err) {
|
537
|
+
var errorMsg = "Getting echo cancellation mode for publisher " + this.id + " failed. " + err;
|
538
|
+
error(errorMsg);
|
539
|
+
throw new Error(errorMsg);
|
540
|
+
}
|
541
|
+
} else {
|
542
|
+
errorMsg = "Publisher "+ this.id + " does not exist.";
|
543
|
+
error(errorMsg);
|
544
|
+
throw new Error(errorMsg);
|
545
|
+
}
|
546
|
+
return mode;
|
547
|
+
};
|
548
|
+
this.publishAudio = function(publishAudioBool) {
|
549
|
+
debug("Publisher.publishAudio()");
|
550
|
+
if (!this.loaded) {
|
551
|
+
this.audioPublished = publishAudioBool;
|
552
|
+
this.modified = true;
|
553
|
+
} else {
|
554
|
+
setStreamProperty(this.id, "publishAudio", publishAudioBool);
|
555
|
+
}
|
556
|
+
};
|
557
|
+
this.publishVideo = function(publishVideoBool) {
|
558
|
+
debug("Publisher.publishVideo()");
|
559
|
+
if (!this.loaded) {
|
560
|
+
this.videoPublished = publishVideoBool;
|
561
|
+
this.modified = true;
|
562
|
+
} else {
|
563
|
+
setStreamProperty(this.id, "publishVideo", publishVideoBool);
|
564
|
+
}
|
565
|
+
};
|
566
|
+
this.setCamera = function(camera) {
|
567
|
+
// Private function
|
568
|
+
debug("Publisher.setCamera(" + camera + ")");
|
569
|
+
setDevice(this.id, camera, true);
|
570
|
+
};
|
571
|
+
this.setMicrophone = function(microphone) {
|
572
|
+
// Private function
|
573
|
+
debug("Publisher.setMicrophone(" + microphone + ")");
|
574
|
+
setDevice(this.id, microphone, false);
|
575
|
+
};
|
576
|
+
|
577
|
+
}
|
578
|
+
|
579
|
+
|
580
|
+
function Subscriber (stream, id, replacedDivId, properties) {
|
581
|
+
this.superClass = VideoComponent;
|
582
|
+
this.superClass(id, replacedDivId);
|
583
|
+
this._style = {
|
584
|
+
nameDisplayMode: "auto",
|
585
|
+
buttonDisplayMode: "auto",
|
586
|
+
backgroundImageURI: null
|
587
|
+
};
|
588
|
+
|
589
|
+
this.modified = false;
|
590
|
+
|
591
|
+
if (properties && properties.hasOwnProperty("style")) {
|
592
|
+
this.setStyle(properties['style']);
|
593
|
+
this.modified = true;
|
594
|
+
}
|
595
|
+
|
596
|
+
this.stream = stream;
|
597
|
+
this.properties = properties;
|
598
|
+
this.loaded = false;
|
599
|
+
this.audioVolume = 50;
|
600
|
+
|
601
|
+
var _isAudioSubscribed = true;
|
602
|
+
var _isVideoSubscribed = true;
|
603
|
+
|
604
|
+
if(properties) {
|
605
|
+
if(properties.hasOwnProperty("subscribeToAudio") && (properties["subscribeToAudio"] == "false" || properties["subscribeToAudio"] == false)) {
|
606
|
+
_isAudioSubscribed = false;
|
607
|
+
}
|
608
|
+
|
609
|
+
if(properties.hasOwnProperty("subscribeToVideo") && (properties["subscribeToVideo"] == "false" || properties["subscribeToVideo"] == false)) {
|
610
|
+
_isVideoSubscribed = false;
|
611
|
+
}
|
612
|
+
|
613
|
+
if(properties.hasOwnProperty("audioVolume")) {
|
614
|
+
this.audioVolume = parseInt(properties["audioVolume"], 10);
|
615
|
+
}
|
616
|
+
}
|
617
|
+
|
618
|
+
this.enableAudio = function() {
|
619
|
+
this.subscribeToAudio(true);
|
620
|
+
};
|
621
|
+
this.disableAudio = function() {
|
622
|
+
this.subscribeToAudio(false);
|
623
|
+
};
|
624
|
+
this.setAudioVolume = function(value) {
|
625
|
+
var component = document.getElementById(this.id);
|
626
|
+
if (!this.loaded) {
|
627
|
+
this.audioVolume = value;
|
628
|
+
} else if (component) {
|
629
|
+
try {
|
630
|
+
component.setAudioVolume(value);
|
631
|
+
} catch (err) {
|
632
|
+
var errorMsg = "Volume adjustment on subscriber "+this.id+" failed";
|
633
|
+
error(errorMsg);
|
634
|
+
throw new Error(errorMsg);
|
635
|
+
}
|
636
|
+
} else {
|
637
|
+
errorMsg = "Subscriber "+ this.id + " does not exist.";
|
638
|
+
error(errorMsg);
|
639
|
+
throw new Error(errorMsg);
|
640
|
+
}
|
641
|
+
return this;
|
642
|
+
};
|
643
|
+
this.getAudioVolume = function() {
|
644
|
+
var component = document.getElementById(this.id);
|
645
|
+
if (!this.loaded) {
|
646
|
+
return this.audioVolume;
|
647
|
+
}
|
648
|
+
if (component) {
|
649
|
+
try {
|
650
|
+
return component.getAudioVolume();
|
651
|
+
} catch (err) {
|
652
|
+
var errorMsg = "Volume adjustment on subscriber "+this.id+" failed";
|
653
|
+
error(errorMsg);
|
654
|
+
throw new Error(errorMsg);
|
655
|
+
}
|
656
|
+
} else {
|
657
|
+
errorMsg = "Subscriber "+ this.id + " does not exist.";
|
658
|
+
error(errorMsg);
|
659
|
+
throw new Error(errorMsg);
|
660
|
+
}
|
661
|
+
return this;
|
662
|
+
};
|
663
|
+
|
664
|
+
/**
|
665
|
+
* Internal function to toggle the subscribeToAudio that respects
|
666
|
+
* the developer's state of subscribing
|
667
|
+
*/
|
668
|
+
this._subscribeToAudio = function(subscribeAudioBool, isTokBox) {
|
669
|
+
debug("Subscriber.subscribeToAudio()");
|
670
|
+
if(!isTokBox || _isAudioSubscribed) {
|
671
|
+
if(!this.loaded) {
|
672
|
+
this.audioSubscribed = subscribeAudioBool;
|
673
|
+
this.modified = true;
|
674
|
+
} else {
|
675
|
+
setStreamProperty(this.id, "subscribeToAudio", subscribeAudioBool);
|
676
|
+
}
|
677
|
+
}
|
678
|
+
};
|
679
|
+
this.subscribeToAudio = function(subscribeAudioBool) {
|
680
|
+
_isAudioSubscribed = subscribeAudioBool;
|
681
|
+
this._subscribeToAudio(_isAudioSubscribed, false);
|
682
|
+
};
|
683
|
+
|
684
|
+
/**
|
685
|
+
* Internal function to toggle the subscribeToVideo that respects
|
686
|
+
* the developer's state of subscribing
|
687
|
+
*/
|
688
|
+
this._subscribeToVideo = function(subscribeVideoBool, isTokBox) {
|
689
|
+
debug("Subscriber.subscribeToVideo()");
|
690
|
+
if(!isTokBox || _isVideoSubscribed) {
|
691
|
+
if(!this.loaded) {
|
692
|
+
this.videoSubscribed = subscribeVideoBool;
|
693
|
+
this.modified = true;
|
694
|
+
} else {
|
695
|
+
setStreamProperty(this.id, "subscribeToVideo", subscribeVideoBool);
|
696
|
+
}
|
697
|
+
}
|
698
|
+
};
|
699
|
+
this.subscribeToVideo = function(subscribeVideoBool) {
|
700
|
+
_isVideoSubscribed = subscribeVideoBool;
|
701
|
+
this._subscribeToVideo(_isVideoSubscribed, false);
|
702
|
+
};
|
703
|
+
|
704
|
+
this.changeOrientation = function(orientation) {
|
705
|
+
// private function
|
706
|
+
debug("Subscriber.changeOrientation()");
|
707
|
+
setStreamProperty(this.id, "changeOrientation", orientation);
|
708
|
+
};
|
709
|
+
}
|
710
|
+
|
711
|
+
function DevicePanel (id, replacedDivId, component, properties) {
|
712
|
+
this.superClass = UIComponent;
|
713
|
+
this.superClass(id, replacedDivId);
|
714
|
+
|
715
|
+
if (component) {
|
716
|
+
this.publisher = component; //publisher is deprecated
|
717
|
+
this.component = component;
|
718
|
+
} else {
|
719
|
+
this.publisher = null;
|
720
|
+
this.component = component;
|
721
|
+
}
|
722
|
+
this.parentCreated = false;
|
723
|
+
this.properties = properties;
|
724
|
+
}
|
725
|
+
|
726
|
+
function Camera (name, status) {
|
727
|
+
this.name = name;
|
728
|
+
this.status = status;
|
729
|
+
}
|
730
|
+
|
731
|
+
function Microphone (name, status) {
|
732
|
+
this.name = name;
|
733
|
+
this.status = status;
|
734
|
+
}
|
735
|
+
|
736
|
+
function Group (sessionId,groupId) {
|
737
|
+
this.superClass = EventDispatcher;
|
738
|
+
this.superClass();
|
739
|
+
|
740
|
+
this.groupId = groupId;
|
741
|
+
this.sessionId = sessionId;
|
742
|
+
this.enableEchoSuppression = function() {
|
743
|
+
debug("Group.enableEchoSuppresion()");
|
744
|
+
setEchoSuppressionEnabled(this.sessionId, this.groupId, true);
|
745
|
+
};
|
746
|
+
this.disableEchoSuppression = function() {
|
747
|
+
debug("Group.disableEchoSuppression()");
|
748
|
+
setEchoSuppressionEnabled(this.sessionId, this.groupId, false);
|
749
|
+
};
|
750
|
+
|
751
|
+
this.getGroupProperties = function() {
|
752
|
+
debug("Group.getGroupProperties()");
|
753
|
+
return getGroupProperties(this.sessionId, this.groupId);
|
754
|
+
};
|
755
|
+
|
756
|
+
}
|
757
|
+
|
758
|
+
function EchoSuppression(isEnabled){
|
759
|
+
this.isEnabled = isEnabled;
|
760
|
+
}
|
761
|
+
|
762
|
+
function Multiplexer(outputStreams,switchType,switchTimeout)
|
763
|
+
{
|
764
|
+
this.numOutputStreams = outputStreams;
|
765
|
+
this.switchType = switchType;
|
766
|
+
this.switchTimeout = switchTimeout;
|
767
|
+
}
|
768
|
+
|
769
|
+
function GroupProperties(group) {
|
770
|
+
this.echoSuppression = new EchoSuppression(group.echoSuppressionEnabled);
|
771
|
+
this.multiplexer = new Multiplexer(group.multiplexerNumOutputStreams,group.multiplexerSwitchType,group.multiplexerSwitchTimeout);
|
772
|
+
}
|
773
|
+
|
774
|
+
function Archive (archiveId, type, title, sessionId, status) {
|
775
|
+
this.archiveId = archiveId;
|
776
|
+
this.type = type;
|
777
|
+
this.title = title;
|
778
|
+
this.sessionId = sessionId;
|
779
|
+
var stateManager;
|
780
|
+
if (status == "sessionRecordingInProgress") {
|
781
|
+
this.recording = true;
|
782
|
+
this.status = "open";
|
783
|
+
}
|
784
|
+
else {
|
785
|
+
this.recording = false;
|
786
|
+
this.status = status;
|
787
|
+
}
|
788
|
+
|
789
|
+
this.startPlayback = function(loop) {
|
790
|
+
if (!loop) {
|
791
|
+
loop = false;
|
792
|
+
}
|
793
|
+
debug("Archive.startPlayback() : " + loop);
|
794
|
+
var controllerId = "controller_" + sessionId;
|
795
|
+
var connection = TB.sessions[sessionId].connection;
|
796
|
+
if (!loadedArchives[sessionId][this.archiveId]) {
|
797
|
+
var errorMsg = "Archive.startPlayback :: Archive not loaded.";
|
798
|
+
error(errorMsg);
|
799
|
+
throw new Error(errorMsg);
|
800
|
+
}
|
801
|
+
if (controllerId && connection && connection.connectionId) {
|
802
|
+
try {
|
803
|
+
var controller = document.getElementById(controllerId);
|
804
|
+
controller.startPlayback(this.archiveId, loop);
|
805
|
+
} catch(err) {
|
806
|
+
errorMsg = "Archive.startPlayback :: " + err;
|
807
|
+
error(errorMsg);
|
808
|
+
throw new Error(errorMsg);
|
809
|
+
}
|
810
|
+
} else {
|
811
|
+
errorMsg = "Archive.startPlayback :: Connection required to play back an archive.";
|
812
|
+
error(errorMsg);
|
813
|
+
throw new Error(errorMsg);
|
814
|
+
}
|
815
|
+
};
|
816
|
+
|
817
|
+
this.stopPlayback = function() {
|
818
|
+
debug("Archive.stopPlayback()");
|
819
|
+
var controllerId = "controller_" + sessionId;
|
820
|
+
var connection = TB.sessions[sessionId].connection;
|
821
|
+
if (controllerId && connection && connection.connectionId) {
|
822
|
+
try {
|
823
|
+
var controller = document.getElementById(controllerId);
|
824
|
+
controller.stopPlayback(this.archiveId);
|
825
|
+
} catch(err) {
|
826
|
+
var errorMsg = "Archive.stopPlayback :: " + err;
|
827
|
+
error(errorMsg);
|
828
|
+
throw new Error(errorMsg);
|
829
|
+
}
|
830
|
+
} else {
|
831
|
+
errorMsg = "Archive.stopPlayback :: Connection required to stop playing back an archive.";
|
832
|
+
error(errorMsg);
|
833
|
+
throw new Error(errorMsg);
|
834
|
+
}
|
835
|
+
};
|
836
|
+
|
837
|
+
this.getStateManager = function() {
|
838
|
+
debug("Archive.getStateManager() " + archiveId);
|
839
|
+
|
840
|
+
if (stateManager) return stateManager;
|
841
|
+
|
842
|
+
else {
|
843
|
+
var controllerId = "controller_" + sessionId;
|
844
|
+
var connection = TB.sessions[sessionId].connection;
|
845
|
+
if (controllerId && connection && connection.connectionId) {
|
846
|
+
stateManager = new StateManager(controllerId, archiveId);
|
847
|
+
return stateManager;
|
848
|
+
}
|
849
|
+
}
|
850
|
+
|
851
|
+
var errorMsg = "Archive.getStateManager :: Connection required to getStateManager. "
|
852
|
+
+ "Make sure that this archive was loaded in a Session.";
|
853
|
+
error(errorMsg);
|
854
|
+
throw new Error(errorMsg);
|
855
|
+
};
|
856
|
+
}
|
857
|
+
|
858
|
+
function Recorder(id, replacedDivId, properties) {
|
859
|
+
this.superClass = VideoComponent;
|
860
|
+
this.superClass(id, replacedDivId);
|
861
|
+
|
862
|
+
this._style = {
|
863
|
+
buttonDisplayMode: "auto",
|
864
|
+
showCameraToggleButton: true,
|
865
|
+
showControlBar: true,
|
866
|
+
showMicButton: true,
|
867
|
+
showPlayCounter: true,
|
868
|
+
showRecordCounter: true,
|
869
|
+
showSaveButton: true,
|
870
|
+
showSettingsButton: true
|
871
|
+
};
|
872
|
+
|
873
|
+
this.id = id;
|
874
|
+
this.properties = properties;
|
875
|
+
|
876
|
+
this.saveArchive = function() {
|
877
|
+
var recorderElement = document.getElementById(this.id);
|
878
|
+
recorderElement.save();
|
879
|
+
};
|
880
|
+
|
881
|
+
this.setCamera = function(camera) {
|
882
|
+
debug("Recorder.setCamera(" + camera + ")");
|
883
|
+
setDevice(this.id, camera, true);
|
884
|
+
};
|
885
|
+
this.setMicrophone = function(microphone) {
|
886
|
+
debug("Recorder.setMicrophone(" + microphone + ")");
|
887
|
+
setDevice(this.id, microphone, false);
|
888
|
+
};
|
889
|
+
|
890
|
+
this.stopRecording = function() {
|
891
|
+
recorderElement = document.getElementById(this.id);
|
892
|
+
recorderElement.stopRecording();
|
893
|
+
};
|
894
|
+
|
895
|
+
this.startRecording = function(title) {
|
896
|
+
recorderElement = document.getElementById(this.id);
|
897
|
+
recorderElement.startRecording(title);
|
898
|
+
};
|
899
|
+
|
900
|
+
this.startPlaying = function() {
|
901
|
+
debug("Recorder.startPlaying()");
|
902
|
+
try {
|
903
|
+
var recorderElement = document.getElementById(this.id);
|
904
|
+
recorderElement.startPlaying();
|
905
|
+
} catch(err) {
|
906
|
+
var errorMsg = "Recorder.startPlaying :: " + err;
|
907
|
+
error(errorMsg);
|
908
|
+
throw new Error(errorMsg);
|
909
|
+
}
|
910
|
+
};
|
911
|
+
|
912
|
+
this.stopPlaying = function() {
|
913
|
+
debug("Recorder.stopPlaying()");
|
914
|
+
try {
|
915
|
+
var recorderElement = document.getElementById(this.id);
|
916
|
+
recorderElement.stopPlaying();
|
917
|
+
} catch(err) {
|
918
|
+
var errorMsg = "Recorder.stopPlaying :: " + err;
|
919
|
+
error(errorMsg);
|
920
|
+
throw new Error(errorMsg);
|
921
|
+
}
|
922
|
+
};
|
923
|
+
|
924
|
+
this.setTitle = function (title) {
|
925
|
+
var component = document.getElementById(this.id);
|
926
|
+
if (!this.loaded) {
|
927
|
+
this._title = title;
|
928
|
+
this.modified = true;
|
929
|
+
} else if (component) {
|
930
|
+
try {
|
931
|
+
component.setTitle(title);
|
932
|
+
} catch (err) {
|
933
|
+
var errorMsg = "Setting archive title on Recorder "+this.id+" failed.";
|
934
|
+
error(errorMsg);
|
935
|
+
throw new Error(errorMsg);
|
936
|
+
}
|
937
|
+
} else {
|
938
|
+
errorMsg = "Recorder "+ this.id + " does not exist.";
|
939
|
+
error(errorMsg);
|
940
|
+
throw new Error(errorMsg);
|
941
|
+
}
|
942
|
+
};
|
943
|
+
|
944
|
+
}
|
945
|
+
|
946
|
+
|
947
|
+
function Player(id, replacedDivId, properties) {
|
948
|
+
this.superClass = VideoComponent;
|
949
|
+
this.superClass(id, replacedDivId);
|
950
|
+
|
951
|
+
this._style = {
|
952
|
+
showPlayButton: true,
|
953
|
+
showStopButton: true,
|
954
|
+
showSpeakerButton: true
|
955
|
+
};
|
956
|
+
|
957
|
+
this.id = id;
|
958
|
+
this.properties = properties;
|
959
|
+
this.archiveId;
|
960
|
+
|
961
|
+
this.loadArchive = function(archiveId) {
|
962
|
+
if (archiveId) {
|
963
|
+
if (this.loaded) {
|
964
|
+
try {
|
965
|
+
var player = document.getElementById(this.id);
|
966
|
+
player.loadArchive(archiveId);
|
967
|
+
this.archiveId = archiveId;
|
968
|
+
} catch(err) {
|
969
|
+
var errorMsg = "Player.loadArchive :: " + err;
|
970
|
+
error(errorMsg);
|
971
|
+
throw new Error(errorMsg);
|
972
|
+
}
|
973
|
+
} else {
|
974
|
+
this._archiveId = archiveId;
|
975
|
+
}
|
976
|
+
} else {
|
977
|
+
errorMsg = "Player.loadArchive :: Archive id required to load an archive.";
|
978
|
+
error(errorMsg);
|
979
|
+
throw new Error(errorMsg);
|
980
|
+
}
|
981
|
+
|
982
|
+
};
|
983
|
+
|
984
|
+
this.play = function() {
|
985
|
+
if (this.loaded) {
|
986
|
+
try {
|
987
|
+
var player = document.getElementById(this.id);
|
988
|
+
player.startPlayback();
|
989
|
+
} catch(err) {
|
990
|
+
var errorMsg = "Player.play :: " + err;
|
991
|
+
error(errorMsg);
|
992
|
+
throw new Error(errorMsg);
|
993
|
+
}
|
994
|
+
} else {
|
995
|
+
this._play = true;
|
996
|
+
}
|
997
|
+
};
|
998
|
+
|
999
|
+
this.stop = function() {
|
1000
|
+
if (this.loaded) {
|
1001
|
+
try {
|
1002
|
+
var player = document.getElementById(this.id);
|
1003
|
+
player.stopPlayback();
|
1004
|
+
} catch(err) {
|
1005
|
+
var errorMsg = "Player.stop :: " + err;
|
1006
|
+
error(errorMsg);
|
1007
|
+
throw new Error(errorMsg);
|
1008
|
+
}
|
1009
|
+
} else {
|
1010
|
+
this._play = false;
|
1011
|
+
}
|
1012
|
+
};
|
1013
|
+
|
1014
|
+
this.pause = function() {
|
1015
|
+
if (this.loaded) {
|
1016
|
+
try {
|
1017
|
+
var player = document.getElementById(this.id);
|
1018
|
+
player.pausePlayback();
|
1019
|
+
} catch(err) {
|
1020
|
+
var errorMsg = "Player.pause :: " + err;
|
1021
|
+
error(errorMsg);
|
1022
|
+
throw new Error(errorMsg);
|
1023
|
+
}
|
1024
|
+
} else {
|
1025
|
+
this._play = false;
|
1026
|
+
}
|
1027
|
+
};
|
1028
|
+
|
1029
|
+
}
|
1030
|
+
|
1031
|
+
function DeviceManager (apiKey) {
|
1032
|
+
this.superClass = EventDispatcher;
|
1033
|
+
this.superClass();
|
1034
|
+
|
1035
|
+
this.apiKey = apiKey;
|
1036
|
+
|
1037
|
+
this.panels = {};
|
1038
|
+
|
1039
|
+
this.showMicSettings = true;
|
1040
|
+
this.showCamSettings = true;
|
1041
|
+
|
1042
|
+
var DEVICE_PANEL_WIDTH = 360;
|
1043
|
+
var DEVICE_PANEL_HEIGHT = 270;
|
1044
|
+
var DEVICE_PANEL_WIDTH_NO_CHROME = 340;
|
1045
|
+
var DEVICE_PANEL_HEIGHT_NO_CHROME = 230;
|
1046
|
+
|
1047
|
+
this.detectDevices = function() {
|
1048
|
+
debug("DeviceManager.detectDevices()");
|
1049
|
+
if (!deviceDetectorId) {
|
1050
|
+
var params = {};
|
1051
|
+
params.allowscriptaccess = "always";
|
1052
|
+
|
1053
|
+
deviceDetectorId = "opentok_deviceDetector";
|
1054
|
+
var attributes = {};
|
1055
|
+
attributes.id = deviceDetectorId;
|
1056
|
+
|
1057
|
+
var properties = {};
|
1058
|
+
|
1059
|
+
swfobject.addDomLoadEvent(function() {
|
1060
|
+
var div = document.createElement('div');
|
1061
|
+
div.setAttribute('id', deviceDetectorId);
|
1062
|
+
div.style.display = "none";
|
1063
|
+
document.body.appendChild(div);
|
1064
|
+
|
1065
|
+
swfobject.embedSWF(WIDGET_URL + "/v0.91.46.b5f48f1/flash/f_devicedetectorwidget.swf?partnerId="+apiKey, deviceDetectorId, 1, 1, "10.0.0", false, properties, params, attributes);
|
1066
|
+
});
|
1067
|
+
} else {
|
1068
|
+
try {
|
1069
|
+
var deviceDetector = document.getElementById(deviceDetectorId);
|
1070
|
+
deviceDetector.detectDevices();
|
1071
|
+
} catch(err) {
|
1072
|
+
error(err);
|
1073
|
+
throw new Error("DeviceManager.detectDevices() :: Failed to locate existing device detector " + err);
|
1074
|
+
}
|
1075
|
+
}
|
1076
|
+
};
|
1077
|
+
|
1078
|
+
this.displayPanel = function(replaceElementId, component, properties) {
|
1079
|
+
debug("DeviceManager.displayPanel(" + replaceElementId + ")");
|
1080
|
+
|
1081
|
+
var panelId;
|
1082
|
+
if (component) panelId = "displayPanel_" + component.id;
|
1083
|
+
else panelId = "displayPanel_global";
|
1084
|
+
|
1085
|
+
// If this is a publisher update the panelId in the publisher object
|
1086
|
+
if (component && TB.sessions) {
|
1087
|
+
for (var i in TB.sessions) {
|
1088
|
+
if (TB.sessions[i].hasOwnProperty("publishers") && TB.sessions[i].publishers[component.id]) {
|
1089
|
+
TB.sessions[i].publishers[component.id].panelId = panelId;
|
1090
|
+
}
|
1091
|
+
}
|
1092
|
+
}
|
1093
|
+
|
1094
|
+
var existingElement = document.getElementById(panelId);
|
1095
|
+
|
1096
|
+
if (existingElement) {
|
1097
|
+
warn("DeviceManager.displayPanel :: there is already a device panel" + (component ? " for this component" : ""));
|
1098
|
+
return this.panels[panelId];
|
1099
|
+
}
|
1100
|
+
|
1101
|
+
var parentCreated = false;
|
1102
|
+
var propertiesCopy = (properties) ? copyObject(properties) : {};
|
1103
|
+
var params = {};
|
1104
|
+
params.allowscriptaccess = "always";
|
1105
|
+
|
1106
|
+
var width = DEVICE_PANEL_WIDTH;
|
1107
|
+
var height = DEVICE_PANEL_HEIGHT;
|
1108
|
+
if ("showCloseButton" in propertiesCopy) {
|
1109
|
+
if (propertiesCopy["showCloseButton"] == false) {
|
1110
|
+
width = DEVICE_PANEL_WIDTH_NO_CHROME;
|
1111
|
+
height = DEVICE_PANEL_HEIGHT_NO_CHROME;
|
1112
|
+
}
|
1113
|
+
} else {
|
1114
|
+
propertiesCopy["showCloseButton"] = true;
|
1115
|
+
}
|
1116
|
+
|
1117
|
+
if(!("showMicSettings" in propertiesCopy)) {
|
1118
|
+
propertiesCopy["showMicSettings"] = this.showMicSettings;
|
1119
|
+
}
|
1120
|
+
|
1121
|
+
if(!("showCamSettings" in propertiesCopy)) {
|
1122
|
+
propertiesCopy["showCamSettings"] = this.showCamSettings;
|
1123
|
+
}
|
1124
|
+
|
1125
|
+
if(!replaceElementId) {
|
1126
|
+
// If they didn't specify a replaceElementId then we will create a new element
|
1127
|
+
replaceElementId = 'devicePanel_replace_div';
|
1128
|
+
var replaceDiv = document.createElement('div');
|
1129
|
+
replaceDiv.setAttribute('id', replaceElementId);
|
1130
|
+
|
1131
|
+
var parentDiv = document.createElement('div');
|
1132
|
+
parentDiv.setAttribute('id', 'devicePanel_parent_' + (component ? component.id : 'global'));
|
1133
|
+
parentDiv.style.position = "absolute";
|
1134
|
+
|
1135
|
+
var yOffset = ("pageYOffset" in window && typeof( window.pageYOffset ) == 'number') ? window["pageYOffset"] :
|
1136
|
+
(document.body && document.body.scrollTop) ? document.body.scrollTop :
|
1137
|
+
(document.documentElement && document.documentElement.scrollTop) ? document.documentElement.scrollTop :
|
1138
|
+
0;
|
1139
|
+
var winHeight = ("innerHeight" in window) ? window.innerHeight :
|
1140
|
+
(document.documentElement && document.documentElement.offsetHeight) ? document.documentElement.offsetHeight :
|
1141
|
+
DEVICE_PANEL_HEIGHT;
|
1142
|
+
yOffset += (winHeight * 0.20); // 20% down the current screen
|
1143
|
+
|
1144
|
+
parentDiv.style.top = yOffset + "px";
|
1145
|
+
parentDiv.style.left = "50%";
|
1146
|
+
parentDiv.style.width = width + "px";
|
1147
|
+
parentDiv.style.height = height + "px";
|
1148
|
+
parentDiv.style.marginLeft = (0 - width/2) + "px";
|
1149
|
+
parentDiv.style.marginTop = (0 - height/4) + "px";
|
1150
|
+
if ("zIndex" in propertiesCopy) {
|
1151
|
+
parentDiv.style.zIndex = propertiesCopy["zIndex"];
|
1152
|
+
delete propertiesCopy["zIndex"];
|
1153
|
+
} else {
|
1154
|
+
parentDiv.style.zIndex = highZ()+1;
|
1155
|
+
}
|
1156
|
+
document.body.appendChild(parentDiv);
|
1157
|
+
parentCreated = true;
|
1158
|
+
parentDiv.appendChild(replaceDiv);
|
1159
|
+
}
|
1160
|
+
|
1161
|
+
var replaceElement = document.getElementById(replaceElementId);
|
1162
|
+
if(!replaceElement) {
|
1163
|
+
var errorMsg = "DeviceManager.displayPanel :: replaceElementId does not exist in DOM.";
|
1164
|
+
error(errorMsg);
|
1165
|
+
throw new Error(errorMsg);
|
1166
|
+
}
|
1167
|
+
|
1168
|
+
var devicePanel;
|
1169
|
+
if (this.panels[panelId]) this.removePanel(this.panels[panelId]);
|
1170
|
+
if (component) devicePanel = new DevicePanel(panelId, replaceElementId, component, propertiesCopy);
|
1171
|
+
else devicePanel = new DevicePanel(panelId, replaceElementId, null, propertiesCopy);
|
1172
|
+
|
1173
|
+
devicePanel.parentCreated = parentCreated;
|
1174
|
+
this.panels[panelId] = devicePanel;
|
1175
|
+
|
1176
|
+
var attributes = {};
|
1177
|
+
attributes.id = devicePanel.id;
|
1178
|
+
attributes.style = "outline:none;";
|
1179
|
+
|
1180
|
+
propertiesCopy["devicePanelId"] = panelId;
|
1181
|
+
|
1182
|
+
if (propertiesCopy.wmode) {
|
1183
|
+
params.wmode = propertiesCopy.wmode;
|
1184
|
+
delete propertiesCopy["wmode"];
|
1185
|
+
} else {
|
1186
|
+
params.wmode = "transparent";
|
1187
|
+
}
|
1188
|
+
|
1189
|
+
embedSWF(WIDGET_URL + "/v0.91.46.b5f48f1/flash/f_devicewidget.swf?partnerId="+this.apiKey, replaceElementId, width, height, MIN_FLASH_VERSION, false, propertiesCopy, params, attributes);
|
1190
|
+
|
1191
|
+
return devicePanel;
|
1192
|
+
};
|
1193
|
+
|
1194
|
+
this.removePanel = function(devicePanel) {
|
1195
|
+
if (!devicePanel.hasOwnProperty("id")) {
|
1196
|
+
var errorMsg = "DeviceManager.removePanel :: invalid DevicePanel object";
|
1197
|
+
error(errorMsg);
|
1198
|
+
throw new Error(errorMsg);
|
1199
|
+
}
|
1200
|
+
|
1201
|
+
debug("DeviceManager.removePanel(" + devicePanel.id + ")");
|
1202
|
+
|
1203
|
+
var devicePanelElement = document.getElementById(devicePanel.id);
|
1204
|
+
if (!devicePanelElement) {
|
1205
|
+
errorMsg = "DeviceManager.removePanel :: DevicePanel does not exist in DOM";
|
1206
|
+
error(errorMsg);
|
1207
|
+
throw new Error(errorMsg);
|
1208
|
+
}
|
1209
|
+
var parentElement = devicePanelElement.parentNode;
|
1210
|
+
var parentCreated = devicePanel.parentCreated;
|
1211
|
+
|
1212
|
+
for (var dp in this.panels) {
|
1213
|
+
if (this.panels[dp].hasOwnProperty("id") && dp == devicePanel.id) {
|
1214
|
+
var panel = this.panels[dp];
|
1215
|
+
unloadComponent(this.panels[dp]);
|
1216
|
+
delete this.panels[dp];
|
1217
|
+
|
1218
|
+
var action = function() {
|
1219
|
+
if (panel.publisher && TB.sessions) {
|
1220
|
+
for (var i in TB.sessions) {
|
1221
|
+
if (TB.sessions[i].hasOwnProperty("disconnect") && TB.sessions[i].publishers[panel.publisher.id]) {
|
1222
|
+
TB.sessions[i].publishers[panel.publisher.id].panelId = null;
|
1223
|
+
}
|
1224
|
+
}
|
1225
|
+
}
|
1226
|
+
};
|
1227
|
+
|
1228
|
+
// The event handler is called asynchronously after 2 milliseconds.
|
1229
|
+
setTimeout(action, 2);
|
1230
|
+
}
|
1231
|
+
}
|
1232
|
+
|
1233
|
+
if (parentCreated) {
|
1234
|
+
// Remove the parent because we created it
|
1235
|
+
try {
|
1236
|
+
var parentNode = parentElement.parentNode;
|
1237
|
+
parentNode.removeChild(parentElement);
|
1238
|
+
} catch (err) {
|
1239
|
+
errorMsg = "Failed to clean up the parent of the device panel " + err;
|
1240
|
+
error(errorMsg);
|
1241
|
+
throw new Error(errorMsg);
|
1242
|
+
}
|
1243
|
+
}
|
1244
|
+
};
|
1245
|
+
|
1246
|
+
}
|
1247
|
+
|
1248
|
+
function RecorderManager (apiKey) {
|
1249
|
+
|
1250
|
+
var recorderCount = 1;
|
1251
|
+
var playerCount = 1;
|
1252
|
+
|
1253
|
+
this.recorders = {};
|
1254
|
+
this.players = {};
|
1255
|
+
this.apiKey = apiKey;
|
1256
|
+
|
1257
|
+
var DEFAULT_WIDTH = 320;
|
1258
|
+
var DEFAULT_HEIGHT = 271;
|
1259
|
+
var CONTROL_BAR_HEIGHT = 31;
|
1260
|
+
|
1261
|
+
this.displayRecorder = function(token, replaceElementId, properties) {
|
1262
|
+
|
1263
|
+
if (!token) {
|
1264
|
+
errorMsg = "RecorderManager.displayRecorder :: Token required to displayRecorder";
|
1265
|
+
error(errorMsg);
|
1266
|
+
throw new Error(errorMsg);
|
1267
|
+
}
|
1268
|
+
|
1269
|
+
var recorderId = "recorder_" + apiKey + "_" + recorderCount++;
|
1270
|
+
|
1271
|
+
var propertiesCopy = (properties) ? copyObject(properties) : {};
|
1272
|
+
propertiesCopy["token"] = token;
|
1273
|
+
propertiesCopy["partnerId"] = apiKey;
|
1274
|
+
propertiesCopy["recorderId"] = recorderId;
|
1275
|
+
|
1276
|
+
if (propertiesCopy.hasOwnProperty("style")) {
|
1277
|
+
var showControlBar = propertiesCopy.style.showControlBar;
|
1278
|
+
propertiesCopy.style = encodeURIComponent(JSONify(propertiesCopy.style));
|
1279
|
+
}
|
1280
|
+
|
1281
|
+
var params = {};
|
1282
|
+
params.allowscriptaccess = "always";
|
1283
|
+
if (propertiesCopy.wmode){
|
1284
|
+
params.wmode = propertiesCopy.wmode;
|
1285
|
+
delete propertiesCopy["wmode"];
|
1286
|
+
} else {
|
1287
|
+
params.wmode = "transparent";
|
1288
|
+
}
|
1289
|
+
|
1290
|
+
var attributes = {};
|
1291
|
+
attributes.id = recorderId;
|
1292
|
+
attributes.style = "outline:none;";
|
1293
|
+
|
1294
|
+
if (!propertiesCopy.width || isNaN(propertiesCopy.width)) {
|
1295
|
+
propertiesCopy.width = DEFAULT_WIDTH;
|
1296
|
+
}
|
1297
|
+
if (!propertiesCopy.height || isNaN(propertiesCopy.height)) {
|
1298
|
+
propertiesCopy.height = DEFAULT_HEIGHT;
|
1299
|
+
if (showControlBar == false) {
|
1300
|
+
propertiesCopy.height -= CONTROL_BAR_HEIGHT;
|
1301
|
+
}
|
1302
|
+
}
|
1303
|
+
|
1304
|
+
var createReplaceElement = false;
|
1305
|
+
if (!replaceElementId) {
|
1306
|
+
// Create a new element for the publisher and append it to the body
|
1307
|
+
replaceElementId = "recorder_replace_" + recorderCount;
|
1308
|
+
createReplaceElement = true;
|
1309
|
+
}
|
1310
|
+
|
1311
|
+
swfobject.addDomLoadEvent(function() {
|
1312
|
+
if (createReplaceElement) {
|
1313
|
+
var div = document.createElement('div');
|
1314
|
+
div.setAttribute('id', replaceElementId);
|
1315
|
+
document.body.appendChild(div);
|
1316
|
+
}
|
1317
|
+
|
1318
|
+
embedSWF(WIDGET_URL + "/v0.91.46.b5f48f1/flash/f_recordwidget.swf?partnerId="+apiKey, replaceElementId, propertiesCopy.width, propertiesCopy.height, MIN_FLASH_VERSION, false, propertiesCopy, params, attributes);
|
1319
|
+
});
|
1320
|
+
|
1321
|
+
this.recorders[recorderId] = new Recorder(recorderId, replaceElementId, propertiesCopy);
|
1322
|
+
|
1323
|
+
return this.recorders[recorderId];
|
1324
|
+
};
|
1325
|
+
|
1326
|
+
this.removeRecorder = function(recorder) {
|
1327
|
+
if (!recorder) {
|
1328
|
+
var errorMsg = "Session.removeRecorder :: recorder cannot be null";
|
1329
|
+
error(errorMsg);
|
1330
|
+
throw new Error(errorMsg);
|
1331
|
+
}
|
1332
|
+
debug("Session.removeRecorder(" + recorder.id + ")");
|
1333
|
+
|
1334
|
+
unloadComponent(recorder);
|
1335
|
+
delete this.recorders[recorder.id];
|
1336
|
+
};
|
1337
|
+
|
1338
|
+
this.displayPlayer = function(archiveId, token, replaceElementId, properties) {
|
1339
|
+
|
1340
|
+
if (!archiveId) {
|
1341
|
+
errorMsg = "RecorderManager.displayPlayer :: Valid ArchiveId required";
|
1342
|
+
error(errorMsg);
|
1343
|
+
throw new Error(errorMsg);
|
1344
|
+
}
|
1345
|
+
|
1346
|
+
var playerId = "player_" + apiKey + "_" + playerCount++;
|
1347
|
+
|
1348
|
+
var propertiesCopy = (properties) ? copyObject(properties) : {};
|
1349
|
+
propertiesCopy["token"] = token;
|
1350
|
+
propertiesCopy["archiveId"] = archiveId;
|
1351
|
+
propertiesCopy["partnerId"] = apiKey;
|
1352
|
+
propertiesCopy["playerId"] = playerId;
|
1353
|
+
|
1354
|
+
if (propertiesCopy.hasOwnProperty("style")) {
|
1355
|
+
var showControlBar = propertiesCopy.style.showControlBar;
|
1356
|
+
propertiesCopy.style = encodeURIComponent(JSONify(propertiesCopy.style));
|
1357
|
+
}
|
1358
|
+
|
1359
|
+
var params = {};
|
1360
|
+
params.allowscriptaccess = "always";
|
1361
|
+
if (propertiesCopy.wmode){
|
1362
|
+
params.wmode = propertiesCopy.wmode;
|
1363
|
+
delete propertiesCopy["wmode"];
|
1364
|
+
} else {
|
1365
|
+
params.wmode = "transparent";
|
1366
|
+
}
|
1367
|
+
|
1368
|
+
var attributes = {};
|
1369
|
+
attributes.id = playerId;
|
1370
|
+
attributes.style = "outline:none;";
|
1371
|
+
|
1372
|
+
if (!propertiesCopy.width || isNaN(propertiesCopy.width)) {
|
1373
|
+
propertiesCopy.width = DEFAULT_WIDTH;
|
1374
|
+
}
|
1375
|
+
if (!propertiesCopy.height || isNaN(propertiesCopy.height)) {
|
1376
|
+
propertiesCopy.height = DEFAULT_HEIGHT;
|
1377
|
+
if (showControlBar == false) {
|
1378
|
+
propertiesCopy.height -= CONTROL_BAR_HEIGHT;
|
1379
|
+
}
|
1380
|
+
}
|
1381
|
+
if (!propertiesCopy.autoPlay) {
|
1382
|
+
propertiesCopy.autoPlay = false;
|
1383
|
+
}
|
1384
|
+
var createReplaceElement = false;
|
1385
|
+
if (!replaceElementId) {
|
1386
|
+
// Create a new element for the player and append it to the body
|
1387
|
+
replaceElementId = "player_replace_" + playerCount;
|
1388
|
+
createReplaceElement = true;
|
1389
|
+
}
|
1390
|
+
|
1391
|
+
swfobject.addDomLoadEvent(function() {
|
1392
|
+
if (createReplaceElement) {
|
1393
|
+
var div = document.createElement('div');
|
1394
|
+
div.setAttribute('id', replaceElementId);
|
1395
|
+
document.body.appendChild(div);
|
1396
|
+
}
|
1397
|
+
|
1398
|
+
embedSWF(WIDGET_URL + "/v0.91.46.b5f48f1/flash/f_playerwidget.swf?partnerId="+apiKey, replaceElementId, propertiesCopy.width, propertiesCopy.height, MIN_FLASH_VERSION, false, propertiesCopy, params, attributes);
|
1399
|
+
});
|
1400
|
+
|
1401
|
+
this.players[playerId] = new Player(playerId, replaceElementId, propertiesCopy);
|
1402
|
+
|
1403
|
+
return this.players[playerId];
|
1404
|
+
};
|
1405
|
+
|
1406
|
+
this.removePlayer = function(player) {
|
1407
|
+
if (!player) {
|
1408
|
+
var errorMsg = "Session.removePlayer :: player cannot be null";
|
1409
|
+
error(errorMsg);
|
1410
|
+
throw new Error(errorMsg);
|
1411
|
+
}
|
1412
|
+
debug("Session.removePlayer(" + player.id + ")");
|
1413
|
+
|
1414
|
+
unloadComponent(player);
|
1415
|
+
delete this.players[player.id];
|
1416
|
+
};
|
1417
|
+
|
1418
|
+
}
|
1419
|
+
|
1420
|
+
function Session (sessionId) {
|
1421
|
+
this.superClass = EventDispatcher;
|
1422
|
+
this.superClass();
|
1423
|
+
|
1424
|
+
this.sessionId = sessionId;
|
1425
|
+
this.connection;
|
1426
|
+
this.subscribers = {};
|
1427
|
+
this.publishers = {};
|
1428
|
+
this.apiKey;
|
1429
|
+
this.capabilities;
|
1430
|
+
this.connected = false;
|
1431
|
+
this.connecting = false;
|
1432
|
+
|
1433
|
+
var publisherCount = 1;
|
1434
|
+
var subscriberCount = 1;
|
1435
|
+
var DEFAULT_WIDTH = 264;
|
1436
|
+
var DEFAULT_HEIGHT = 198;
|
1437
|
+
var controllerId;
|
1438
|
+
var stateManager;
|
1439
|
+
|
1440
|
+
this.connect = function(apiKey, token, properties) {
|
1441
|
+
if (this.connecting) {
|
1442
|
+
warn("Session.connect :: Patience, please.");
|
1443
|
+
return;
|
1444
|
+
}
|
1445
|
+
|
1446
|
+
debug("Session.connect(" + apiKey + ")");
|
1447
|
+
|
1448
|
+
if (!TB.checkSystemRequirements()) {
|
1449
|
+
var errorMsg = "Session.connect :: Flash Player Version 10+ required";
|
1450
|
+
error(errorMsg);
|
1451
|
+
throw new Error(errorMsg);
|
1452
|
+
}
|
1453
|
+
if (!apiKey) {
|
1454
|
+
errorMsg = "Session.connect :: API key required to connect";
|
1455
|
+
error(errorMsg);
|
1456
|
+
throw new Error(errorMsg);
|
1457
|
+
}
|
1458
|
+
if (!token) {
|
1459
|
+
errorMsg = "Session.connect :: Token required to connect";
|
1460
|
+
error(errorMsg);
|
1461
|
+
throw new Error(errorMsg);
|
1462
|
+
}
|
1463
|
+
if (this.connected) {
|
1464
|
+
warn("Session.connect :: Session already connected");
|
1465
|
+
return;
|
1466
|
+
}
|
1467
|
+
|
1468
|
+
this.connecting = true;
|
1469
|
+
|
1470
|
+
var propertiesCopy = (properties) ? copyObject(properties) : {};
|
1471
|
+
|
1472
|
+
this.apiKey = apiKey;
|
1473
|
+
this.token = token;
|
1474
|
+
this.properties = properties;
|
1475
|
+
var params = {};
|
1476
|
+
params.allowscriptaccess = "always";
|
1477
|
+
if (propertiesCopy.wmode) {
|
1478
|
+
params.wmode = propertiesCopy.wmode;
|
1479
|
+
delete propertiesCopy["wmode"];
|
1480
|
+
}
|
1481
|
+
|
1482
|
+
if (propertiesCopy.connectionData) {
|
1483
|
+
propertiesCopy.connectionData = encodeURIComponent(propertiesCopy.connectionData);
|
1484
|
+
}
|
1485
|
+
|
1486
|
+
controllerId = "controller_" + this.sessionId;
|
1487
|
+
var attributes = {};
|
1488
|
+
attributes.id = controllerId;
|
1489
|
+
|
1490
|
+
propertiesCopy["sessionId"] = this.sessionId;
|
1491
|
+
propertiesCopy["token"] = this.token;
|
1492
|
+
|
1493
|
+
var replaceId = "replace_" + this.sessionId;
|
1494
|
+
swfobject.addDomLoadEvent(function() {
|
1495
|
+
var div = document.createElement('div');
|
1496
|
+
div.setAttribute('id', replaceId);
|
1497
|
+
div.style.display = "none";
|
1498
|
+
document.body.appendChild(div);
|
1499
|
+
var nowDate = new Date();
|
1500
|
+
propertiesCopy["startTime"] = nowDate.getTime();
|
1501
|
+
swfobject.embedSWF(WIDGET_URL + "/v0.91.46.b5f48f1/flash/f_controllerwidget.swf?partnerId="+apiKey, replaceId, 1, 1, MIN_FLASH_VERSION, false, propertiesCopy, params, attributes);
|
1502
|
+
});
|
1503
|
+
if (window.location.protocol == "file:") {
|
1504
|
+
setTimeout("TB.controllerLoadCheck()", 8000);
|
1505
|
+
}
|
1506
|
+
};
|
1507
|
+
|
1508
|
+
this.disconnect = function() {
|
1509
|
+
debug("Session.disconnect()");
|
1510
|
+
|
1511
|
+
if (!controllerId || this.connecting) {
|
1512
|
+
warn("Session.disconnect :: No connection to disconnect");
|
1513
|
+
return;
|
1514
|
+
}
|
1515
|
+
|
1516
|
+
// Disconnect controller
|
1517
|
+
var controller = document.getElementById(controllerId);
|
1518
|
+
if (controller) {
|
1519
|
+
if (!isUnloading) {
|
1520
|
+
try {
|
1521
|
+
controller.cleanupView();
|
1522
|
+
|
1523
|
+
} catch(e) {
|
1524
|
+
var errorMsg = "Session.disconnect :: Failed to disconnect - " + e;
|
1525
|
+
error(errorMsg);
|
1526
|
+
throw new Error(errorMsg);
|
1527
|
+
}
|
1528
|
+
}
|
1529
|
+
} else {
|
1530
|
+
warn("Session.disconnect :: No connection to disconnect");
|
1531
|
+
}
|
1532
|
+
};
|
1533
|
+
|
1534
|
+
this.disconnectComponents = function() {
|
1535
|
+
debug("Session.disconnectComponents() - disconnecting publishers and subscribers");
|
1536
|
+
// As part of cleaning up connections, disconnect any publishers and subscribers
|
1537
|
+
|
1538
|
+
for (var publisher in this.publishers) {
|
1539
|
+
if (this.publishers[publisher].hasOwnProperty("id"))
|
1540
|
+
disconnectComponent(this.publishers[publisher]);
|
1541
|
+
}
|
1542
|
+
|
1543
|
+
for (var subscriber in this.subscribers) {
|
1544
|
+
if (this.subscribers[subscriber].hasOwnProperty("id"))
|
1545
|
+
disconnectComponent(this.subscribers[subscriber]);
|
1546
|
+
}
|
1547
|
+
};
|
1548
|
+
|
1549
|
+
this.cleanup = function() {
|
1550
|
+
debug("Session.cleanup()");
|
1551
|
+
for (var publisher in this.publishers) {
|
1552
|
+
if (this.publishers[publisher].hasOwnProperty("id"))
|
1553
|
+
this.unpublish(this.publishers[publisher]);
|
1554
|
+
}
|
1555
|
+
for (var subscriber in this.subscribers) {
|
1556
|
+
if (this.subscribers[subscriber].hasOwnProperty("id"))
|
1557
|
+
this.unsubscribe(this.subscribers[subscriber]);
|
1558
|
+
}
|
1559
|
+
};
|
1560
|
+
|
1561
|
+
this.cleanupConnection = function() {
|
1562
|
+
// private function
|
1563
|
+
debug("Session.cleanupConnection() - removing controller");
|
1564
|
+
this.connection = null;
|
1565
|
+
|
1566
|
+
if (!controllerId) {
|
1567
|
+
warn("Session.cleanup :: No connection to clean up");
|
1568
|
+
return;
|
1569
|
+
}
|
1570
|
+
|
1571
|
+
if (document.getElementById(controllerId)) {
|
1572
|
+
setTimeout(function() { removeSWF(controllerId, "TB.sessionDisconnected :: "); controllerId = null; }, 0); // must be asynchronous
|
1573
|
+
} else {
|
1574
|
+
warn("Session.cleanup :: No connection to clean up");
|
1575
|
+
}
|
1576
|
+
};
|
1577
|
+
|
1578
|
+
|
1579
|
+
this.publish = function(replaceElementId, properties) {
|
1580
|
+
debug("Session.publish(" + replaceElementId + "):" + properties);
|
1581
|
+
|
1582
|
+
|
1583
|
+
if (!this.connection || !this.connection.connectionId) {
|
1584
|
+
var errorMsg = "Session.publish :: Connection required to publish";
|
1585
|
+
error(errorMsg);
|
1586
|
+
throw new Error(errorMsg);
|
1587
|
+
}
|
1588
|
+
if (!replaceElementId) {
|
1589
|
+
// Create a new element for the publisher and append it to the body
|
1590
|
+
var div = document.createElement('div');
|
1591
|
+
replaceElementId = "publisher_replace_" + this.sessionId + "_" + publisherCount;
|
1592
|
+
div.setAttribute('id', replaceElementId);
|
1593
|
+
document.body.appendChild(div);
|
1594
|
+
}
|
1595
|
+
|
1596
|
+
// Check the name & data properties for length
|
1597
|
+
var propertiesCopy = (properties) ? copyObject(properties) : {};
|
1598
|
+
|
1599
|
+
if (propertiesCopy["name"] != undefined && propertiesCopy["name"].length > 1000) {
|
1600
|
+
errorMsg = "Session.publish :: name property longer than 1000 chars.";
|
1601
|
+
error(errorMsg);
|
1602
|
+
throw new Error(errorMsg);
|
1603
|
+
}
|
1604
|
+
|
1605
|
+
if (propertiesCopy["data"] != undefined && propertiesCopy["data"].length > 1000) {
|
1606
|
+
errorMsg = "Session.publish :: data property longer than 1000 chars.";
|
1607
|
+
error(errorMsg);
|
1608
|
+
throw new Error(errorMsg);
|
1609
|
+
}
|
1610
|
+
|
1611
|
+
var publisherId = "publisher_" + this.sessionId + "_" + publisherCount++;
|
1612
|
+
var publisher = new Publisher(publisherId, replaceElementId, propertiesCopy);
|
1613
|
+
return this._embedPublisher(publisher);
|
1614
|
+
};
|
1615
|
+
|
1616
|
+
// This function is not intended for publish use, it is so that we can republish when someone clicks
|
1617
|
+
// the deny button
|
1618
|
+
this._embedPublisher = function (publisher) {
|
1619
|
+
var replaceElement = document.getElementById(publisher.replacedDivId);
|
1620
|
+
if(!replaceElement) {
|
1621
|
+
errorMsg = "Session.publish :: replaceElementId does not exist in DOM.";
|
1622
|
+
error(errorMsg);
|
1623
|
+
throw new Error(errorMsg);
|
1624
|
+
}
|
1625
|
+
|
1626
|
+
var params = {};
|
1627
|
+
params.allowscriptaccess = "always";
|
1628
|
+
params.cameraSelected = cameraSelected;
|
1629
|
+
|
1630
|
+
if (publisher.properties.wmode){
|
1631
|
+
params.wmode = publisher.properties.wmode;
|
1632
|
+
delete publisher.properties["wmode"];
|
1633
|
+
} else {
|
1634
|
+
params.wmode = "transparent";
|
1635
|
+
}
|
1636
|
+
|
1637
|
+
if (publisher.properties.hasOwnProperty("style")) {
|
1638
|
+
publisher.properties.style = encodeURIComponent(JSONify(publisher.properties.style));
|
1639
|
+
}
|
1640
|
+
|
1641
|
+
var attributes = {};
|
1642
|
+
attributes.id = publisher.id;
|
1643
|
+
attributes.style = "outline:none;";
|
1644
|
+
|
1645
|
+
publisher.properties["publisherId"] = publisher.id;
|
1646
|
+
publisher.properties["connectionId"] = this.connection.connectionId;
|
1647
|
+
publisher.properties["sessionId"] = this.sessionId;
|
1648
|
+
publisher.properties["token"] = this.token;
|
1649
|
+
publisher.properties["cameraSelected"] = cameraSelected;
|
1650
|
+
publisher.properties["simulateMobile"] = TB.simulateMobile;
|
1651
|
+
publisher.properties["publishCapability"] = this.capabilities.publish;
|
1652
|
+
|
1653
|
+
if (!publisher.properties.width || isNaN(publisher.properties.width))
|
1654
|
+
publisher.properties.width = DEFAULT_WIDTH;
|
1655
|
+
if (!publisher.properties.height || isNaN(publisher.properties.height))
|
1656
|
+
publisher.properties.height = DEFAULT_HEIGHT;
|
1657
|
+
/** if (!publisher.properties.encodedWidth || isNaN(publisher.properties.encodedWidth))
|
1658
|
+
publisher.properties.encodedWidth = DEFAULT_WIDTH;
|
1659
|
+
if (!publisher.properties.encodedHeight || isNaN(publisher.properties.encodedHeight))
|
1660
|
+
publisher.properties.encodedHeight = DEFAULT_HEIGHT;
|
1661
|
+
*/
|
1662
|
+
this.publishers[publisher.id] = publisher;
|
1663
|
+
var nowDate = new Date();
|
1664
|
+
publisher.properties["startTime"] = nowDate.getTime();
|
1665
|
+
embedSWF(WIDGET_URL + "/v0.91.46.b5f48f1/flash/f_publishwidget.swf?partnerId="+this.apiKey, publisher.replacedDivId, publisher.properties.width, publisher.properties.height, MIN_FLASH_VERSION, false, publisher.properties, params, attributes);
|
1666
|
+
|
1667
|
+
return publisher;
|
1668
|
+
};
|
1669
|
+
|
1670
|
+
|
1671
|
+
this.unpublish = function(publisher) {
|
1672
|
+
if (!publisher) {
|
1673
|
+
var errorMsg = "Session.unpublish :: publisher cannot be null";
|
1674
|
+
error(errorMsg);
|
1675
|
+
throw new Error(errorMsg);
|
1676
|
+
}
|
1677
|
+
debug("Session.unpublish(" + publisher.id + ")");
|
1678
|
+
|
1679
|
+
if (publisher.panelId && deviceManager && deviceManager.panels[publisher.panelId]) {
|
1680
|
+
deviceManager.removePanel(deviceManager.panels[publisher.panelId]);
|
1681
|
+
}
|
1682
|
+
|
1683
|
+
unloadComponent(publisher);
|
1684
|
+
delete this.publishers[publisher.id];
|
1685
|
+
};
|
1686
|
+
|
1687
|
+
this.forceUnpublish = function(stream) {
|
1688
|
+
var streamId;
|
1689
|
+
if (stream && typeof(stream) == "string") {
|
1690
|
+
streamId = stream;
|
1691
|
+
} else if (stream && typeof(stream) == "object" && stream.hasOwnProperty("streamId")) {
|
1692
|
+
streamId = stream.streamId;
|
1693
|
+
} else {
|
1694
|
+
var errorMsg = "Session.forceUnpublish :: Invalid stream type";
|
1695
|
+
error(errorMsg);
|
1696
|
+
throw new Error(errorMsg);
|
1697
|
+
}
|
1698
|
+
debug("Session.forceUnpublish(" + streamId + ")");
|
1699
|
+
|
1700
|
+
if (streamId) {
|
1701
|
+
try {
|
1702
|
+
var controller = document.getElementById(controllerId);
|
1703
|
+
controller.forceUnpublish(streamId);
|
1704
|
+
} catch(err) {
|
1705
|
+
errorMsg = "Session.forceUnpublish :: "+ err;
|
1706
|
+
error(errorMsg);
|
1707
|
+
throw new Error(errorMsg);
|
1708
|
+
}
|
1709
|
+
} else {
|
1710
|
+
errorMsg = "Session.forceUnpublish :: Stream does not exist.";
|
1711
|
+
error(errorMsg);
|
1712
|
+
throw new Error(errorMsg);
|
1713
|
+
}
|
1714
|
+
};
|
1715
|
+
|
1716
|
+
this.subscribe = function(stream, replaceElementId, properties) {
|
1717
|
+
if (!this.connection || !this.connection.connectionId) {
|
1718
|
+
var errorMsg = "Session.subscribe :: Connection required to subscribe";
|
1719
|
+
error(errorMsg);
|
1720
|
+
throw new Error(errorMsg);
|
1721
|
+
}
|
1722
|
+
|
1723
|
+
if (!stream) {
|
1724
|
+
errorMsg = "Session.subscribe :: stream cannot be null";
|
1725
|
+
error(errorMsg);
|
1726
|
+
throw new Error(errorMsg);
|
1727
|
+
}
|
1728
|
+
if (!stream.hasOwnProperty("streamId")) {
|
1729
|
+
errorMsg = "Session.subscribe :: invalid stream object";
|
1730
|
+
error(errorMsg);
|
1731
|
+
throw new Error(errorMsg);
|
1732
|
+
}
|
1733
|
+
debug("Session.subscribe(" + stream.streamId + ")");
|
1734
|
+
|
1735
|
+
if (!replaceElementId) {
|
1736
|
+
// Create a new element for the subscriber and append it to the body
|
1737
|
+
var div = document.createElement('div');
|
1738
|
+
replaceElementId = "subscriber_replace_" + this.sessionId + "_" + subscriberCount;
|
1739
|
+
div.setAttribute('id', replaceElementId);
|
1740
|
+
document.body.appendChild(div);
|
1741
|
+
}
|
1742
|
+
|
1743
|
+
var replaceElement = document.getElementById(replaceElementId);
|
1744
|
+
if(!replaceElement) {
|
1745
|
+
errorMsg = "Session.subscribe :: replaceElementId does not exist in DOM.";
|
1746
|
+
error(errorMsg);
|
1747
|
+
throw new Error(errorMsg);
|
1748
|
+
}
|
1749
|
+
|
1750
|
+
var propertiesCopy = (properties) ? copyObject(properties) : {};
|
1751
|
+
|
1752
|
+
if( stream && stream.hasOwnProperty("type") && stream.type == "multiplexed") {
|
1753
|
+
propertiesCopy.mixedStreamURI = "live-lowlatency";
|
1754
|
+
}
|
1755
|
+
|
1756
|
+
var subscriberId = "subscriber_" + stream.streamId + "_" + subscriberCount++;
|
1757
|
+
var subscriber = new Subscriber(stream, subscriberId, replaceElementId, propertiesCopy);
|
1758
|
+
|
1759
|
+
var params = {};
|
1760
|
+
params.allowscriptaccess = "always";
|
1761
|
+
if (propertiesCopy.wmode){
|
1762
|
+
params.wmode = propertiesCopy.wmode;
|
1763
|
+
delete propertiesCopy["wmode"];
|
1764
|
+
} else {
|
1765
|
+
params.wmode = "transparent";
|
1766
|
+
}
|
1767
|
+
|
1768
|
+
if (propertiesCopy.hasOwnProperty("style")) {
|
1769
|
+
propertiesCopy.style = encodeURIComponent(JSONify(propertiesCopy.style));
|
1770
|
+
}
|
1771
|
+
|
1772
|
+
var attributes = {};
|
1773
|
+
attributes.id = subscriber.id;
|
1774
|
+
attributes.style = "outline:none;";
|
1775
|
+
|
1776
|
+
propertiesCopy["subscriberId"] = subscriberId;
|
1777
|
+
propertiesCopy["connectionId"] = this.connection.connectionId;
|
1778
|
+
propertiesCopy["sessionId"] = this.sessionId;
|
1779
|
+
propertiesCopy["streamId"] = stream.streamId;
|
1780
|
+
propertiesCopy["streamType"] = stream.type;
|
1781
|
+
propertiesCopy["name"] = stream.name;
|
1782
|
+
propertiesCopy["token"] = this.token;
|
1783
|
+
propertiesCopy["simulateMobile"] = TB.simulateMobile;
|
1784
|
+
propertiesCopy["isPublishing"] = (Object.keys(this.publishers).length > 0);
|
1785
|
+
|
1786
|
+
if(!stream.hasAudio) {
|
1787
|
+
propertiesCopy["subscribeToAudio"] = "false";
|
1788
|
+
}
|
1789
|
+
if(!stream.hasVideo) {
|
1790
|
+
propertiesCopy["subscribeToVideo"] = "false";
|
1791
|
+
}
|
1792
|
+
propertiesCopy["orientation"] = stream.orientation;
|
1793
|
+
propertiesCopy["peerId"] = stream.peerId;
|
1794
|
+
|
1795
|
+
if (!propertiesCopy.width || isNaN(propertiesCopy.width))
|
1796
|
+
propertiesCopy.width = DEFAULT_WIDTH;
|
1797
|
+
if (!propertiesCopy.height || isNaN(propertiesCopy.height))
|
1798
|
+
propertiesCopy.height = DEFAULT_HEIGHT;
|
1799
|
+
|
1800
|
+
this.subscribers[subscriber.id] = subscriber;
|
1801
|
+
|
1802
|
+
var nowDate = new Date();
|
1803
|
+
propertiesCopy["startTime"] = nowDate.getTime();
|
1804
|
+
embedSWF(WIDGET_URL + "/v0.91.46.b5f48f1/flash/f_subscribewidget.swf?partnerId="+this.apiKey, replaceElementId, propertiesCopy.width, propertiesCopy.height, MIN_FLASH_VERSION, false, propertiesCopy, params, attributes);
|
1805
|
+
|
1806
|
+
return subscriber;
|
1807
|
+
};
|
1808
|
+
|
1809
|
+
this.unsubscribe = function(subscriber) {
|
1810
|
+
if (!subscriber) {
|
1811
|
+
var errorMsg = "Subscribe.unsubscribe :: subscriber cannot be null";
|
1812
|
+
error(errorMsg);
|
1813
|
+
throw new Error(errorMsg);
|
1814
|
+
}
|
1815
|
+
debug("Session.unsubscribe(" + subscriber.id + ")");
|
1816
|
+
|
1817
|
+
unloadComponent(subscriber);
|
1818
|
+
delete this.subscribers[subscriber.id];
|
1819
|
+
};
|
1820
|
+
|
1821
|
+
this.signal = function() {
|
1822
|
+
debug("Session.signal()");
|
1823
|
+
if (controllerId && this.connection && this.connection.connectionId) {
|
1824
|
+
try {
|
1825
|
+
var controller = document.getElementById(controllerId);
|
1826
|
+
controller.sendSignal();
|
1827
|
+
} catch(err) {
|
1828
|
+
var errorMsg = "Session.signal :: " + err;
|
1829
|
+
error(errorMsg);
|
1830
|
+
throw new Error(errorMsg);
|
1831
|
+
}
|
1832
|
+
} else {
|
1833
|
+
errorMsg = "Session.signal :: Connection required to signal.";
|
1834
|
+
error(errorMsg);
|
1835
|
+
throw new Error(errorMsg);
|
1836
|
+
}
|
1837
|
+
};
|
1838
|
+
|
1839
|
+
|
1840
|
+
this.forceDisconnect = function(connection) {
|
1841
|
+
if (connection) debug("Session.forceDisconnect(" + connection.connectionId + ")");
|
1842
|
+
var connectionId;
|
1843
|
+
if (connection && typeof(connection) == "string")
|
1844
|
+
connectionId = connection;
|
1845
|
+
else if (connection && typeof(connection) == "object" && connection.hasOwnProperty("connectionId"))
|
1846
|
+
connectionId = connection.connectionId;
|
1847
|
+
else {
|
1848
|
+
var errorMsg = "Session.forceDisconnect :: Invalid connection type";
|
1849
|
+
error(errorMsg);
|
1850
|
+
throw new Error(errorMsg);
|
1851
|
+
}
|
1852
|
+
|
1853
|
+
if (controllerId && this.connection && this.connection.connectionId) {
|
1854
|
+
try {
|
1855
|
+
var controller = document.getElementById(controllerId);
|
1856
|
+
controller.forceDisconnect(connectionId);
|
1857
|
+
} catch(err) {
|
1858
|
+
errorMsg = "Session.forceDisconnect :: "+ err;
|
1859
|
+
error(errorMsg);
|
1860
|
+
throw new Error(errorMsg);
|
1861
|
+
}
|
1862
|
+
} else {
|
1863
|
+
errorMsg = "Session.forceDisconnect :: Connection required to forceDisconnect.";
|
1864
|
+
error(errorMsg);
|
1865
|
+
throw new Error(errorMsg);
|
1866
|
+
}
|
1867
|
+
};
|
1868
|
+
|
1869
|
+
this.getSubscribersForStream = function(stream) {
|
1870
|
+
var res = null;
|
1871
|
+
if (!stream) {
|
1872
|
+
var errorMsg = "Session.getSubscribersForStream :: stream cannot be null";
|
1873
|
+
error(errorMsg);
|
1874
|
+
throw new Error(errorMsg);
|
1875
|
+
} else {
|
1876
|
+
var streamId;
|
1877
|
+
if (typeof(stream) == "string") {
|
1878
|
+
streamId = stream;
|
1879
|
+
} else if (typeof(stream) == "object" && stream.hasOwnProperty("streamId")) {
|
1880
|
+
streamId = stream.streamId;
|
1881
|
+
} else {
|
1882
|
+
errorMsg = "Session.getSubscribersForStream :: Invalid stream type";
|
1883
|
+
error(errorMsg);
|
1884
|
+
throw new Error(errorMsg);
|
1885
|
+
}
|
1886
|
+
|
1887
|
+
res = [];
|
1888
|
+
for (var sr in this.subscribers) {
|
1889
|
+
if (this.subscribers[sr].hasOwnProperty("stream") && this.subscribers[sr].stream.streamId == streamId)
|
1890
|
+
res.push(this.subscribers[sr]);
|
1891
|
+
}
|
1892
|
+
}
|
1893
|
+
|
1894
|
+
return res;
|
1895
|
+
};
|
1896
|
+
|
1897
|
+
this.getPublisherForStream = function(stream) {
|
1898
|
+
if (!stream) {
|
1899
|
+
var errorMsg = "Session.getPublisherForStream :: stream cannot be null";
|
1900
|
+
error(errorMsg);
|
1901
|
+
throw new Error(errorMsg);
|
1902
|
+
} else {
|
1903
|
+
var streamId;
|
1904
|
+
if (typeof(stream) == "string") {
|
1905
|
+
streamId = stream;
|
1906
|
+
} else if (typeof(stream) == "object" && stream.hasOwnProperty("streamId")) {
|
1907
|
+
streamId = stream.streamId;
|
1908
|
+
} else {
|
1909
|
+
errorMsg = "Session.getPublisherForStream :: Invalid stream type";
|
1910
|
+
error(errorMsg);
|
1911
|
+
throw new Error(errorMsg);
|
1912
|
+
}
|
1913
|
+
|
1914
|
+
for (var pub in this.publishers) {
|
1915
|
+
var publisher = document.getElementById(this.publishers[pub].id);
|
1916
|
+
if (publisher) {
|
1917
|
+
try {
|
1918
|
+
if (publisher.getStreamId() == streamId) return this.publishers[pub];
|
1919
|
+
} catch (err) {
|
1920
|
+
warn("Failed to get streamId for publisher: " + this.publishers[pub].id);
|
1921
|
+
}
|
1922
|
+
}
|
1923
|
+
}
|
1924
|
+
}
|
1925
|
+
|
1926
|
+
return null;
|
1927
|
+
};
|
1928
|
+
|
1929
|
+
this.createArchive = function(apiKey, type, title) {
|
1930
|
+
debug("Session.createArchive()");
|
1931
|
+
if (controllerId && this.connection && this.connection.connectionId) {
|
1932
|
+
if (type == TB.PER_SESSION || type == TB.PER_STREAM) {
|
1933
|
+
try {
|
1934
|
+
var controller = document.getElementById(controllerId);
|
1935
|
+
controller.createArchive(apiKey, type, title);
|
1936
|
+
} catch(err) {
|
1937
|
+
errorMsg = "Session.createArchive :: " + err;
|
1938
|
+
error(errorMsg);
|
1939
|
+
throw new Error(errorMsg);
|
1940
|
+
}
|
1941
|
+
} else {
|
1942
|
+
errorMsg = "Session.createArchive :: Invalid type specfied.";
|
1943
|
+
error(errorMsg);
|
1944
|
+
throw new Error(errorMsg);
|
1945
|
+
}
|
1946
|
+
} else {
|
1947
|
+
errorMsg = "Session.createArchive :: Connection required to create an archive.";
|
1948
|
+
error(errorMsg);
|
1949
|
+
throw new Error(errorMsg);
|
1950
|
+
}
|
1951
|
+
};
|
1952
|
+
|
1953
|
+
this.loadArchive = function(archiveId) {
|
1954
|
+
debug("Session.loadArchive()");
|
1955
|
+
if (controllerId && this.connection && this.connection.connectionId) {
|
1956
|
+
try {
|
1957
|
+
var controller = document.getElementById(controllerId);
|
1958
|
+
controller.loadArchive(archiveId);
|
1959
|
+
} catch(err) {
|
1960
|
+
var errorMsg = "Session.loadArchive :: " + err;
|
1961
|
+
error(errorMsg);
|
1962
|
+
throw new Error(errorMsg);
|
1963
|
+
}
|
1964
|
+
} else {
|
1965
|
+
errorMsg = "Session.loadArchive :: Connection required to load an archive.";
|
1966
|
+
error(errorMsg);
|
1967
|
+
throw new Error(errorMsg);
|
1968
|
+
}
|
1969
|
+
};
|
1970
|
+
|
1971
|
+
this.startRecording = function(archive) {
|
1972
|
+
debug("Session.startRecording()");
|
1973
|
+
archive = createdArchives[this.sessionId][archive.archiveId];
|
1974
|
+
if (!archive) {
|
1975
|
+
var errorMsg = "Session.startRecording :: Archive not created.";
|
1976
|
+
error(errorMsg);
|
1977
|
+
throw new Error(errorMsg);
|
1978
|
+
}
|
1979
|
+
if (archive.type != TB.PER_SESSION) {
|
1980
|
+
errorMsg = "Session.startRecording :: Trying to record per session on a " + archive.type + " archive";
|
1981
|
+
error(errorMsg);
|
1982
|
+
throw new Error(errorMsg);
|
1983
|
+
}
|
1984
|
+
if (archive.recording) {
|
1985
|
+
warn("Session.startRecording :: Trying to start recording when the archive is already recording");
|
1986
|
+
return;
|
1987
|
+
}
|
1988
|
+
if (controllerId && this.connection && this.connection.connectionId) {
|
1989
|
+
try {
|
1990
|
+
var controller = document.getElementById(controllerId);
|
1991
|
+
controller.startRecordingSession(archive.archiveId);
|
1992
|
+
archive.recording = true;
|
1993
|
+
} catch(err) {
|
1994
|
+
errorMsg = "Session.startRecording :: " + err;
|
1995
|
+
error(errorMsg);
|
1996
|
+
throw new Error(errorMsg);
|
1997
|
+
}
|
1998
|
+
} else {
|
1999
|
+
errorMsg = "Session.startRecording :: Connection required to record an archive.";
|
2000
|
+
error(errorMsg);
|
2001
|
+
throw new Error(errorMsg);
|
2002
|
+
}
|
2003
|
+
};
|
2004
|
+
|
2005
|
+
this.stopRecording = function(archive) {
|
2006
|
+
debug("Session.stopRecording()");
|
2007
|
+
archive = createdArchives[this.sessionId][archive.archiveId];
|
2008
|
+
if (!archive) {
|
2009
|
+
var errorMsg = "Session.stopRecording :: Archive not created.";
|
2010
|
+
error(errorMsg);
|
2011
|
+
throw new Error(errorMsg);
|
2012
|
+
}
|
2013
|
+
if (archive.type != TB.PER_SESSION) {
|
2014
|
+
errorMsg = "Session.stopRecording :: Trying to stop recording per session on a " + archive.type + " archive";
|
2015
|
+
error(errorMsg);
|
2016
|
+
throw new Error(errorMsg);
|
2017
|
+
}
|
2018
|
+
if (controllerId && this.connection && this.connection.connectionId) {
|
2019
|
+
try {
|
2020
|
+
var controller = document.getElementById(controllerId);
|
2021
|
+
controller.stopRecordingSession(archive.archiveId);
|
2022
|
+
archive.recording = false;
|
2023
|
+
} catch(err) {
|
2024
|
+
errorMsg = "Session.stopRecording :: " + err;
|
2025
|
+
error(errorMsg);
|
2026
|
+
throw new Error(errorMsg);
|
2027
|
+
}
|
2028
|
+
} else {
|
2029
|
+
errorMsg = "Session.stopRecording :: Connection required to record an archive.";
|
2030
|
+
error(errorMsg);
|
2031
|
+
throw new Error(errorMsg);
|
2032
|
+
}
|
2033
|
+
};
|
2034
|
+
|
2035
|
+
this.closeArchive = function(archive) {
|
2036
|
+
debug("Session.closeArchive()");
|
2037
|
+
if (controllerId && this.connection && this.connection.connectionId) {
|
2038
|
+
try {
|
2039
|
+
var controller = document.getElementById(controllerId);
|
2040
|
+
controller.closeArchive(archive.archiveId);
|
2041
|
+
} catch(err) {
|
2042
|
+
var errorMsg = "Session.closeArchive :: " + err;
|
2043
|
+
error(errorMsg);
|
2044
|
+
throw new Error(errorMsg);
|
2045
|
+
}
|
2046
|
+
} else {
|
2047
|
+
errorMsg = "Session.closeArchive :: Connection required to close an archive.";
|
2048
|
+
error(errorMsg);
|
2049
|
+
throw new Error(errorMsg);
|
2050
|
+
}
|
2051
|
+
};
|
2052
|
+
|
2053
|
+
this.getStateManager = function() {
|
2054
|
+
debug("Session.getStateManager()");
|
2055
|
+
|
2056
|
+
if (stateManager) return stateManager;
|
2057
|
+
else if (controllerId && this.connection && this.connection.connectionId) {
|
2058
|
+
stateManager = new StateManager(controllerId);
|
2059
|
+
return stateManager;
|
2060
|
+
}
|
2061
|
+
|
2062
|
+
var errorMsg = "Session.getStateManager :: Connection required to getState. Wait for sessionConnected before you getStateManager.";
|
2063
|
+
error(errorMsg);
|
2064
|
+
throw new Error(errorMsg);
|
2065
|
+
};
|
2066
|
+
}
|
2067
|
+
|
2068
|
+
function StateManager(controllerId, archiveId) {
|
2069
|
+
this.superClass = EventDispatcher;
|
2070
|
+
this.superClass();
|
2071
|
+
|
2072
|
+
var MAX_KEYS = 20;
|
2073
|
+
|
2074
|
+
this.archiveId = archiveId;
|
2075
|
+
|
2076
|
+
this.set = function(key, value) {
|
2077
|
+
var values = key;
|
2078
|
+
if (archiveId) {
|
2079
|
+
var errorMsg = "StateManager.set :: not allowed on StateManager objects for archives.";
|
2080
|
+
error(errorMsg);
|
2081
|
+
throw new Error(errorMsg);
|
2082
|
+
}
|
2083
|
+
if (typeof(key) == "string" && (typeof(value) == "string" || value == null)) {
|
2084
|
+
values = {};
|
2085
|
+
values[key] = value;
|
2086
|
+
} else if (typeof(key) == "object" && value == null) {
|
2087
|
+
if (Object.keys(values).length > MAX_KEYS) {
|
2088
|
+
error("StateManager.set :: Maximum number of keys exceeded");
|
2089
|
+
this.dispatchEvent(new ChangeFailedEvent("changeFailed", 405, "Maximum number of keys exceeded", values));
|
2090
|
+
return;
|
2091
|
+
}
|
2092
|
+
} else {
|
2093
|
+
errorMsg = "StateManager.set :: Invalid parameters passed. set() takes either two string parameters or one object of key value pairs.";
|
2094
|
+
error(errorMsg);
|
2095
|
+
throw new Error(errorMsg);
|
2096
|
+
}
|
2097
|
+
|
2098
|
+
for (var k in values) {
|
2099
|
+
if (typeof(values[k]) != "string" && values[k] != null) {
|
2100
|
+
error("StateManager.set :: Invalid value " + values[k].toString() + " is not a string");
|
2101
|
+
this.dispatchEvent(new ChangeFailedEvent("changeFailed", 403, " Invalid value, value must be a string", values));
|
2102
|
+
return;
|
2103
|
+
}
|
2104
|
+
};
|
2105
|
+
|
2106
|
+
if (controllerId) {
|
2107
|
+
try {
|
2108
|
+
var controller = document.getElementById(controllerId);
|
2109
|
+
controller.setState(values);
|
2110
|
+
} catch (err) {
|
2111
|
+
errorMsg = "StateManager.set :: " + err;
|
2112
|
+
error(errorMsg);
|
2113
|
+
throw new Error(errorMsg);
|
2114
|
+
}
|
2115
|
+
}
|
2116
|
+
};
|
2117
|
+
|
2118
|
+
this.superAddEventListener = this.addEventListener;
|
2119
|
+
this.addEventListener = function(type, listener) {
|
2120
|
+
var key = false;
|
2121
|
+
if (type == "changed") {
|
2122
|
+
key = null;
|
2123
|
+
} else if (type.indexOf("changed:") == 0) {
|
2124
|
+
// Tell the controller which keys we want to subscribe to
|
2125
|
+
key = type.split(":")[1];
|
2126
|
+
}
|
2127
|
+
|
2128
|
+
if (key !== false) {
|
2129
|
+
if (archiveId) {
|
2130
|
+
key = "TB_archive_" + archiveId + "_";
|
2131
|
+
}
|
2132
|
+
// Tell the controller that we want to subscribe to all keys
|
2133
|
+
if (controllerId) {
|
2134
|
+
try {
|
2135
|
+
var controller = document.getElementById(controllerId);
|
2136
|
+
controller.subscribeToKeyChange(key);
|
2137
|
+
} catch(err) {
|
2138
|
+
var errorMsg = "StateManager.addEventListener :: " + err;
|
2139
|
+
error(errorMsg);
|
2140
|
+
throw new Error(errorMsg);
|
2141
|
+
}
|
2142
|
+
}
|
2143
|
+
}
|
2144
|
+
|
2145
|
+
this.superAddEventListener(type, listener);
|
2146
|
+
};
|
2147
|
+
|
2148
|
+
// Need to figure out how to know whether there are any event listeners for a key
|
2149
|
+
// if there are none then we can stop listening on the shared object, otherwise we should
|
2150
|
+
// keep listening.
|
2151
|
+
// this.superRemoveEventListener = this.removeEventListener;
|
2152
|
+
// this.removeEventListener = function(type, listener) {
|
2153
|
+
// var key = false;
|
2154
|
+
// if (type == "changed") {
|
2155
|
+
// key = null;
|
2156
|
+
// } else if (type.indexOf("changed:") == 0) {
|
2157
|
+
// // Tell the controller which keys we want to subscribe to
|
2158
|
+
// key = type.split(":")[1];
|
2159
|
+
// }
|
2160
|
+
//
|
2161
|
+
// if (key !== false) {
|
2162
|
+
// // Tell the controller that we want to subscribe to all keys
|
2163
|
+
// if (controllerId) {
|
2164
|
+
// try {
|
2165
|
+
// var controller = document.getElementById(controllerId);
|
2166
|
+
// controller.unsubscribeFromKeyChange(key);
|
2167
|
+
// } catch(err) {
|
2168
|
+
// var errorMsg = "StateManager.removeEventListener :: " + err;
|
2169
|
+
// error(errorMsg);
|
2170
|
+
// throw new Error(errorMsg);
|
2171
|
+
// }
|
2172
|
+
// }
|
2173
|
+
// }
|
2174
|
+
//
|
2175
|
+
// this.superRemoveEventListener(type, listener);
|
2176
|
+
// };
|
2177
|
+
}
|
2178
|
+
|
2179
|
+
|
2180
|
+
//--------------------------------------
|
2181
|
+
// PRIVATE HELPER FUNCTIONS
|
2182
|
+
//--------------------------------------
|
2183
|
+
|
2184
|
+
function setEchoSuppressionEnabled(sessionId, groupId, isEnabled) {
|
2185
|
+
try {
|
2186
|
+
var controller = document.getElementById("controller_" + sessionId);
|
2187
|
+
controller.setEchoSuppressionEnabled(groupId, isEnabled);
|
2188
|
+
} catch(err) {
|
2189
|
+
var errorMsg = "Group :: " + err;
|
2190
|
+
error(errorMsg);
|
2191
|
+
throw new Error(errorMsg);
|
2192
|
+
}
|
2193
|
+
}
|
2194
|
+
|
2195
|
+
function getGroupProperties(sessionId, groupId) {
|
2196
|
+
var groupProperties = null;
|
2197
|
+
try {
|
2198
|
+
var controller = document.getElementById("controller_" + sessionId);
|
2199
|
+
var groupObject = controller.getGroupProperties(groupId);
|
2200
|
+
|
2201
|
+
groupProperties = new GroupProperties(groupObject);
|
2202
|
+
} catch(err) {
|
2203
|
+
var errorMsg = "Group :: " + err;
|
2204
|
+
error(errorMsg);
|
2205
|
+
throw new Error(errorMsg);
|
2206
|
+
}
|
2207
|
+
|
2208
|
+
return groupProperties;
|
2209
|
+
}
|
2210
|
+
|
2211
|
+
function embedCallback (event) {
|
2212
|
+
if (!event.success) {
|
2213
|
+
error("Failed to embed SWF " + event.id);
|
2214
|
+
TB.exceptionHandler("Failed to embed SWF " + event.id, "Embed Failed", 2001);
|
2215
|
+
}
|
2216
|
+
}
|
2217
|
+
|
2218
|
+
function embedSWF(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj) {
|
2219
|
+
if (!swfobject.hasFlashPlayerVersion(swfVersionStr)) {
|
2220
|
+
error("Flash Player " + swfVersionStr + " or higher required");
|
2221
|
+
TB.exceptionHandler("Flash Player " + swfVersionStr + " or higher required", "Embed Failed", 2001);
|
2222
|
+
return;
|
2223
|
+
}
|
2224
|
+
|
2225
|
+
swfobject.embedSWF(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj, embedCallback);
|
2226
|
+
}
|
2227
|
+
|
2228
|
+
function createHandler(func, event) {
|
2229
|
+
return function() {
|
2230
|
+
if(func != null) {
|
2231
|
+
func(event);
|
2232
|
+
} else {
|
2233
|
+
error('Event handler is null');
|
2234
|
+
}
|
2235
|
+
};
|
2236
|
+
}
|
2237
|
+
|
2238
|
+
function flashdebug (str) {
|
2239
|
+
window.opentokdebug.debug("[FLASHDEBUG] opentok: " + str);
|
2240
|
+
}
|
2241
|
+
|
2242
|
+
function debug (str) {
|
2243
|
+
window.opentokdebug.debug("[DEBUG] opentok: " + str);
|
2244
|
+
}
|
2245
|
+
|
2246
|
+
function info (str) {
|
2247
|
+
window.opentokdebug.info("[INFO] opentok: " + str);
|
2248
|
+
}
|
2249
|
+
|
2250
|
+
function warn (str) {
|
2251
|
+
window.opentokdebug.warn("[WARN] opentok: " + str);
|
2252
|
+
}
|
2253
|
+
|
2254
|
+
function error (str) {
|
2255
|
+
window.opentokdebug.error("[ERROR] opentok: " + str);
|
2256
|
+
}
|
2257
|
+
|
2258
|
+
function traceOut (level, str) {
|
2259
|
+
var element = document.getElementById('opentok_console');
|
2260
|
+
if (element) element.innerHTML += (str + '<br>');
|
2261
|
+
}
|
2262
|
+
|
2263
|
+
function getConnectionFromConnectionId (connectionId) {
|
2264
|
+
if (connectionMap.hasOwnProperty(connectionId)) {
|
2265
|
+
var connection = connectionMap[connectionId];
|
2266
|
+
} else {
|
2267
|
+
connection = new Connection(connectionId, NaN, null);
|
2268
|
+
}
|
2269
|
+
return connection;
|
2270
|
+
}
|
2271
|
+
|
2272
|
+
function getStream(streamObject, sessionId) {
|
2273
|
+
return new Stream(streamObject.streamId, getConnectionFromConnectionId(streamObject.connectionId), streamObject.name, streamObject.streamData, streamObject.type, streamObject.creationTime, streamObject.hasAudio, streamObject.hasVideo, streamObject.orientation, sessionId, streamObject.peerId, streamObject.quality);
|
2274
|
+
}
|
2275
|
+
|
2276
|
+
function getStreams (streamObjects, sessionId) {
|
2277
|
+
var streams = [];
|
2278
|
+
for (var i=0; i < streamObjects.length; i++) {
|
2279
|
+
streams.push(getStream(streamObjects[i], sessionId));
|
2280
|
+
}
|
2281
|
+
|
2282
|
+
return streams;
|
2283
|
+
}
|
2284
|
+
|
2285
|
+
function getArchive (archive, sessionId) {
|
2286
|
+
var newArchive = new Archive(archive.id, archive.type, archive.title, sessionId, archive.status);
|
2287
|
+
if (!createdArchives.hasOwnProperty(sessionId)) createdArchives[sessionId] = {};
|
2288
|
+
createdArchives[sessionId][archive.id] = newArchive;
|
2289
|
+
|
2290
|
+
return newArchive;
|
2291
|
+
}
|
2292
|
+
|
2293
|
+
function getConnections (connectionObjects) {
|
2294
|
+
var connections = [];
|
2295
|
+
|
2296
|
+
for (var i=0; i < connectionObjects.length; i++) {
|
2297
|
+
var connection = new Connection(connectionObjects[i].connectionId, connectionObjects[i].creationTime, connectionObjects[i].data);
|
2298
|
+
connections.push(connection);
|
2299
|
+
|
2300
|
+
connectionMap[connection.connectionId] = connection;
|
2301
|
+
};
|
2302
|
+
|
2303
|
+
return connections;
|
2304
|
+
}
|
2305
|
+
|
2306
|
+
function getGroups (sessionId,groupObjects) {
|
2307
|
+
var groups = [];
|
2308
|
+
for (var key in groupObjects) {
|
2309
|
+
if (groupObjects[key].hasOwnProperty("groupId"))
|
2310
|
+
groups.push(new Group(sessionId,groupObjects[key].groupId));
|
2311
|
+
}
|
2312
|
+
|
2313
|
+
return groups;
|
2314
|
+
}
|
2315
|
+
|
2316
|
+
function getCamera (cameraObj) {
|
2317
|
+
if (cameraObj.status == TB.ACTIVE) {
|
2318
|
+
return new Camera(cameraObj.name, TB.ACTIVE);
|
2319
|
+
} else if (cameraObj.status == TB.INACTIVE) {
|
2320
|
+
return new Camera(cameraObj.name, TB.INACTIVE);
|
2321
|
+
} else {
|
2322
|
+
return new Camera(cameraObj.name, TB.UNKNOWN);
|
2323
|
+
}
|
2324
|
+
}
|
2325
|
+
|
2326
|
+
function getMicrophone (microphoneObj) {
|
2327
|
+
return new Microphone(microphoneObj.name, microphoneObj.status);
|
2328
|
+
}
|
2329
|
+
|
2330
|
+
function getCameras (cameraObjects) {
|
2331
|
+
var cameras = new Array();
|
2332
|
+
|
2333
|
+
for (var i=0; i < cameraObjects.length; i++) {
|
2334
|
+
cameras.push(new Camera(cameraObjects[i].name, cameraObjects[i].status));
|
2335
|
+
};
|
2336
|
+
|
2337
|
+
return cameras;
|
2338
|
+
}
|
2339
|
+
|
2340
|
+
function getMicrophones (microphoneObjects) {
|
2341
|
+
var microphones = new Array();
|
2342
|
+
|
2343
|
+
for (var i=0; i < microphoneObjects.length; i++) {
|
2344
|
+
microphones.push(new Microphone(microphoneObjects[i].name, microphoneObjects[i].status));
|
2345
|
+
};
|
2346
|
+
|
2347
|
+
return microphones;
|
2348
|
+
}
|
2349
|
+
|
2350
|
+
function disconnectComponent(component) {
|
2351
|
+
if(!component.hasOwnProperty("id")){
|
2352
|
+
return;
|
2353
|
+
}
|
2354
|
+
var uicomponent = document.getElementById(component.id);
|
2355
|
+
|
2356
|
+
if (uicomponent) {
|
2357
|
+
try {
|
2358
|
+
uicomponent.cleanupView();
|
2359
|
+
} catch(e) {
|
2360
|
+
warn("Disconnecting " + component.id + " failed");
|
2361
|
+
}
|
2362
|
+
} else {
|
2363
|
+
warn("Disconnecting " + component.id + " failed");
|
2364
|
+
}
|
2365
|
+
}
|
2366
|
+
|
2367
|
+
function unloadComponent (component) {
|
2368
|
+
var uicomponent = document.getElementById(component.id);
|
2369
|
+
if (uicomponent) {
|
2370
|
+
try {
|
2371
|
+
uicomponent.cleanupView();
|
2372
|
+
|
2373
|
+
var parentNode = uicomponent.parentNode;
|
2374
|
+
parentNode.removeChild(uicomponent);
|
2375
|
+
} catch(e) {
|
2376
|
+
warn("Removing " + component.id + " failed " + e);
|
2377
|
+
}
|
2378
|
+
} else {
|
2379
|
+
warn("Element " + component.id + " does not exist");
|
2380
|
+
}
|
2381
|
+
}
|
2382
|
+
|
2383
|
+
function removeSWF (componentId, message) {
|
2384
|
+
try {
|
2385
|
+
if (componentId) {
|
2386
|
+
swfobject.removeSWF(componentId);
|
2387
|
+
componentId = null;
|
2388
|
+
}
|
2389
|
+
} catch(err) {
|
2390
|
+
var errorMsg = message + err;
|
2391
|
+
error(errorMsg);
|
2392
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
2393
|
+
}
|
2394
|
+
}
|
2395
|
+
|
2396
|
+
function setStreamProperty (id, property, value) {
|
2397
|
+
var component = document.getElementById(id);
|
2398
|
+
if (component) {
|
2399
|
+
try {
|
2400
|
+
component.setStreamProperty(property, value);
|
2401
|
+
} catch (err) {
|
2402
|
+
var errorMsg = "Changing settings on component " + id + " failed.";
|
2403
|
+
error(errorMsg);
|
2404
|
+
throw new Error(errorMsg);
|
2405
|
+
}
|
2406
|
+
} else {
|
2407
|
+
errorMsg = "Component "+id + " does not exist.";
|
2408
|
+
error(errorMsg);
|
2409
|
+
throw new Error(errorMsg);
|
2410
|
+
}
|
2411
|
+
}
|
2412
|
+
|
2413
|
+
function setDevice (id, device, isCamera) {
|
2414
|
+
var component = document.getElementById(id);
|
2415
|
+
if (component) {
|
2416
|
+
try {
|
2417
|
+
if (isCamera) component.setCamera(device.name);
|
2418
|
+
else component.setMicrophone(device.name);
|
2419
|
+
} catch (err) {
|
2420
|
+
var errorMsg = "Changing hardware settings on publisher " + id + " failed.";
|
2421
|
+
error(errorMsg);
|
2422
|
+
throw new Error(errorMsg);
|
2423
|
+
}
|
2424
|
+
} else {
|
2425
|
+
errorMsg = "Publisher "+ id + " does not exist.";
|
2426
|
+
error(errorMsg);
|
2427
|
+
throw new Error(errorMsg);
|
2428
|
+
}
|
2429
|
+
}
|
2430
|
+
|
2431
|
+
// Find highest Z-index - via StackOverflow <http://bit.ly/dFaOw9>
|
2432
|
+
function highZ(parent, limit){
|
2433
|
+
limit = limit || Infinity;
|
2434
|
+
parent = parent || document.body;
|
2435
|
+
var who, temp, max= 1, A= [], i= 0;
|
2436
|
+
var children = parent.childNodes, length = children.length;
|
2437
|
+
while(i<length){
|
2438
|
+
who = children[i++];
|
2439
|
+
if (who.nodeType != 1) continue;
|
2440
|
+
if (deepCss(who,"position") !== "static") { // element nodes only
|
2441
|
+
temp = deepCss(who,"z-index");
|
2442
|
+
if (temp == "auto") { // z-index is auto, so not a new stacking context
|
2443
|
+
temp = highZ(who);
|
2444
|
+
} else {
|
2445
|
+
temp = parseInt(temp, 10) || 0;
|
2446
|
+
}
|
2447
|
+
} else { // non-positioned element, so not a new stacking context
|
2448
|
+
temp = highZ(who);
|
2449
|
+
}
|
2450
|
+
if (temp > max && temp <= limit) max = temp;
|
2451
|
+
}
|
2452
|
+
return max;
|
2453
|
+
}
|
2454
|
+
|
2455
|
+
// This function is only intended for highZ(). Other uses may be unpredictable.
|
2456
|
+
function deepCss(who, css) {
|
2457
|
+
var sty, val, dv= document.defaultView || window;
|
2458
|
+
if (who.nodeType == 1) {
|
2459
|
+
sty = css.replace(/\-([a-z])/g, function(a, b){
|
2460
|
+
return b.toUpperCase();
|
2461
|
+
});
|
2462
|
+
val = who.style[sty];
|
2463
|
+
if (!val) {
|
2464
|
+
if(who.currentStyle) val= who.currentStyle[sty];
|
2465
|
+
else if (dv.getComputedStyle) {
|
2466
|
+
val= dv.getComputedStyle(who,"").getPropertyValue(css);
|
2467
|
+
}
|
2468
|
+
}
|
2469
|
+
}
|
2470
|
+
return val || "";
|
2471
|
+
}
|
2472
|
+
|
2473
|
+
function createHiddenElement (form, key, value) {
|
2474
|
+
var hiddenField = document.createElement("input");
|
2475
|
+
hiddenField.setAttribute("name", key);
|
2476
|
+
hiddenField.setAttribute("value", value);
|
2477
|
+
hiddenField.setAttribute("type", "hidden");
|
2478
|
+
form.appendChild(hiddenField);
|
2479
|
+
}
|
2480
|
+
|
2481
|
+
function getDataForUIComponent (componentId) {
|
2482
|
+
try {
|
2483
|
+
var element = document.getElementById(componentId);
|
2484
|
+
if (element) {
|
2485
|
+
return element.fetchData();
|
2486
|
+
}
|
2487
|
+
} catch (err) {
|
2488
|
+
warn("Failed to get logs for " + componentId + " " + err);
|
2489
|
+
return "";
|
2490
|
+
}
|
2491
|
+
}
|
2492
|
+
|
2493
|
+
function JSONify(object) {
|
2494
|
+
// JSONify the style property
|
2495
|
+
var styleString = "{ ";
|
2496
|
+
for (var key in object) {
|
2497
|
+
if (typeof(object[key]) == "boolean")
|
2498
|
+
styleString += '"' + key + '":' + object[key] + ', ';
|
2499
|
+
else
|
2500
|
+
styleString += '"' + key + '":"' + object[key].toString() + '", ';
|
2501
|
+
};
|
2502
|
+
if (styleString.length > 1) {
|
2503
|
+
styleString = styleString.substring(0, styleString.length - 2) + " }";
|
2504
|
+
} else {
|
2505
|
+
styleString = "{}";
|
2506
|
+
}
|
2507
|
+
|
2508
|
+
return styleString;
|
2509
|
+
}
|
2510
|
+
|
2511
|
+
function copyObject(obj) {
|
2512
|
+
var newObj = (obj instanceof Array) ? [] : {};
|
2513
|
+
for (var i in obj) {
|
2514
|
+
if (i == 'clone') continue;
|
2515
|
+
if (obj[i] && typeof obj[i] == "object") {
|
2516
|
+
newObj[i] = copyObject(obj[i]);
|
2517
|
+
} else newObj[i] = obj[i];
|
2518
|
+
}
|
2519
|
+
return newObj;
|
2520
|
+
}
|
2521
|
+
|
2522
|
+
|
2523
|
+
//--------------------------------------
|
2524
|
+
// EVENT HANDLERS
|
2525
|
+
//--------------------------------------
|
2526
|
+
|
2527
|
+
this.isUnloading = false;
|
2528
|
+
window.onunload = function() {
|
2529
|
+
isUnloading = true;
|
2530
|
+
for (var i in TB.sessions) {
|
2531
|
+
if (TB.sessions[i].hasOwnProperty("disconnect")) {
|
2532
|
+
// Stop sessionDisconnectedHandler from happening. Was causing crashes on Safari.
|
2533
|
+
// We are just doing all the cleanup now.
|
2534
|
+
TB.sessionDisconnectedHandler = function() {};
|
2535
|
+
|
2536
|
+
TB.sessions[i].disconnect();
|
2537
|
+
TB.sessions[i].cleanupConnection();
|
2538
|
+
TB.sessions[i].cleanup();
|
2539
|
+
}
|
2540
|
+
}
|
2541
|
+
};
|
2542
|
+
|
2543
|
+
|
2544
|
+
//--------------------------------------
|
2545
|
+
// PRIVATE STATIC VARIABLES
|
2546
|
+
//--------------------------------------
|
2547
|
+
|
2548
|
+
var MIN_FLASH_VERSION = "10.0.0";
|
2549
|
+
|
2550
|
+
// Minimum width and height to fit the adobe settings UI
|
2551
|
+
var MIN_ADOBE_WIDTH = 215;
|
2552
|
+
var MIN_ADOBE_HEIGHT = 138;
|
2553
|
+
|
2554
|
+
var deviceManager;
|
2555
|
+
var recorderManager;
|
2556
|
+
var deviceDetectorId;
|
2557
|
+
var cameraSelected = false;
|
2558
|
+
var showingIssueForm = false;
|
2559
|
+
|
2560
|
+
var connectionMap = {};
|
2561
|
+
|
2562
|
+
var SUPPORT_SSL = "true";
|
2563
|
+
|
2564
|
+
var WIDGET_URL = "http://staging.tokbox.com";
|
2565
|
+
|
2566
|
+
if (SUPPORT_SSL == "true" && window.location.protocol == "https:") {
|
2567
|
+
WIDGET_URL = "https://staging.tokbox.com";
|
2568
|
+
}
|
2569
|
+
|
2570
|
+
var dispatcher = new EventDispatcher();
|
2571
|
+
var createdArchives = {};
|
2572
|
+
var loadedArchives = {};
|
2573
|
+
|
2574
|
+
var controllerLoaded = false;
|
2575
|
+
|
2576
|
+
return {
|
2577
|
+
|
2578
|
+
//--------------------------------------
|
2579
|
+
// TB PUBLIC STATIC VARIABLES
|
2580
|
+
//--------------------------------------
|
2581
|
+
|
2582
|
+
sessions: {},
|
2583
|
+
groups: {},
|
2584
|
+
|
2585
|
+
LOG: 5,
|
2586
|
+
DEBUG: 4,
|
2587
|
+
INFO: 3,
|
2588
|
+
WARN: 2,
|
2589
|
+
ERROR: 1,
|
2590
|
+
NONE: 0,
|
2591
|
+
|
2592
|
+
// Activity Status for cams/mics
|
2593
|
+
ACTIVE: "active",
|
2594
|
+
INACTIVE: "inactive",
|
2595
|
+
UNKNOWN: "unknown",
|
2596
|
+
|
2597
|
+
// Archive types
|
2598
|
+
PER_SESSION: "perSession",
|
2599
|
+
PER_STREAM: "perStream",
|
2600
|
+
|
2601
|
+
// TB Events
|
2602
|
+
EXCEPTION: "exception",
|
2603
|
+
|
2604
|
+
// Session Events
|
2605
|
+
SESSION_CONNECTED: "sessionConnected",
|
2606
|
+
SESSION_DISCONNECTED: "sessionDisconnected",
|
2607
|
+
STREAM_CREATED: "streamCreated",
|
2608
|
+
STREAM_DESTROYED: "streamDestroyed",
|
2609
|
+
CONNECTION_CREATED: "connectionCreated",
|
2610
|
+
CONNECTION_DESTROYED: "connectionDestroyed",
|
2611
|
+
SIGNAL_RECEIVED: "signalReceived",
|
2612
|
+
STREAM_PROPERTY_CHANGED: "streamPropertyChanged",
|
2613
|
+
MICROPHONE_LEVEL_CHANGED: "microphoneLevelChanged",
|
2614
|
+
ARCHIVE_CREATED: "archiveCreated",
|
2615
|
+
ARCHIVE_CLOSED: "archiveClosed",
|
2616
|
+
ARCHIVE_LOADED: "archiveLoaded",
|
2617
|
+
ARCHIVE_SAVED: "archiveSaved",
|
2618
|
+
SESSION_RECORDING_STARTED: "sessionRecordingStarted",
|
2619
|
+
SESSION_RECORDING_STOPPED: "sessionRecordingStopped",
|
2620
|
+
SESSION_RECORDING_IN_PROGRESS: "sessionRecordingInProgress",
|
2621
|
+
STREAM_RECORDING_IN_PROGRESS: "streamRecordingInProgress",
|
2622
|
+
SESSION_NOT_RECORDING: "sessionNotRecording",
|
2623
|
+
STREAM_RECORDING_STARTED: "streamRecordingStarted",
|
2624
|
+
STREAM_RECORDING_STOPPED: "streamRecordingStopped",
|
2625
|
+
PLAYBACK_STARTED: "playbackStarted",
|
2626
|
+
PLAYBACK_STOPPED: "playbackStopped",
|
2627
|
+
RECORDING_STARTED: "recordingStarted",
|
2628
|
+
RECORDING_STOPPED: "recordingStopped",
|
2629
|
+
// Group Events
|
2630
|
+
GROUP_PROPERTIES_UPDATED: "groupPropertiesUpdated",
|
2631
|
+
|
2632
|
+
// Publisher Events
|
2633
|
+
RESIZE: "resize",
|
2634
|
+
SETTINGS_BUTTON_CLICK: "settingsButtonClick",
|
2635
|
+
DEVICE_INACTIVE: "deviceInactive",
|
2636
|
+
ACCESS_ALLOWED: "accessAllowed",
|
2637
|
+
ACCESS_DENIED: "accessDenied",
|
2638
|
+
ECHO_CANCELLATION_MODE_CHANGED: "echoCancellationModeChanged",
|
2639
|
+
|
2640
|
+
// DeviceManager Events
|
2641
|
+
DEVICES_DETECTED: "devicesDetected",
|
2642
|
+
|
2643
|
+
// DevicePanel Events
|
2644
|
+
DEVICES_SELECTED: "devicesSelected",
|
2645
|
+
CLOSE_BUTTON_CLICK: "closeButtonClick",
|
2646
|
+
|
2647
|
+
HAS_REQUIREMENTS: 1,
|
2648
|
+
OLD_FLASH_VERSION: 0,
|
2649
|
+
|
2650
|
+
// Stream types
|
2651
|
+
BASIC_STREAM: "basic",
|
2652
|
+
MULTIPLEXED_STREAM: "multiplexed",
|
2653
|
+
ARCHIVED: "archive",
|
2654
|
+
|
2655
|
+
// Global group ID
|
2656
|
+
GLOBAL_GROUP: "global",
|
2657
|
+
|
2658
|
+
// Multiplexer Switch Type
|
2659
|
+
MULTIPLEXER_TIMEOUT_BASED_SWITCH: 0,
|
2660
|
+
MULTIPLEXER_ACTIVITY_BASED_SWITCH: 1,
|
2661
|
+
|
2662
|
+
simulateMobile: false,
|
2663
|
+
|
2664
|
+
//--------------------------------------
|
2665
|
+
// TB STATIC FUNCTIONS
|
2666
|
+
//--------------------------------------
|
2667
|
+
|
2668
|
+
setLogLevel: function(value) {
|
2669
|
+
window.opentokdebug.setLevel(value);
|
2670
|
+
if (value == this.NONE) window.opentokdebug.setCallback(null);
|
2671
|
+
else window.opentokdebug.setCallback(traceOut, true);
|
2672
|
+
debug("TB.setLogLevel(" + value + ")" );
|
2673
|
+
},
|
2674
|
+
|
2675
|
+
|
2676
|
+
log: function(str) {
|
2677
|
+
window.opentokdebug.log("[LOG] opentok: " + str);
|
2678
|
+
},
|
2679
|
+
|
2680
|
+
initSession: function(sessionId) {
|
2681
|
+
debug("TB.initSession(" + sessionId + ")");
|
2682
|
+
if (sessionId == null || sessionId == "") {
|
2683
|
+
var errorMsg = "TB.initSession :: sessionId cannot be null";
|
2684
|
+
error(errorMsg);
|
2685
|
+
throw new Error(errorMsg);
|
2686
|
+
}
|
2687
|
+
|
2688
|
+
if (!this.sessions.hasOwnProperty(sessionId)) {
|
2689
|
+
this.sessions[sessionId] = new Session(sessionId);
|
2690
|
+
}
|
2691
|
+
|
2692
|
+
return this.sessions[sessionId];
|
2693
|
+
},
|
2694
|
+
|
2695
|
+
initDeviceManager: function(apiKey) {
|
2696
|
+
debug("TB.initDeviceManager(" + apiKey + ")");
|
2697
|
+
if (!apiKey) {
|
2698
|
+
var errorMsg = "TB.initDeviceManager :: apiKey cannot be null";
|
2699
|
+
error(errorMsg);
|
2700
|
+
throw new Error(errorMsg);
|
2701
|
+
}
|
2702
|
+
if (!deviceManager) {
|
2703
|
+
deviceManager = new DeviceManager(apiKey);
|
2704
|
+
}
|
2705
|
+
return deviceManager;
|
2706
|
+
},
|
2707
|
+
|
2708
|
+
initRecorderManager: function(apiKey) {
|
2709
|
+
debug("TB.initRecorderManager(" + apiKey + ")");
|
2710
|
+
if (!apiKey) {
|
2711
|
+
var errorMsg = "TB.initRecorderManager :: apiKey cannot be null";
|
2712
|
+
error(errorMsg);
|
2713
|
+
throw new Error(errorMsg);
|
2714
|
+
}
|
2715
|
+
if (!recorderManager) {
|
2716
|
+
recorderManager = new RecorderManager(apiKey);
|
2717
|
+
}
|
2718
|
+
return recorderManager;
|
2719
|
+
},
|
2720
|
+
|
2721
|
+
addEventListener: function(type, callback) {
|
2722
|
+
debug("TB.addEventListener(" + type + ")");
|
2723
|
+
dispatcher.addEventListener(type, callback);
|
2724
|
+
},
|
2725
|
+
|
2726
|
+
removeEventListener: function(type, callback) {
|
2727
|
+
debug("TB.removeEventListener(" + type + ")");
|
2728
|
+
dispatcher.removeEventListener(type, callback);
|
2729
|
+
},
|
2730
|
+
|
2731
|
+
dispatchEvent: function(event) {
|
2732
|
+
debug("TB.dispatchEvent()");
|
2733
|
+
event.target = this;
|
2734
|
+
dispatcher.dispatchEvent(event);
|
2735
|
+
},
|
2736
|
+
|
2737
|
+
checkSystemRequirements: function() {
|
2738
|
+
debug("TB.checkSystemRequirements()");
|
2739
|
+
return swfobject.hasFlashPlayerVersion(MIN_FLASH_VERSION) ? this.HAS_REQUIREMENTS : this.OLD_FLASH_VERSION;
|
2740
|
+
},
|
2741
|
+
|
2742
|
+
//--------------------------------------
|
2743
|
+
// FLASH CALLBACK HANDLERS
|
2744
|
+
//--------------------------------------
|
2745
|
+
|
2746
|
+
// TB callbacks
|
2747
|
+
exceptionHandler: function(msg, title, errorCode) {
|
2748
|
+
error("TB.exception :: title: " + title + " msg: " + msg + " errorCode: " + errorCode);
|
2749
|
+
try {
|
2750
|
+
this.dispatchEvent(new ExceptionEvent(this.EXCEPTION, msg, title, errorCode));
|
2751
|
+
} catch(err) {
|
2752
|
+
var errorMsg = "TB.exception :: Failed to dispatch exception - " + err;
|
2753
|
+
error(errorMsg);
|
2754
|
+
// Don't throw an error because this is asynchronous
|
2755
|
+
// don't do an exceptionHandler because that would be recursive
|
2756
|
+
}
|
2757
|
+
},
|
2758
|
+
|
2759
|
+
// private callback
|
2760
|
+
controllerLoadedHandler: function() {
|
2761
|
+
controllerLoaded = true;
|
2762
|
+
},
|
2763
|
+
|
2764
|
+
controllerLoadCheck: function(event) {
|
2765
|
+
if (!controllerLoaded) {
|
2766
|
+
var confirmMsg = "The connection timed out. Make sure that you have allowed this page in the"
|
2767
|
+
+ "Flash Player Global Settings Manager. Go to:";
|
2768
|
+
adobeURL = "http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html";
|
2769
|
+
prompt(confirmMsg, adobeURL);
|
2770
|
+
}
|
2771
|
+
},
|
2772
|
+
|
2773
|
+
// private callback
|
2774
|
+
flashLogger: function(msg) {
|
2775
|
+
flashdebug(msg);
|
2776
|
+
},
|
2777
|
+
|
2778
|
+
// private callback
|
2779
|
+
destroyStreamHandler: function(sessionId, streamObjects) {
|
2780
|
+
debug("TB.destroyStream");
|
2781
|
+
try {
|
2782
|
+
var session = this.sessions[sessionId];
|
2783
|
+
var streams = getStreams(streamObjects, sessionId);
|
2784
|
+
|
2785
|
+
var action = function() {
|
2786
|
+
for (var i = 0; i < streams.length; i++) {
|
2787
|
+
var publisher = session.getPublisherForStream(streams[i]);
|
2788
|
+
if (publisher) {
|
2789
|
+
session.unpublish(publisher);
|
2790
|
+
}
|
2791
|
+
}
|
2792
|
+
};
|
2793
|
+
|
2794
|
+
// The event handler is called asynchronously after 2 milliseconds.
|
2795
|
+
setTimeout(action, 2);
|
2796
|
+
} catch(err) {
|
2797
|
+
var errorMsg = "TB.destroyStream :: " + err;
|
2798
|
+
error(errorMsg);
|
2799
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
2800
|
+
}
|
2801
|
+
},
|
2802
|
+
|
2803
|
+
// Session callbacks
|
2804
|
+
sessionConnectedHandler: function(sessionId, connectionId, connectionObjects, streamObjects, groupObjects, capabilities, connectionQuality, p_archives) {
|
2805
|
+
debug("TB.sessionConnected");
|
2806
|
+
try {
|
2807
|
+
var session = this.sessions[sessionId];
|
2808
|
+
for(var i=0, len = connectionObjects.length; i < len; i++) {
|
2809
|
+
connection = connectionObjects[i];
|
2810
|
+
if(connection.connectionId == connectionId) {
|
2811
|
+
session.connection = new Connection(connectionId, connection.creationTime, connection.data);
|
2812
|
+
break;
|
2813
|
+
}
|
2814
|
+
}
|
2815
|
+
session.connected = true;
|
2816
|
+
session.connecting = false;
|
2817
|
+
session.connection.quality = connectionQuality;
|
2818
|
+
session.capabilities = capabilities;
|
2819
|
+
var connections = getConnections(connectionObjects);
|
2820
|
+
var streams = getStreams(streamObjects, session.sessionId);
|
2821
|
+
var groups = getGroups(sessionId,groupObjects);
|
2822
|
+
for (var i=0; i < groups.length; i++) {
|
2823
|
+
this.groups[sessionId + "_" + groups[i].groupId] = groups[i];
|
2824
|
+
}
|
2825
|
+
|
2826
|
+
var archives = [];
|
2827
|
+
for (var i=0; i < p_archives.length; i++) {
|
2828
|
+
var newArchive = getArchive(p_archives[i], sessionId);
|
2829
|
+
archives.push(newArchive);
|
2830
|
+
};
|
2831
|
+
|
2832
|
+
session.dispatchEvent(new SessionConnectEvent(this.SESSION_CONNECTED, connections, streams, groups, archives));
|
2833
|
+
}
|
2834
|
+
catch(err) {
|
2835
|
+
var errorMsg = "TB.sessionConnected :: "+err;
|
2836
|
+
error(errorMsg);
|
2837
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
2838
|
+
}
|
2839
|
+
},
|
2840
|
+
|
2841
|
+
sessionDisconnectedHandler: function(sessionId, reason) {
|
2842
|
+
debug("TB.sessionDisconnected(" + reason + ")");
|
2843
|
+
try {
|
2844
|
+
var session = this.sessions[sessionId];
|
2845
|
+
session.disconnectComponents();
|
2846
|
+
session.cleanupConnection();
|
2847
|
+
session.connected = false;
|
2848
|
+
|
2849
|
+
var event = new SessionDisconnectEvent(this.SESSION_DISCONNECTED, reason, true);
|
2850
|
+
session.dispatchEvent(event);
|
2851
|
+
|
2852
|
+
var defaultAction = function() {
|
2853
|
+
if (!event.isDefaultPrevented()) {
|
2854
|
+
session.cleanup();
|
2855
|
+
}
|
2856
|
+
};
|
2857
|
+
|
2858
|
+
// The event handler is called asynchronously after 1 millisecond. The default action happens after that.
|
2859
|
+
setTimeout(defaultAction, 2);
|
2860
|
+
} catch(err) {
|
2861
|
+
var errorMsg = "TB.sessionDisconnected :: " + err;
|
2862
|
+
error(errorMsg);
|
2863
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
2864
|
+
}
|
2865
|
+
},
|
2866
|
+
|
2867
|
+
streamCreatedHandler: function(sessionId, streamObjects, reason) {
|
2868
|
+
debug("TB.streamCreated");
|
2869
|
+
try {
|
2870
|
+
var session = this.sessions[sessionId];
|
2871
|
+
|
2872
|
+
var streams = getStreams(streamObjects, sessionId);
|
2873
|
+
session.dispatchEvent(new StreamEvent(this.STREAM_CREATED, streams, reason));
|
2874
|
+
|
2875
|
+
//notify publisher if there's an archive in flight
|
2876
|
+
var myArchives = createdArchives[sessionId];
|
2877
|
+
for (var bob in myArchives) {
|
2878
|
+
for (var i=0; i<streams.length; i++) {
|
2879
|
+
if (streams[i].connection.connectionId == connection.connectionId) {
|
2880
|
+
for (var pub in session.publishers) {
|
2881
|
+
if (session.publishers[pub].hasOwnProperty("id")) {
|
2882
|
+
var publisher = document.getElementById(session.publishers[pub].id);
|
2883
|
+
if (bob && myArchives[bob] && myArchives[bob].type == TB.PER_SESSION && myArchives[bob].recording == true) {
|
2884
|
+
publisher.signalRecordingStarted();
|
2885
|
+
}
|
2886
|
+
}
|
2887
|
+
}
|
2888
|
+
}
|
2889
|
+
}
|
2890
|
+
}
|
2891
|
+
|
2892
|
+
} catch(err) {
|
2893
|
+
var errorMsg = "TB.streamCreated :: "+err;
|
2894
|
+
error(errorMsg);
|
2895
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
2896
|
+
}
|
2897
|
+
},
|
2898
|
+
|
2899
|
+
streamDestroyedHandler: function(sessionId, streamObjects, reason) {
|
2900
|
+
debug("TB.streamDestroyed");
|
2901
|
+
try {
|
2902
|
+
var session = this.sessions[sessionId];
|
2903
|
+
var streams = getStreams(streamObjects, sessionId);
|
2904
|
+
var event = new StreamEvent(this.STREAM_DESTROYED, streams, reason, true);
|
2905
|
+
session.dispatchEvent(event);
|
2906
|
+
|
2907
|
+
var defaultAction = function() {
|
2908
|
+
if (!event.isDefaultPrevented()) {
|
2909
|
+
for (var i = 0; i < event.streams.length; i++) {
|
2910
|
+
var subscribers = session.getSubscribersForStream(event.streams[i]);
|
2911
|
+
for (var j = 0; j < subscribers.length; j++) {
|
2912
|
+
session.unsubscribe(subscribers[j]);
|
2913
|
+
}
|
2914
|
+
var publisher = session.getPublisherForStream(event.streams[i]);
|
2915
|
+
if (publisher) {
|
2916
|
+
session.unpublish(publisher);
|
2917
|
+
}
|
2918
|
+
}
|
2919
|
+
}
|
2920
|
+
};
|
2921
|
+
|
2922
|
+
// The event handler is called asynchronously after 1 millisecond. The default action happens after that.
|
2923
|
+
setTimeout(defaultAction, 2);
|
2924
|
+
} catch(err) {
|
2925
|
+
var errorMsg = "TB.streamDestroyed :: " + err;
|
2926
|
+
error(errorMsg);
|
2927
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
2928
|
+
}
|
2929
|
+
},
|
2930
|
+
|
2931
|
+
streamPropertyChangedHandler: function(sessionId, streamObj, changedProperty, oldValue, newValue) {
|
2932
|
+
debug("TB.streamPropertyChangedHandler");
|
2933
|
+
|
2934
|
+
var session = this.sessions[sessionId];
|
2935
|
+
var stream = getStream(streamObj, sessionId);
|
2936
|
+
|
2937
|
+
var event = new StreamPropertyChangedEvent(this.STREAM_PROPERTY_CHANGED, stream, changedProperty, oldValue, newValue);
|
2938
|
+
|
2939
|
+
session.dispatchEvent(event);
|
2940
|
+
|
2941
|
+
try {
|
2942
|
+
var subscriber;
|
2943
|
+
if ("hasAudio" == changedProperty) {
|
2944
|
+
for (var componentId in session.subscribers) {
|
2945
|
+
subscriber = session.subscribers[componentId];
|
2946
|
+
if (subscriber.hasOwnProperty("stream") && subscriber.stream.streamId == stream.streamId) {
|
2947
|
+
subscriber._subscribeToAudio(newValue, true);
|
2948
|
+
break;
|
2949
|
+
}
|
2950
|
+
}
|
2951
|
+
} else if ("hasVideo" == changedProperty) {
|
2952
|
+
for (componentId in session.subscribers) {
|
2953
|
+
subscriber = session.subscribers[componentId];
|
2954
|
+
if (subscriber.hasOwnProperty("stream") && subscriber.stream.streamId == stream.streamId) {
|
2955
|
+
subscriber._subscribeToVideo(newValue, true);
|
2956
|
+
break;
|
2957
|
+
}
|
2958
|
+
}
|
2959
|
+
} else if ("orientation" == changedProperty) {
|
2960
|
+
for (componentId in session.subscribers) {
|
2961
|
+
subscriber = session.subscribers[componentId];
|
2962
|
+
if (subscriber.hasOwnProperty("stream") && subscriber.stream.streamId == stream.streamId) {
|
2963
|
+
subscriber.changeOrientation(newValue);
|
2964
|
+
break;
|
2965
|
+
}
|
2966
|
+
}
|
2967
|
+
} else if ("quality" == changedProperty) {
|
2968
|
+
//do nothing.
|
2969
|
+
} else {
|
2970
|
+
debug("Unknown property changed");
|
2971
|
+
}
|
2972
|
+
} catch(err) {
|
2973
|
+
var errorMsg = "TB.streamPropertyChangedHandler :: " + err;
|
2974
|
+
error(errorMsg);
|
2975
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
2976
|
+
}
|
2977
|
+
},
|
2978
|
+
|
2979
|
+
microphoneLevelChangedHandler: function(sessionId, componentId, streamId, volume){
|
2980
|
+
//debug("TB.microphoneLevelChangedHandler: " + streamId);
|
2981
|
+
try {
|
2982
|
+
var session = this.sessions[sessionId];
|
2983
|
+
|
2984
|
+
if (!session) {
|
2985
|
+
var errorMsg = "TB.microphoneLevelChangedHandler :: Invalid session ID: " + sessionId;
|
2986
|
+
error(errorMsg);
|
2987
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
2988
|
+
return;
|
2989
|
+
}
|
2990
|
+
|
2991
|
+
var subscriber = session.subscribers[componentId];
|
2992
|
+
|
2993
|
+
var event = new VolumeEvent(this.MICROPHONE_LEVEL_CHANGED, streamId, volume);
|
2994
|
+
session.dispatchEvent(event);
|
2995
|
+
} catch (err) {
|
2996
|
+
errorMsg = "microphoneLevelChanged :: " + err;
|
2997
|
+
error(errorMsg);
|
2998
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
2999
|
+
}
|
3000
|
+
},
|
3001
|
+
|
3002
|
+
connectionCreatedHandler: function(sessionId, connectionObjects, reason) {
|
3003
|
+
debug("TB.connectionCreated");
|
3004
|
+
try {
|
3005
|
+
var session = this.sessions[sessionId];
|
3006
|
+
|
3007
|
+
var connections = getConnections(connectionObjects);
|
3008
|
+
session.dispatchEvent(new ConnectionEvent(this.CONNECTION_CREATED, connections, reason));
|
3009
|
+
} catch(err) {
|
3010
|
+
var errorMsg = "TB.connectionCreated :: "+err;
|
3011
|
+
error(errorMsg);
|
3012
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3013
|
+
}
|
3014
|
+
},
|
3015
|
+
|
3016
|
+
connectionDestroyedHandler: function(sessionId, connectionObjects, reason) {
|
3017
|
+
debug("TB.connectionDestroyed");
|
3018
|
+
try {
|
3019
|
+
var session = this.sessions[sessionId];
|
3020
|
+
|
3021
|
+
var connections = getConnections(connectionObjects);
|
3022
|
+
|
3023
|
+
session.dispatchEvent(new ConnectionEvent(this.CONNECTION_DESTROYED, connections, reason));
|
3024
|
+
} catch(err) {
|
3025
|
+
var errorMsg = "TB.connectionDestroyed :: "+err;
|
3026
|
+
error(errorMsg);
|
3027
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3028
|
+
}
|
3029
|
+
},
|
3030
|
+
|
3031
|
+
signalHandler: function(sessionId, fromId) {
|
3032
|
+
debug("TB.signal");
|
3033
|
+
try {
|
3034
|
+
var session = this.sessions[sessionId];
|
3035
|
+
|
3036
|
+
session.dispatchEvent(new SignalEvent(this.SIGNAL_RECEIVED, getConnectionFromConnectionId(fromId)));
|
3037
|
+
} catch(err) {
|
3038
|
+
var errorMsg = "TB.signal ::"+err;
|
3039
|
+
error(errorMsg);
|
3040
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3041
|
+
}
|
3042
|
+
},
|
3043
|
+
|
3044
|
+
archiveCreatedHandler: function(sessionId, archive) {
|
3045
|
+
debug("TB.archiveCreatedHandler:" + sessionId + " - " + archive);
|
3046
|
+
try {
|
3047
|
+
var session = this.sessions[sessionId];
|
3048
|
+
var newArchive = getArchive(archive, sessionId);
|
3049
|
+
session.dispatchEvent(new ArchiveEvent(this.ARCHIVE_CREATED, [newArchive]));
|
3050
|
+
} catch(err) {
|
3051
|
+
var errorMsg = "TB.archiveCreatedHandler :: " + err;
|
3052
|
+
error(errorMsg);
|
3053
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3054
|
+
}
|
3055
|
+
},
|
3056
|
+
|
3057
|
+
archiveClosedHandler: function(sessionId, archive) {
|
3058
|
+
debug("TB.archiveClosedHandler:" + sessionId + " - " + archive.id);
|
3059
|
+
try {
|
3060
|
+
var session = this.sessions[sessionId];
|
3061
|
+
session.dispatchEvent(new ArchiveEvent(this.ARCHIVE_CLOSED, [createdArchives[sessionId][archive.id]]));
|
3062
|
+
delete createdArchives[sessionId][archive.id];
|
3063
|
+
} catch(err) {
|
3064
|
+
var errorMsg = "TB.archiveClosedHandler :: " + err;
|
3065
|
+
error(errorMsg);
|
3066
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3067
|
+
}
|
3068
|
+
},
|
3069
|
+
|
3070
|
+
archiveLoadedHandler: function(sessionId, archive) {
|
3071
|
+
debug("TB.archiveLoadedHandler:" + sessionId + " - " + archive.archiveId);
|
3072
|
+
try {
|
3073
|
+
var session = this.sessions[sessionId];
|
3074
|
+
var newArchive = new Archive(archive.id, archive.type, archive.title, sessionId);
|
3075
|
+
if (!loadedArchives.hasOwnProperty(sessionId)) loadedArchives[sessionId] = {};
|
3076
|
+
loadedArchives[sessionId][archive.id] = newArchive;
|
3077
|
+
session.dispatchEvent(new ArchiveEvent(this.ARCHIVE_LOADED, [newArchive]));
|
3078
|
+
} catch(err) {
|
3079
|
+
var errorMsg = "TB.archiveLoadedHandler :: " + err;
|
3080
|
+
error(errorMsg);
|
3081
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3082
|
+
}
|
3083
|
+
},
|
3084
|
+
|
3085
|
+
sessionRecordingStartedHandler: function(sessionId, archive) {
|
3086
|
+
debug("TB.sessionRecordingStartedHandler:" + sessionId + " - " + archive.id);
|
3087
|
+
try {
|
3088
|
+
var session = this.sessions[sessionId];
|
3089
|
+
session.dispatchEvent(new ArchiveEvent(this.SESSION_RECORDING_STARTED, [createdArchives[archive.id]]));
|
3090
|
+
} catch(err) {
|
3091
|
+
var errorMsg = "TB.sessionRecordingStartedHandler :: " + err;
|
3092
|
+
error(errorMsg);
|
3093
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3094
|
+
}
|
3095
|
+
},
|
3096
|
+
|
3097
|
+
sessionRecordingStoppedHandler: function(sessionId, archive) {
|
3098
|
+
debug("TB.sessionRecordingStoppedHandler:" + sessionId + " - " + archive);
|
3099
|
+
try {
|
3100
|
+
var session = this.sessions[sessionId];
|
3101
|
+
session.dispatchEvent(new ArchiveEvent(this.SESSION_RECORDING_STOPPED, [createdArchives[archive.id]]));
|
3102
|
+
|
3103
|
+
for (var pub in session.publishers) {
|
3104
|
+
if (session.publishers[pub].hasOwnProperty("id")) {
|
3105
|
+
var publisher = document.getElementById(session.publishers[pub].id);
|
3106
|
+
publisher.signalRecordingStopped();
|
3107
|
+
}
|
3108
|
+
};
|
3109
|
+
} catch(err) {
|
3110
|
+
var errorMsg = "TB.sessionRecordingStoppedHandler :: " + err;
|
3111
|
+
error(errorMsg);
|
3112
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3113
|
+
}
|
3114
|
+
},
|
3115
|
+
|
3116
|
+
sessionRecordingInProgressHandler: function(sessionId) {
|
3117
|
+
debug("TB.sessionRecordingInProgressHandler");
|
3118
|
+
try {
|
3119
|
+
var session = this.sessions[sessionId];
|
3120
|
+
session.dispatchEvent(new Event(this.SESSION_RECORDING_IN_PROGRESS, false));
|
3121
|
+
} catch(err) {
|
3122
|
+
var errorMsg = "TB.sessionRecordingStartedHandler :: " + err;
|
3123
|
+
error(errorMsg);
|
3124
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3125
|
+
}
|
3126
|
+
},
|
3127
|
+
|
3128
|
+
sessionNotRecordingHandler: function(sessionId) {
|
3129
|
+
debug("TB.sessionNotRecordingHandler");
|
3130
|
+
try {
|
3131
|
+
var session = this.sessions[sessionId];
|
3132
|
+
session.dispatchEvent(new Event(this.SESSION_NOT_RECORDING, false));
|
3133
|
+
} catch(err) {
|
3134
|
+
var errorMsg = "TB.sessionNotRecordingHandler :: " + err;
|
3135
|
+
error(errorMsg);
|
3136
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3137
|
+
}
|
3138
|
+
},
|
3139
|
+
|
3140
|
+
streamRecordingStartedHandler: function(sessionId, streamObjects) {
|
3141
|
+
debug("TB.streamRecordingStartedHandler:" + sessionId);
|
3142
|
+
try {
|
3143
|
+
var session = this.sessions[sessionId];
|
3144
|
+
var streams = getStreams(streamObjects, sessionId);
|
3145
|
+
session.dispatchEvent(new StreamEvent(this.STREAM_RECORDING_STARTED, streams, "", false));
|
3146
|
+
|
3147
|
+
for (var pub in session.publishers) {
|
3148
|
+
if (session.publishers[pub].hasOwnProperty("id")) {
|
3149
|
+
var publisher = document.getElementById(session.publishers[pub].id);
|
3150
|
+
for (var i=0; i < streamObjects.length; i++) {
|
3151
|
+
if (publisher.getStreamId() == streamObjects[i].streamId) {
|
3152
|
+
publisher.signalRecordingStarted();
|
3153
|
+
debug("TB.streamRecordingStartedHandler: signal: " + streamObjects[i].streamId);
|
3154
|
+
break;
|
3155
|
+
}
|
3156
|
+
};
|
3157
|
+
}
|
3158
|
+
};
|
3159
|
+
} catch(err) {
|
3160
|
+
var errorMsg = "TB.streamRecordingStartedHandler :: " + err;
|
3161
|
+
error(errorMsg);
|
3162
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3163
|
+
}
|
3164
|
+
},
|
3165
|
+
|
3166
|
+
streamRecordingStoppedHandler: function(sessionId, streamObjects) {
|
3167
|
+
debug("TB.streamRecordingStoppedHandler");
|
3168
|
+
try {
|
3169
|
+
var session = this.sessions[sessionId];
|
3170
|
+
var streams = getStreams(streamObjects, sessionId);
|
3171
|
+
session.dispatchEvent(new StreamEvent(this.STREAM_RECORDING_STOPPED, streams, "", false));
|
3172
|
+
|
3173
|
+
for (var pub in session.publishers) {
|
3174
|
+
if (session.publishers[pub].hasOwnProperty("id")) {
|
3175
|
+
var publisher = document.getElementById(session.publishers[pub].id);
|
3176
|
+
|
3177
|
+
for (var i=0; i < streamObjects.length; i++) {
|
3178
|
+
if (publisher.getStreamId() == streamObjects[i].streamId) {
|
3179
|
+
publisher.signalRecordingStopped();
|
3180
|
+
debug("TB.streamRecordingStoppedHandler: signal: " + streamObjects[i].streamId);
|
3181
|
+
break;
|
3182
|
+
}
|
3183
|
+
}
|
3184
|
+
}
|
3185
|
+
};
|
3186
|
+
} catch(err) {
|
3187
|
+
var errorMsg = "TB.streamRecordingStoppedHandler :: " + err;
|
3188
|
+
error(errorMsg);
|
3189
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3190
|
+
}
|
3191
|
+
},
|
3192
|
+
|
3193
|
+
streamRecordingInProgressHandler: function(sessionId, streamObjects) {
|
3194
|
+
debug("TB.streamRecordingInProgressHandler");
|
3195
|
+
try {
|
3196
|
+
var session = this.sessions[sessionId];
|
3197
|
+
var streams = getStreams(streamObjects, sessionId);
|
3198
|
+
session.dispatchEvent(new StreamEvent(this.STREAM_RECORDING_IN_PROGRESS, streams, "", false));
|
3199
|
+
} catch(err) {
|
3200
|
+
var errorMsg = "TB.streamRecordingInProgressHandler :: " + err;
|
3201
|
+
error(errorMsg);
|
3202
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3203
|
+
}
|
3204
|
+
},
|
3205
|
+
|
3206
|
+
playbackStartedHandler: function(sessionId, archive) {
|
3207
|
+
debug("TB.playbackStartedHandler");
|
3208
|
+
try {
|
3209
|
+
var session = this.sessions[sessionId];
|
3210
|
+
archiveObj = new Archive(archive.id, archive.type, archive.title, sessionId);
|
3211
|
+
session.dispatchEvent(new ArchiveEvent(this.PLAYBACK_STARTED, [archiveObj]));
|
3212
|
+
} catch(err) {
|
3213
|
+
var errorMsg = "TB.playbackStartedHandler :: " + err;
|
3214
|
+
error(errorMsg);
|
3215
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3216
|
+
}
|
3217
|
+
},
|
3218
|
+
|
3219
|
+
playbackStoppedHandler: function(sessionId, archive) {
|
3220
|
+
debug("TB.playbackStoppedHandler");
|
3221
|
+
try {
|
3222
|
+
var session = this.sessions[sessionId];
|
3223
|
+
archiveObj = new Archive(archive.id, archive.type, archive.title, sessionId);
|
3224
|
+
session.dispatchEvent(new ArchiveEvent(this.PLAYBACK_STOPPED, [archiveObj]));
|
3225
|
+
} catch(err) {
|
3226
|
+
var errorMsg = "TB.playbackStoppedHandler :: " + err;
|
3227
|
+
error(errorMsg);
|
3228
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3229
|
+
}
|
3230
|
+
},
|
3231
|
+
|
3232
|
+
// Group callbacks
|
3233
|
+
groupPropertiesUpdatedHandler: function(sessionId, groupObject) {
|
3234
|
+
debug("TB.groupPropertiesUpdated");
|
3235
|
+
try {
|
3236
|
+
var group = this.groups[sessionId + "_" + groupObject.groupId];
|
3237
|
+
if(!group) {
|
3238
|
+
error("TB.groupPropertiesUpdated :: Invalid group ID: " + sessionId + "_" + groupObject.groupId);
|
3239
|
+
return;
|
3240
|
+
}
|
3241
|
+
|
3242
|
+
group.dispatchEvent(new Event(this.GROUP_PROPERTIES_UPDATED));
|
3243
|
+
} catch(err) {
|
3244
|
+
var errorMsg ="TB.groupPropertiesUpdated :: " + err;
|
3245
|
+
error(errorMsg);
|
3246
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3247
|
+
}
|
3248
|
+
},
|
3249
|
+
|
3250
|
+
// Publisher or Subscriber callbacks
|
3251
|
+
|
3252
|
+
//publisher callbacks:
|
3253
|
+
|
3254
|
+
videoComponentLoadedHandler: function(sessionId, componentId) {
|
3255
|
+
try {
|
3256
|
+
if (sessionId) {
|
3257
|
+
var session = this.sessions[sessionId];
|
3258
|
+
if(!session) return;
|
3259
|
+
|
3260
|
+
var publisher = session.publishers[componentId];
|
3261
|
+
var subscriber = session.subscribers[componentId];
|
3262
|
+
|
3263
|
+
if (publisher && !publisher.loaded) {
|
3264
|
+
publisher.loaded = true;
|
3265
|
+
if (publisher.modified) {
|
3266
|
+
if (publisher.audioPublished != null) publisher.publishAudio(publisher.audioPublished);
|
3267
|
+
if (publisher.videoPublished != null) publisher.publishVideo(publisher.videoPublished);
|
3268
|
+
publisher.setMicrophoneGain(publisher.gain);
|
3269
|
+
publisher.setStyle(publisher._style);
|
3270
|
+
publisher.modified = false;
|
3271
|
+
}
|
3272
|
+
publisher.dispatchEvent(new Event("loaded"));
|
3273
|
+
}
|
3274
|
+
|
3275
|
+
if (subscriber && !subscriber.loaded) {
|
3276
|
+
subscriber.loaded = true;
|
3277
|
+
if (subscriber.modified) {
|
3278
|
+
if (subscriber.audioSubscribed != null) subscriber.subscribeToAudio(subscriber.audioSubscribed);
|
3279
|
+
if (subscriber.videoSubscribed != null) subscriber.subscribeToVideo(subscriber.videoSubscribed);
|
3280
|
+
subscriber.setAudioVolume(subscriber.audioVolume);
|
3281
|
+
subscriber.setStyle(subscriber._style);
|
3282
|
+
subscriber.modified = false;
|
3283
|
+
}
|
3284
|
+
subscriber.dispatchEvent(new Event("loaded"));
|
3285
|
+
}
|
3286
|
+
} else {
|
3287
|
+
var player = recorderManager.players[componentId];
|
3288
|
+
if (player && player._archiveId) {
|
3289
|
+
player.loadArchive(player._archiveId);
|
3290
|
+
player._archiveId = null;
|
3291
|
+
}
|
3292
|
+
|
3293
|
+
if (player && player._play) {
|
3294
|
+
player.play();
|
3295
|
+
player._play = false;
|
3296
|
+
}
|
3297
|
+
|
3298
|
+
var recorder = recorderManager.recorders[componentId];
|
3299
|
+
var component = player ? player : recorder;
|
3300
|
+
if (component && !component.loaded) {
|
3301
|
+
component.loaded = true;
|
3302
|
+
if (component.modified) {
|
3303
|
+
component.setStyle(component._style);
|
3304
|
+
if (component == recorder && component._title) {
|
3305
|
+
component.setTitle(_title);
|
3306
|
+
_title = "";
|
3307
|
+
}
|
3308
|
+
component.modified = false;
|
3309
|
+
}
|
3310
|
+
component.dispatchEvent(new Event("loaded"));
|
3311
|
+
}
|
3312
|
+
|
3313
|
+
}
|
3314
|
+
} catch (err) {
|
3315
|
+
var errorMsg = "videoComponentLoaded:: initialize component " + componentId + " - " + err;
|
3316
|
+
error(errorMsg);
|
3317
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3318
|
+
}
|
3319
|
+
},
|
3320
|
+
|
3321
|
+
// Used in resizing the publisher
|
3322
|
+
pubWidgetStyleHeightFrom: null,
|
3323
|
+
pubWidgetStyleWidthFrom: null,
|
3324
|
+
|
3325
|
+
// Publisher callbacks
|
3326
|
+
resizePublisherToTarget: function(sessionId, publisherId) {
|
3327
|
+
debug("TB.resize");
|
3328
|
+
try {
|
3329
|
+
var session = this.sessions[sessionId];
|
3330
|
+
if (!session) {
|
3331
|
+
var errorMsg = "TB.resize :: Invalid session ID: " + sessionId;
|
3332
|
+
error(errorMsg);
|
3333
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3334
|
+
return;
|
3335
|
+
}
|
3336
|
+
|
3337
|
+
var publisher = session.publishers[publisherId];
|
3338
|
+
if (!publisher) {
|
3339
|
+
errorMsg = "TB.resize :: Invalid publisher ID: " + publisherId;
|
3340
|
+
error(errorMsg);
|
3341
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3342
|
+
return;
|
3343
|
+
}
|
3344
|
+
|
3345
|
+
var pubWidget = document.getElementById(publisherId);
|
3346
|
+
if (!pubWidget) {
|
3347
|
+
errorMsg = "TB.resize :: Publisher " + publisherId + " does not exist in the DOM";
|
3348
|
+
error(errorMsg);
|
3349
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3350
|
+
return;
|
3351
|
+
}
|
3352
|
+
|
3353
|
+
var widthFrom = pubWidget.width;
|
3354
|
+
var heightFrom = pubWidget.height;
|
3355
|
+
|
3356
|
+
if (pubWidget.width != publisher.properties.width) {
|
3357
|
+
pubWidget.width = publisher.properties.width;
|
3358
|
+
}
|
3359
|
+
|
3360
|
+
if (pubWidget.height != publisher.properties.height) {
|
3361
|
+
pubWidget.height = publisher.properties.height;
|
3362
|
+
}
|
3363
|
+
if (pubWidget.style.height != pubWidgetStyleHeightFrom) {
|
3364
|
+
pubWidget.style.height = pubWidgetStyleHeightFrom;
|
3365
|
+
}
|
3366
|
+
|
3367
|
+
if (pubWidget.style.width != pubWidgetStyleWidthFrom) {
|
3368
|
+
pubWidget.style.width = pubWidgetStyleWidthFrom;
|
3369
|
+
}
|
3370
|
+
|
3371
|
+
var widthTo = pubWidget.width;
|
3372
|
+
var heightTo = pubWidget.height;
|
3373
|
+
|
3374
|
+
if (widthFrom != widthTo || heightFrom != heightTo) {
|
3375
|
+
// Only dispatch the resize event if we did resize
|
3376
|
+
publisher.dispatchEvent(new ResizeEvent(this.RESIZE, widthFrom, widthTo, heightFrom, heightTo));
|
3377
|
+
}
|
3378
|
+
} catch(err) {
|
3379
|
+
errorMsg = "resizePublisherToTarget :: Error resizing publisher - " + err;
|
3380
|
+
error(errorMsg);
|
3381
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3382
|
+
}
|
3383
|
+
},
|
3384
|
+
|
3385
|
+
|
3386
|
+
resizePublisherToShowSecurity: function(sessionId, publisherId, scaleFactor){
|
3387
|
+
debug("TB.resize");
|
3388
|
+
var session = this.sessions[sessionId];
|
3389
|
+
if (!session) {
|
3390
|
+
var errorMsg = "TB.resize :: Invalid session ID: " + sessionId;
|
3391
|
+
error(errorMsg);
|
3392
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3393
|
+
return;
|
3394
|
+
}
|
3395
|
+
|
3396
|
+
var publisher = session.publishers[publisherId];
|
3397
|
+
if (!publisher) {
|
3398
|
+
errorMsg = "TB.resize :: Invalid publisher ID: " + publisherId;
|
3399
|
+
error(errorMsg);
|
3400
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3401
|
+
return;
|
3402
|
+
}
|
3403
|
+
|
3404
|
+
var pubWidget = document.getElementById(publisherId);
|
3405
|
+
if (!pubWidget) {
|
3406
|
+
errorMsg = "TB.resize :: Publisher " + publisherId + " does not exist in the DOM";
|
3407
|
+
error(errorMsg);
|
3408
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3409
|
+
return;
|
3410
|
+
}
|
3411
|
+
|
3412
|
+
var widthFrom = publisher.properties.width = pubWidget.width;
|
3413
|
+
var heightFrom = publisher.properties.height = pubWidget.height;
|
3414
|
+
|
3415
|
+
pubWidgetStyleHeightFrom = pubWidget.style.height;
|
3416
|
+
pubWidgetStyleWidthFrom = pubWidget.style.width;
|
3417
|
+
|
3418
|
+
// The scaleFactor takes browser zoom into account
|
3419
|
+
var minWidth = MIN_ADOBE_WIDTH * scaleFactor;
|
3420
|
+
var minHeight = MIN_ADOBE_HEIGHT * scaleFactor;
|
3421
|
+
|
3422
|
+
if (pubWidget.width < minWidth) {
|
3423
|
+
pubWidget.width = minWidth;
|
3424
|
+
pubWidget.style.width = minWidth + "px";
|
3425
|
+
}
|
3426
|
+
if (pubWidget.height < minHeight) {
|
3427
|
+
pubWidget.height = minHeight;
|
3428
|
+
pubWidget.style.height = minHeight + "px";
|
3429
|
+
}
|
3430
|
+
|
3431
|
+
var widthTo = pubWidget.width;
|
3432
|
+
var heightTo = pubWidget.height;
|
3433
|
+
var styleTo = pubWidget.style;
|
3434
|
+
|
3435
|
+
if (widthFrom != widthTo || heightFrom != heightTo || pubWidgetStyleWidthFrom != styleTo.width || pubWidgetStyleHeightFrom != styleTo.height) {
|
3436
|
+
// Only dispatch the resize event if we did resize
|
3437
|
+
publisher.dispatchEvent(new ResizeEvent(this.RESIZE, widthFrom, widthTo, heightFrom, heightTo));
|
3438
|
+
}
|
3439
|
+
|
3440
|
+
},
|
3441
|
+
|
3442
|
+
settingsButtonClickHandler: function(sessionId, publisherId) {
|
3443
|
+
debug("TB.settingsButtonClick");
|
3444
|
+
try {
|
3445
|
+
var session = this.sessions[sessionId];
|
3446
|
+
if(!session) {
|
3447
|
+
var errorMsg = "TB.settingsButtonClick :: Invalid session ID: "+sessionId;
|
3448
|
+
error(errorMsg);
|
3449
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3450
|
+
return;
|
3451
|
+
}
|
3452
|
+
|
3453
|
+
var publisher = session.publishers[publisherId];
|
3454
|
+
if(!publisher) {
|
3455
|
+
errorMsg = "TB.settingsButtonClick :: Invalid publisher ID: "+publisherId;
|
3456
|
+
error(errorMsg);
|
3457
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3458
|
+
return;
|
3459
|
+
}
|
3460
|
+
|
3461
|
+
var event = new Event(this.SETTINGS_BUTTON_CLICK, true);
|
3462
|
+
publisher.dispatchEvent(event);
|
3463
|
+
|
3464
|
+
var defaultAction = function() {
|
3465
|
+
if (!event.isDefaultPrevented()) {
|
3466
|
+
var dm = TB.initDeviceManager(session.apiKey);
|
3467
|
+
dm.displayPanel(null, publisher, {});
|
3468
|
+
}
|
3469
|
+
};
|
3470
|
+
|
3471
|
+
// The event handler is called asynchronously after 1 millisecond. The default action happens after that.
|
3472
|
+
setTimeout(defaultAction, 2);
|
3473
|
+
} catch(err){
|
3474
|
+
errorMsg = "settingsButtonClick :: " + err;
|
3475
|
+
error(errorMsg);
|
3476
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3477
|
+
}
|
3478
|
+
},
|
3479
|
+
|
3480
|
+
|
3481
|
+
|
3482
|
+
recorderSettingsButtonClickHandler: function(recorderId) {
|
3483
|
+
debug("TB.recorderSettingsButtonClick");
|
3484
|
+
try {
|
3485
|
+
var recorder = recorderManager.recorders[recorderId];
|
3486
|
+
if(!recorder) {
|
3487
|
+
errorMsg = "TB.recorderSettingsButtonClick :: Invalid recorder ID: "+recorderId;
|
3488
|
+
error(errorMsg);
|
3489
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3490
|
+
return;
|
3491
|
+
}
|
3492
|
+
|
3493
|
+
var event = new Event(this.SETTINGS_BUTTON_CLICK, true);
|
3494
|
+
recorder.dispatchEvent(event);
|
3495
|
+
|
3496
|
+
var defaultAction = function() {
|
3497
|
+
if (!event.isDefaultPrevented()) {
|
3498
|
+
var dm = TB.initDeviceManager(recorderManager.apiKey);
|
3499
|
+
dm.displayPanel(null, recorder, {});
|
3500
|
+
}
|
3501
|
+
};
|
3502
|
+
|
3503
|
+
// The event handler is called asynchronously after 1 millisecond. The default action happens after that.
|
3504
|
+
setTimeout(defaultAction, 2);
|
3505
|
+
} catch(err){
|
3506
|
+
errorMsg = "recorderSettingsButtonClick :: " + err;
|
3507
|
+
error(errorMsg);
|
3508
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3509
|
+
}
|
3510
|
+
},
|
3511
|
+
|
3512
|
+
deviceAccessHandler: function(sessionId, publisherId, type) {
|
3513
|
+
debug("TB.deviceAccessHandler: " + type);
|
3514
|
+
try {
|
3515
|
+
var session = this.sessions[sessionId];
|
3516
|
+
if (!session) {
|
3517
|
+
var errorMsg = "TB.deviceAccessHandler :: Invalid session ID: " + sessionId;
|
3518
|
+
error(errorMsg);
|
3519
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3520
|
+
return;
|
3521
|
+
}
|
3522
|
+
|
3523
|
+
var publisher = session.publishers[publisherId];
|
3524
|
+
if (!publisher) {
|
3525
|
+
errorMsg = "TB.deviceAccessHandler :: Invalid publisher ID: " + publisherId;
|
3526
|
+
error(errorMsg);
|
3527
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3528
|
+
return;
|
3529
|
+
}
|
3530
|
+
|
3531
|
+
var event = new Event(type, true);
|
3532
|
+
publisher.dispatchEvent(event);
|
3533
|
+
|
3534
|
+
if (type == TB.ACCESS_DENIED) {
|
3535
|
+
var defaultAction = function() {
|
3536
|
+
var publisherElement = document.getElementById(publisher.id);
|
3537
|
+
if (publisherElement) {
|
3538
|
+
var parentNode = publisherElement.parentNode;
|
3539
|
+
session.unpublish(publisher);
|
3540
|
+
|
3541
|
+
var replaceElement = document.createElement("div");
|
3542
|
+
replaceElement.setAttribute("id", publisher.replacedDivId);
|
3543
|
+
parentNode.appendChild(replaceElement);
|
3544
|
+
|
3545
|
+
session._embedPublisher(publisher);
|
3546
|
+
}
|
3547
|
+
};
|
3548
|
+
|
3549
|
+
// The event handler is called asynchronously after 1 millisecond. The default action happens after that.
|
3550
|
+
setTimeout(defaultAction, 2);
|
3551
|
+
}
|
3552
|
+
} catch(err) {
|
3553
|
+
errorMsg = type + " :: " + err;
|
3554
|
+
error(errorMsg);
|
3555
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3556
|
+
}
|
3557
|
+
},
|
3558
|
+
|
3559
|
+
deviceInactiveHandler: function(sessionId, publisherId, camera, microphone){
|
3560
|
+
debug("TB.deviceInactiveHandler");
|
3561
|
+
|
3562
|
+
try {
|
3563
|
+
var session = this.sessions[sessionId];
|
3564
|
+
|
3565
|
+
if (!session) {
|
3566
|
+
var errorMsg = "TB.deviceInactiveHandler :: Invalid session ID: " + sessionId;
|
3567
|
+
error(errorMsg);
|
3568
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3569
|
+
return;
|
3570
|
+
}
|
3571
|
+
|
3572
|
+
var publisher = session.publishers[publisherId];
|
3573
|
+
|
3574
|
+
if (!publisher) {
|
3575
|
+
error("TB.deviceInactiveHandler :: Invalid publisher ID: " + publisherId);
|
3576
|
+
return;
|
3577
|
+
}
|
3578
|
+
|
3579
|
+
var event = new DeviceEvent(this.DEVICE_INACTIVE, camera, microphone);
|
3580
|
+
publisher.dispatchEvent(event);
|
3581
|
+
} catch (err) {
|
3582
|
+
errorMsg = "deviceInactive :: " + err;
|
3583
|
+
error(errorMsg);
|
3584
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3585
|
+
}
|
3586
|
+
},
|
3587
|
+
|
3588
|
+
echoCancellationModeChangedHandler: function(sessionId, publisherId, camera, microphone){
|
3589
|
+
debug("TB.echoCancellationModeChangedHandler");
|
3590
|
+
|
3591
|
+
try {
|
3592
|
+
var session = this.sessions[sessionId];
|
3593
|
+
|
3594
|
+
if (!session) {
|
3595
|
+
var errorMsg = "TB.echoCancellationModeChangedHandler :: Invalid session ID: " + sessionId;
|
3596
|
+
error(errorMsg);
|
3597
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3598
|
+
return;
|
3599
|
+
}
|
3600
|
+
|
3601
|
+
var publisher = session.publishers[publisherId];
|
3602
|
+
|
3603
|
+
if (!publisher) {
|
3604
|
+
error("TB.echoCancellationModeChangedHandler :: Invalid publisher ID: " + publisherId);
|
3605
|
+
return;
|
3606
|
+
}
|
3607
|
+
|
3608
|
+
var event = new DeviceEvent(this.ECHO_CANCELLATION_MODE_CHANGED, camera, microphone);
|
3609
|
+
publisher.dispatchEvent(event);
|
3610
|
+
} catch (err) {
|
3611
|
+
errorMsg = "echoCancellationModeChanged :: " + err;
|
3612
|
+
error(errorMsg);
|
3613
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3614
|
+
}
|
3615
|
+
},
|
3616
|
+
|
3617
|
+
// DeviceManager callbacks
|
3618
|
+
devicesDetectedHandler: function(cameraObjects, microphoneObjects, selectedCameraIndex, selectedMicrophoneIndex) {
|
3619
|
+
debug("TB.devicesDetected");
|
3620
|
+
try {
|
3621
|
+
var cameras = getCameras(cameraObjects);
|
3622
|
+
var microphones = getMicrophones(microphoneObjects);
|
3623
|
+
|
3624
|
+
deviceManager.dispatchEvent(new DeviceStatusEvent(this.DEVICES_DETECTED, cameras, microphones, cameras[selectedCameraIndex], microphones[selectedMicrophoneIndex]));
|
3625
|
+
setTimeout(function() { removeSWF(deviceDetectorId, "devicesDetectedHandler :: "); deviceDetectorId = null; }, 0); // must be asynchronous
|
3626
|
+
} catch(err) {
|
3627
|
+
var errorMsg = "devicesDetectedHandler :: " + err;
|
3628
|
+
error(errorMsg);
|
3629
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3630
|
+
}
|
3631
|
+
},
|
3632
|
+
|
3633
|
+
// DevicePanel callbacks
|
3634
|
+
devicesSelectedHandler: function(devicePanelId, camera, microphone) {
|
3635
|
+
debug("TB.devicesSelected");
|
3636
|
+
try {
|
3637
|
+
cameraSelected = true;
|
3638
|
+
var devicePanel = deviceManager.panels[devicePanelId];
|
3639
|
+
if(!devicePanel) {
|
3640
|
+
error("TB.devicesSelected :: Invalid DevicePanel ID: "+devicePanelId);
|
3641
|
+
return;
|
3642
|
+
}
|
3643
|
+
|
3644
|
+
if (devicePanel.component) {
|
3645
|
+
devicePanel.component.setCamera(camera);
|
3646
|
+
devicePanel.component.setMicrophone(microphone);
|
3647
|
+
}
|
3648
|
+
|
3649
|
+
devicePanel.dispatchEvent(new DeviceEvent(this.DEVICES_SELECTED, camera, microphone));
|
3650
|
+
} catch(err){
|
3651
|
+
var errorMsg = "devicesSelected :: " + err;
|
3652
|
+
error(errorMsg);
|
3653
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3654
|
+
}
|
3655
|
+
},
|
3656
|
+
|
3657
|
+
closeButtonClickHandler: function(devicePanelId) {
|
3658
|
+
debug("TB.closeButtonClick");
|
3659
|
+
try {
|
3660
|
+
var devicePanel = deviceManager.panels[devicePanelId];
|
3661
|
+
if(!devicePanel) {
|
3662
|
+
var errorMsg = "TB.devicesSelected :: Invalid DevicePanel ID: "+devicePanelId;
|
3663
|
+
error(errorMsg);
|
3664
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3665
|
+
return;
|
3666
|
+
}
|
3667
|
+
|
3668
|
+
var event = new Event(this.CLOSE_BUTTON_CLICK, true);
|
3669
|
+
devicePanel.dispatchEvent(event);
|
3670
|
+
|
3671
|
+
var defaultAction = function() {
|
3672
|
+
if (!event.isDefaultPrevented()) {
|
3673
|
+
deviceManager.removePanel(devicePanel);
|
3674
|
+
}
|
3675
|
+
};
|
3676
|
+
|
3677
|
+
// The event handler is called asynchronously after 1 millisecond. The default action happens after that.
|
3678
|
+
setTimeout(defaultAction, 2);
|
3679
|
+
} catch(err) {
|
3680
|
+
errorMsg = "closeButtonClick :: " + err;
|
3681
|
+
error(errorMsg);
|
3682
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3683
|
+
}
|
3684
|
+
},
|
3685
|
+
|
3686
|
+
// Player callbacks
|
3687
|
+
playerArchiveLoadedHandler: function(playerId) {
|
3688
|
+
debug("Player.archiveLoadedHandler");
|
3689
|
+
try {
|
3690
|
+
var player = recorderManager.players[playerId];
|
3691
|
+
player.dispatchEvent(new Event(this.ARCHIVE_LOADED));
|
3692
|
+
} catch(err) {
|
3693
|
+
var errorMsg = "Player.archiveLoadedHandler :: " + err;
|
3694
|
+
error(errorMsg);
|
3695
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3696
|
+
}
|
3697
|
+
},
|
3698
|
+
|
3699
|
+
playingStartedHandler: function(playerId) {
|
3700
|
+
debug("Player.playingHandler");
|
3701
|
+
try {
|
3702
|
+
var player = recorderManager.players[playerId];
|
3703
|
+
player.dispatchEvent(new Event(this.PLAYBACK_STARTED));
|
3704
|
+
} catch(err) {
|
3705
|
+
var errorMsg = "Player.playingStartedHandler :: " + err;
|
3706
|
+
error(errorMsg);
|
3707
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3708
|
+
}
|
3709
|
+
},
|
3710
|
+
|
3711
|
+
playingStoppedHandler: function(playerId, archive) {
|
3712
|
+
debug("Player.playingStoppedHandler");
|
3713
|
+
try {
|
3714
|
+
var player = recorderManager.players[playerId];
|
3715
|
+
player.dispatchEvent(new Event(this.PLAYBACK_STOPPED));
|
3716
|
+
} catch(err) {
|
3717
|
+
var errorMsg = "Player.playingStoppedHandler :: " + err;
|
3718
|
+
error(errorMsg);
|
3719
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3720
|
+
}
|
3721
|
+
},
|
3722
|
+
|
3723
|
+
// Recorder callbacks
|
3724
|
+
recordingStartedHandler: function(recorderId) {
|
3725
|
+
debug("Recorder.recordingStartedHandler");
|
3726
|
+
try {
|
3727
|
+
var recorder = recorderManager.recorders[recorderId];
|
3728
|
+
recorder.dispatchEvent(new Event(this.RECORDING_STARTED));
|
3729
|
+
} catch(err) {
|
3730
|
+
var errorMsg = "Recorder.recordingStartedHandler :: " + err;
|
3731
|
+
error(errorMsg);
|
3732
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3733
|
+
}
|
3734
|
+
},
|
3735
|
+
|
3736
|
+
recordingStoppedHandler: function(recorderId) {
|
3737
|
+
debug("Recorder.recordingStoppedHandler");
|
3738
|
+
try {
|
3739
|
+
var recorder = recorderManager.recorders[recorderId];
|
3740
|
+
recorder.dispatchEvent(new Event(this.RECORDING_STOPPED));
|
3741
|
+
} catch(err) {
|
3742
|
+
var errorMsg = "Recorder.recordingStoppedHandler :: " + err;
|
3743
|
+
error(errorMsg);
|
3744
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3745
|
+
}
|
3746
|
+
},
|
3747
|
+
|
3748
|
+
recorderPlaybackStartedHandler: function(recorderId) {
|
3749
|
+
debug("Recorder.playbackStartedddHandler");
|
3750
|
+
try {
|
3751
|
+
var recorder = recorderManager.recorders[recorderId];
|
3752
|
+
recorder.dispatchEvent(new Event(this.PLAYBACK_STARTED));
|
3753
|
+
} catch(err) {
|
3754
|
+
var errorMsg = "Recorder.playbackStartedHandler :: " + err;
|
3755
|
+
error(errorMsg);
|
3756
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3757
|
+
}
|
3758
|
+
},
|
3759
|
+
|
3760
|
+
recorderPlaybackStoppedHandler: function(recorderId) {
|
3761
|
+
debug("Recorder.playbackStoppedHandler");
|
3762
|
+
try {
|
3763
|
+
var recorder = recorderManager.recorders[recorderId];
|
3764
|
+
recorder.dispatchEvent(new Event(this.PLAYBACK_STOPPED));
|
3765
|
+
} catch(err) {
|
3766
|
+
var errorMsg = "Recorder.playbackStoppedHandler :: " + err;
|
3767
|
+
error(errorMsg);
|
3768
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3769
|
+
}
|
3770
|
+
},
|
3771
|
+
|
3772
|
+
archiveSavedHandler: function(recorderId, archive) {
|
3773
|
+
debug("Recorder.archiveSavedHandler");
|
3774
|
+
try {
|
3775
|
+
var recorder = recorderManager.recorders[recorderId];
|
3776
|
+
var newArchive = new Archive(archive.id, archive.type, archive.title);
|
3777
|
+
recorder.dispatchEvent(new ArchiveEvent(this.ARCHIVE_SAVED, [newArchive]));
|
3778
|
+
} catch(err) {
|
3779
|
+
var errorMsg = "Recorder.archiveSavedHandler :: " + err;
|
3780
|
+
error(errorMsg);
|
3781
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3782
|
+
}
|
3783
|
+
},
|
3784
|
+
|
3785
|
+
stateChangedHandler: function(sessionId, values) {
|
3786
|
+
debug("TB.stateChangeHandler");
|
3787
|
+
var session = this.sessions[sessionId];
|
3788
|
+
if(!session) {
|
3789
|
+
var errorMsg = "TB.stateChangedHandler :: Invalid session ID: "+sessionId;
|
3790
|
+
error(errorMsg);
|
3791
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3792
|
+
return;
|
3793
|
+
}
|
3794
|
+
|
3795
|
+
function getStateMgrForKey(key) {
|
3796
|
+
key = key.replace(/"/g, "");
|
3797
|
+
var match = key.match(/TB_archive_([^_]+)_(.*)/);
|
3798
|
+
if (match) {
|
3799
|
+
archiveId = match[1];
|
3800
|
+
key = match[2];
|
3801
|
+
var archive = loadedArchives[sessionId][archiveId];
|
3802
|
+
if (!archive) {
|
3803
|
+
var errorMsg = "Archive.startPlayback :: Archive not loaded.";
|
3804
|
+
error(errorMsg);
|
3805
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3806
|
+
return;
|
3807
|
+
}
|
3808
|
+
|
3809
|
+
return archive.getStateManager();
|
3810
|
+
}
|
3811
|
+
|
3812
|
+
return session.getStateManager();
|
3813
|
+
}
|
3814
|
+
|
3815
|
+
var changedEventDispatched = false;
|
3816
|
+
for (var key in values) {
|
3817
|
+
var stateMgr = getStateMgrForKey(key);
|
3818
|
+
|
3819
|
+
if (!changedEventDispatched) {
|
3820
|
+
stateMgr.dispatchEvent(new StateChangedEvent("changed", values));
|
3821
|
+
changedEventDispatched = true;
|
3822
|
+
}
|
3823
|
+
|
3824
|
+
var changedValues = {};
|
3825
|
+
changedValues[key] = values[key];
|
3826
|
+
|
3827
|
+
stateMgr.dispatchEvent(new StateChangedEvent("changed:" + key, changedValues));
|
3828
|
+
}
|
3829
|
+
|
3830
|
+
if (!changedEventDispatched) {
|
3831
|
+
session.getStateManager().dispatchEvent(new StateChangedEvent("changed", values));
|
3832
|
+
}
|
3833
|
+
},
|
3834
|
+
|
3835
|
+
stateChangedFailedHandler: function(sessionId, reasonCode, reason, failedValues){
|
3836
|
+
debug("TB.stateChangedFailedHandler");
|
3837
|
+
var session = this.sessions[sessionId];
|
3838
|
+
if(!session) {
|
3839
|
+
var errorMsg = "TB.stateChangedFailedHandler :: Invalid session ID: "+sessionId;
|
3840
|
+
error(errorMsg);
|
3841
|
+
TB.exceptionHandler(errorMsg, "Internal Error", 2000);
|
3842
|
+
return;
|
3843
|
+
}
|
3844
|
+
|
3845
|
+
var stateMgr = session.getStateManager();
|
3846
|
+
stateMgr.dispatchEvent(new ChangeFailedEvent("changeFailed", reasonCode, reason, failedValues));
|
3847
|
+
},
|
3848
|
+
|
3849
|
+
reportIssueHandler: function(issueId, showReport){
|
3850
|
+
debug("TB.reportIssue");
|
3851
|
+
|
3852
|
+
if (showReport == null) showReport = false;
|
3853
|
+
if (showingIssueForm) return;
|
3854
|
+
|
3855
|
+
// Setup form
|
3856
|
+
var form = document.createElement("form");
|
3857
|
+
form.setAttribute("action", "http://staging.tokbox.com/reportIssue.php");
|
3858
|
+
form.setAttribute("method", "post");
|
3859
|
+
form.setAttribute("target", "formresult");
|
3860
|
+
|
3861
|
+
createHiddenElement(form, "issueId", issueId);
|
3862
|
+
|
3863
|
+
// Add client info
|
3864
|
+
createHiddenElement(form, "userAgent", navigator.userAgent);
|
3865
|
+
createHiddenElement(form, "environment", "JS");
|
3866
|
+
var playerVersion = swfobject.getFlashPlayerVersion();
|
3867
|
+
createHiddenElement(form, "flashVersion", playerVersion.major + "." + playerVersion.minor + "." + playerVersion.release);
|
3868
|
+
|
3869
|
+
// Add JS Logs
|
3870
|
+
var jsLogs = window.opentokdebug.getLogs();
|
3871
|
+
createHiddenElement(form, "jsLogs", jsLogs);
|
3872
|
+
|
3873
|
+
var addedAPIKey = false;
|
3874
|
+
|
3875
|
+
var sessionCount = 0;
|
3876
|
+
for (var i in TB.sessions) {
|
3877
|
+
var session = TB.sessions[i];
|
3878
|
+
if (!session.hasOwnProperty("sessionId")) {
|
3879
|
+
continue;
|
3880
|
+
}
|
3881
|
+
if (!addedAPIKey) {
|
3882
|
+
createHiddenElement(form, "apiKey", session.apiKey);
|
3883
|
+
addedAPIKey = true;
|
3884
|
+
}
|
3885
|
+
var widgetCount = 0;
|
3886
|
+
|
3887
|
+
createHiddenElement(form, "session_" + ++sessionCount, session.sessionId);
|
3888
|
+
// Add controller logs
|
3889
|
+
var controllerId = "controller_" + session.sessionId;
|
3890
|
+
var controllerLogs = getDataForUIComponent(controllerId);
|
3891
|
+
|
3892
|
+
// This may be undefined if a session was initialized but never connected
|
3893
|
+
if(controllerLogs)
|
3894
|
+
createHiddenElement(form, "widget_" + session.sessionId + "_" + ++widgetCount, controllerLogs);
|
3895
|
+
|
3896
|
+
// Add subscriber logs
|
3897
|
+
if (session.hasOwnProperty("subscribers")) {
|
3898
|
+
for (var subscriber in session.subscribers) {
|
3899
|
+
if (session.subscribers[subscriber].hasOwnProperty("id")) {
|
3900
|
+
var subscriberLogs = getDataForUIComponent(session.subscribers[subscriber].id);
|
3901
|
+
createHiddenElement(form, "widget_" + session.sessionId + "_" + ++widgetCount, subscriberLogs);
|
3902
|
+
}
|
3903
|
+
}
|
3904
|
+
}
|
3905
|
+
|
3906
|
+
// Add publisher logs
|
3907
|
+
if (session.hasOwnProperty("publishers")) {
|
3908
|
+
var publisherCount = 0;
|
3909
|
+
for (var publisher in session.publishers) {
|
3910
|
+
if (session.publishers[publisher].hasOwnProperty("id")) {
|
3911
|
+
var publisherLogs = getDataForUIComponent(session.publishers[publisher].id);
|
3912
|
+
createHiddenElement(form, "widget_" + session.sessionId + "_" + ++widgetCount, publisherLogs);
|
3913
|
+
}
|
3914
|
+
}
|
3915
|
+
}
|
3916
|
+
}
|
3917
|
+
|
3918
|
+
if (!showReport) {
|
3919
|
+
var textField = document.createElement("textarea");
|
3920
|
+
textField.setAttribute("name", "description");
|
3921
|
+
textField.setAttribute("rows", 8);
|
3922
|
+
textField.setAttribute("cols", 40);
|
3923
|
+
textField.style.height = "110px";
|
3924
|
+
textField.style.width = "300px";
|
3925
|
+
textField.style.display = "block";
|
3926
|
+
textField.style.visibility = "visible";
|
3927
|
+
form.appendChild(textField);
|
3928
|
+
|
3929
|
+
var submitBtn = document.createElement("input");
|
3930
|
+
submitBtn.setAttribute("type", "submit");
|
3931
|
+
submitBtn.setAttribute("value", "Report Issue");
|
3932
|
+
submitBtn.style.display = "inline";
|
3933
|
+
submitBtn.style.visibility = "visible";
|
3934
|
+
form.appendChild(submitBtn);
|
3935
|
+
|
3936
|
+
var cancelBtn = document.createElement("input");
|
3937
|
+
cancelBtn.setAttribute("type", "button");
|
3938
|
+
cancelBtn.setAttribute("value", "Cancel");
|
3939
|
+
cancelBtn.style.display = "inline";
|
3940
|
+
cancelBtn.style.visibility = "visible";
|
3941
|
+
form.appendChild(cancelBtn);
|
3942
|
+
|
3943
|
+
var width = 390;
|
3944
|
+
var height = 242;
|
3945
|
+
var div = document.createElement("div");
|
3946
|
+
div.setAttribute('id', 'opentokReportIssue');
|
3947
|
+
div.style.position = "absolute";
|
3948
|
+
div.style.top = "25%";
|
3949
|
+
div.style.left = "50%";
|
3950
|
+
div.style.width = width + "px";
|
3951
|
+
div.style.height = height + "px";
|
3952
|
+
div.style.marginLeft = (0 - width/2) + "px";
|
3953
|
+
div.style.marginTop = (0 - height/4) + "px";
|
3954
|
+
div.style.paddingLeft = "32px";
|
3955
|
+
div.style.paddingRight = "15px";
|
3956
|
+
div.style.paddingTop = "15px";
|
3957
|
+
div.style.display = "block";
|
3958
|
+
div.style.visibility = "visible";
|
3959
|
+
div.style.lineHeight = "15px";
|
3960
|
+
div.style.zIndex = highZ() + 1;
|
3961
|
+
|
3962
|
+
div.innerHTML = "<span style=\"color:#4c4c4c;font-size:18px;display:inline;visibility:visible;\">We're sorry to hear that something went wrong.</span><br/><br/>Please help us to debug your issue by providing a description of what happened.";
|
3963
|
+
div.style.backgroundColor = "#F7F7F7";
|
3964
|
+
div.style.border = "1px solid #CCC";
|
3965
|
+
div.style.fontWeight = "normal";
|
3966
|
+
div.style.fontFamily = "'Lucida Grande', 'Trebuchet MS', sans-serif";
|
3967
|
+
div.style.color = "#4c4c4c";
|
3968
|
+
div.style.fontSize = "13px";
|
3969
|
+
|
3970
|
+
div.appendChild(form);
|
3971
|
+
document.body.appendChild(div);
|
3972
|
+
|
3973
|
+
showingIssueForm = true;
|
3974
|
+
|
3975
|
+
closeForm = function() {
|
3976
|
+
document.body.removeChild(div);
|
3977
|
+
showingIssueForm = false;
|
3978
|
+
};
|
3979
|
+
|
3980
|
+
cancelBtn.onclick = closeForm;
|
3981
|
+
}
|
3982
|
+
|
3983
|
+
form.onsubmit = function() {
|
3984
|
+
window.open('#', 'formresult', 'scrollbars=no,menubar=no,height=200,width=400,resizable=yes,toolbar=no,status=no');
|
3985
|
+
setTimeout(function() {closeForm();}, 1000);
|
3986
|
+
};
|
3987
|
+
|
3988
|
+
if (showReport) {
|
3989
|
+
createHiddenElement(form, "showReport", true);
|
3990
|
+
document.body.appendChild(form);
|
3991
|
+
|
3992
|
+
form.submit();
|
3993
|
+
}
|
3994
|
+
}
|
3995
|
+
|
3996
|
+
};
|
3997
|
+
}();
|
3998
|
+
/*!
|
3999
|
+
* SWFObject v2.2 <http://code.google.com/p/swfobject/>
|
4000
|
+
* is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
|
4001
|
+
*
|
4002
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
4003
|
+
* of this software and associated documentation files (the "Software"), to deal
|
4004
|
+
* in the Software without restriction, including without limitation the rights
|
4005
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
4006
|
+
* copies of the Software, and to permit persons to whom the Software is
|
4007
|
+
* furnished to do so, subject to the following conditions:
|
4008
|
+
*
|
4009
|
+
* The above copyright notice and this permission notice shall be included in
|
4010
|
+
* all copies or substantial portions of the Software
|
4011
|
+
*/
|
4012
|
+
var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y<X;Y++){U[Y]()}}function K(X){if(J){X()}else{U[U.length]=X}}function s(Y){if(typeof O.addEventListener!=D){O.addEventListener("load",Y,false)}else{if(typeof j.addEventListener!=D){j.addEventListener("load",Y,false)}else{if(typeof O.attachEvent!=D){i(O,"onload",Y)}else{if(typeof O.onload=="function"){var X=O.onload;O.onload=function(){X();Y()}}else{O.onload=Y}}}}}function h(){if(T){V()}else{H()}}function V(){var X=j.getElementsByTagName("body")[0];var aa=C(r);aa.setAttribute("type",q);var Z=X.appendChild(aa);if(Z){var Y=0;(function(){if(typeof Z.GetVariable!=D){var ab=Z.GetVariable("$version");if(ab){ab=ab.split(" ")[1].split(",");M.pv=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}else{if(Y<10){Y++;setTimeout(arguments.callee,10);return}}X.removeChild(aa);Z=null;H()})()}else{H()}}function H(){var ag=o.length;if(ag>0){for(var af=0;af<ag;af++){var Y=o[af].id;var ab=o[af].callbackFn;var aa={success:false,id:Y};if(M.pv[0]>0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad<ac;ad++){if(X[ad].getAttribute("name").toLowerCase()!="movie"){ah[X[ad].getAttribute("name")]=X[ad].getAttribute("value")}}P(ai,ah,Y,ab)}else{p(ae);if(ab){ab(aa)}}}}}else{w(Y,true);if(ab){var Z=z(Y);if(Z&&typeof Z.SetVariable!=D){aa.success=true;aa.ref=Z}ab(aa)}}}}}function z(aa){var X=null;var Y=c(aa);if(Y&&Y.nodeName=="OBJECT"){if(typeof Y.SetVariable!=D){X=Y}else{var Z=Y.getElementsByTagName(r)[0];if(Z){X=Z}}}return X}function A(){return !a&&F("6.0.65")&&(M.win||M.mac)&&!(M.wk&&M.wk<312)}function P(aa,ab,X,Z){a=true;E=Z||null;B={success:false,id:X};var ae=c(X);if(ae){if(ae.nodeName=="OBJECT"){l=g(ae);Q=null}else{l=ae;Q=X}aa.id=R;if(typeof aa.width==D||(!/%$/.test(aa.width)&&parseInt(aa.width,10)<310)){aa.width="310"}if(typeof aa.height==D||(!/%$/.test(aa.height)&&parseInt(aa.height,10)<137)){aa.height="137"}j.title=j.title.slice(0,47)+" - Flash Player Installation";var ad=M.ie&&M.win?"ActiveX":"PlugIn",ac="MMredirectURL="+O.location.toString().replace(/&/g,"%26")+"&MMplayerType="+ad+"&MMdoctitle="+j.title;if(typeof ab.flashvars!=D){ab.flashvars+="&"+ac}else{ab.flashvars=ac}if(M.ie&&M.win&&ae.readyState!=4){var Y=C("div");X+="SWFObjectNew";Y.setAttribute("id",X);ae.parentNode.insertBefore(Y,ae);ae.style.display="none";(function(){if(ae.readyState==4){ae.parentNode.removeChild(ae)}else{setTimeout(arguments.callee,10)}})()}u(aa,ab,X)}}function p(Y){if(M.ie&&M.win&&Y.readyState!=4){var X=C("div");Y.parentNode.insertBefore(X,Y);X.parentNode.replaceChild(g(Y),X);Y.style.display="none";(function(){if(Y.readyState==4){Y.parentNode.removeChild(Y)}else{setTimeout(arguments.callee,10)}})()}else{Y.parentNode.replaceChild(g(Y),Y)}}function g(ab){var aa=C("div");if(M.win&&M.ie){aa.innerHTML=ab.innerHTML}else{var Y=ab.getElementsByTagName(r)[0];if(Y){var ad=Y.childNodes;if(ad){var X=ad.length;for(var Z=0;Z<X;Z++){if(!(ad[Z].nodeType==1&&ad[Z].nodeName=="PARAM")&&!(ad[Z].nodeType==8)){aa.appendChild(ad[Z].cloneNode(true))}}}}}return aa}function u(ai,ag,Y){var X,aa=c(Y);if(M.wk&&M.wk<312){return X}if(aa){if(typeof ai.id==D){ai.id=Y}if(M.ie&&M.win){var ah="";for(var ae in ai){if(ai[ae]!=Object.prototype[ae]){if(ae.toLowerCase()=="data"){ag.movie=ai[ae]}else{if(ae.toLowerCase()=="styleclass"){ah+=' class="'+ai[ae]+'"'}else{if(ae.toLowerCase()!="classid"){ah+=" "+ae+'="'+ai[ae]+'"'}}}}}var af="";for(var ad in ag){if(ag[ad]!=Object.prototype[ad]){af+='<param name="'+ad+'" value="'+ag[ad]+'" />'}}aa.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+ah+">"+af+"</object>";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab<ac;ab++){I[ab][0].detachEvent(I[ab][1],I[ab][2])}var Z=N.length;for(var aa=0;aa<Z;aa++){y(N[aa])}for(var Y in M){M[Y]=null}M=null;for(var X in swfobject){swfobject[X]=null}swfobject=null})}}();return{registerObject:function(ab,X,aa,Z){if(M.w3&&ab&&X){var Y={};Y.id=ab;Y.swfVersion=X;Y.expressInstall=aa;Y.callbackFn=Z;o[o.length]=Y;w(ab,false)}else{if(Z){Z({success:false,id:ab})}}},getObjectById:function(X){if(M.w3){return z(X)}},embedSWF:function(ab,ah,ae,ag,Y,aa,Z,ad,af,ac){var X={success:false,id:ah};if(M.w3&&!(M.wk&&M.wk<312)&&ab&&ah&&ae&&ag&&Y){w(ah,false);K(function(){ae+="";ag+="";var aj={};if(af&&typeof af===r){for(var al in af){aj[al]=af[al]}}aj.data=ab;aj.width=ae;aj.height=ag;var am={};if(ad&&typeof ad===r){for(var ak in ad){am[ak]=ad[ak]}}if(Z&&typeof Z===r){for(var ai in Z){if(typeof am.flashvars!=D){am.flashvars+="&"+ai+"="+Z[ai]}else{am.flashvars=ai+"="+Z[ai]}}}if(F(Y)){var an=u(aj,am,ah);if(aj.id==ah){w(ah,true)}X.success=true;X.ref=an}else{if(aa&&A()){aj.data=aa;P(aj,am,ah,ac);return}else{w(ah,true)}}if(ac){ac(X)}})}else{if(ac){ac(X)}}},switchOffAutoHideShow:function(){m=false},ua:M,getFlashPlayerVersion:function(){return{major:M.pv[0],minor:M.pv[1],release:M.pv[2]}},hasFlashPlayerVersion:F,createSWF:function(Z,Y,X){if(M.w3){return u(Z,Y,X)}else{return undefined}},showExpressInstall:function(Z,aa,X,Y){if(M.w3&&A()){P(Z,aa,X,Y)}},removeSWF:function(X){if(M.w3){y(X)}},createCSS:function(aa,Z,Y,X){if(M.w3){v(aa,Z,Y,X)}},addDomLoadEvent:K,addLoadEvent:s,getQueryParamValue:function(aa){var Z=j.location.search||j.location.hash;if(Z){if(/\?/.test(Z)){Z=Z.split("?")[1]}if(aa==null){return L(Z)}var Y=Z.split("&");for(var X=0;X<Y.length;X++){if(Y[X].substring(0,Y[X].indexOf("="))==aa){return L(Y[X].substring((Y[X].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(a){var X=c(R);if(X&&l){X.parentNode.replaceChild(l,X);if(Q){w(Q,true);if(M.ie&&M.win){l.style.display="block"}}if(E){E(B)}}a=false}}}}();/*!
|
4013
|
+
* JavaScript Debug - v0.4 - 6/22/2010
|
4014
|
+
* http://benalman.com/projects/javascript-debug-console-log/
|
4015
|
+
*
|
4016
|
+
* Copyright (c) 2010 "Cowboy" Ben Alman
|
4017
|
+
* Dual licensed under the MIT and GPL licenses.
|
4018
|
+
* http://benalman.com/about/license/
|
4019
|
+
*
|
4020
|
+
* Permission is hereby granted, free of charge, to any person
|
4021
|
+
* obtaining a copy of this software and associated documentation
|
4022
|
+
* files (the "Software"), to deal in the Software without
|
4023
|
+
* restriction, including without limitation the rights to use,
|
4024
|
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
4025
|
+
* copies of the Software, and to permit persons to whom the
|
4026
|
+
* Software is furnished to do so, subject to the following
|
4027
|
+
* conditions:
|
4028
|
+
*
|
4029
|
+
* The above copyright notice and this permission notice shall be
|
4030
|
+
* included in all copies or substantial portions of the Software.
|
4031
|
+
*/
|
4032
|
+
|
4033
|
+
// Script: JavaScript Debug: A simple wrapper for console.log
|
4034
|
+
//
|
4035
|
+
// *Version: 0.4, Last Updated: 6/22/2010*
|
4036
|
+
//
|
4037
|
+
// Tested with Internet Explorer 6-8, Firefox 3-3.6, Safari 3-4, Chrome 3-5, Opera 9.6-10.5
|
4038
|
+
//
|
4039
|
+
// Home - http://benalman.com/projects/javascript-debug-console-log/
|
4040
|
+
// GitHub - http://github.com/cowboy/javascript-debug/
|
4041
|
+
// Source - http://github.com/cowboy/javascript-debug/raw/master/ba-debug.js
|
4042
|
+
// (Minified) - http://github.com/cowboy/javascript-debug/raw/master/ba-debug.min.js (1.1kb)
|
4043
|
+
//
|
4044
|
+
// About: License
|
4045
|
+
//
|
4046
|
+
// Copyright (c) 2010 "Cowboy" Ben Alman,
|
4047
|
+
// Dual licensed under the MIT and GPL licenses.
|
4048
|
+
// http://benalman.com/about/license/
|
4049
|
+
//
|
4050
|
+
// About: Support and Testing
|
4051
|
+
//
|
4052
|
+
// Information about what browsers this code has been tested in.
|
4053
|
+
//
|
4054
|
+
// Browsers Tested - Internet Explorer 6-8, Firefox 3-3.6, Safari 3-4, Chrome
|
4055
|
+
// 3-5, Opera 9.6-10.5
|
4056
|
+
//
|
4057
|
+
// About: Examples
|
4058
|
+
//
|
4059
|
+
// These working examples, complete with fully commented code, illustrate a few
|
4060
|
+
// ways in which this plugin can be used.
|
4061
|
+
//
|
4062
|
+
// Examples - http://benalman.com/code/projects/javascript-debug/examples/debug/
|
4063
|
+
//
|
4064
|
+
// About: Revision History
|
4065
|
+
//
|
4066
|
+
// 0.4 - (6/22/2010) Added missing passthrough methods: exception,
|
4067
|
+
// groupCollapsed, table
|
4068
|
+
// 0.3 - (6/8/2009) Initial release
|
4069
|
+
//
|
4070
|
+
// Topic: Pass-through console methods
|
4071
|
+
//
|
4072
|
+
// assert, clear, count, dir, dirxml, exception, group, groupCollapsed,
|
4073
|
+
// groupEnd, profile, profileEnd, table, time, timeEnd, trace
|
4074
|
+
//
|
4075
|
+
// These console methods are passed through (but only if both the console and
|
4076
|
+
// the method exists), so use them without fear of reprisal. Note that these
|
4077
|
+
// methods will not be passed through if the logging level is set to 0 via
|
4078
|
+
// <debug.setLevel>.
|
4079
|
+
|
4080
|
+
window.opentokdebug = (function(){
|
4081
|
+
var window = this,
|
4082
|
+
|
4083
|
+
// Some convenient shortcuts.
|
4084
|
+
aps = Array.prototype.slice,
|
4085
|
+
con = window.console,
|
4086
|
+
|
4087
|
+
// Public object to be returned.
|
4088
|
+
that = {},
|
4089
|
+
|
4090
|
+
callback_func, callback_force,
|
4091
|
+
|
4092
|
+
// OpenTok has a default of no logging.
|
4093
|
+
log_level = 0,
|
4094
|
+
|
4095
|
+
// Logging methods, in "priority order". Not all console implementations
|
4096
|
+
// will utilize these, but they will be used in the callback passed to
|
4097
|
+
// setCallback.
|
4098
|
+
log_methods = ['error', 'warn', 'info', 'debug', 'log'],
|
4099
|
+
|
4100
|
+
// Pass these methods through to the console if they exist, otherwise just
|
4101
|
+
// fail gracefully. These methods are provided for convenience.
|
4102
|
+
pass_methods = 'assert clear count dir dirxml exception group groupCollapsed groupEnd profile profileEnd table time timeEnd trace'.split(' '),
|
4103
|
+
idx = pass_methods.length,
|
4104
|
+
|
4105
|
+
// Logs are stored here so that they can be recalled as necessary.
|
4106
|
+
logs = [];
|
4107
|
+
|
4108
|
+
while (--idx >= 0) {
|
4109
|
+
(function(method) {
|
4110
|
+
|
4111
|
+
// Generate pass-through methods. These methods will be called, if they
|
4112
|
+
// exist, as long as the logging level is non-zero.
|
4113
|
+
that[method] = function() {
|
4114
|
+
log_level !== 0 && con && con[method] && con[method].apply(con, arguments);
|
4115
|
+
};
|
4116
|
+
|
4117
|
+
})(pass_methods[idx]);
|
4118
|
+
}
|
4119
|
+
|
4120
|
+
idx = log_methods.length;
|
4121
|
+
while (--idx >= 0) {
|
4122
|
+
(function(idx, level) {
|
4123
|
+
|
4124
|
+
// Method: debug.log
|
4125
|
+
//
|
4126
|
+
// Call the console.log method if available. Adds an entry into the logs
|
4127
|
+
// array for a callback specified via <debug.setCallback>.
|
4128
|
+
//
|
4129
|
+
// Usage:
|
4130
|
+
//
|
4131
|
+
// debug.log( object [, object, ...] ); - -
|
4132
|
+
//
|
4133
|
+
// Arguments:
|
4134
|
+
//
|
4135
|
+
// object - (Object) Any valid JavaScript object.
|
4136
|
+
// Method: debug.debug
|
4137
|
+
//
|
4138
|
+
// Call the console.debug method if available, otherwise call console.log.
|
4139
|
+
// Adds an entry into the logs array for a callback specified via
|
4140
|
+
// <debug.setCallback>.
|
4141
|
+
//
|
4142
|
+
// Usage:
|
4143
|
+
//
|
4144
|
+
// debug.debug( object [, object, ...] ); - -
|
4145
|
+
//
|
4146
|
+
// Arguments:
|
4147
|
+
//
|
4148
|
+
// object - (Object) Any valid JavaScript object.
|
4149
|
+
// Method: debug.info
|
4150
|
+
//
|
4151
|
+
// Call the console.info method if available, otherwise call console.log.
|
4152
|
+
// Adds an entry into the logs array for a callback specified via
|
4153
|
+
// <debug.setCallback>.
|
4154
|
+
//
|
4155
|
+
// Usage:
|
4156
|
+
//
|
4157
|
+
// debug.info( object [, object, ...] ); - -
|
4158
|
+
//
|
4159
|
+
// Arguments:
|
4160
|
+
//
|
4161
|
+
// object - (Object) Any valid JavaScript object.
|
4162
|
+
// Method: debug.warn
|
4163
|
+
//
|
4164
|
+
// Call the console.warn method if available, otherwise call console.log.
|
4165
|
+
// Adds an entry into the logs array for a callback specified via
|
4166
|
+
// <debug.setCallback>.
|
4167
|
+
//
|
4168
|
+
// Usage:
|
4169
|
+
//
|
4170
|
+
// debug.warn( object [, object, ...] ); - -
|
4171
|
+
//
|
4172
|
+
// Arguments:
|
4173
|
+
//
|
4174
|
+
// object - (Object) Any valid JavaScript object.
|
4175
|
+
// Method: debug.error
|
4176
|
+
//
|
4177
|
+
// Call the console.error method if available, otherwise call console.log.
|
4178
|
+
// Adds an entry into the logs array for a callback specified via
|
4179
|
+
// <debug.setCallback>.
|
4180
|
+
//
|
4181
|
+
// Usage:
|
4182
|
+
//
|
4183
|
+
// debug.error( object [, object, ...] ); - -
|
4184
|
+
//
|
4185
|
+
// Arguments:
|
4186
|
+
//
|
4187
|
+
// object - (Object) Any valid JavaScript object.
|
4188
|
+
that[level] = function() {
|
4189
|
+
var args = aps.call(arguments),
|
4190
|
+
log_arr = [level].concat(args);
|
4191
|
+
|
4192
|
+
logs.push(log_arr);
|
4193
|
+
|
4194
|
+
if (!con || !is_level(idx)) {
|
4195
|
+
return;
|
4196
|
+
}
|
4197
|
+
exec_callback(log_arr); // OpenTok executes callback only if the proper level
|
4198
|
+
// OpenTok - this is a fix for firebug 1.6.0 submitted by someone else. hopefully it'll get incorporated into
|
4199
|
+
// the next official release and it can be removed.
|
4200
|
+
(con.firebug || window.Firebug) ? con[level].apply(con, args) : con[level] ? con[level](args) : con.log(args);
|
4201
|
+
};
|
4202
|
+
|
4203
|
+
})(idx, log_methods[idx]);
|
4204
|
+
}
|
4205
|
+
|
4206
|
+
// Execute the callback function if set.
|
4207
|
+
function exec_callback(args) {
|
4208
|
+
if (callback_func && (callback_force || !con || !con.log)) {
|
4209
|
+
callback_func.apply(window, args);
|
4210
|
+
}
|
4211
|
+
};
|
4212
|
+
|
4213
|
+
// Method: debug.setLevel
|
4214
|
+
//
|
4215
|
+
// Set a minimum or maximum logging level for the console. Doesn't affect
|
4216
|
+
// the <debug.setCallback> callback function, but if set to 0 to disable
|
4217
|
+
// logging, <Pass-through console methods> will be disabled as well.
|
4218
|
+
//
|
4219
|
+
// Usage:
|
4220
|
+
//
|
4221
|
+
// debug.setLevel( [ level ] ) - -
|
4222
|
+
//
|
4223
|
+
// Arguments:
|
4224
|
+
//
|
4225
|
+
// level - (Number) If 0, disables logging. If negative, shows N lowest
|
4226
|
+
// priority levels of log messages. If positive, shows N highest priority
|
4227
|
+
// levels of log messages.
|
4228
|
+
//
|
4229
|
+
// Priority levels:
|
4230
|
+
//
|
4231
|
+
// log (1) < debug (2) < info (3) < warn (4) < error (5)
|
4232
|
+
that.setLevel = function(level) {
|
4233
|
+
log_level = typeof level === 'number' ? level : 9;
|
4234
|
+
};
|
4235
|
+
|
4236
|
+
// Determine if the level is visible given the current log_level.
|
4237
|
+
function is_level(level) {
|
4238
|
+
return log_level > 0 ? log_level > level : log_methods.length + log_level <= level;
|
4239
|
+
};
|
4240
|
+
|
4241
|
+
// Method: debug.setCallback
|
4242
|
+
//
|
4243
|
+
// Set a callback to be used if logging isn't possible due to console.log
|
4244
|
+
// not existing. If unlogged logs exist when callback is set, they will all
|
4245
|
+
// be logged immediately unless a limit is specified.
|
4246
|
+
//
|
4247
|
+
// Usage:
|
4248
|
+
//
|
4249
|
+
// debug.setCallback( callback [, force ] [, limit ] )
|
4250
|
+
//
|
4251
|
+
// Arguments:
|
4252
|
+
//
|
4253
|
+
// callback - (Function) The aforementioned callback function. The first
|
4254
|
+
// argument is the logging level, and all subsequent arguments are those
|
4255
|
+
// passed to the initial debug logging method.
|
4256
|
+
// force - (Boolean) If false, log to console.log if available, otherwise
|
4257
|
+
// callback. If true, log to both console.log and callback.
|
4258
|
+
// limit - (Number) If specified, number of lines to limit initial scrollback
|
4259
|
+
// to.
|
4260
|
+
that.setCallback = function() {
|
4261
|
+
var args = aps.call(arguments),
|
4262
|
+
max = logs.length,
|
4263
|
+
i = max;
|
4264
|
+
|
4265
|
+
callback_func = args.shift() || null;
|
4266
|
+
callback_force = typeof args[0] === 'boolean' ? args.shift() : false;
|
4267
|
+
|
4268
|
+
i -= typeof args[0] === 'number' ? args.shift() : max;
|
4269
|
+
|
4270
|
+
while (i < max) {
|
4271
|
+
exec_callback(logs[i++]);
|
4272
|
+
}
|
4273
|
+
};
|
4274
|
+
|
4275
|
+
that.getLogs = function() {
|
4276
|
+
return logs.join('\n');
|
4277
|
+
};
|
4278
|
+
|
4279
|
+
return that;
|
4280
|
+
})();// Add missing IE methods
|
4281
|
+
|
4282
|
+
// This was taken from:
|
4283
|
+
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys
|
4284
|
+
if (!Object.keys) Object.keys = function(o) {
|
4285
|
+
if (o !== Object(o)) throw new TypeError('Object.keys called on non-object');
|
4286
|
+
var ret = [],
|
4287
|
+
p;
|
4288
|
+
for (p in o) {
|
4289
|
+
if (Object.prototype.hasOwnProperty.call(o, p)) {
|
4290
|
+
ret.push(p);
|
4291
|
+
}
|
4292
|
+
}
|
4293
|
+
return ret;
|
4294
|
+
};
|
4295
|
+
|
4296
|
+
// This was taken from:
|
4297
|
+
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
|
4298
|
+
if (!Array.prototype.indexOf) {
|
4299
|
+
Array.prototype.indexOf = function(searchElement) {
|
4300
|
+
"use strict";
|
4301
|
+
if (this === void 0 || this === null) {
|
4302
|
+
throw new TypeError();
|
4303
|
+
}
|
4304
|
+
var t = Object(this);
|
4305
|
+
var len = t.length >>> 0;
|
4306
|
+
if (len === 0) {
|
4307
|
+
return -1;
|
4308
|
+
}
|
4309
|
+
var n = 0;
|
4310
|
+
if (arguments.length > 0) {
|
4311
|
+
n = Number(arguments[1]);
|
4312
|
+
if (n !== n) { // shortcut for verifying if it's NaN
|
4313
|
+
n = 0;
|
4314
|
+
} else if (n !== 0 && n !== Infinity && n !== -Infinity) {
|
4315
|
+
n = (n > 0 || -1) * Math.floor(Math.abs(n));
|
4316
|
+
}
|
4317
|
+
}
|
4318
|
+
if (n >= len) {
|
4319
|
+
return -1;
|
4320
|
+
}
|
4321
|
+
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
|
4322
|
+
for (; k < len; k++) {
|
4323
|
+
if (k in t && t[k] === searchElement) {
|
4324
|
+
return k;
|
4325
|
+
}
|
4326
|
+
}
|
4327
|
+
return -1;
|
4328
|
+
};
|
4329
|
+
}
|