OLD | NEW |
1 /** | 1 /** |
2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 * Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 /** @private */ | 7 /** @private */ |
8 var gTransformOutgoingSdp = function(sdp) { return sdp; } | 8 var gTransformOutgoingSdp = function(sdp) { return sdp; }; |
9 | 9 |
10 /** @private */ | 10 /** @private */ |
11 var gCreateAnswerConstraints = {}; | 11 var gCreateAnswerConstraints = {}; |
12 | 12 |
13 /** @private */ | 13 /** @private */ |
14 var gCreateOfferConstraints = {}; | 14 var gCreateOfferConstraints = {}; |
15 | 15 |
16 /** @private */ | 16 /** @private */ |
17 var gDataChannel = null; | 17 var gDataChannel = null; |
18 | 18 |
19 /** @private */ | 19 /** @private */ |
20 var gDataStatusCallback = function(status) {}; | 20 var gDataStatusCallback = function(status) {}; |
21 | 21 |
22 /** @private */ | 22 /** @private */ |
23 var gDataCallback = function(data) {}; | 23 var gDataCallback = function(data) {}; |
24 | 24 |
25 /** @private */ | 25 /** @private */ |
26 var gDtmfSender = null; | 26 var gDtmfSender = null; |
27 | 27 |
28 /** @private */ | 28 /** @private */ |
29 var gDtmfOnToneChange = function(tone) {}; | 29 var gDtmfOnToneChange = function(tone) {}; |
30 | 30 |
31 /** | 31 /** |
32 * Sets the transform to apply just before setting the local description and | 32 * Sets the transform to apply just before setting the local description and |
33 * sending to the peer. | 33 * sending to the peer. |
34 * @param{function} transformFunction A function which takes one SDP string as | 34 * @param {function} transformFunction A function which takes one SDP string as |
35 * argument and returns the modified SDP string. | 35 * argument and returns the modified SDP string. |
36 */ | 36 */ |
37 function setOutgoingSdpTransform(transformFunction) { | 37 function setOutgoingSdpTransform(transformFunction) { |
38 gTransformOutgoingSdp = transformFunction; | 38 gTransformOutgoingSdp = transformFunction; |
39 } | 39 } |
40 | 40 |
41 /** | 41 /** |
42 * Sets the MediaConstraints to be used for PeerConnection createAnswer() calls. | 42 * Sets the MediaConstraints to be used for PeerConnection createAnswer() calls. |
43 * @param{string} mediaConstraints The constraints, as defined in the | 43 * @param {string} mediaConstraints The constraints, as defined in the |
44 * PeerConnection JS API spec. | 44 * PeerConnection JS API spec. |
45 */ | 45 */ |
46 function setCreateAnswerConstraints(mediaConstraints) { | 46 function setCreateAnswerConstraints(mediaConstraints) { |
47 gCreateAnswerConstraints = mediaConstraints; | 47 gCreateAnswerConstraints = mediaConstraints; |
48 } | 48 } |
49 | 49 |
50 /** | 50 /** |
51 * Sets the MediaConstraints to be used for PeerConnection createOffer() calls. | 51 * Sets the MediaConstraints to be used for PeerConnection createOffer() calls. |
52 * @param{string} mediaConstraints The constraints, as defined in the | 52 * @param {string} mediaConstraints The constraints, as defined in the |
53 * PeerConnection JS API spec. | 53 * PeerConnection JS API spec. |
54 */ | 54 */ |
55 function setCreateOfferConstraints(mediaConstraints) { | 55 function setCreateOfferConstraints(mediaConstraints) { |
56 gCreateOfferConstraints = mediaConstraints; | 56 gCreateOfferConstraints = mediaConstraints; |
57 } | 57 } |
58 | 58 |
59 /** | 59 /** |
60 * Sets the callback functions that will receive DataChannel readyState updates | 60 * Sets the callback functions that will receive DataChannel readyState updates |
61 * and received data. | 61 * and received data. |
62 * @param{function} status_callback The function that will receive a string with | 62 * @param {function} status_callback The function that will receive a string |
| 63 * with |
63 * the current DataChannel readyState. | 64 * the current DataChannel readyState. |
64 * @param{function} data_callback The function that will a string with data | 65 * @param {function} data_callback The function that will a string with data |
65 * received from the remote peer. | 66 * received from the remote peer. |
66 */ | 67 */ |
67 function setDataCallbacks(status_callback, data_callback) { | 68 function setDataCallbacks(status_callback, data_callback) { |
68 gDataStatusCallback = status_callback; | 69 gDataStatusCallback = status_callback; |
69 gDataCallback = data_callback; | 70 gDataCallback = data_callback; |
70 } | 71 } |
71 | 72 |
72 /** | 73 /** |
73 * Sends data on an active DataChannel. | 74 * Sends data on an active DataChannel. |
74 * @param{string} data The string that will be sent to the remote peer. | 75 * @param {string} data The string that will be sent to the remote peer. |
75 */ | 76 */ |
76 function sendDataOnChannel(data) { | 77 function sendDataOnChannel(data) { |
77 if (gDataChannel == null) | 78 if (gDataChannel == null) |
78 throw failTest('Trying to send data, but there is no DataChannel.'); | 79 throw failTest('Trying to send data, but there is no DataChannel.'); |
79 gDataChannel.send(data); | 80 gDataChannel.send(data); |
80 } | 81 } |
81 | 82 |
82 /** | 83 /** |
83 * Sets the callback function that will receive DTMF sender ontonechange events. | 84 * Sets the callback function that will receive DTMF sender ontonechange events. |
84 * @param{function} ontonechange The function that will receive a string with | 85 * @param {function} ontonechange The function that will receive a string with |
85 * the tone that has just begun playout. | 86 * the tone that has just begun playout. |
86 */ | 87 */ |
87 function setOnToneChange(ontonechange) { | 88 function setOnToneChange(ontonechange) { |
88 gDtmfOnToneChange = ontonechange; | 89 gDtmfOnToneChange = ontonechange; |
89 } | 90 } |
90 | 91 |
91 /** | 92 /** |
92 * Inserts DTMF tones on an active DTMF sender. | 93 * Inserts DTMF tones on an active DTMF sender. |
93 * @param{string} data The string that will be sent to the remote peer. | 94 * @param {string} data The string that will be sent to the remote peer. |
94 */ | 95 */ |
95 function insertDtmf(tones, duration, interToneGap) { | 96 function insertDtmf(tones, duration, interToneGap) { |
96 if (gDtmfSender == null) | 97 if (gDtmfSender == null) |
97 throw failTest('Trying to send DTMF, but there is no DTMF sender.'); | 98 throw failTest('Trying to send DTMF, but there is no DTMF sender.'); |
98 gDtmfSender.insertDTMF(tones, duration, interToneGap); | 99 gDtmfSender.insertDTMF(tones, duration, interToneGap); |
99 } | 100 } |
100 | 101 |
101 // Public interface towards the other javascript files, such as | 102 // Public interface towards the other javascript files, such as |
102 // message_handling.js. The contract for these functions is described in | 103 // message_handling.js. The contract for these functions is described in |
103 // message_handling.js. | 104 // message_handling.js. |
104 | 105 |
105 function handleMessage(peerConnection, message) { | 106 function handleMessage(peerConnection, message) { |
106 var parsed_msg = JSON.parse(message); | 107 var parsed_msg = JSON.parse(message); |
107 if (parsed_msg.type) { | 108 if (parsed_msg.type) { |
108 var session_description = new RTCSessionDescription(parsed_msg); | 109 var session_description = new RTCSessionDescription(parsed_msg); |
109 peerConnection.setRemoteDescription( | 110 peerConnection.setRemoteDescription( |
110 session_description, | 111 session_description, |
111 function() { success_('setRemoteDescription'); }, | 112 function() { success_('setRemoteDescription'); }, |
112 function() { failure_('setRemoteDescription'); }); | 113 function() { failure_('setRemoteDescription'); }); |
113 if (session_description.type == "offer") { | 114 if (session_description.type == 'offer') { |
114 debug('createAnswer with constraints: ' + | 115 debug('createAnswer with constraints: ' + |
115 JSON.stringify(gCreateAnswerConstraints, null, ' ')); | 116 JSON.stringify(gCreateAnswerConstraints, null, ' ')); |
116 peerConnection.createAnswer( | 117 peerConnection.createAnswer( |
117 setLocalAndSendMessage_, | 118 setLocalAndSendMessage_, |
118 function() { failure_('createAnswer'); }, | 119 function() { failure_('createAnswer'); }, |
119 gCreateAnswerConstraints); | 120 gCreateAnswerConstraints); |
120 } | 121 } |
121 return; | 122 return; |
122 } else if (parsed_msg.candidate) { | 123 } else if (parsed_msg.candidate) { |
123 var candidate = new RTCIceCandidate(parsed_msg); | 124 var candidate = new RTCIceCandidate(parsed_msg); |
124 peerConnection.addIceCandidate(candidate); | 125 peerConnection.addIceCandidate(candidate); |
125 return; | 126 return; |
126 } | 127 } |
127 addTestFailure("unknown message received"); | 128 addTestFailure('unknown message received'); |
128 return; | 129 return; |
129 } | 130 } |
130 | 131 |
131 function createPeerConnection(stun_server) { | 132 function createPeerConnection(stun_server) { |
132 servers = {iceServers:[{url:"stun:" + stun_server}]}; | 133 servers = {iceServers: [{url: 'stun:' + stun_server}]}; |
133 try { | 134 try { |
134 peerConnection = new webkitRTCPeerConnection( | 135 peerConnection = new webkitRTCPeerConnection( |
135 servers, { optional:[ { RtpDataChannels: true } ]}); | 136 servers, { optional: [{ RtpDataChannels: true }]}); |
136 } catch (exception) { | 137 } catch (exception) { |
137 throw failTest('Failed to create peer connection: ' + exception); | 138 throw failTest('Failed to create peer connection: ' + exception); |
138 } | 139 } |
139 peerConnection.onaddstream = addStreamCallback_; | 140 peerConnection.onaddstream = addStreamCallback_; |
140 peerConnection.onremovestream = removeStreamCallback_; | 141 peerConnection.onremovestream = removeStreamCallback_; |
141 peerConnection.onicecandidate = iceCallback_; | 142 peerConnection.onicecandidate = iceCallback_; |
142 peerConnection.ondatachannel = onCreateDataChannelCallback_; | 143 peerConnection.ondatachannel = onCreateDataChannelCallback_; |
143 return peerConnection; | 144 return peerConnection; |
144 } | 145 } |
145 | 146 |
146 function setupCall(peerConnection) { | 147 function setupCall(peerConnection) { |
147 debug('createOffer with constraints: ' + | 148 debug('createOffer with constraints: ' + |
148 JSON.stringify(gCreateOfferConstraints, null, ' ')); | 149 JSON.stringify(gCreateOfferConstraints, null, ' ')); |
149 peerConnection.createOffer( | 150 peerConnection.createOffer( |
150 setLocalAndSendMessage_, | 151 setLocalAndSendMessage_, |
151 function () { failure_('createOffer'); }, | 152 function() { failure_('createOffer'); }, |
152 gCreateOfferConstraints); | 153 gCreateOfferConstraints); |
153 } | 154 } |
154 | 155 |
155 function answerCall(peerConnection, message) { | 156 function answerCall(peerConnection, message) { |
156 handleMessage(peerConnection, message); | 157 handleMessage(peerConnection, message); |
157 } | 158 } |
158 | 159 |
159 function createDataChannel(peerConnection, label) { | 160 function createDataChannel(peerConnection, label) { |
160 if (gDataChannel != null && gDataChannel.readyState != 'closed') { | 161 if (gDataChannel != null && gDataChannel.readyState != 'closed') { |
161 throw failTest('Creating DataChannel, but we already have one.'); | 162 throw failTest('Creating DataChannel, but we already have one.'); |
162 } | 163 } |
163 | 164 |
164 gDataChannel = peerConnection.createDataChannel(label, { reliable : false }); | 165 gDataChannel = peerConnection.createDataChannel(label, { reliable: false }); |
165 debug('DataChannel with label ' + gDataChannel.label + ' initiated locally.'); | 166 debug('DataChannel with label ' + gDataChannel.label + ' initiated locally.'); |
166 hookupDataChannelEvents(); | 167 hookupDataChannelEvents(); |
167 } | 168 } |
168 | 169 |
169 function closeDataChannel(peerConnection) { | 170 function closeDataChannel(peerConnection) { |
170 if (gDataChannel == null) | 171 if (gDataChannel == null) |
171 throw failTest('Closing DataChannel, but none exists.'); | 172 throw failTest('Closing DataChannel, but none exists.'); |
172 debug('DataChannel with label ' + gDataChannel.label + ' is beeing closed.'); | 173 debug('DataChannel with label ' + gDataChannel.label + ' is beeing closed.'); |
173 gDataChannel.close(); | 174 gDataChannel.close(); |
174 } | 175 } |
(...skipping 27 matching lines...) Expand all Loading... |
202 sendToPeer(gRemotePeerId, JSON.stringify(event.candidate)); | 203 sendToPeer(gRemotePeerId, JSON.stringify(event.candidate)); |
203 } | 204 } |
204 | 205 |
205 /** @private */ | 206 /** @private */ |
206 function setLocalAndSendMessage_(session_description) { | 207 function setLocalAndSendMessage_(session_description) { |
207 session_description.sdp = gTransformOutgoingSdp(session_description.sdp); | 208 session_description.sdp = gTransformOutgoingSdp(session_description.sdp); |
208 peerConnection.setLocalDescription( | 209 peerConnection.setLocalDescription( |
209 session_description, | 210 session_description, |
210 function() { success_('setLocalDescription'); }, | 211 function() { success_('setLocalDescription'); }, |
211 function() { failure_('setLocalDescription'); }); | 212 function() { failure_('setLocalDescription'); }); |
212 debug("Sending SDP message:\n" + session_description.sdp); | 213 debug('Sending SDP message:\n' + session_description.sdp); |
213 sendToPeer(gRemotePeerId, JSON.stringify(session_description)); | 214 sendToPeer(gRemotePeerId, JSON.stringify(session_description)); |
214 } | 215 } |
215 | 216 |
216 /** @private */ | 217 /** @private */ |
217 function addStreamCallback_(event) { | 218 function addStreamCallback_(event) { |
218 debug('Receiving remote stream...'); | 219 debug('Receiving remote stream...'); |
219 var videoTag = document.getElementById('remote-view'); | 220 var videoTag = document.getElementById('remote-view'); |
220 videoTag.src = webkitURL.createObjectURL(event.stream); | 221 videoTag.src = webkitURL.createObjectURL(event.stream); |
221 | 222 |
222 // Due to crbug.com/110938 the size is 0 when onloadedmetadata fires. | 223 // Due to crbug.com/110938 the size is 0 when onloadedmetadata fires. |
223 // videoTag.onloadedmetadata = updateVideoTagSize_('remote-view'); | 224 // videoTag.onloadedmetadata = displayVideoSize_(videoTag); |
224 // Use setTimeout as a workaround for now. | 225 // Use setTimeout as a workaround for now. |
225 setTimeout(function() {updateVideoTagSize_('remote-view')}, 500); | 226 // Displays the remote video size for both the video element and the stream. |
| 227 setTimeout(function() {displayVideoSize_(videoTag);}, 500); |
226 } | 228 } |
227 | 229 |
228 /** @private */ | 230 /** @private */ |
229 function removeStreamCallback_(event) { | 231 function removeStreamCallback_(event) { |
230 debug('Call ended.'); | 232 debug('Call ended.'); |
231 document.getElementById("remote-view").src = ''; | 233 document.getElementById('remote-view').src = ''; |
232 } | 234 } |
233 | 235 |
234 /** @private */ | 236 /** @private */ |
235 function onCreateDataChannelCallback_(event) { | 237 function onCreateDataChannelCallback_(event) { |
236 if (gDataChannel != null && gDataChannel.readyState != 'closed') { | 238 if (gDataChannel != null && gDataChannel.readyState != 'closed') { |
237 throw failTest('Received DataChannel, but we already have one.'); | 239 throw failTest('Received DataChannel, but we already have one.'); |
238 } | 240 } |
239 | 241 |
240 gDataChannel = event.channel; | 242 gDataChannel = event.channel; |
241 debug('DataChannel with label ' + gDataChannel.label + | 243 debug('DataChannel with label ' + gDataChannel.label + |
(...skipping 10 matching lines...) Expand all Loading... |
252 // about the created data channel. | 254 // about the created data channel. |
253 onDataChannelReadyStateChange_(); | 255 onDataChannelReadyStateChange_(); |
254 } | 256 } |
255 | 257 |
256 /** @private */ | 258 /** @private */ |
257 function onDataChannelReadyStateChange_() { | 259 function onDataChannelReadyStateChange_() { |
258 var readyState = gDataChannel.readyState; | 260 var readyState = gDataChannel.readyState; |
259 debug('DataChannel state:' + readyState); | 261 debug('DataChannel state:' + readyState); |
260 gDataStatusCallback(readyState); | 262 gDataStatusCallback(readyState); |
261 } | 263 } |
OLD | NEW |