44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/static/sync/index.js:
--------------------------------------------------------------------------------
1 | $(function () {
2 | //We'll use message to tell the user what's happening
3 | var $message = $('#message');
4 |
5 | //Get handle to the game board buttons
6 | var $buttons = $('#board .board-row button');
7 |
8 | //Our interface to the Sync service
9 | var syncClient;
10 |
11 | // Every browser Sync client relies on FPA tokens to authenticate and authorize it
12 | // for access to your Sync data.
13 | //
14 | // In this quickstart, we're using our own token generator. You can generate a token
15 | // in any backend language that Twilio supports, or generate a Twilio Function so
16 | // Twilio can host it for you. See the docs for more details.
17 | //
18 | $.getJSON('/token', function (tokenResponse) {
19 |
20 | // Once we have the token, we can initialize the Sync client and start subscribing
21 | // to data. The client will initialize asynchronously while we load the rest of
22 | // the user interface.
23 | //
24 | syncClient = new Twilio.Sync.Client(tokenResponse.token, { logLevel: 'info' });
25 | syncClient.on('connectionStateChanged', function(state) {
26 | if (state != 'connected') {
27 | $message.html('Sync is not live (websocket connection ' + state + ')…');
28 | } else {
29 | // Now that we're connected, lets light up our board and play!
30 | $buttons.attr('disabled', false);
31 | $message.html('Sync is live!');
32 | }
33 | });
34 |
35 | // Let's pop a message on the screen to show that Sync is working
36 | $message.html('Loading board data…');
37 |
38 | // Our game state is stored in a Sync document. Here, we'll attach to that document
39 | // (or create it, if it doesn't exist) and connect the necessary event handlers.
40 | //
41 | syncClient.document('SyncGame').then(function(syncDoc) {
42 | var data = syncDoc.value;
43 | if (data.board) {
44 | updateUserInterface(data);
45 | }
46 |
47 | // Any time the board changes, we want to show the new state. The 'updated'
48 | // event is for this.
49 | syncDoc.on('updated', function(event) {
50 | console.debug("Board was updated", event.isLocal? "locally." : "by the other guy.");
51 | updateUserInterface(event.value);
52 | });
53 |
54 | // Let's make our buttons control the game state in Sync…
55 | $buttons.on('click', function (e) {
56 | // Toggle the value: X, O, or empty
57 | toggleCellValue($(e.target));
58 |
59 | // Send updated document to Sync. This will trigger "updated" events for all players.
60 | var data = readGameBoardFromUserInterface();
61 | syncDoc.set(data);
62 | });
63 | });
64 |
65 | });
66 |
67 | //Toggle the value: X, O, or empty ( for UI)
68 | function toggleCellValue($cell) {
69 | var cellValue = $cell.html();
70 |
71 | if (cellValue === 'X') {
72 | $cell.html('O');
73 | } else if (cellValue === 'O') {
74 | $cell.html(' ');
75 | } else {
76 | $cell.html('X');
77 | }
78 | }
79 |
80 | //Read the state of the UI and create a new document
81 | function readGameBoardFromUserInterface() {
82 | var board = [
83 | ['', '', ''],
84 | ['', '', ''],
85 | ['', '', '']
86 | ];
87 |
88 | for (var row = 0; row < 3; row++) {
89 | for (var col = 0; col < 3; col++) {
90 | var selector = '[data-row="' + row + '"]' +
91 | '[data-col="' + col + '"]';
92 | board[row][col] = $(selector).html().replace(' ', '');
93 | }
94 | }
95 |
96 | return {board: board};
97 | }
98 |
99 | //Update the buttons on the board to match our document
100 | function updateUserInterface(data) {
101 | for (var row = 0; row < 3; row++) {
102 | for (var col = 0; col < 3; col++) {
103 | var this_cell = '[data-row="' + row + '"]' + '[data-col="' + col + '"]';
104 | var cellValue = data.board[row][col];
105 | $(this_cell).html(cellValue === '' ? ' ' : cellValue);
106 | }
107 | }
108 | }
109 | });
110 |
--------------------------------------------------------------------------------
/static/video/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Twilio Video - Video Quickstart
5 |
6 |
7 |
8 |
9 |
10 |
11 |
Hello Beautiful
12 |
13 |
14 |
15 |
16 |
17 |
Room Name:
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/static/video/quickstart.js:
--------------------------------------------------------------------------------
1 | var activeRoom;
2 | var previewTracks;
3 | var identity;
4 | var roomName;
5 |
6 | function attachTracks(tracks, container) {
7 | tracks.forEach(function(track) {
8 | container.appendChild(track.attach());
9 | });
10 | }
11 |
12 | function attachParticipantTracks(participant, container) {
13 | var tracks = Array.from(participant.tracks.values());
14 | attachTracks(tracks, container);
15 | }
16 |
17 | function detachTracks(tracks) {
18 | tracks.forEach(function(track) {
19 | track.detach().forEach(function(detachedElement) {
20 | detachedElement.remove();
21 | });
22 | });
23 | }
24 |
25 | function detachParticipantTracks(participant) {
26 | var tracks = Array.from(participant.tracks.values());
27 | detachTracks(tracks);
28 | }
29 |
30 | // Check for WebRTC
31 | if (!navigator.webkitGetUserMedia && !navigator.mozGetUserMedia) {
32 | alert('WebRTC is not available in your browser.');
33 | }
34 |
35 | // When we are about to transition away from this page, disconnect
36 | // from the room, if joined.
37 | window.addEventListener('beforeunload', leaveRoomIfJoined);
38 |
39 | $.getJSON('/token', function(data) {
40 | identity = data.identity;
41 |
42 | document.getElementById('room-controls').style.display = 'block';
43 |
44 | // Bind button to join room
45 | document.getElementById('button-join').onclick = function () {
46 | roomName = document.getElementById('room-name').value;
47 | if (roomName) {
48 | log("Joining room '" + roomName + "'...");
49 |
50 | var connectOptions = { name: roomName, logLevel: 'debug' };
51 | if (previewTracks) {
52 | connectOptions.tracks = previewTracks;
53 | }
54 |
55 | Twilio.Video.connect(data.token, connectOptions).then(roomJoined, function(error) {
56 | log('Could not connect to Twilio: ' + error.message);
57 | });
58 | } else {
59 | alert('Please enter a room name.');
60 | }
61 | };
62 |
63 | // Bind button to leave room
64 | document.getElementById('button-leave').onclick = function () {
65 | log('Leaving room...');
66 | activeRoom.disconnect();
67 | };
68 | });
69 |
70 | // Successfully connected!
71 | function roomJoined(room) {
72 | activeRoom = room;
73 |
74 | log("Joined as '" + identity + "'");
75 | document.getElementById('button-join').style.display = 'none';
76 | document.getElementById('button-leave').style.display = 'inline';
77 |
78 | // Draw local video, if not already previewing
79 | var previewContainer = document.getElementById('local-media');
80 | if (!previewContainer.querySelector('video')) {
81 | attachParticipantTracks(room.localParticipant, previewContainer);
82 | }
83 |
84 | room.participants.forEach(function(participant) {
85 | log("Already in Room: '" + participant.identity + "'");
86 | var previewContainer = document.getElementById('remote-media');
87 | attachParticipantTracks(participant, previewContainer);
88 | });
89 |
90 | // When a participant joins, draw their video on screen
91 | room.on('participantConnected', function(participant) {
92 | log("Joining: '" + participant.identity + "'");
93 | });
94 |
95 | room.on('trackAdded', function(track, participant) {
96 | log(participant.identity + " added track: " + track.kind);
97 | var previewContainer = document.getElementById('remote-media');
98 | attachTracks([track], previewContainer);
99 | });
100 |
101 | room.on('trackRemoved', function(track, participant) {
102 | log(participant.identity + " removed track: " + track.kind);
103 | detachTracks([track]);
104 | });
105 |
106 | // When a participant disconnects, note in log
107 | room.on('participantDisconnected', function(participant) {
108 | log("Participant '" + participant.identity + "' left the room");
109 | detachParticipantTracks(participant);
110 | });
111 |
112 | // When we are disconnected, stop capturing local video
113 | // Also remove media for all remote participants
114 | room.on('disconnected', function() {
115 | log('Left');
116 | detachParticipantTracks(room.localParticipant);
117 | room.participants.forEach(detachParticipantTracks);
118 | activeRoom = null;
119 | document.getElementById('button-join').style.display = 'inline';
120 | document.getElementById('button-leave').style.display = 'none';
121 | });
122 | }
123 |
124 | // Local video preview
125 | document.getElementById('button-preview').onclick = function() {
126 | var localTracksPromise = previewTracks
127 | ? Promise.resolve(previewTracks)
128 | : Twilio.Video.createLocalTracks();
129 |
130 | localTracksPromise.then(function(tracks) {
131 | previewTracks = tracks;
132 | var previewContainer = document.getElementById('local-media');
133 | if (!previewContainer.querySelector('video')) {
134 | attachTracks(tracks, previewContainer);
135 | }
136 | }, function(error) {
137 | console.error('Unable to access local media', error);
138 | log('Unable to access Camera and Microphone');
139 | });
140 | };
141 |
142 | // Activity log
143 | function log(message) {
144 | var logDiv = document.getElementById('log');
145 | logDiv.innerHTML += '