| 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 |