Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / test / data / webrtc / getusermedia.js
blobbee3ae100f91569c15781c1eeb38c9ea7b5137cd
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 */
7 /**
8 * See http://dev.w3.org/2011/webrtc/editor/getusermedia.html for more
9 * information on getUserMedia.
12 /**
13 * Keeps track of our local stream (e.g. what our local webcam is streaming).
14 * @private
16 var gLocalStream = null;
18 /**
19 * The MediaConstraints to use when connecting the local stream with a peer
20 * connection.
21 * @private
23 var gAddStreamConstraints = {};
25 /**
26 * String which keeps track of what happened when we requested user media.
27 * @private
29 var gRequestWebcamAndMicrophoneResult = 'not-called-yet';
31 /**
32 * Used as a shortcut. Moved to the top of the page due to race conditions.
33 * @param {string} id is a case-sensitive string representing the unique ID of
34 * the element being sought.
35 * @return {string} id returns the element object specified as a parameter
37 $ = function(id) {
38 return document.getElementById(id);
41 /**
42 * This function asks permission to use the webcam and mic from the browser. It
43 * will return ok-requested to the test. This does not mean the request was
44 * approved though. The test will then have to click past the dialog that
45 * appears in Chrome, which will run either the OK or failed callback as a
46 * a result. To see which callback was called, use obtainGetUserMediaResult().
48 * @param {string} constraints Defines what to be requested, with mandatory
49 * and optional constraints defined. The contents of this parameter depends
50 * on the WebRTC version. This should be JavaScript code that we eval().
52 function doGetUserMedia(constraints) {
53 if (!getUserMedia) {
54 returnToTest('Browser does not support WebRTC.');
55 return;
57 try {
58 var evaluatedConstraints;
59 eval('evaluatedConstraints = ' + constraints);
60 } catch (exception) {
61 throw failTest('Not valid JavaScript expression: ' + constraints);
63 debug('Requesting doGetUserMedia: constraints: ' + constraints);
64 getUserMedia(evaluatedConstraints,
65 function(stream) {
66 ensureGotAllExpectedStreams_(stream, constraints);
67 getUserMediaOkCallback_(stream);
69 getUserMediaFailedCallback_);
70 returnToTest('ok-requested');
73 /**
74 * Must be called after calling doGetUserMedia.
75 * @return {string} Returns not-called-yet if we have not yet been called back
76 * by WebRTC. Otherwise it returns either ok-got-stream or
77 * failed-with-error-x (where x is the error code from the error
78 * callback) depending on which callback got called by WebRTC.
80 function obtainGetUserMediaResult() {
81 // Translate from the old error to the new. Remove when rename fully deployed.
82 if (gRequestWebcamAndMicrophoneResult === 'PERMISSION_DENIED')
83 gRequestWebcamAndMicrophoneResult = 'PermissionDeniedError';
85 returnToTest(gRequestWebcamAndMicrophoneResult);
86 return gRequestWebcamAndMicrophoneResult;
89 /**
90 * Stops the local stream.
92 function stopLocalStream() {
93 if (gLocalStream == null)
94 throw failTest('Tried to stop local stream, ' +
95 'but media access is not granted.');
97 gLocalStream.stop();
98 returnToTest('ok-stopped');
101 // Functions callable from other JavaScript modules.
104 * Adds the current local media stream to a peer connection.
105 * @param {RTCPeerConnection} peerConnection
107 function addLocalStreamToPeerConnection(peerConnection) {
108 if (gLocalStream == null)
109 throw failTest('Tried to add local stream to peer connection, ' +
110 'but there is no stream yet.');
111 try {
112 peerConnection.addStream(gLocalStream, gAddStreamConstraints);
113 } catch (exception) {
114 throw failTest('Failed to add stream with constraints ' +
115 gAddStreamConstraints + ': ' + exception);
117 debug('Added local stream.');
121 * Removes the local stream from the peer connection.
122 * @param {rtcpeerconnection} peerConnection
124 function removeLocalStreamFromPeerConnection(peerConnection) {
125 if (gLocalStream == null)
126 throw failTest('Tried to remove local stream from peer connection, ' +
127 'but there is no stream yet.');
128 try {
129 peerConnection.removeStream(gLocalStream);
130 } catch (exception) {
131 throw failTest('Could not remove stream: ' + exception);
133 debug('Removed local stream.');
137 * @return {string} Returns the current local stream - |gLocalStream|.
139 function getLocalStream() {
140 return gLocalStream;
143 // Internals.
146 * @private
147 * @param {MediaStream} stream Media stream from getUserMedia.
148 * @param {String} constraints The constraints passed
150 function ensureGotAllExpectedStreams_(stream, constraints) {
151 var requestedVideo = /video\s*:\s*true/i;
152 if (requestedVideo.test(constraints) && stream.getVideoTracks().length == 0) {
153 gRequestWebcamAndMicrophoneResult = 'failed-to-get-video';
154 throw ('Requested video, but did not receive a video stream from ' +
155 'getUserMedia. Perhaps the machine you are running on ' +
156 'does not have a webcam.');
158 var requestedAudio = /audio\s*:\s*true/i;
159 if (requestedAudio.test(constraints) && stream.getAudioTracks().length == 0) {
160 gRequestWebcamAndMicrophoneResult = 'failed-to-get-audio';
161 throw ('Requested audio, but did not receive an audio stream ' +
162 'from getUserMedia. Perhaps the machine you are running ' +
163 'on does not have audio devices.');
168 * @private
169 * @param {MediaStream} stream Media stream.
171 function getUserMediaOkCallback_(stream) {
172 gLocalStream = stream;
173 gRequestWebcamAndMicrophoneResult = 'ok-got-stream';
175 if (stream.getVideoTracks().length > 0) {
176 // Show the video tag if we did request video in the getUserMedia call.
177 var videoTag = $('local-view');
178 attachMediaStream(videoTag, stream);
180 // Due to crbug.com/110938 the size is 0 when onloadedmetadata fires.
181 // videoTag.onloadedmetadata = displayVideoSize_(videoTag);.
182 // Use setTimeout as a workaround for now.
183 setTimeout(function() {displayVideoSize_(videoTag);}, 500);
188 * @private
189 * @param {string} videoTagId The ID of the video tag to update.
190 * @param {string} width The width of the video to update the video tag, if
191 * width or height is 0, size will be taken from videoTag.videoWidth.
192 * @param {string} height The height of the video to update the video tag, if
193 * width or height is 0 size will be taken from the videoTag.videoHeight.
195 function updateVideoTagSize_(videoTagId, width, height) {
196 var videoTag = $(videoTagId);
197 if (width > 0 || height > 0) {
198 videoTag.width = width;
199 videoTag.height = height;
201 else {
202 if (videoTag.videoWidth > 0 || videoTag.videoHeight > 0) {
203 videoTag.width = videoTag.videoWidth;
204 videoTag.height = videoTag.videoHeight;
206 else {
207 debug('"' + videoTagId + '" video stream size is 0, skipping resize');
210 debug('Set video tag "' + videoTagId + '" size to ' + videoTag.width + 'x' +
211 videoTag.height);
212 displayVideoSize_(videoTag);
216 * @private
217 * @param {string} videoTag The ID of the video tag + stream used to
218 * write the size to a HTML tag based on id if the div's exists.
220 function displayVideoSize_(videoTag) {
221 if ($(videoTag.id + '-stream-size') && $(videoTag.id + '-size')) {
222 if (videoTag.videoWidth > 0 || videoTag.videoHeight > 0) {
223 $(videoTag.id + '-stream-size').innerHTML = '(stream size: ' +
224 videoTag.videoWidth + 'x' +
225 videoTag.videoHeight + ')';
226 $(videoTag.id + '-size').innerHTML = videoTag.width + 'x' +
227 videoTag.height;
230 else {
231 debug('Skipping updating -stream-size and -size tags due to div\'s are ' +
232 'missing');
237 * Enumerates the audio and video devices available in Chrome and adds the
238 * devices to the HTML elements with Id 'audiosrc' and 'videosrc'.
239 * Checks if device enumeration is supported and if the 'audiosrc' + 'videosrc'
240 * elements exists, if not a debug printout will be displayed.
241 * If the device label is empty, audio/video + sequence number will be used to
242 * populate the name. Also makes sure the children has been loaded in order
243 * to update the constraints.
245 function getDevices() {
246 if ($('audiosrc') && $('videosrc') && $('get-devices')) {
247 var audio_select = $('audiosrc');
248 var video_select = $('videosrc');
249 var get_devices = $('get-devices');
250 audio_select.innerHTML = '';
251 video_select.innerHTML = '';
252 try {
253 eval(MediaStreamTrack.getSources(function() {}));
254 } catch (exception) {
255 audio_select.disabled = true;
256 video_select.disabled = true;
257 get_devices.disabled = true;
258 updateGetUserMediaConstraints();
259 debug('Device enumeration not supported. ' + exception);
260 return;
262 MediaStreamTrack.getSources(function(devices) {
263 for (var i = 0; i < devices.length; i++) {
264 var option = document.createElement('option');
265 option.value = devices[i].id;
266 option.text = devices[i].label;
267 if (devices[i].kind == 'audio') {
268 if (option.text == '') {
269 option.text = devices[i].id;
271 audio_select.appendChild(option);
273 else if (devices[i].kind == 'video') {
274 if (option.text == '') {
275 option.text = devices[i].id;
277 video_select.appendChild(option);
279 else {
280 debug('Device type ' + devices[i].kind + ' not recognized, cannot ' +
281 'enumerate device. Currently only device types \'audio\' and ' +
282 '\'video\' are supported');
283 updateGetUserMediaConstraints();
284 return;
288 checkIfDeviceDropdownsArePopulated();
290 else {
291 debug('Device DOM elements cannot be found, cannot display devices');
292 updateGetUserMediaConstraints();
297 * This provides the selected source id from the objects in the parameters
298 * provided to this function. If the audio_select or video_select objects does
299 * not have any HTMLOptions children it will return null in the source object.
300 * @param {object} audio_select HTML drop down element with audio devices added
301 * as HTMLOptionsCollection children.
302 * @param {object} video_select HTML drop down element with audio devices added
303 * as HTMLPptionsCollection children.
304 * @return {object} audio_id video_id Containing audio and video source ID from
305 * the selected devices in the drop down menus provided as parameters to
306 * this function.
308 function getSourcesFromField(audio_select, video_select) {
309 var source = {
310 audio_id: null,
311 video_id: null
313 if (audio_select.options.length > 0) {
314 source.audio_id = audio_select.options[audio_select.selectedIndex].value;
316 if (video_select.options.length > 0) {
317 source.video_id = video_select.options[video_select.selectedIndex].value;
319 return source;
323 * @private
324 * @param {NavigatorUserMediaError} error Error containing details.
326 function getUserMediaFailedCallback_(error) {
327 // Translate from the old error to the new. Remove when rename fully deployed.
328 var errorName = error.name;
329 if (errorName === 'PERMISSION_DENIED')
330 errorName = 'PermissionDeniedError';
332 debug('GetUserMedia FAILED: Maybe the camera is in use by another process?');
333 gRequestWebcamAndMicrophoneResult = 'failed-with-error-' + errorName;
334 debug(gRequestWebcamAndMicrophoneResult);