-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathindex.html
390 lines (346 loc) · 13.6 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
<html>
<body onunload="logout()">
<script src="/_ah/channel/jsapi"></script>
<script type="text/javascript">
<!--
// The unique random stream for this client, also used as ClientID for creating channel.
var stream = Math.floor(Math.random()*100000000).toString();
// The name of this user, is prompted to change.
var me = "user" + stream;
// The name of the person I am connected to.
var you = null;
// The base URL of the application, so that absolute API URL can be formed.
var base_url = location.href.substring(0,location.href.lastIndexOf('/'));
// The Adobe stratus URL for my application
var media_url = 'rtmfp://stratus.rtmfp.net/d1e1e5b3f17e90eb35d244fd-c711881365d9/';
// The VideoIO play URL of my stream.
var src = null;
// The VideoIO play URL of other person's stream
var dest = null;
// The periodic timer to periodically login in soft-state.
var timer = null;
// The periodic timer interval for login soft-state.
var publish_interval = 60000;
// The socket created with channel API, created in createChannel().
var socket = null;
// The channelId for the channel API for this client's ID (stream).
var channelId = null;
// The channel created with channel API, created in createChannel().
var channel = null;
// Create an AJAX request object based on browser type.
function getRequest() {
var ajaxRequest; // The variable that makes Ajax possible!
try{ // Opera 8.0+, Firefox, Safari
ajaxRequest = new XMLHttpRequest();
} catch (e) { // Internet Explorer Browsers
try{
ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
return false; // Something went wrong
}
}
}
return ajaxRequest;
}
// Get the Flash Movie by name, e.g., "video1" or "video2".
function getFlashMovie(movieName) {
var isIE = navigator.appName.indexOf("Microsoft") != -1;
return (isIE) ? window[movieName] : document[movieName];
}
// On startup, create a channel using the channel API.
// Request: POST /create/?stream={stream}
// Response: {"token": ... }
// The token is used in new goog.appengine.Channel(...) to create a channel.
// Once connected, the server sends JSON messages, with "method" attribute
// of value "send" or "connect". This function invokes received() and connected()
// respectively for these messages.
function createChannel() {
var request = getRequest();
var url = base_url + "/create/?stream=" + stream;
request.onreadystatechange = function() {
if (request.readyState == 4) {
if (request.status == 200) {
// log("response " + request.responseText);
data = eval("(" + request.responseText + ")");
channelId = data.token;
log("channel created");
channel = new goog.appengine.Channel(channelId);
socket = channel.open();
socket.onmessage = function(event) {
obj = eval("(" + event.data + ")");
if (obj.method == "send") {
received(obj.body);
} else if (obj.method == "connect") {
connected(obj.play);
}
};
socket.onerror = function(event) {
log("socket error: " + event.code + " " + event.description);
};
} else {
log("create channel failed");
}
}
};
request.open("POST", url, true);
request.send('dummy');
}
// When the page is launched, it creates a channel first.
createChannel();
// Prompt the user for his name.
function promptNickname() {
while (true) {
me = prompt("Enter your nickname\n(alphanumeric, no spaces, at most 32 characters)", me);
if (me == null || me.length <= 32 && me.match(/^([a-zA-Z0-9_-]+)$/)) {
return me;
}
}
}
// When the page is launched, it prompts for user name.
promptNickname();
// When VideoIO is created, and user has specified the name, start local video.
function onCreationComplete(event) {
if (event.objectID == "video1") {
if (me) {
var url = media_url + "?publish=" + stream;
getFlashMovie("video1").setProperty("src", url);
}
}
}
// When local video's nearID is set, set our "src" property and initiate login.
function onPropertyChange(event) {
if (event.property == "nearID" && event.objectID == "video1") {
src = media_url + "?nickname=" + me + "&play=" + stream + "&farID=" + event.newValue;
setTimeout("login(true)", 1000); // first invocation after 1 second.
timer = setInterval("login()", publish_interval);
}
}
// Initiate the login process. If change is true, then request a change of
// connected person, when the user clicks on "Next Person" link.
// Request: /login/?stream={stream} or /login/?stream={stream}&change=true
// Request-body: {"publish": ...}
// Response-body: {"play": ...}
// Where publish and play are play URLs for local and remote VideoIO objects.
function login(change) {
if (!src) {
alert("You must Login before publishing");
return;
}
var request = getRequest();
var url = base_url + "/login/?stream=" + stream + (change ? "&change=true" : "");
request.onreadystatechange = function() {
if (request.readyState == 4) {
if (request.status == 200) {
// log("response " + request.responseText);
} else {
log("login failed");
}
}
};
request.open("POST", url, true);
request.send('{"publish":"' + src + '"}');
}
// Logout the local user, and clear the periodic login timer.
// Request: POST /logout/?stream={stream}
function logout() {
if (timer)
clearInterval(timer);
var request = getRequest();
var url = base_url + "/logout/?stream=" + stream;
request.open("POST", url, true);
request.send(src);
}
// Send a text chat message, if connected to other person.
// Request: POST /send/?stream={stream}
// Request-body: {"dest": ..., "body": ... }
// Here dest is the other person's VideoIO play URL.
function send() {
var msg = document.getElementById("input").value;
if (msg) {
document.getElementById("input").value = "";
if (dest) {
log("Me: " + msg);
var request = getRequest();
var url = base_url + "/send/" + "?stream=" + stream;
request.open("POST", url, true);
request.send('{"dest":"' + dest + '", "body": "You: ' + msg + '"}');
}
else {
log("Me (not connected): " + msg);
}
}
}
// When the server says we are connected to the supplied play URL,
// change the remote VideoIO's "src" attribute, and update "you" and "dest".
function connected(play) {
//log("connected to " + play);
var olddest = dest;
you = "";
dest = play;
if (!dest)
dest = null;
if (dest) {
index = dest.indexOf("?");
var parts = dest.substr(index+1).split("&");
for (var i=0; i<parts.length; ++i) {
var part = parts[i];
if (part.indexOf("nickname=") == 0) {
you = part.substr(9);
}
}
}
if (olddest != dest) {
getFlashMovie("video2").setProperty("src", dest);
}
if (you) {
log("connected to " + you);
document.getElementById("remote").innerHTML = you;
} else {
log("you are not connected");
document.getElementById("remote").innerHTML = "You are not connected";
}
}
// When the server sends us a text message, just display the message.
function received(body) {
log(body);
}
// When the user toggle's the Login/Logout link, set or reset the local and
// remote VideoIO. On logout, also invoke the logout() function. On logout, the
// login() function will be invoked when the local VideoIO is ready with nearId.
function toggleLogin() {
var button = document.getElementById("login");
if (button.innerHTML == "Logout") {
button.innerHTML = "Login";
log("logged out");
logout();
getFlashMovie("video1").setProperty("src", null);
getFlashMovie("video2").setProperty("src", null);
document.getElementById("remote").innerHTML = "You are not connected";
you = "";
src = null;
dest = null;
}
else {
if (me != null || promptNickname()) {
document.getElementById("local").innerHTML = "I am " + me;
log("logging in");
button.innerHTML = "Logout";
var url = media_url + "?publish=" + stream;
getFlashMovie("video1").setProperty("src", url);
}
}
}
// Write a message to the chat history text area.
function log(msg) {
var obj = document.getElementById("history");
obj.value += (obj.value == "" ? "" : "\n") + msg;
}
//-->
</script>
<div style="position: absolute; left: 10px; top: 10px; width: 320px; height: 240px;">
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
id="video1" width="320" height="240"
codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
<param name="movie" value="/static/VideoIO.swf" />
<param name="quality" value="high" />
<param name="bgcolor" value="#000000" />
<param name="allowFullScreen" value="true" />
<param name="flashVars" value="controls=true&cameraQuality=80" />
<param name="allowScriptAccess" value="always" />
<embed src="/static/VideoIO.swf" quality="high" bgcolor="#000000"
width="320" height="240" name="video1" align="middle"
play="true" loop="false" quality="high"
allowFullScreen="true"
flashVars="controls=true&cameraQuality=80"
allowScriptAccess="always"
type="application/x-shockwave-flash"
pluginspage="http://www.adobe.com/go/getflashplayer">
</embed>
</object>
</div>
<div style="position: absolute; left: 10px; top: 260px; width: 320px; height: 240px;">
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
id="video2" width="320" height="240"
codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
<param name="movie" value="/static/VideoIO.swf" />
<param name="quality" value="high" />
<param name="bgcolor" value="#000000" />
<param name="allowFullScreen" value="true" />
<param name="flashVars" value="controls=true" />
<param name="allowScriptAccess" value="always" />
<embed src="/static/VideoIO.swf" quality="high" bgcolor="#000000"
width="320" height="240" name="video2" align="middle"
play="true" loop="false" quality="high"
allowFullScreen="true"
allowScriptAccess="always"
flashVars="controls=true"
type="application/x-shockwave-flash"
pluginspage="http://www.adobe.com/go/getflashplayer">
</embed>
</object>
</div>
<div style="position: absolute; left: 340px; top: 10px; width: 320px; height: 490px;">
<div style="float: right; height: 18px;">
<div id="local" style="float: left;"></div> |
<a id="login" href="#" onclick="javascript: toggleLogin()">Logout</script></a>
</div>
<script>
if (!me)
document.getElementById("login").innerHTML = "Login";
document.getElementById("local").innerHTML = me ? "I am " + me : "";
</script>
<br/>
<textarea id="history" autocomplete="off"
style="width: 320px; height: 410px;"></textarea>
<br/>
Enter your text message:
<input id="input" type="text" autocomplete="off"
style="width: 320px; height: 24px;"
onkeypress="javascript: if ((event.keyCode || event.which) == 13) { send(); return false; }"/>
<div style="float: right; height: 18px;">
<div id="remote" style="float: left;">You are not connected</div> |
<a href="#" onclick="javascript: login(true); return false;">Next Person</a>
</div>
</div>
<div style="position: absolute; left: 670px; top: 10px; width: 320px; height: 490px; border: 1px 1px 1px 1px;">
<h2 style="margin-top: 0px;" >What is this?</h2>
<p style="font-size: 12px; text-align: justify;">
This is a <a href="http://en.wikipedia.org/wiki/Chatroulette" target="_blank">chatroulette</a>-type
application built using the
<a href="https://github.com/theintencity/flash-videoio" target="_blank">Flash VideoIO</a> component on
<a href="http://labs.adobe.com/technologies/stratus/" target="_blank">Adobe Stratus</a>
service and <a href="http://en.wikipedia.org/wiki/Google_App_Engine" target="_blank">Google App Engine</a>.
This site is just a demonstration of how such services can be
built using the generic Flash-VideoIO component, and not meant for production
use.</p>
<p style="font-size: 12px; text-align: justify;">
When you land on this page, it prompts you for some nickname, and starts publishing
your audio and video stream, after you approve the device access.
It tries to connect you with another person who is
also on the page publishing his or her video. The status of the connection is
displayed in the chat history area. You can also type a message to send to the
person you are talking with.</p>
<p style="font-size: 12px; text-align: justify;">
It uses Google App Engine for all session initiation and discovery of other users,
and Adobe Stratus to do media negotiation for peer-to-peer media streams. The project
contains one HTML file with some javascript and one Python file, with about 400 lines
total. There is no authentication, but is easy to add using Google App Engine.
You can right-click on this page to view the HTML and javascript source code which
contributes to all front-end interactions and shows how to use Flash-VideoIO for
chatroulette type applications.
</p>
<p style="font-size: 12px; text-align: justify;">
This version of the project uses the Channel API available in Google App Engine
for asynchronous notifications of connections, disconnections and chat messages.
</p>
<p style="font-size: 12px; text-align: justify;">
You can view the source code of two files: <a href="/static/index.html.txt">index.html</a>
and <a href="/static/main.py.txt">main.py</a> where former renders the user interface
and latter is the back-end service code on Google App Engine.
</p>
</div>
</body>
</html>