blob: 6be2932078024e6e709c24551fb63c84f7acb305 [file] [log] [blame]
kjellander@webrtc.orgc4225b62013-11-06 13:26:34 +00001// Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
2//
3// Use of this source code is governed by a BSD-style license
4// that can be found in the LICENSE file in the root of the source
5// tree. An additional intellectual property rights grant can be found
6// in the file PATENTS. All contributing project authors may
7// be found in the AUTHORS file in the root of the source tree.
8
9setup({timeout:10000});
10
11// Helper functions to minimize code duplication.
12function failedCallback(test) {
13 return test.step_func(function (error) {
14 assert_unreached('Should not get an error callback');
15 });
16}
17function invokeGetUserMedia(test, okCallback) {
18 getUserMedia({ video: true, audio: true }, okCallback,
19 failedCallback(test));
20}
21
22// 4.2 MediaStream.
23var mediaStreamTest = async_test('4.2 MediaStream');
24
25function verifyMediaStream(stream) {
26 // TODO(kjellander): Add checks for default values where applicable.
27 test(function () {
28 assert_own_property(stream, 'id');
29 assert_true(typeof stream.id === 'string');
30 assert_readonly(stream, 'id');
31 }, '[MediaStream] id attribute');
32
33 test(function () {
34 assert_inherits(stream, 'getAudioTracks');
35 assert_true(typeof stream.getAudioTracks === 'function');
36 }, '[MediaStream] getAudioTracks function');
37
38 test(function () {
39 assert_inherits(stream, 'getVideoTracks');
40 assert_true(typeof stream.getVideoTracks === 'function');
41 }, '[MediaStream] getVideoTracks function');
42
43 test(function () {
44 assert_inherits(stream, 'getTrackById');
45 assert_true(typeof stream.getTrackById === 'function');
46 }, '[MediaStream] getTrackById function');
47
48 test(function () {
49 assert_inherits(stream, 'addTrack');
50 assert_true(typeof stream.addTrack === 'function');
51 }, '[MediaStream] addTrack function');
52
53 test(function () {
54 assert_inherits(stream, 'removeTrack');
55 assert_true(typeof stream.removeTrack === 'function');
56 }, '[MediaStream] removeTrack function');
57
58 test(function () {
59 // Missing in Chrome.
60 assert_inherits(stream, 'clone');
61 assert_true(typeof stream.clone === 'function');
62 }, '[MediaStream] clone function');
63
64 test(function () {
65 assert_own_property(stream, 'ended');
66 assert_true(typeof stream.ended === 'boolean');
67 assert_readonly(stream, 'ended');
68 }, '[MediaStream] ended attribute');
69
70 test(function () {
71 assert_own_property(stream, 'onended');
72 assert_true(stream.onended === null);
73 }, '[MediaStream] onended EventHandler');
74
75 test(function () {
76 assert_own_property(stream, 'onaddtrack');
77 assert_true(stream.onaddtrack === null);
78 }, '[MediaStream] onaddtrack EventHandler');
79
80 test(function () {
81 assert_own_property(stream, 'onremovetrack');
82 assert_true(stream.onremovetrack === null);
83 }, '[MediaStream] onremovetrack EventHandler');
84}
85
86mediaStreamTest.step(function() {
87 var okCallback = mediaStreamTest.step_func(function (stream) {
88 verifyMediaStream(stream);
89
90 var videoTracks = stream.getVideoTracks();
91 assert_true(videoTracks.length > 0);
92
93 // Verify event handlers are working.
94 stream.onaddtrack = onAddTrackCallback
95 stream.onremovetrack = onRemoveTrackCallback
96 stream.removeTrack(videoTracks[0]);
97 stream.addTrack(videoTracks[0]);
98 mediaStreamTest.done();
99 });
100 var onAddTrackCallback = mediaStreamTest.step_func(function () {
101 // TODO(kjellander): verify number of tracks.
102 mediaStreamTest.done();
103 });
104 var onRemoveTrackCallback = mediaStreamTest.step_func(function () {
105 // TODO(kjellander): verify number of tracks.
106 mediaStreamTest.done();
107 });
108 invokeGetUserMedia(mediaStreamTest, okCallback);;
109});
110
111// 4.3 MediaStreamTrack.
112var mediaStreamTrackTest = async_test('4.3 MediaStreamTrack');
113
114function verifyTrack(type, track) {
115 test(function () {
116 assert_own_property(track, 'kind');
117 assert_readonly(track, 'kind');
118 assert_true(typeof track.kind === 'string',
119 'kind is an object (DOMString)');
120 }, '[MediaStreamTrack (' + type + ')] kind attribute');
121
122 test(function () {
123 assert_own_property(track, 'id');
124 assert_readonly(track, 'id');
125 assert_true(typeof track.id === 'string',
126 'id is an object (DOMString)');
127 }, '[MediaStreamTrack (' + type + ')] id attribute');
128
129 test(function () {
130 assert_own_property(track, 'label');
131 assert_readonly(track, 'label');
132 assert_true(typeof track.label === 'string',
133 'label is an object (DOMString)');
134 }, '[MediaStreamTrack (' + type + ')] label attribute');
135
136 test(function () {
137 assert_own_property(track, 'enabled');
138 assert_true(typeof track.enabled === 'boolean');
139 assert_true(track.enabled, 'enabled property must be true initially');
140 }, '[MediaStreamTrack (' + type + ')] enabled attribute');
141
142 test(function () {
143 // Missing in Chrome.
144 assert_own_property(track, 'muted');
145 assert_readonly(track, 'muted');
146 assert_true(typeof track.muted === 'boolean');
147 assert_false(track.muted, 'muted property must be false initially');
148 }, '[MediaStreamTrack (' + type + ')] muted attribute');
149
150 test(function () {
151 assert_own_property(track, 'onmute');
152 assert_true(track.onmute === null);
153 }, '[MediaStreamTrack (' + type + ')] onmute EventHandler');
154
155 test(function () {
156 assert_own_property(track, 'onunmute');
157 assert_true(track.onunmute === null);
158 }, '[MediaStreamTrack (' + type + ')] onunmute EventHandler');
159
160 test(function () {
161 // Missing in Chrome.
162 assert_own_property(track, '_readonly');
163 assert_readonly(track, '_readonly');
164 assert_true(typeof track._readonly === 'boolean');
165 }, '[MediaStreamTrack (' + type + ')] _readonly attribute');
166
167 test(function () {
168 // Missing in Chrome.
169 assert_own_property(track, 'remote');
170 assert_readonly(track, 'remote');
171 assert_true(typeof track.remote === 'boolean');
172 }, '[MediaStreamTrack (' + type + ')] remote attribute');
173
174 test(function () {
175 assert_own_property(track, 'readyState');
176 assert_readonly(track, 'readyState');
177 assert_true(typeof track.readyState === 'string');
178 // TODO(kjellander): verify the initial state.
179 }, '[MediaStreamTrack (' + type + ')] readyState attribute');
180
181 test(function () {
182 // Missing in Chrome.
183 assert_own_property(track, 'onstarted');
184 assert_true(track.onstarted === null);
185 }, '[MediaStreamTrack (' + type + ')] onstarted EventHandler');
186
187 test(function () {
188 assert_own_property(track, 'onended');
189 assert_true(track.onended === null);
190 }, '[MediaStreamTrack (' + type + ')] onended EventHandler');
191
192 test(function () {
193 // Missing in Chrome.
194 assert_inherits(track, 'getSourceInfos');
195 assert_true(typeof track.getSourceInfos === 'function');
196 }, '[MediaStreamTrack (' + type + ')]: getSourceInfos function');
197
198 test(function () {
199 // Missing in Chrome.
200 assert_inherits(track, 'constraints');
201 assert_true(typeof track.constraints === 'function');
202 }, '[MediaStreamTrack (' + type + ')]: constraints function');
203
204 test(function () {
205 // Missing in Chrome.
206 assert_inherits(track, 'states');
207 assert_true(typeof track.states === 'function');
208 }, '[MediaStreamTrack (' + type + ')]: states function');
209
210 test(function () {
211 // Missing in Chrome.
212 assert_inherits(track, 'capabilities');
213 assert_true(typeof track.capabilities === 'function');
214 }, '[MediaStreamTrack (' + type + ')]: capabilities function');
215
216 test(function () {
217 // Missing in Chrome.
218 assert_inherits(track, 'applyConstraints');
219 assert_true(typeof track.applyConstraints === 'function');
220 }, '[MediaStreamTrack (' + type + ')]: applyConstraints function');
221
222 test(function () {
223 // Missing in Chrome.
224 assert_own_property(track, 'onoverconstrained');
225 assert_true(track.onoverconstrained === null);
226 }, '[MediaStreamTrack (' + type + ')] onoverconstrained EventHandler');
227
228 test(function () {
229 // Missing in Chrome.
230 assert_inherits(track, 'clone');
231 assert_true(typeof track.clone === 'function');
232 }, '[MediaStreamTrack (' + type + ')] clone function');
233
234 test(function () {
235 // Missing in Chrome.
236 assert_inherits(track, 'stop');
237 assert_true(typeof track.stop === 'function');
238 }, '[MediaStreamTrack (' + type + ')] stop function');
239};
240mediaStreamTrackTest.step(function() {
241 var okCallback = mediaStreamTrackTest.step_func(function (stream) {
242 verifyTrack('audio', stream.getAudioTracks()[0]);
243 verifyTrack('video', stream.getVideoTracks()[0]);
244 mediaStreamTrackTest.done();
245 });
246 invokeGetUserMedia(mediaStreamTrackTest, okCallback);
247});
248
249mediaStreamTrackTest.step(function() {
250 var okCallback = mediaStreamTrackTest.step_func(function (stream) {
251 // Verify event handlers are working.
252 var track = stream.getVideoTracks()[0];
253 track.onended = onendedCallback
254 track.stop();
255 mediaStreamTrackTest.done();
256 });
257 var onendedCallback = mediaStreamTrackTest.step_func(function () {
258 assert_true(track.ended);
259 mediaStreamTrackTest.done();
260 });
261 invokeGetUserMedia(mediaStreamTrackTest, okCallback);
262});
263
264// 4.4 MediaStreamTrackEvent tests.
265var mediaStreamTrackEventTest = async_test('4.4 MediaStreamTrackEvent');
266mediaStreamTrackEventTest.step(function() {
267 var okCallback = mediaStreamTrackEventTest.step_func(function (stream) {
268 // TODO(kjellander): verify attributes
269 mediaStreamTrackEventTest.done();
270 });
271 invokeGetUserMedia(mediaStreamTrackEventTest, okCallback);
272});
273
274// 4.5 Video and Audio Tracks tests.
275var avTracksTest = async_test('4.5 Video and Audio Tracks');
276avTracksTest.step(function() {
277 var okCallback = avTracksTest.step_func(function (stream) {
278 // TODO(kjellander): verify attributes
279 avTracksTest.done();
280 });
281 invokeGetUserMedia(avTracksTest, okCallback);
282});
283
284// 5. The model: sources, sinks, constraints, and states
285
286// 6. Source states
287// 6.1 Dictionary MediaSourceStates Members
288
289// 7. Source capabilities
290// 7.1 Dictionary CapabilityRange Members
291// 7.2 CapabilityList array
292// 7.3 Dictionary AllVideoCapabilities Members
293// 7.4 Dictionary AllAudioCapabilities Members
294
295// 8. URL tests.
296var createObjectURLTest = async_test('8.1 URL createObjectURL method');
297createObjectURLTest.step(function() {
298 var okCallback = createObjectURLTest.step_func(function (stream) {
299 var url = webkitURL.createObjectURL(stream);
300 assert_true(typeof url === 'string');
301 createObjectURLTest.done();
302 });
303 invokeGetUserMedia(createObjectURLTest, okCallback);
304});
305
306// 9. MediaStreams as Media Elements.
307var mediaElementsTest = async_test('9. MediaStreams as Media Elements');
308
309function verifyVideoTagWithStream(videoTag) {
310 test(function () {
311 assert_equals(videoTag.buffered.length, 0);
312 }, '[Video tag] buffered attribute');
313
314 test(function () {
315 // Attempts to alter currentTime shall be ignored.
316 assert_true(videoTag.currentTime >= 0);
317 assert_throws('InvalidStateError',
318 function () { videoTag.currentTime = 1234; },
319 'Attempts to modify currentTime shall throw ' +
320 'InvalidStateError');
321 }, '[Video tag] currentTime attribute');
322
323 test(function () {
324 assert_equals(videoTag.duration, Infinity, 'videoTag.duration');
325 }, '[Video tag] duration attribute');
326
327 test(function () {
328 assert_false(videoTag.seeking, 'videoTag.seeking');
329 }, '[Video tag] seeking attribute');
330
331 test(function () {
332 assert_equals(videoTag.defaultPlaybackRate, 1.0);
333 assert_throws('DOMException',
334 function () { videoTag.defaultPlaybackRate = 2.0; },
335 'Attempts to alter videoTag.defaultPlaybackRate MUST fail');
336 }, '[Video tag] defaultPlaybackRate attribute');
337
338 test(function () {
339 assert_equals(videoTag.playbackRate, 1.0);
340 assert_throws('DOMException',
341 function () { videoTag.playbackRate = 2.0; },
342 'Attempts to alter videoTag.playbackRate MUST fail');
343 }, '[Video tag] playbackRate attribute');
344
345 test(function () {
346 assert_equals(videoTag.played.length, 1, 'videoTag.played.length');
347 assert_equals(videoTag.played.start(0), 0);
348 assert_true(videoTag.played.end(0) >= videoTag.currentTime);
349 }, '[Video tag] played attribute');
350
351 test(function () {
352 assert_equals(videoTag.seekable.length, 0);
353 assert_equals(videoTag.seekable.start(), videoTag.currentTime);
354 assert_equals(videoTag.seekable.end(), videoTag.currentTime);
355 assert_equals(videoTag.startDate, NaN, 'videoTag.startDate');
356 }, '[Video tag] seekable attribute');
357
358 test(function () {
359 assert_false(videoTag.loop);
360 }, '[Video tag] loop attribute');
361};
362
363mediaElementsTest.step(function() {
364 var okCallback = mediaElementsTest.step_func(function (stream) {
365 var videoTag = document.getElementById('local-view');
366 // Call the polyfill wrapper to attach the media stream to this element.
367 attachMediaStream(videoTag, stream);
368 verifyVideoTagWithStream(videoTag);
369 mediaElementsTest.done();
370 });
371 invokeGetUserMedia(mediaElementsTest, okCallback);
372});
373
374// 11. Obtaining local multimedia content.
375
376// 11.1 NavigatorUserMedia.
377var getUserMediaTest = async_test('11.1 NavigatorUserMedia');
378getUserMediaTest.step(function() {
379 var okCallback = getUserMediaTest.step_func(function (stream) {
380 assert_true(stream !== null);
381 getUserMediaTest.done();
382 });
383
384 // boolean parameters, without failure callback:
385 getUserMedia({ video: true, audio: true }, okCallback);
386 getUserMedia({ video: true, audio: false }, okCallback);
387 getUserMedia({ video: false, audio: true }, okCallback);
388
389 // boolean parameters, with failure callback:
390 getUserMedia({ video: true, audio: true }, okCallback,
391 failedCallback(getUserMediaTest));
392 getUserMedia({ video: true, audio: false }, okCallback,
393 failedCallback(getUserMediaTest));
394 getUserMedia({ video: false, audio: true }, okCallback,
395 failedCallback(getUserMediaTest));
396});
397
398// 11.2 MediaStreamConstraints.
399var constraintsTest = async_test('11.2 MediaStreamConstraints');
400constraintsTest.step(function() {
401 var okCallback = constraintsTest.step_func(function (stream) {
402 assert_true(stream !== null);
403 constraintsTest.done();
404 });
405
406 // Constraints on video.
407 // See http://webrtc.googlecode.com/svn/trunk/samples/js/demos/html/constraints-and-stats.html
408 // for more examples of constraints.
409 var constraints = {};
410 constraints.audio = true;
411 constraints.video = { mandatory: {}, optional: [] };
412 constraints.video.mandatory.minWidth = 640;
413 constraints.video.mandatory.minHeight = 480;
414 constraints.video.mandatory.minFrameRate = 15;
415
416 getUserMedia(constraints, okCallback, failedCallback(constraintsTest));
417});
418
419// 11.3 NavigatorUserMediaSuccessCallback.
420var successCallbackTest =
421 async_test('11.3 NavigatorUserMediaSuccessCallback');
422successCallbackTest.step(function() {
423 var okCallback = successCallbackTest.step_func(function (stream) {
424 assert_true(stream !== null);
425 successCallbackTest.done();
426 });
427 invokeGetUserMedia(successCallbackTest, okCallback);
428});
429
430// 11.4 NavigatorUserMediaError and NavigatorUserMediaErrorCallback.
431var errorCallbackTest = async_test('11.4 NavigatorUserMediaError and ' +
432 'NavigatorUserMediaErrorCallback');
433errorCallbackTest.step(function() {
434 var okCallback = errorCallbackTest.step_func(function (stream) {
435 assert_unreached('Should not get a success callback');
436 });
437 var errorCallback = errorCallbackTest.step_func(function (error) {
438 assert_own_property(error, 'name');
439 assert_readonly(error.name);
440 assert_true(typeof error.name === 'string');
441 assert_equals(error.name, 'ConstraintNotSatisfiedError', 'error.name');
442 errorCallbackTest.done();
443 });
444 // Setting both audio and video to false triggers an error callback.
445 // TODO(kjellander): Figure out if there's a way in the spec to trigger an
446 // error callback.
447
448 // TODO(kjellander): Investigate why the error callback is not called when
449 // false/false is provided in Chrome.
450 getUserMedia({ video: false, audio: false }, okCallback, errorCallback);
451});