Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 var Cc = SpecialPowers.Cc;
6 var Ci = SpecialPowers.Ci;
7 var Cr = SpecialPowers.Cr;
9 // Specifies whether we are using fake streams to run this automation
10 var FAKE_ENABLED = true;
13 /**
14 * Create the necessary HTML elements for head and body as used by Mochitests
15 *
16 * @param {object} meta
17 * Meta information of the test
18 * @param {string} meta.title
19 * Description of the test
20 * @param {string} [meta.bug]
21 * Bug the test was created for
22 * @param {boolean} [meta.visible=false]
23 * Visibility of the media elements
24 */
25 function createHTML(meta) {
26 var test = document.getElementById('test');
28 // Create the head content
29 var elem = document.createElement('meta');
30 elem.setAttribute('charset', 'utf-8');
31 document.head.appendChild(elem);
33 var title = document.createElement('title');
34 title.textContent = meta.title;
35 document.head.appendChild(title);
37 // Create the body content
38 var anchor = document.createElement('a');
39 anchor.setAttribute('target', '_blank');
41 if (meta.bug) {
42 anchor.setAttribute('href', 'https://bugzilla.mozilla.org/show_bug.cgi?id=' + meta.bug);
43 }
45 anchor.textContent = meta.title;
46 document.body.insertBefore(anchor, test);
48 var display = document.createElement('p');
49 display.setAttribute('id', 'display');
50 document.body.insertBefore(display, test);
52 var content = document.createElement('div');
53 content.setAttribute('id', 'content');
54 content.style.display = meta.visible ? 'block' : "none";
55 document.body.appendChild(content);
56 }
59 /**
60 * Create the HTML element if it doesn't exist yet and attach
61 * it to the content node.
62 *
63 * @param {string} type
64 * Type of media element to create ('audio' or 'video')
65 * @param {string} label
66 * Description to use for the element
67 * @return {HTMLMediaElement} The created HTML media element
68 */
69 function createMediaElement(type, label) {
70 var id = label + '_' + type;
71 var element = document.getElementById(id);
73 // Sanity check that we haven't created the element already
74 if (element)
75 return element;
77 element = document.createElement(type === 'audio' ? 'audio' : 'video');
78 element.setAttribute('id', id);
79 element.setAttribute('height', 100);
80 element.setAttribute('width', 150);
81 element.setAttribute('controls', 'controls');
82 document.getElementById('content').appendChild(element);
84 return element;
85 }
88 /**
89 * Wrapper function for mozGetUserMedia to allow a singular area of control
90 * for determining whether we run this with fake devices or not.
91 *
92 * @param {Dictionary} constraints
93 * The constraints for this mozGetUserMedia callback
94 * @param {Function} onSuccess
95 * The success callback if the stream is successfully retrieved
96 * @param {Function} onError
97 * The error callback if the stream fails to be retrieved
98 */
99 function getUserMedia(constraints, onSuccess, onError) {
100 constraints["fake"] = FAKE_ENABLED;
102 info("Call getUserMedia for " + JSON.stringify(constraints));
103 navigator.mozGetUserMedia(constraints, onSuccess, onError);
104 }
107 /**
108 * Setup any Mochitest for WebRTC by enabling the preference for
109 * peer connections. As by bug 797979 it will also enable mozGetUserMedia()
110 * and disable the mozGetUserMedia() permission checking.
111 *
112 * @param {Function} aCallback
113 * Test method to execute after initialization
114 */
115 function runTest(aCallback) {
116 if (window.SimpleTest) {
117 // Running as a Mochitest.
118 SimpleTest.waitForExplicitFinish();
119 SpecialPowers.pushPrefEnv({'set': [
120 ['dom.messageChannel.enabled', true],
121 ['media.peerconnection.enabled', true],
122 ['media.peerconnection.identity.enabled', true],
123 ['media.peerconnection.identity.timeout', 12000],
124 ['media.navigator.permission.disabled', true]]
125 }, function () {
126 try {
127 aCallback();
128 }
129 catch (err) {
130 generateErrorCallback()(err);
131 }
132 });
133 } else {
134 // Steeplechase, let it call the callback.
135 window.run_test = function(is_initiator) {
136 var options = {is_local: is_initiator,
137 is_remote: !is_initiator};
138 aCallback(options);
139 };
140 // Also load the steeplechase test code.
141 var s = document.createElement("script");
142 s.src = "/test.js";
143 document.head.appendChild(s);
144 }
145 }
147 /**
148 * Checks that the media stream tracks have the expected amount of tracks
149 * with the correct kind and id based on the type and constraints given.
150 *
151 * @param {Object} constraints specifies whether the stream should have
152 * audio, video, or both
153 * @param {String} type the type of media stream tracks being checked
154 * @param {sequence<MediaStreamTrack>} mediaStreamTracks the media stream
155 * tracks being checked
156 */
157 function checkMediaStreamTracksByType(constraints, type, mediaStreamTracks) {
158 if(constraints[type]) {
159 is(mediaStreamTracks.length, 1, 'One ' + type + ' track shall be present');
161 if(mediaStreamTracks.length) {
162 is(mediaStreamTracks[0].kind, type, 'Track kind should be ' + type);
163 ok(mediaStreamTracks[0].id, 'Track id should be defined');
164 }
165 } else {
166 is(mediaStreamTracks.length, 0, 'No ' + type + ' tracks shall be present');
167 }
168 }
170 /**
171 * Check that the given media stream contains the expected media stream
172 * tracks given the associated audio & video constraints provided.
173 *
174 * @param {Object} constraints specifies whether the stream should have
175 * audio, video, or both
176 * @param {MediaStream} mediaStream the media stream being checked
177 */
178 function checkMediaStreamTracks(constraints, mediaStream) {
179 checkMediaStreamTracksByType(constraints, 'audio',
180 mediaStream.getAudioTracks());
181 checkMediaStreamTracksByType(constraints, 'video',
182 mediaStream.getVideoTracks());
183 }
185 /**
186 * Utility methods
187 */
189 /**
190 * Returns the contents of a blob as text
191 *
192 * @param {Blob} blob
193 The blob to retrieve the contents from
194 * @param {Function} onSuccess
195 Callback with the blobs content as parameter
196 */
197 function getBlobContent(blob, onSuccess) {
198 var reader = new FileReader();
200 // Listen for 'onloadend' which will always be called after a success or failure
201 reader.onloadend = function (event) {
202 onSuccess(event.target.result);
203 };
205 reader.readAsText(blob);
206 }
208 /**
209 * Generates a callback function fired only under unexpected circumstances
210 * while running the tests. The generated function kills off the test as well
211 * gracefully.
212 *
213 * @param {String} [message]
214 * An optional message to show if no object gets passed into the
215 * generated callback method.
216 */
217 function generateErrorCallback(message) {
218 var stack = new Error().stack.split("\n");
219 stack.shift(); // Don't include this instantiation frame
221 /**
222 * @param {object} aObj
223 * The object fired back from the callback
224 */
225 return function (aObj) {
226 if (aObj) {
227 if (aObj.name && aObj.message) {
228 ok(false, "Unexpected callback for '" + aObj.name +
229 "' with message = '" + aObj.message + "' at " +
230 JSON.stringify(stack));
231 } else {
232 ok(false, "Unexpected callback with = '" + aObj +
233 "' at: " + JSON.stringify(stack));
234 }
235 } else {
236 ok(false, "Unexpected callback with message = '" + message +
237 "' at: " + JSON.stringify(stack));
238 }
239 SimpleTest.finish();
240 }
241 }
243 /**
244 * Generates a callback function fired only for unexpected events happening.
245 *
246 * @param {String} description
247 Description of the object for which the event has been fired
248 * @param {String} eventName
249 Name of the unexpected event
250 */
251 function unexpectedEventAndFinish(message, eventName) {
252 var stack = new Error().stack.split("\n");
253 stack.shift(); // Don't include this instantiation frame
255 return function () {
256 ok(false, "Unexpected event '" + eventName + "' fired with message = '" +
257 message + "' at: " + JSON.stringify(stack));
258 SimpleTest.finish();
259 }
260 }