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