summaryrefslogtreecommitdiffstats
path: root/dom/media/test
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/test')
-rw-r--r--dom/media/test/16bit_wave_extrametadata.wavbin0 -> 97814 bytes
-rw-r--r--dom/media/test/16bit_wave_extrametadata.wav^headers^1
-rw-r--r--dom/media/test/320x240.ogvbin0 -> 28942 bytes
-rw-r--r--dom/media/test/320x240.ogv^headers^1
-rw-r--r--dom/media/test/448636.ogvbin0 -> 7799 bytes
-rw-r--r--dom/media/test/448636.ogv^headers^1
-rw-r--r--dom/media/test/A4.ogvbin0 -> 94372 bytes
-rw-r--r--dom/media/test/A4.ogv^headers^1
-rw-r--r--dom/media/test/VID_0001.oggbin0 -> 633435 bytes
-rw-r--r--dom/media/test/VID_0001.ogg^headers^1
-rw-r--r--dom/media/test/allowed.sjs56
-rw-r--r--dom/media/test/audio-gaps-short.oggbin0 -> 5233 bytes
-rw-r--r--dom/media/test/audio-gaps-short.ogg^headers^1
-rw-r--r--dom/media/test/audio-gaps.oggbin0 -> 12306 bytes
-rw-r--r--dom/media/test/audio-gaps.ogg^headers^1
-rw-r--r--dom/media/test/audio-overhang.oggbin0 -> 45463 bytes
-rw-r--r--dom/media/test/audio-overhang.ogg^headers^1
-rw-r--r--dom/media/test/audio.wavbin0 -> 1422 bytes
-rw-r--r--dom/media/test/audio.wav^headers^1
-rw-r--r--dom/media/test/background_video.js115
-rw-r--r--dom/media/test/bad-signature.vtt1
-rw-r--r--dom/media/test/badtags.oggbin0 -> 5033 bytes
-rw-r--r--dom/media/test/badtags.ogg^headers^1
-rw-r--r--dom/media/test/basic.vtt27
-rw-r--r--dom/media/test/beta-phrasebook.oggbin0 -> 47411 bytes
-rw-r--r--dom/media/test/beta-phrasebook.ogg^headers^1
-rw-r--r--dom/media/test/big-short.wavbin0 -> 12366 bytes
-rw-r--r--dom/media/test/big-short.wav^headers^1
-rw-r--r--dom/media/test/big.wavbin0 -> 102444 bytes
-rw-r--r--dom/media/test/big.wav^headers^1
-rw-r--r--dom/media/test/bipbop-cenc-audio-key1.xml28
-rw-r--r--dom/media/test/bipbop-cenc-audio-key2.xml28
-rw-r--r--dom/media/test/bipbop-cenc-audio1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop-cenc-audio1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop-cenc-audio2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop-cenc-audio2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop-cenc-audio3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop-cenc-audio3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop-cenc-audioinit.mp4bin0 -> 1000 bytes
-rw-r--r--dom/media/test/bipbop-cenc-audioinit.mp4^headers^1
-rw-r--r--dom/media/test/bipbop-cenc-video-key1.xml28
-rw-r--r--dom/media/test/bipbop-cenc-video-key2.xml28
-rw-r--r--dom/media/test/bipbop-cenc-video1.m4sbin0 -> 25211 bytes
-rw-r--r--dom/media/test/bipbop-cenc-video1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop-cenc-video2.m4sbin0 -> 22934 bytes
-rw-r--r--dom/media/test/bipbop-cenc-video2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop-cenc-videoinit.mp4bin0 -> 1058 bytes
-rw-r--r--dom/media/test/bipbop-cenc-videoinit.mp4^headers^1
-rwxr-xr-xdom/media/test/bipbop-cenc.sh29
-rw-r--r--dom/media/test/bipbop-frag-cenc.xml57
-rw-r--r--dom/media/test/bipbop-lateaudio.mp4bin0 -> 70404 bytes
-rw-r--r--dom/media/test/bipbop-lateaudio.mp4^headers^1
-rw-r--r--dom/media/test/bipbop-no-edts.mp4bin0 -> 285681 bytes
-rw-r--r--dom/media/test/bipbop.mp4bin0 -> 285765 bytes
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-4.m4sbin0 -> 389 bytes
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-4.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-init.mp4bin0 -> 1020 bytes
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-4.m4sbin0 -> 389 bytes
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-4.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-init.mp4bin0 -> 1020 bytes
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-video-key1-1.m4sbin0 -> 37646 bytes
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-video-key1-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-video-key1-init.mp4bin0 -> 1086 bytes
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-video-key1-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-video-key2-1.m4sbin0 -> 37646 bytes
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-video-key2-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-video-key2-init.mp4bin0 -> 1086 bytes
-rw-r--r--dom/media/test/bipbop_225w_175kbps-cenc-video-key2-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_225w_175kbps.mp4bin0 -> 38713 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key1-1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key1-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key1-2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key1-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key1-3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key1-3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key1-4.m4sbin0 -> 389 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key1-4.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key1-init.mp4bin0 -> 874 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key1-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key2-1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key2-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key2-2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key2-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key2-3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key2-3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key2-4.m4sbin0 -> 389 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key2-4.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key2-init.mp4bin0 -> 874 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-audio-key2-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-video-key1-1.m4sbin0 -> 25211 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-video-key1-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-video-key1-2.m4sbin0 -> 22938 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-video-key1-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-video-key1-init.mp4bin0 -> 932 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-video-key1-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-video-key2-1.m4sbin0 -> 25211 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-video-key2-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-video-key2-2.m4sbin0 -> 22938 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-video-key2-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-video-key2-init.mp4bin0 -> 932 bytes
-rw-r--r--dom/media/test/bipbop_300_215kbps-cenc-video-key2-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_300_215kbps.mp4bin0 -> 47795 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-4.m4sbin0 -> 389 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-4.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-init.mp4bin0 -> 1020 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-4.m4sbin0 -> 389 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-4.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-init.mp4bin0 -> 1020 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-1.m4sbin0 -> 25211 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-2.m4sbin0 -> 22938 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-init.mp4bin0 -> 1094 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-1.m4sbin0 -> 25211 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-2.m4sbin0 -> 22938 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-init.mp4bin0 -> 1094 bytes
-rw-r--r--dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_300wp_227kbps.mp4bin0 -> 48355 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-4.m4sbin0 -> 389 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-4.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-init.mp4bin0 -> 1020 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-4.m4sbin0 -> 389 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-4.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-init.mp4bin0 -> 1020 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-video-key1-1.m4sbin0 -> 53149 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-video-key1-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-video-key1-init.mp4bin0 -> 1088 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-video-key1-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-video-key2-1.m4sbin0 -> 53149 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-video-key2-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-video-key2-init.mp4bin0 -> 1088 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-cenc-video-key2-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps-clearkey-audio.webmbin0 -> 7553 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-clearkey-audio.webm^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps-clearkey-video-vp8.webmbin0 -> 44671 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-clearkey-video-vp8.webm^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps-clearkey-video-vp9.webmbin0 -> 46030 bytes
-rw-r--r--dom/media/test/bipbop_360w_253kbps-clearkey-video-vp9.webm^headers^1
-rw-r--r--dom/media/test/bipbop_360w_253kbps.mp4bin0 -> 54218 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key1-1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key1-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key1-2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key1-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key1-3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key1-3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key1-4.m4sbin0 -> 389 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key1-4.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key1-init.mp4bin0 -> 874 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key1-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key2-1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key2-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key2-2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key2-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key2-3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key2-3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key2-4.m4sbin0 -> 389 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key2-4.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key2-init.mp4bin0 -> 874 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-audio-key2-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-video-key1-1.m4sbin0 -> 68025 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-video-key1-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-video-key1-2.m4sbin0 -> 66457 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-video-key1-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-video-key1-init.mp4bin0 -> 932 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-video-key1-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-video-key2-1.m4sbin0 -> 68025 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-video-key2-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-video-key2-2.m4sbin0 -> 66457 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-video-key2-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-video-key2-init.mp4bin0 -> 932 bytes
-rw-r--r--dom/media/test/bipbop_480_624kbps-cenc-video-key2-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_480_624kbps.mp4bin0 -> 133264 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key1-1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key1-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key1-2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key1-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key1-3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key1-3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key1-4.m4sbin0 -> 389 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key1-4.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key1-init.mp4bin0 -> 874 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key1-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key2-1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key2-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key2-2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key2-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key2-3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key2-3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key2-4.m4sbin0 -> 389 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key2-4.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key2-init.mp4bin0 -> 874 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-audio-key2-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-video-key1-1.m4sbin0 -> 101203 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-video-key1-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-video-key1-2.m4sbin0 -> 99366 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-video-key1-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-video-key1-init.mp4bin0 -> 932 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-video-key1-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-video-key2-1.m4sbin0 -> 101203 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-video-key2-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-video-key2-2.m4sbin0 -> 99366 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-video-key2-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-video-key2-init.mp4bin0 -> 932 bytes
-rw-r--r--dom/media/test/bipbop_480_959kbps-cenc-video-key2-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_480_959kbps.mp4bin0 -> 199351 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-4.m4sbin0 -> 389 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-4.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-init.mp4bin0 -> 1020 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-4.m4sbin0 -> 389 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-4.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-init.mp4bin0 -> 1020 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-1.m4sbin0 -> 101203 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-2.m4sbin0 -> 99366 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-init.mp4bin0 -> 1094 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-1.m4sbin0 -> 101203 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-2.m4sbin0 -> 99366 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-init.mp4bin0 -> 1094 bytes
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_1001kbps.mp4bin0 -> 199911 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-4.m4sbin0 -> 389 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-4.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-init.mp4bin0 -> 1020 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-1.m4sbin0 -> 921 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-2.m4sbin0 -> 565 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-3.m4sbin0 -> 977 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-3.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-4.m4sbin0 -> 389 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-4.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-init.mp4bin0 -> 1020 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-1.m4sbin0 -> 68025 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-2.m4sbin0 -> 66457 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-init.mp4bin0 -> 1094 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-1.m4sbin0 -> 68025 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-1.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-2.m4sbin0 -> 66457 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-2.m4s^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-init.mp4bin0 -> 1094 bytes
-rw-r--r--dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-init.mp4^headers^1
-rw-r--r--dom/media/test/bipbop_480wp_663kbps.mp4bin0 -> 133824 bytes
-rw-r--r--dom/media/test/black100x100-aspect3to2.ogvbin0 -> 3428 bytes
-rw-r--r--dom/media/test/black100x100-aspect3to2.ogv^headers^1
-rw-r--r--dom/media/test/bogus.duh45
-rw-r--r--dom/media/test/bogus.ogv45
-rw-r--r--dom/media/test/bogus.ogv^headers^1
-rw-r--r--dom/media/test/bogus.wav45
-rw-r--r--dom/media/test/bogus.wav^headers^1
-rw-r--r--dom/media/test/bug1066943.webmbin0 -> 18442 bytes
-rw-r--r--dom/media/test/bug1066943.webm^headers^1
-rw-r--r--dom/media/test/bug1301226-odd.wavbin0 -> 244 bytes
-rw-r--r--dom/media/test/bug1301226-odd.wav^headers^1
-rw-r--r--dom/media/test/bug1301226.wavbin0 -> 240 bytes
-rw-r--r--dom/media/test/bug1301226.wav^headers^1
-rw-r--r--dom/media/test/bug461281.oggbin0 -> 16521 bytes
-rw-r--r--dom/media/test/bug461281.ogg^headers^1
-rw-r--r--dom/media/test/bug482461-theora.ogvbin0 -> 280904 bytes
-rw-r--r--dom/media/test/bug482461-theora.ogv^headers^1
-rw-r--r--dom/media/test/bug482461.ogvbin0 -> 305785 bytes
-rw-r--r--dom/media/test/bug482461.ogv^headers^1
-rw-r--r--dom/media/test/bug495129.ogvbin0 -> 122207 bytes
-rw-r--r--dom/media/test/bug495129.ogv^headers^1
-rw-r--r--dom/media/test/bug495794.oggbin0 -> 4837 bytes
-rw-r--r--dom/media/test/bug495794.ogg^headers^1
-rw-r--r--dom/media/test/bug498380.ogvbin0 -> 65535 bytes
-rw-r--r--dom/media/test/bug498380.ogv^headers^1
-rw-r--r--dom/media/test/bug498855-1.ogvbin0 -> 20480 bytes
-rw-r--r--dom/media/test/bug498855-1.ogv^headers^1
-rw-r--r--dom/media/test/bug498855-2.ogvbin0 -> 20480 bytes
-rw-r--r--dom/media/test/bug498855-2.ogv^headers^1
-rw-r--r--dom/media/test/bug498855-3.ogvbin0 -> 20480 bytes
-rw-r--r--dom/media/test/bug498855-3.ogv^headers^1
-rw-r--r--dom/media/test/bug499519.ogvbin0 -> 20480 bytes
-rw-r--r--dom/media/test/bug499519.ogv^headers^1
-rw-r--r--dom/media/test/bug500311.ogvbin0 -> 55834 bytes
-rw-r--r--dom/media/test/bug500311.ogv^headers^1
-rw-r--r--dom/media/test/bug501279.oggbin0 -> 2361 bytes
-rw-r--r--dom/media/test/bug501279.ogg^headers^1
-rw-r--r--dom/media/test/bug504613.ogvbin0 -> 35000 bytes
-rw-r--r--dom/media/test/bug504613.ogv^headers^1
-rw-r--r--dom/media/test/bug504644.ogvbin0 -> 131114 bytes
-rw-r--r--dom/media/test/bug504644.ogv^headers^1
-rw-r--r--dom/media/test/bug504843.ogvbin0 -> 65536 bytes
-rw-r--r--dom/media/test/bug504843.ogv^headers^1
-rw-r--r--dom/media/test/bug506094.ogvbin0 -> 8195 bytes
-rw-r--r--dom/media/test/bug506094.ogv^headers^1
-rw-r--r--dom/media/test/bug516323.indexed.ogvbin0 -> 162193 bytes
-rw-r--r--dom/media/test/bug516323.indexed.ogv^headers^1
-rw-r--r--dom/media/test/bug516323.ogvbin0 -> 161789 bytes
-rw-r--r--dom/media/test/bug516323.ogv^headers^1
-rw-r--r--dom/media/test/bug520493.oggbin0 -> 3901 bytes
-rw-r--r--dom/media/test/bug520493.ogg^headers^1
-rw-r--r--dom/media/test/bug520500.oggbin0 -> 21978 bytes
-rw-r--r--dom/media/test/bug520500.ogg^headers^1
-rw-r--r--dom/media/test/bug520908.ogvbin0 -> 28942 bytes
-rw-r--r--dom/media/test/bug520908.ogv^headers^1
-rw-r--r--dom/media/test/bug523816.ogvbin0 -> 40585 bytes
-rw-r--r--dom/media/test/bug523816.ogv^headers^1
-rw-r--r--dom/media/test/bug533822.oggbin0 -> 35010 bytes
-rw-r--r--dom/media/test/bug533822.ogg^headers^1
-rw-r--r--dom/media/test/bug556821.ogvbin0 -> 196608 bytes
-rw-r--r--dom/media/test/bug556821.ogv^headers^1
-rw-r--r--dom/media/test/bug557094.ogvbin0 -> 76966 bytes
-rw-r--r--dom/media/test/bug557094.ogv^headers^1
-rw-r--r--dom/media/test/bug580982.webmbin0 -> 215594 bytes
-rw-r--r--dom/media/test/bug580982.webm^headers^1
-rw-r--r--dom/media/test/bug603918.webmbin0 -> 103227 bytes
-rw-r--r--dom/media/test/bug603918.webm^headers^1
-rw-r--r--dom/media/test/bug604067.webmbin0 -> 103227 bytes
-rw-r--r--dom/media/test/bug604067.webm^headers^1
-rw-r--r--dom/media/test/bug883173.vtt16
-rw-r--r--dom/media/test/can_play_type_dash.js27
-rw-r--r--dom/media/test/can_play_type_ogg.js78
-rw-r--r--dom/media/test/can_play_type_wave.js29
-rw-r--r--dom/media/test/can_play_type_webm.js54
-rw-r--r--dom/media/test/cancellable_request.sjs154
-rw-r--r--dom/media/test/chain.oggbin0 -> 63610 bytes
-rw-r--r--dom/media/test/chain.ogg^headers^1
-rw-r--r--dom/media/test/chain.ogvbin0 -> 45463 bytes
-rw-r--r--dom/media/test/chain.ogv^headers^1
-rw-r--r--dom/media/test/chain.opusbin0 -> 50101 bytes
-rw-r--r--dom/media/test/chain.opus^headers^1
-rw-r--r--dom/media/test/chained-audio-video.oggbin0 -> 92552 bytes
-rw-r--r--dom/media/test/chained-audio-video.ogg^headers^1
-rw-r--r--dom/media/test/chained-video.ogvbin0 -> 57906 bytes
-rw-r--r--dom/media/test/chained-video.ogv^headers^1
-rw-r--r--dom/media/test/contentType.sjs77
-rw-r--r--dom/media/test/crashtests/0-timescale.html14
-rw-r--r--dom/media/test/crashtests/0-timescale.mp4bin0 -> 14718 bytes
-rw-r--r--dom/media/test/crashtests/1012609.html9
-rw-r--r--dom/media/test/crashtests/1015662.html4
-rw-r--r--dom/media/test/crashtests/1020205.html22
-rw-r--r--dom/media/test/crashtests/1028458.html23
-rw-r--r--dom/media/test/crashtests/1041466.html21
-rw-r--r--dom/media/test/crashtests/1045650.html18
-rw-r--r--dom/media/test/crashtests/1080986.html3
-rw-r--r--dom/media/test/crashtests/1080986.wavbin0 -> 592 bytes
-rw-r--r--dom/media/test/crashtests/1122218.html24
-rw-r--r--dom/media/test/crashtests/1127188.html3
-rw-r--r--dom/media/test/crashtests/1157994.html21
-rw-r--r--dom/media/test/crashtests/1158427.html21
-rw-r--r--dom/media/test/crashtests/1185176.html24
-rw-r--r--dom/media/test/crashtests/1185192.html18
-rw-r--r--dom/media/test/crashtests/1223670.html23
-rw-r--r--dom/media/test/crashtests/1228484.html13
-rw-r--r--dom/media/test/crashtests/1236639.html9
-rw-r--r--dom/media/test/crashtests/1236639.mp3bin0 -> 1080 bytes
-rw-r--r--dom/media/test/crashtests/1291702.html72
-rw-r--r--dom/media/test/crashtests/1304948.html33
-rw-r--r--dom/media/test/crashtests/1319486.html27
-rw-r--r--dom/media/test/crashtests/459439-1.html36
-rw-r--r--dom/media/test/crashtests/466607-1.html14
-rw-r--r--dom/media/test/crashtests/466945-1.html25
-rw-r--r--dom/media/test/crashtests/468763-1.html1
-rw-r--r--dom/media/test/crashtests/474744-1.html15
-rw-r--r--dom/media/test/crashtests/481136-1.html3
-rw-r--r--dom/media/test/crashtests/492286-1.xhtml1
-rw-r--r--dom/media/test/crashtests/493915-1.html18
-rw-r--r--dom/media/test/crashtests/495794-1.html8
-rw-r--r--dom/media/test/crashtests/495794-1.oggbin0 -> 4837 bytes
-rw-r--r--dom/media/test/crashtests/576612-1.html15
-rw-r--r--dom/media/test/crashtests/691096-1.html31
-rw-r--r--dom/media/test/crashtests/752784-1.html15
-rw-r--r--dom/media/test/crashtests/789075-1.html9
-rw-r--r--dom/media/test/crashtests/789075.webmbin0 -> 12294 bytes
-rw-r--r--dom/media/test/crashtests/795892-1.html23
-rw-r--r--dom/media/test/crashtests/844563.html5
-rw-r--r--dom/media/test/crashtests/846612.html8
-rw-r--r--dom/media/test/crashtests/852838.html11
-rw-r--r--dom/media/test/crashtests/865537-1.html13
-rw-r--r--dom/media/test/crashtests/868504.html14
-rw-r--r--dom/media/test/crashtests/874869.html15
-rw-r--r--dom/media/test/crashtests/874915.html24
-rw-r--r--dom/media/test/crashtests/874934.html23
-rw-r--r--dom/media/test/crashtests/874952.html11
-rw-r--r--dom/media/test/crashtests/875144.html81
-rw-r--r--dom/media/test/crashtests/875596.html12
-rw-r--r--dom/media/test/crashtests/875911.html3
-rw-r--r--dom/media/test/crashtests/876024-1.html5
-rw-r--r--dom/media/test/crashtests/876024-2.html17
-rw-r--r--dom/media/test/crashtests/876118.html16
-rw-r--r--dom/media/test/crashtests/876207.html30
-rw-r--r--dom/media/test/crashtests/876215.html14
-rw-r--r--dom/media/test/crashtests/876249.html27
-rw-r--r--dom/media/test/crashtests/876252.html23
-rw-r--r--dom/media/test/crashtests/876834.html4
-rw-r--r--dom/media/test/crashtests/877527.html37
-rw-r--r--dom/media/test/crashtests/877820.html4
-rw-r--r--dom/media/test/crashtests/878014.html31
-rw-r--r--dom/media/test/crashtests/878328.html5
-rw-r--r--dom/media/test/crashtests/878407.html11
-rw-r--r--dom/media/test/crashtests/878478.html30
-rw-r--r--dom/media/test/crashtests/880129.html9
-rw-r--r--dom/media/test/crashtests/880202.html33
-rw-r--r--dom/media/test/crashtests/880342-1.html208
-rw-r--r--dom/media/test/crashtests/880342-2.html8
-rw-r--r--dom/media/test/crashtests/880384.html8
-rw-r--r--dom/media/test/crashtests/880404.html6
-rw-r--r--dom/media/test/crashtests/880724.html13
-rw-r--r--dom/media/test/crashtests/881775.html25
-rw-r--r--dom/media/test/crashtests/882549.html13
-rw-r--r--dom/media/test/crashtests/882956.html15
-rw-r--r--dom/media/test/crashtests/884459.html12
-rw-r--r--dom/media/test/crashtests/889042.html4
-rw-r--r--dom/media/test/crashtests/894104.html20
-rw-r--r--dom/media/test/crashtests/907986-1.html17
-rw-r--r--dom/media/test/crashtests/907986-2.html17
-rw-r--r--dom/media/test/crashtests/907986-3.html17
-rw-r--r--dom/media/test/crashtests/907986-4.html15
-rw-r--r--dom/media/test/crashtests/910171-1.html17
-rw-r--r--dom/media/test/crashtests/920987.html6
-rw-r--r--dom/media/test/crashtests/925619-1.html14
-rw-r--r--dom/media/test/crashtests/925619-2.html15
-rw-r--r--dom/media/test/crashtests/926619.html24
-rw-r--r--dom/media/test/crashtests/933151.html16
-rw-r--r--dom/media/test/crashtests/933156.html23
-rw-r--r--dom/media/test/crashtests/944851.html17
-rw-r--r--dom/media/test/crashtests/952756.html19
-rw-r--r--dom/media/test/crashtests/966636.html45
-rw-r--r--dom/media/test/crashtests/986901.html16
-rw-r--r--dom/media/test/crashtests/990794.html22
-rw-r--r--dom/media/test/crashtests/995289.html9
-rw-r--r--dom/media/test/crashtests/analyser-channels-1.html16
-rw-r--r--dom/media/test/crashtests/audiocontext-double-suspend.html5
-rw-r--r--dom/media/test/crashtests/buffer-source-duration-1.html14
-rw-r--r--dom/media/test/crashtests/buffer-source-ended-1.html16
-rw-r--r--dom/media/test/crashtests/buffer-source-resampling-start-1.html16
-rw-r--r--dom/media/test/crashtests/cors.webmbin0 -> 215529 bytes
-rw-r--r--dom/media/test/crashtests/cors.webm^headers^1
-rw-r--r--dom/media/test/crashtests/crashtests.list103
-rw-r--r--dom/media/test/crashtests/disconnect-wrong-destination.html13
-rw-r--r--dom/media/test/crashtests/doppler-1.html23
-rw-r--r--dom/media/test/crashtests/media-element-source-seek-1.html27
-rw-r--r--dom/media/test/crashtests/offline-buffer-source-ended-1.html15
-rw-r--r--dom/media/test/crashtests/oscillator-ended-1.html15
-rw-r--r--dom/media/test/crashtests/oscillator-ended-2.html15
-rw-r--r--dom/media/test/crashtests/sound.oggbin0 -> 2603 bytes
-rw-r--r--dom/media/test/crashtests/video-crash.webmbin0 -> 58482 bytes
-rw-r--r--dom/media/test/crashtests/video-replay-after-audio-end.html43
-rw-r--r--dom/media/test/dash/dash-manifest-garbled-webm.mpd35
-rw-r--r--dom/media/test/dash/dash-manifest-garbled.mpd1
-rw-r--r--dom/media/test/dash/dash-manifest-sjs.mpd35
-rw-r--r--dom/media/test/dash/dash-manifest.mpd35
-rw-r--r--dom/media/test/dash/dash-webm-audio-128k.webmbin0 -> 41946 bytes
-rw-r--r--dom/media/test/dash/dash-webm-video-320x180.webmbin0 -> 35123 bytes
-rw-r--r--dom/media/test/dash/dash-webm-video-428x240.webmbin0 -> 50206 bytes
-rw-r--r--dom/media/test/dash/garbled.webm1
-rw-r--r--dom/media/test/dash_detect_stream_switch.sjs114
-rw-r--r--dom/media/test/detodos-recorder-test.opusbin0 -> 1507 bytes
-rw-r--r--dom/media/test/detodos-recorder-test.opus^headers^1
-rw-r--r--dom/media/test/detodos-short.opusbin0 -> 648 bytes
-rw-r--r--dom/media/test/detodos-short.opus^headers^1
-rw-r--r--dom/media/test/detodos-short.webmbin0 -> 1085 bytes
-rw-r--r--dom/media/test/detodos-short.webm^headers^1
-rw-r--r--dom/media/test/detodos.opusbin0 -> 6270 bytes
-rw-r--r--dom/media/test/detodos.opus^headers^1
-rw-r--r--dom/media/test/detodos.webmbin0 -> 11701 bytes
-rw-r--r--dom/media/test/detodos.webm^headers^1
-rw-r--r--dom/media/test/dirac.oggbin0 -> 106338 bytes
-rw-r--r--dom/media/test/dirac.ogg^headers^1
-rw-r--r--dom/media/test/dynamic_redirect.sjs67
-rw-r--r--dom/media/test/dynamic_resource.sjs48
-rw-r--r--dom/media/test/eme.js495
-rw-r--r--dom/media/test/external/MANIFEST.in4
-rw-r--r--dom/media/test/external/README.md5
-rw-r--r--dom/media/test/external/docs/Makefile216
-rw-r--r--dom/media/test/external/docs/conf.py297
-rw-r--r--dom/media/test/external/docs/external_media_harness.rst19
-rw-r--r--dom/media/test/external/docs/external_media_tests.media_tests.video_puppeteer.rst27
-rw-r--r--dom/media/test/external/docs/external_media_tests.media_tests.youtube_puppeteer.rst26
-rw-r--r--dom/media/test/external/docs/external_media_tests.rst26
-rw-r--r--dom/media/test/external/docs/index.rst33
-rw-r--r--dom/media/test/external/docs/make.bat263
-rw-r--r--dom/media/test/external/external_media_harness/__init__.py5
-rw-r--r--dom/media/test/external/external_media_harness/runtests.py103
-rw-r--r--dom/media/test/external/external_media_harness/testcase.py362
-rw-r--r--dom/media/test/external/external_media_tests/__init__.py10
-rw-r--r--dom/media/test/external/external_media_tests/manifest.ini1
-rw-r--r--dom/media/test/external/external_media_tests/media_utils/__init__.py0
-rw-r--r--dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py448
-rw-r--r--dom/media/test/external/external_media_tests/media_utils/youtube_puppeteer.py496
-rw-r--r--dom/media/test/external/external_media_tests/playback/eme.ini1
-rw-r--r--dom/media/test/external/external_media_tests/playback/limiting_bandwidth.ini2
-rw-r--r--dom/media/test/external/external_media_tests/playback/manifest.ini1
-rw-r--r--dom/media/test/external/external_media_tests/playback/netflix_limiting_bandwidth.ini1
-rw-r--r--dom/media/test/external/external_media_tests/playback/test_eme_playback.py18
-rw-r--r--dom/media/test/external/external_media_tests/playback/test_eme_playback_limiting_bandwidth.py24
-rw-r--r--dom/media/test/external/external_media_tests/playback/test_full_playback.py25
-rw-r--r--dom/media/test/external/external_media_tests/playback/test_playback_limiting_bandwidth.py17
-rw-r--r--dom/media/test/external/external_media_tests/playback/test_shaka_playback.py42
-rw-r--r--dom/media/test/external/external_media_tests/playback/test_ultra_low_bandwidth.py15
-rw-r--r--dom/media/test/external/external_media_tests/playback/test_video_playback.py15
-rw-r--r--dom/media/test/external/external_media_tests/playback/youtube/manifest.ini1
-rw-r--r--dom/media/test/external/external_media_tests/playback/youtube/test_basic_playback.py74
-rw-r--r--dom/media/test/external/external_media_tests/playback/youtube/test_prefs.py46
-rw-r--r--dom/media/test/external/external_media_tests/resources/mozilla.html45
-rw-r--r--dom/media/test/external/external_media_tests/test_example.py21
-rw-r--r--dom/media/test/external/external_media_tests/urls/default.ini9
-rw-r--r--dom/media/test/external/external_media_tests/urls/netflix/default.ini8
-rw-r--r--dom/media/test/external/external_media_tests/urls/shaka-player/default.ini30
-rw-r--r--dom/media/test/external/external_media_tests/urls/youtube/archive/crash_videos.ini25
-rw-r--r--dom/media/test/external/external_media_tests/urls/youtube/archive/other_videos.ini19
-rw-r--r--dom/media/test/external/external_media_tests/urls/youtube/archive/video_data.ini21
-rw-r--r--dom/media/test/external/external_media_tests/urls/youtube/archive/youtube.ini38
-rw-r--r--dom/media/test/external/external_media_tests/urls/youtube/long1-720.ini5
-rw-r--r--dom/media/test/external/external_media_tests/urls/youtube/long2-crashes-720.ini39
-rw-r--r--dom/media/test/external/external_media_tests/urls/youtube/long3-crashes-900.ini86
-rw-r--r--dom/media/test/external/external_media_tests/urls/youtube/medium1-60.ini18
-rw-r--r--dom/media/test/external/external_media_tests/urls/youtube/short1-10.ini13
-rw-r--r--dom/media/test/external/external_media_tests/urls/youtube/short2-crashes-15.ini17
-rw-r--r--dom/media/test/external/external_media_tests/utils.py68
-rw-r--r--dom/media/test/external/mach_commands.py74
-rw-r--r--dom/media/test/external/requirements-docs.txt5
-rw-r--r--dom/media/test/external/requirements.txt5
-rw-r--r--dom/media/test/external/setup.py42
-rw-r--r--dom/media/test/file_access_controls.html156
-rwxr-xr-xdom/media/test/flac-noheader-s16.flacbin0 -> 242826 bytes
-rw-r--r--dom/media/test/flac-noheader-s16.flac^headers^1
-rw-r--r--dom/media/test/flac-s24.flacbin0 -> 980951 bytes
-rw-r--r--dom/media/test/flac-s24.flac^headers^1
-rw-r--r--dom/media/test/fragment_noplay.js14
-rw-r--r--dom/media/test/fragment_play.js67
-rw-r--r--dom/media/test/gizmo-frag.mp4bin0 -> 152132 bytes
-rw-r--r--dom/media/test/gizmo-noaudio.mp4bin0 -> 342980 bytes
-rw-r--r--dom/media/test/gizmo-noaudio.mp4^headers^1
-rw-r--r--dom/media/test/gizmo-noaudio.webmbin0 -> 112663 bytes
-rw-r--r--dom/media/test/gizmo-noaudio.webm^headers^1
-rw-r--r--dom/media/test/gizmo-short.mp4bin0 -> 29905 bytes
-rw-r--r--dom/media/test/gizmo-short.mp4^headers^1
-rw-r--r--dom/media/test/gizmo.mp4bin0 -> 455255 bytes
-rw-r--r--dom/media/test/gizmo.mp4^headers^1
-rw-r--r--dom/media/test/gizmo.webmbin0 -> 159035 bytes
-rw-r--r--dom/media/test/gizmo.webm^headers^1
-rw-r--r--dom/media/test/graph_latency.py104
-rw-r--r--dom/media/test/huge-id3.mp3bin0 -> 141774 bytes
-rw-r--r--dom/media/test/huge-id3.mp3^headers^1
-rw-r--r--dom/media/test/id3tags.mp3bin0 -> 3530 bytes
-rw-r--r--dom/media/test/id3tags.mp3^headers^1
-rw-r--r--dom/media/test/invalid-cmap-s0c0.opusbin0 -> 6835 bytes
-rw-r--r--dom/media/test/invalid-cmap-s0c0.opus^headers^1
-rw-r--r--dom/media/test/invalid-cmap-s0c2.opusbin0 -> 6834 bytes
-rw-r--r--dom/media/test/invalid-cmap-s0c2.opus^headers^1
-rw-r--r--dom/media/test/invalid-cmap-s1c2.opusbin0 -> 6848 bytes
-rw-r--r--dom/media/test/invalid-cmap-s1c2.opus^headers^1
-rw-r--r--dom/media/test/invalid-cmap-short.opusbin0 -> 6854 bytes
-rw-r--r--dom/media/test/invalid-cmap-short.opus^headers^1
-rw-r--r--dom/media/test/invalid-discard_on_multi_blocks.webmbin0 -> 19636 bytes
-rw-r--r--dom/media/test/invalid-discard_on_multi_blocks.webm^headers^1
-rw-r--r--dom/media/test/invalid-excess_discard.webmbin0 -> 18442 bytes
-rw-r--r--dom/media/test/invalid-excess_discard.webm^headers^1
-rw-r--r--dom/media/test/invalid-excess_neg_discard.webmbin0 -> 18442 bytes
-rw-r--r--dom/media/test/invalid-excess_neg_discard.webm^headers^1
-rw-r--r--dom/media/test/invalid-m0c0.opusbin0 -> 2471 bytes
-rw-r--r--dom/media/test/invalid-m0c0.opus^headers^1
-rw-r--r--dom/media/test/invalid-m0c3.opusbin0 -> 2471 bytes
-rw-r--r--dom/media/test/invalid-m0c3.opus^headers^1
-rw-r--r--dom/media/test/invalid-m1c0.opusbin0 -> 6836 bytes
-rw-r--r--dom/media/test/invalid-m1c0.opus^headers^1
-rw-r--r--dom/media/test/invalid-m1c9.opusbin0 -> 6836 bytes
-rw-r--r--dom/media/test/invalid-m1c9.opus^headers^1
-rw-r--r--dom/media/test/invalid-m2c0.opusbin0 -> 2471 bytes
-rw-r--r--dom/media/test/invalid-m2c0.opus^headers^1
-rw-r--r--dom/media/test/invalid-m2c1.opusbin0 -> 2455 bytes
-rw-r--r--dom/media/test/invalid-m2c1.opus^headers^1
-rw-r--r--dom/media/test/invalid-neg_discard.webmbin0 -> 18442 bytes
-rw-r--r--dom/media/test/invalid-neg_discard.webm^headers^1
-rw-r--r--dom/media/test/invalid-preskip.webmbin0 -> 7251 bytes
-rw-r--r--dom/media/test/invalid-preskip.webm^headers^1
-rw-r--r--dom/media/test/long.vtt8001
-rw-r--r--dom/media/test/make-headers.sh18
-rw-r--r--dom/media/test/manifest.js1725
-rw-r--r--dom/media/test/mochitest.ini922
-rw-r--r--dom/media/test/multiple-bos-more-header-fileds.oggbin0 -> 27527 bytes
-rw-r--r--dom/media/test/multiple-bos-more-header-fileds.ogg^headers^1
-rw-r--r--dom/media/test/multiple-bos.oggbin0 -> 33045 bytes
-rw-r--r--dom/media/test/multiple-bos.ogg^headers^1
-rw-r--r--dom/media/test/no-cues.webmbin0 -> 220609 bytes
-rw-r--r--dom/media/test/no-cues.webm^headers^1
-rw-r--r--dom/media/test/notags.mp3bin0 -> 2506 bytes
-rw-r--r--dom/media/test/notags.mp3^headers^1
-rw-r--r--dom/media/test/owl-funnier-id3.mp3bin0 -> 69603 bytes
-rw-r--r--dom/media/test/owl-funnier-id3.mp3^headers^1
-rw-r--r--dom/media/test/owl-funny-id3.mp3bin0 -> 71696 bytes
-rw-r--r--dom/media/test/owl-funny-id3.mp3^headers^1
-rw-r--r--dom/media/test/owl-short.mp3bin0 -> 11016 bytes
-rw-r--r--dom/media/test/owl-short.mp3^headers^1
-rw-r--r--dom/media/test/owl.mp3bin0 -> 67430 bytes
-rw-r--r--dom/media/test/owl.mp3^headers^1
-rw-r--r--dom/media/test/parser.vtt6
-rw-r--r--dom/media/test/pixel_aspect_ratio.mp4bin0 -> 1806042 bytes
-rw-r--r--dom/media/test/r11025_msadpcm_c1.wavbin0 -> 5978 bytes
-rw-r--r--dom/media/test/r11025_msadpcm_c1.wav^headers^1
-rw-r--r--dom/media/test/r11025_s16_c1-short.wavbin0 -> 8270 bytes
-rw-r--r--dom/media/test/r11025_s16_c1-short.wav^headers^1
-rw-r--r--dom/media/test/r11025_s16_c1.wavbin0 -> 22094 bytes
-rw-r--r--dom/media/test/r11025_s16_c1.wav^headers^1
-rw-r--r--dom/media/test/r11025_s16_c1_trailing.wavbin0 -> 22095 bytes
-rw-r--r--dom/media/test/r11025_s16_c1_trailing.wav^headers^1
-rw-r--r--dom/media/test/r11025_u8_c1.wavbin0 -> 11069 bytes
-rw-r--r--dom/media/test/r11025_u8_c1.wav^headers^1
-rw-r--r--dom/media/test/r11025_u8_c1_trunc.wavbin0 -> 20000 bytes
-rw-r--r--dom/media/test/r11025_u8_c1_trunc.wav^headers^1
-rw-r--r--dom/media/test/r16000_u8_c1_list.wavbin0 -> 68318 bytes
-rw-r--r--dom/media/test/r16000_u8_c1_list.wav^headers^1
-rw-r--r--dom/media/test/reactivate_helper.html57
-rw-r--r--dom/media/test/red-46x48.mp4bin0 -> 1548 bytes
-rw-r--r--dom/media/test/red-46x48.mp4^headers^1
-rw-r--r--dom/media/test/red-48x46.mp4bin0 -> 1548 bytes
-rw-r--r--dom/media/test/red-48x46.mp4^headers^1
-rw-r--r--dom/media/test/redirect.sjs26
-rw-r--r--dom/media/test/referer.sjs45
-rw-r--r--dom/media/test/region.vtt5
-rw-r--r--dom/media/test/resolution-change.webmbin0 -> 7166 bytes
-rw-r--r--dom/media/test/resolution-change.webm^headers^1
-rw-r--r--dom/media/test/sample-fisbone-skeleton4.ogvbin0 -> 8747 bytes
-rw-r--r--dom/media/test/sample-fisbone-skeleton4.ogv^headers^1
-rw-r--r--dom/media/test/sample-fisbone-wrong-header.ogvbin0 -> 8703 bytes
-rw-r--r--dom/media/test/sample-fisbone-wrong-header.ogv^headers^1
-rw-r--r--dom/media/test/sample.3g2bin0 -> 28561 bytes
-rw-r--r--dom/media/test/sample.3gpbin0 -> 28561 bytes
-rw-r--r--dom/media/test/seek-short.ogvbin0 -> 79921 bytes
-rw-r--r--dom/media/test/seek-short.ogv^headers^1
-rw-r--r--dom/media/test/seek-short.webmbin0 -> 19267 bytes
-rw-r--r--dom/media/test/seek-short.webm^headers^1
-rw-r--r--dom/media/test/seek.ogvbin0 -> 285310 bytes
-rw-r--r--dom/media/test/seek.ogv^headers^1
-rw-r--r--dom/media/test/seek.webmbin0 -> 215529 bytes
-rw-r--r--dom/media/test/seek.webm^headers^1
-rw-r--r--dom/media/test/seek.yuvbin0 -> 1267408 bytes
-rw-r--r--dom/media/test/seekLies.sjs23
-rw-r--r--dom/media/test/seek_support.js55
-rw-r--r--dom/media/test/seek_with_sound.oggbin0 -> 299507 bytes
-rw-r--r--dom/media/test/seek_with_sound.ogg^headers^1
-rw-r--r--dom/media/test/sequential.vtt10
-rw-r--r--dom/media/test/short-audio-fragmented-cenc-without-pssh.mp4bin0 -> 9261 bytes
-rw-r--r--dom/media/test/short-audio-fragmented-cenc-without-pssh.mp4^headers^1
-rw-r--r--dom/media/test/short-cenc.mp4bin0 -> 14860 bytes
-rw-r--r--dom/media/test/short-cenc.xml37
-rw-r--r--dom/media/test/short-video.ogvbin0 -> 16049 bytes
-rw-r--r--dom/media/test/short-video.ogv^headers^1
-rw-r--r--dom/media/test/short.mp4bin0 -> 13651 bytes
-rw-r--r--dom/media/test/short.mp4^headers^1
-rw-r--r--dom/media/test/sine.webmbin0 -> 17510 bytes
-rw-r--r--dom/media/test/sine.webm^headers^1
-rw-r--r--dom/media/test/small-shot-mp3.mp4bin0 -> 7491 bytes
-rw-r--r--dom/media/test/small-shot-mp3.mp4^headers^1
-rw-r--r--dom/media/test/small-shot.flacbin0 -> 16430 bytes
-rw-r--r--dom/media/test/small-shot.m4abin0 -> 2710 bytes
-rw-r--r--dom/media/test/small-shot.mp3bin0 -> 6825 bytes
-rw-r--r--dom/media/test/small-shot.mp3^headers^1
-rw-r--r--dom/media/test/small-shot.oggbin0 -> 6416 bytes
-rw-r--r--dom/media/test/small-shot.ogg^headers^1
-rw-r--r--dom/media/test/sound.oggbin0 -> 2603 bytes
-rw-r--r--dom/media/test/sound.ogg^headers^1
-rw-r--r--dom/media/test/spacestorm-1000Hz-100ms.oggbin0 -> 3270 bytes
-rw-r--r--dom/media/test/spacestorm-1000Hz-100ms.ogg^headers^1
-rw-r--r--dom/media/test/split.webmbin0 -> 105755 bytes
-rw-r--r--dom/media/test/split.webm^headers^1
-rw-r--r--dom/media/test/street.mp4bin0 -> 1505751 bytes
-rw-r--r--dom/media/test/street.mp4^headers^1
-rw-r--r--dom/media/test/test-1-mono.opusbin0 -> 4086 bytes
-rw-r--r--dom/media/test/test-1-mono.opus^headers^1
-rw-r--r--dom/media/test/test-2-stereo.opusbin0 -> 24973 bytes
-rw-r--r--dom/media/test/test-2-stereo.opus^headers^1
-rw-r--r--dom/media/test/test-3-LCR.opusbin0 -> 39471 bytes
-rw-r--r--dom/media/test/test-3-LCR.opus^headers^1
-rw-r--r--dom/media/test/test-4-quad.opusbin0 -> 129906 bytes
-rw-r--r--dom/media/test/test-4-quad.opus^headers^1
-rw-r--r--dom/media/test/test-5-5.0.opusbin0 -> 164935 bytes
-rw-r--r--dom/media/test/test-5-5.0.opus^headers^1
-rw-r--r--dom/media/test/test-6-5.1.opusbin0 -> 288195 bytes
-rw-r--r--dom/media/test/test-6-5.1.opus^headers^1
-rw-r--r--dom/media/test/test-7-6.1.opusbin0 -> 401668 bytes
-rw-r--r--dom/media/test/test-7-6.1.opus^headers^1
-rw-r--r--dom/media/test/test-8-7.1.opusbin0 -> 543119 bytes
-rw-r--r--dom/media/test/test-8-7.1.opus^headers^1
-rw-r--r--dom/media/test/test_VideoPlaybackQuality.html64
-rw-r--r--dom/media/test/test_VideoPlaybackQuality_disabled.html37
-rw-r--r--dom/media/test/test_access_control.html52
-rw-r--r--dom/media/test/test_aspectratio_mp4.html52
-rw-r--r--dom/media/test/test_audio1.html33
-rw-r--r--dom/media/test/test_audio2.html33
-rw-r--r--dom/media/test/test_audioDocumentTitle.html56
-rw-r--r--dom/media/test/test_autoplay.html35
-rw-r--r--dom/media/test/test_autoplay_contentEditable.html67
-rw-r--r--dom/media/test/test_background_video_no_suspend_disabled.html36
-rw-r--r--dom/media/test/test_background_video_no_suspend_short_vid.html38
-rw-r--r--dom/media/test/test_background_video_suspend.html50
-rw-r--r--dom/media/test/test_background_video_suspend_ends.html39
-rw-r--r--dom/media/test/test_buffered.html119
-rw-r--r--dom/media/test/test_bug1018933.html50
-rw-r--r--dom/media/test/test_bug1113600.html50
-rw-r--r--dom/media/test/test_bug1242338.html66
-rw-r--r--dom/media/test/test_bug1242594.html46
-rw-r--r--dom/media/test/test_bug1248229.html34
-rw-r--r--dom/media/test/test_bug448534.html71
-rw-r--r--dom/media/test/test_bug463162.xhtml78
-rw-r--r--dom/media/test/test_bug465498.html83
-rw-r--r--dom/media/test/test_bug495145.html99
-rw-r--r--dom/media/test/test_bug495300.html63
-rw-r--r--dom/media/test/test_bug654550.html84
-rw-r--r--dom/media/test/test_bug686942.html72
-rw-r--r--dom/media/test/test_bug726904.html56
-rw-r--r--dom/media/test/test_bug874897.html68
-rw-r--r--dom/media/test/test_bug879717.html134
-rw-r--r--dom/media/test/test_bug883173.html59
-rw-r--r--dom/media/test/test_bug895091.html60
-rw-r--r--dom/media/test/test_bug895305.html41
-rw-r--r--dom/media/test/test_bug919265.html30
-rw-r--r--dom/media/test/test_bug957847.html30
-rw-r--r--dom/media/test/test_can_play_type.html40
-rw-r--r--dom/media/test/test_can_play_type_mpeg.html167
-rw-r--r--dom/media/test/test_can_play_type_no_ogg.html42
-rw-r--r--dom/media/test/test_can_play_type_ogg.html37
-rw-r--r--dom/media/test/test_can_play_type_wave.html30
-rw-r--r--dom/media/test/test_can_play_type_webm.html29
-rw-r--r--dom/media/test/test_chaining.html87
-rw-r--r--dom/media/test/test_clone_media_element.html54
-rw-r--r--dom/media/test/test_closing_connections.html58
-rw-r--r--dom/media/test/test_constants.html228
-rw-r--r--dom/media/test/test_controls.html33
-rw-r--r--dom/media/test/test_cueless_webm_seek-1.html136
-rw-r--r--dom/media/test/test_cueless_webm_seek-2.html126
-rw-r--r--dom/media/test/test_cueless_webm_seek-3.html122
-rw-r--r--dom/media/test/test_currentTime.html19
-rw-r--r--dom/media/test/test_decode_error.html66
-rw-r--r--dom/media/test/test_decoder_disable.html78
-rw-r--r--dom/media/test/test_defaultMuted.html54
-rw-r--r--dom/media/test/test_delay_load.html108
-rw-r--r--dom/media/test/test_eme_canvas_blocked.html58
-rw-r--r--dom/media/test/test_eme_detach_media_keys.html63
-rw-r--r--dom/media/test/test_eme_initDataTypes.html133
-rw-r--r--dom/media/test/test_eme_missing_pssh.html92
-rw-r--r--dom/media/test/test_eme_non_mse_fails.html103
-rw-r--r--dom/media/test/test_eme_playback.html188
-rw-r--r--dom/media/test/test_eme_requestKeySystemAccess.html484
-rw-r--r--dom/media/test/test_eme_request_notifications.html88
-rw-r--r--dom/media/test/test_eme_session_callable_value.html35
-rw-r--r--dom/media/test/test_eme_setMediaKeys_before_attach_MediaSource.html41
-rw-r--r--dom/media/test/test_eme_stream_capture_blocked_case1.html52
-rw-r--r--dom/media/test/test_eme_stream_capture_blocked_case2.html55
-rw-r--r--dom/media/test/test_eme_stream_capture_blocked_case3.html54
-rw-r--r--dom/media/test/test_eme_waitingforkey.html117
-rw-r--r--dom/media/test/test_empty_resource.html58
-rw-r--r--dom/media/test/test_error_in_video_document.html68
-rw-r--r--dom/media/test/test_error_on_404.html84
-rw-r--r--dom/media/test/test_fastSeek-forwards.html77
-rw-r--r--dom/media/test/test_fastSeek.html88
-rw-r--r--dom/media/test/test_fragment_noplay.html135
-rw-r--r--dom/media/test/test_fragment_play.html92
-rw-r--r--dom/media/test/test_gmp_playback.html40
-rw-r--r--dom/media/test/test_imagecapture.html156
-rw-r--r--dom/media/test/test_info_leak.html169
-rw-r--r--dom/media/test/test_invalid_reject.html58
-rw-r--r--dom/media/test/test_invalid_reject_play.html44
-rw-r--r--dom/media/test/test_invalid_seek.html32
-rw-r--r--dom/media/test/test_load.html226
-rw-r--r--dom/media/test/test_load_candidates.html84
-rw-r--r--dom/media/test/test_load_same_resource.html100
-rw-r--r--dom/media/test/test_load_source.html76
-rw-r--r--dom/media/test/test_loop.html61
-rw-r--r--dom/media/test/test_media_selection.html146
-rw-r--r--dom/media/test/test_media_sniffer.html67
-rw-r--r--dom/media/test/test_mediarecorder_avoid_recursion.html51
-rw-r--r--dom/media/test/test_mediarecorder_bitrate.html128
-rw-r--r--dom/media/test/test_mediarecorder_creation.html45
-rw-r--r--dom/media/test/test_mediarecorder_creation_fail.html66
-rw-r--r--dom/media/test/test_mediarecorder_getencodeddata.html67
-rw-r--r--dom/media/test/test_mediarecorder_principals.html119
-rw-r--r--dom/media/test/test_mediarecorder_record_4ch_audiocontext.html80
-rw-r--r--dom/media/test/test_mediarecorder_record_audiocontext.html66
-rw-r--r--dom/media/test/test_mediarecorder_record_audiocontext_mlk.html24
-rw-r--r--dom/media/test/test_mediarecorder_record_audionode.html126
-rw-r--r--dom/media/test/test_mediarecorder_record_canvas_captureStream.html73
-rw-r--r--dom/media/test/test_mediarecorder_record_changing_video_resolution.html69
-rw-r--r--dom/media/test/test_mediarecorder_record_getdata_afterstart.html79
-rw-r--r--dom/media/test/test_mediarecorder_record_gum_video_timeslice.html87
-rw-r--r--dom/media/test/test_mediarecorder_record_immediate_stop.html122
-rw-r--r--dom/media/test/test_mediarecorder_record_no_timeslice.html105
-rw-r--r--dom/media/test/test_mediarecorder_record_session.html75
-rw-r--r--dom/media/test/test_mediarecorder_record_startstopstart.html77
-rw-r--r--dom/media/test/test_mediarecorder_record_stopms.html47
-rw-r--r--dom/media/test/test_mediarecorder_record_timeslice.html104
-rw-r--r--dom/media/test/test_mediarecorder_reload_crash.html27
-rw-r--r--dom/media/test/test_mediarecorder_state_transition.html171
-rw-r--r--dom/media/test/test_mediarecorder_unsupported_src.html99
-rw-r--r--dom/media/test/test_mediarecorder_webm_support.html18
-rw-r--r--dom/media/test/test_mediatrack_consuming_mediaresource.html181
-rw-r--r--dom/media/test/test_mediatrack_consuming_mediastream.html155
-rw-r--r--dom/media/test/test_mediatrack_events.html133
-rw-r--r--dom/media/test/test_mediatrack_parsing_ogg.html72
-rw-r--r--dom/media/test/test_mediatrack_replay_from_end.html146
-rw-r--r--dom/media/test/test_metadata.html81
-rw-r--r--dom/media/test/test_mixed_principals.html94
-rw-r--r--dom/media/test/test_mozHasAudio.html42
-rw-r--r--dom/media/test/test_multiple_mediastreamtracks.html46
-rw-r--r--dom/media/test/test_networkState.html47
-rw-r--r--dom/media/test/test_new_audio.html49
-rw-r--r--dom/media/test/test_no_load_event.html53
-rw-r--r--dom/media/test/test_paused.html21
-rw-r--r--dom/media/test/test_paused_after_ended.html53
-rw-r--r--dom/media/test/test_play_events.html63
-rw-r--r--dom/media/test/test_play_events_2.html60
-rw-r--r--dom/media/test/test_play_twice.html95
-rw-r--r--dom/media/test/test_playback.html123
-rw-r--r--dom/media/test/test_playback_errors.html48
-rw-r--r--dom/media/test/test_playback_rate.html175
-rw-r--r--dom/media/test/test_playback_rate_playpause.html66
-rw-r--r--dom/media/test/test_playback_reactivate.html97
-rw-r--r--dom/media/test/test_played.html250
-rw-r--r--dom/media/test/test_preload_actions.html618
-rw-r--r--dom/media/test/test_preload_attribute.html44
-rw-r--r--dom/media/test/test_preload_suspend.html112
-rw-r--r--dom/media/test/test_preserve_playbackrate_after_ui_play.html60
-rw-r--r--dom/media/test/test_progress.html52
-rw-r--r--dom/media/test/test_reactivate.html64
-rw-r--r--dom/media/test/test_readyState.html51
-rw-r--r--dom/media/test/test_referer.html88
-rw-r--r--dom/media/test/test_replay_metadata.html120
-rw-r--r--dom/media/test/test_reset_events_async.html58
-rw-r--r--dom/media/test/test_reset_src.html98
-rw-r--r--dom/media/test/test_resolution_change.html52
-rw-r--r--dom/media/test/test_resume.html47
-rw-r--r--dom/media/test/test_seek-1.html84
-rw-r--r--dom/media/test/test_seek-10.html56
-rw-r--r--dom/media/test/test_seek-11.html76
-rw-r--r--dom/media/test/test_seek-12.html59
-rw-r--r--dom/media/test/test_seek-13.html72
-rw-r--r--dom/media/test/test_seek-2.html76
-rw-r--r--dom/media/test/test_seek-3.html70
-rw-r--r--dom/media/test/test_seek-4.html70
-rw-r--r--dom/media/test/test_seek-5.html69
-rw-r--r--dom/media/test/test_seek-6.html65
-rw-r--r--dom/media/test/test_seek-7.html60
-rw-r--r--dom/media/test/test_seek-8.html42
-rw-r--r--dom/media/test/test_seek-9.html41
-rw-r--r--dom/media/test/test_seekLies.html28
-rw-r--r--dom/media/test/test_seekToNextFrame.html87
-rw-r--r--dom/media/test/test_seek_negative.html77
-rw-r--r--dom/media/test/test_seek_nosrc.html58
-rw-r--r--dom/media/test/test_seek_out_of_range.html82
-rw-r--r--dom/media/test/test_seekable1.html66
-rw-r--r--dom/media/test/test_source.html92
-rw-r--r--dom/media/test/test_source_media.html71
-rw-r--r--dom/media/test/test_source_null.html30
-rw-r--r--dom/media/test/test_source_write.html40
-rw-r--r--dom/media/test/test_standalone.html61
-rw-r--r--dom/media/test/test_streams_autoplay.html46
-rw-r--r--dom/media/test/test_streams_capture_origin.html47
-rw-r--r--dom/media/test/test_streams_element_capture.html98
-rw-r--r--dom/media/test/test_streams_element_capture_createObjectURL.html71
-rw-r--r--dom/media/test/test_streams_element_capture_playback.html47
-rw-r--r--dom/media/test/test_streams_element_capture_reset.html134
-rw-r--r--dom/media/test/test_streams_gc.html44
-rw-r--r--dom/media/test/test_streams_individual_pause.html79
-rw-r--r--dom/media/test/test_streams_srcObject.html62
-rw-r--r--dom/media/test/test_streams_tracks.html54
-rw-r--r--dom/media/test/test_temporary_file_blob_video_plays.html73
-rw-r--r--dom/media/test/test_texttrack.html126
-rw-r--r--dom/media/test/test_texttrack_moz.html66
-rw-r--r--dom/media/test/test_texttrackcue.html269
-rw-r--r--dom/media/test/test_texttrackcue_moz.html34
-rw-r--r--dom/media/test/test_texttrackevents_video.html90
-rw-r--r--dom/media/test/test_texttracklist.html51
-rw-r--r--dom/media/test/test_texttracklist_moz.html34
-rw-r--r--dom/media/test/test_texttrackregion.html64
-rw-r--r--dom/media/test/test_timeupdate_small_files.html88
-rw-r--r--dom/media/test/test_trackelementevent.html69
-rw-r--r--dom/media/test/test_trackelementsrc.html53
-rw-r--r--dom/media/test/test_trackevent.html70
-rw-r--r--dom/media/test/test_unseekable.html101
-rw-r--r--dom/media/test/test_videoDocumentTitle.html57
-rw-r--r--dom/media/test/test_video_dimensions.html96
-rw-r--r--dom/media/test/test_video_in_audio_element.html68
-rw-r--r--dom/media/test/test_video_to_canvas.html68
-rw-r--r--dom/media/test/test_volume.html41
-rw-r--r--dom/media/test/test_vttparser.html44
-rw-r--r--dom/media/test/test_wav_ended1.html43
-rw-r--r--dom/media/test/test_wav_ended2.html62
-rw-r--r--dom/media/test/test_webvtt_empty_displaystate.html86
-rw-r--r--dom/media/test/test_webvtt_positionalign.html95
-rw-r--r--dom/media/test/variable-channel.oggbin0 -> 27749 bytes
-rw-r--r--dom/media/test/variable-channel.ogg^headers^1
-rw-r--r--dom/media/test/variable-channel.opusbin0 -> 46597 bytes
-rw-r--r--dom/media/test/variable-channel.opus^headers^1
-rw-r--r--dom/media/test/variable-preskip.opusbin0 -> 17660 bytes
-rw-r--r--dom/media/test/variable-preskip.opus^headers^1
-rw-r--r--dom/media/test/variable-samplerate.oggbin0 -> 22325 bytes
-rw-r--r--dom/media/test/variable-samplerate.ogg^headers^1
-rw-r--r--dom/media/test/variable-samplerate.opusbin0 -> 28111 bytes
-rw-r--r--dom/media/test/variable-samplerate.opus^headers^1
-rw-r--r--dom/media/test/vbr-head.mp3bin0 -> 4474 bytes
-rw-r--r--dom/media/test/vbr-head.mp3^headers^1
-rw-r--r--dom/media/test/vbr.mp3bin0 -> 300553 bytes
-rw-r--r--dom/media/test/vbr.mp3^headers^1
-rw-r--r--dom/media/test/video-overhang.oggbin0 -> 301831 bytes
-rw-r--r--dom/media/test/video-overhang.ogg^headers^1
-rw-r--r--dom/media/test/vp9-short.webmbin0 -> 3107 bytes
-rw-r--r--dom/media/test/vp9-short.webm^headers^1
-rw-r--r--dom/media/test/vp9.webmbin0 -> 97465 bytes
-rw-r--r--dom/media/test/vp9.webm^headers^1
-rw-r--r--dom/media/test/vp9cake-short.webmbin0 -> 25155 bytes
-rw-r--r--dom/media/test/vp9cake-short.webm^headers^1
-rw-r--r--dom/media/test/vp9cake.webmbin0 -> 141743 bytes
-rw-r--r--dom/media/test/vp9cake.webm^headers^1
-rw-r--r--dom/media/test/vttPositionAlign.vtt25
-rw-r--r--dom/media/test/wave_metadata.wavbin0 -> 42706 bytes
-rw-r--r--dom/media/test/wave_metadata.wav^headers^1
-rw-r--r--dom/media/test/wave_metadata_bad_len.wavbin0 -> 42706 bytes
-rw-r--r--dom/media/test/wave_metadata_bad_len.wav^headers^1
-rw-r--r--dom/media/test/wave_metadata_bad_no_null.wavbin0 -> 42706 bytes
-rw-r--r--dom/media/test/wave_metadata_bad_no_null.wav^headers^1
-rw-r--r--dom/media/test/wave_metadata_bad_utf8.wavbin0 -> 42704 bytes
-rw-r--r--dom/media/test/wave_metadata_bad_utf8.wav^headers^1
-rw-r--r--dom/media/test/wave_metadata_unknown_tag.wavbin0 -> 42706 bytes
-rw-r--r--dom/media/test/wave_metadata_unknown_tag.wav^headers^1
-rw-r--r--dom/media/test/wave_metadata_utf8.wavbin0 -> 42704 bytes
-rw-r--r--dom/media/test/wave_metadata_utf8.wav^headers^1
-rw-r--r--dom/media/test/wavedata_alaw.wavbin0 -> 11067 bytes
-rw-r--r--dom/media/test/wavedata_alaw.wav^headers^1
-rw-r--r--dom/media/test/wavedata_s16.wavbin0 -> 22062 bytes
-rw-r--r--dom/media/test/wavedata_s16.wav^headers^1
-rw-r--r--dom/media/test/wavedata_s24.wavbin0 -> 33071 bytes
-rw-r--r--dom/media/test/wavedata_s24.wav^headers^1
-rw-r--r--dom/media/test/wavedata_u8.wavbin0 -> 11037 bytes
-rw-r--r--dom/media/test/wavedata_u8.wav^headers^1
-rw-r--r--dom/media/test/wavedata_ulaw.wavbin0 -> 11067 bytes
-rw-r--r--dom/media/test/wavedata_ulaw.wav^headers^1
1003 files changed, 35208 insertions, 0 deletions
diff --git a/dom/media/test/16bit_wave_extrametadata.wav b/dom/media/test/16bit_wave_extrametadata.wav
new file mode 100644
index 000000000..443ec73a3
--- /dev/null
+++ b/dom/media/test/16bit_wave_extrametadata.wav
Binary files differ
diff --git a/dom/media/test/16bit_wave_extrametadata.wav^headers^ b/dom/media/test/16bit_wave_extrametadata.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/16bit_wave_extrametadata.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/320x240.ogv b/dom/media/test/320x240.ogv
new file mode 100644
index 000000000..093158432
--- /dev/null
+++ b/dom/media/test/320x240.ogv
Binary files differ
diff --git a/dom/media/test/320x240.ogv^headers^ b/dom/media/test/320x240.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/320x240.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/448636.ogv b/dom/media/test/448636.ogv
new file mode 100644
index 000000000..628df924f
--- /dev/null
+++ b/dom/media/test/448636.ogv
Binary files differ
diff --git a/dom/media/test/448636.ogv^headers^ b/dom/media/test/448636.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/448636.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/A4.ogv b/dom/media/test/A4.ogv
new file mode 100644
index 000000000..de99616ec
--- /dev/null
+++ b/dom/media/test/A4.ogv
Binary files differ
diff --git a/dom/media/test/A4.ogv^headers^ b/dom/media/test/A4.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/A4.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/VID_0001.ogg b/dom/media/test/VID_0001.ogg
new file mode 100644
index 000000000..0068b9af8
--- /dev/null
+++ b/dom/media/test/VID_0001.ogg
Binary files differ
diff --git a/dom/media/test/VID_0001.ogg^headers^ b/dom/media/test/VID_0001.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/VID_0001.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/allowed.sjs b/dom/media/test/allowed.sjs
new file mode 100644
index 000000000..3c2258557
--- /dev/null
+++ b/dom/media/test/allowed.sjs
@@ -0,0 +1,56 @@
+function parseQuery(request, key) {
+ var params = request.queryString.split('&');
+ for (var j = 0; j < params.length; ++j) {
+ var p = params[j];
+ if (p == key)
+ return true;
+ if (p.indexOf(key + "=") == 0)
+ return p.substring(key.length + 1);
+ if (p.indexOf("=") < 0 && key == "")
+ return p;
+ }
+ return false;
+}
+
+var types = {
+ js: "text/javascript",
+ m4s: "video/mp4",
+ mp4: "video/mp4",
+ ogg: "video/ogg",
+ ogv: "video/ogg",
+ oga: "audio/ogg",
+ webm: "video/webm",
+ wav: "audio/x-wav"
+};
+
+// Return file with name as per the query string with access control
+// allow headers.
+function handleRequest(request, response)
+{
+ var resource = parseQuery(request, "");
+
+ var file = Components.classes["@mozilla.org/file/directory_service;1"].
+ getService(Components.interfaces.nsIProperties).
+ get("CurWorkD", Components.interfaces.nsILocalFile);
+ var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
+ createInstance(Components.interfaces.nsIFileInputStream);
+ var bis = Components.classes["@mozilla.org/binaryinputstream;1"].
+ createInstance(Components.interfaces.nsIBinaryInputStream);
+ var paths = "tests/dom/media/test/" + resource;
+ var split = paths.split("/");
+ for(var i = 0; i < split.length; ++i) {
+ file.append(split[i]);
+ }
+ fis.init(file, -1, -1, false);
+ dump("file=" + file + "\n");
+ bis.setInputStream(fis);
+ var bytes = bis.readBytes(bis.available());
+ response.setStatusLine(request.httpVersion, 206, "Partial Content");
+ response.setHeader("Content-Range", "bytes 0-" + (bytes.length - 1) + "/" + bytes.length);
+ response.setHeader("Content-Length", ""+bytes.length, false);
+ var ext = resource.substring(resource.lastIndexOf(".")+1);
+ response.setHeader("Content-Type", types[ext], false);
+ response.setHeader("Access-Control-Allow-Origin", "*");
+ response.write(bytes, bytes.length);
+ bis.close();
+}
diff --git a/dom/media/test/audio-gaps-short.ogg b/dom/media/test/audio-gaps-short.ogg
new file mode 100644
index 000000000..e01a24bfd
--- /dev/null
+++ b/dom/media/test/audio-gaps-short.ogg
Binary files differ
diff --git a/dom/media/test/audio-gaps-short.ogg^headers^ b/dom/media/test/audio-gaps-short.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/audio-gaps-short.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/audio-gaps.ogg b/dom/media/test/audio-gaps.ogg
new file mode 100644
index 000000000..ce96748cc
--- /dev/null
+++ b/dom/media/test/audio-gaps.ogg
Binary files differ
diff --git a/dom/media/test/audio-gaps.ogg^headers^ b/dom/media/test/audio-gaps.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/audio-gaps.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/audio-overhang.ogg b/dom/media/test/audio-overhang.ogg
new file mode 100644
index 000000000..c07986e7a
--- /dev/null
+++ b/dom/media/test/audio-overhang.ogg
Binary files differ
diff --git a/dom/media/test/audio-overhang.ogg^headers^ b/dom/media/test/audio-overhang.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/audio-overhang.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/audio.wav b/dom/media/test/audio.wav
new file mode 100644
index 000000000..c6fd5cb86
--- /dev/null
+++ b/dom/media/test/audio.wav
Binary files differ
diff --git a/dom/media/test/audio.wav^headers^ b/dom/media/test/audio.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/audio.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/background_video.js b/dom/media/test/background_video.js
new file mode 100644
index 000000000..06618d30f
--- /dev/null
+++ b/dom/media/test/background_video.js
@@ -0,0 +1,115 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* jshint esversion: 6, -W097 */
+/* globals SimpleTest, SpecialPowers, info, is, ok */
+
+"use strict";
+
+function startTest(test) {
+ info(test.desc);
+ SimpleTest.waitForExplicitFinish();
+ SpecialPowers.pushPrefEnv({ 'set': test.prefs }, () => {
+ manager.runTests(test.tests, test.runTest);
+ });
+}
+
+/**
+ * @param {string} url video src.
+ * @returns {HTMLMediaElement} The created video element.
+ */
+function appendVideoToDoc(url, token, width, height) {
+ // Default size of (160, 120) is used by other media tests.
+ if (width === undefined) { width = 160; }
+ if (height === undefined) { height = 3*width/4; }
+
+ let v = document.createElement('video');
+ v.token = token;
+ document.body.appendChild(v);
+ v.width = width;
+ v.height = height;
+ v.src = url;
+ return v;
+}
+
+/**
+ * @param {HTMLMediaElement} video Video element under test.
+ * @returns {Promise} Promise that is resolved when video 'playing' event fires and rejected on error.
+ */
+function waitUntilPlaying(video) {
+ var p = once(video, 'playing', () => { ok(true, video.token + " played."); });
+ Log(video.token, "Start playing");
+ video.play();
+ return p;
+}
+
+/**
+ * @param {HTMLMediaElement} video Video element under test.
+ * @returns {Promise} Promise which is resolved when video 'ended' event fires.
+ */
+function waitUntilEnded(video) {
+ Log(video.token, "Waiting for ended");
+ if (video.ended) {
+ ok(true, video.token + " already ended");
+ return Promise.resolve();
+ }
+
+ return once(video, 'ended', () => { ok(true, video.token + " ended"); });
+}
+
+/**
+ * @param {HTMLMediaElement} video Video element under test.
+ * @returns {Promise} Promise that is resolved when video decode suspends.
+ */
+function testVideoSuspendsWhenHidden(video) {
+ let p = once(video, 'mozentervideosuspend').then(() => {
+ ok(true, video.token + " suspends");
+ });
+ Log(video.token, "Set hidden");
+ video.setVisible(false);
+ return p;
+}
+
+/**
+ * @param {HTMLMediaElement} video Video element under test.
+ * @returns {Promise} Promise that is resolved when video decode resumes.
+ */
+function testVideoResumesWhenShown(video) {
+ var p = once(video, 'mozexitvideosuspend').then(() => {
+ ok(true, video.token + " resumes");
+ });
+ Log(video.token, "Set visible");
+ video.setVisible(true);
+ return p;
+}
+
+/**
+ * @param {HTMLVideoElement} video Video element under test.
+ * @returns {Promise} Promise that is resolved if video ends and rejects if video suspends.
+ */
+function checkVideoDoesntSuspend(video) {
+ let p = Promise.race([
+ waitUntilEnded(video).then(() => { ok(true, video.token + ' ended before decode was suspended')}),
+ once(video, 'mozentervideosuspend', () => { Promise.reject(new Error(video.token + ' suspended')) })
+ ]);
+ Log(video.token, "Set hidden.");
+ video.setVisible(false);
+ return p;
+}
+
+/**
+ * @param {HTMLMediaElement} video Video element under test.
+ * @param {number} time video current time to wait til.
+ * @returns {Promise} Promise that is resolved once currentTime passes time.
+ */
+function waitTil(video, time) {
+ Log(video.token, "Waiting for time to reach " + time + "s");
+ return new Promise(resolve => {
+ video.addEventListener('timeupdate', function timeUpdateEvent() {
+ if (video.currentTime > time) {
+ video.removeEventListener(name, timeUpdateEvent);
+ resolve();
+ }
+ });
+ });
+}
diff --git a/dom/media/test/bad-signature.vtt b/dom/media/test/bad-signature.vtt
new file mode 100644
index 000000000..c9a59b35e
--- /dev/null
+++ b/dom/media/test/bad-signature.vtt
@@ -0,0 +1 @@
+WEB
diff --git a/dom/media/test/badtags.ogg b/dom/media/test/badtags.ogg
new file mode 100644
index 000000000..12d835873
--- /dev/null
+++ b/dom/media/test/badtags.ogg
Binary files differ
diff --git a/dom/media/test/badtags.ogg^headers^ b/dom/media/test/badtags.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/badtags.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/basic.vtt b/dom/media/test/basic.vtt
new file mode 100644
index 000000000..7781790d0
--- /dev/null
+++ b/dom/media/test/basic.vtt
@@ -0,0 +1,27 @@
+WEBVTT
+Region: id=testOne lines=2 width=30%
+Region: id=testTwo lines=4 width=20%
+
+1
+00:00.500 --> 00:00.700 region:testOne
+This
+
+2
+00:01.200 --> 00:02.400 region:testTwo
+Is
+
+2.5
+00:02.000 --> 00:03.500 region:testOne
+(Over here?!)
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+5
+00:03.217 --> 00:03.989
+And more!
diff --git a/dom/media/test/beta-phrasebook.ogg b/dom/media/test/beta-phrasebook.ogg
new file mode 100644
index 000000000..7e6ef77ec
--- /dev/null
+++ b/dom/media/test/beta-phrasebook.ogg
Binary files differ
diff --git a/dom/media/test/beta-phrasebook.ogg^headers^ b/dom/media/test/beta-phrasebook.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/beta-phrasebook.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/big-short.wav b/dom/media/test/big-short.wav
new file mode 100644
index 000000000..c850e5fd1
--- /dev/null
+++ b/dom/media/test/big-short.wav
Binary files differ
diff --git a/dom/media/test/big-short.wav^headers^ b/dom/media/test/big-short.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/big-short.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/big.wav b/dom/media/test/big.wav
new file mode 100644
index 000000000..5f66bc1f0
--- /dev/null
+++ b/dom/media/test/big.wav
Binary files differ
diff --git a/dom/media/test/big.wav^headers^ b/dom/media/test/big.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/big.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop-cenc-audio-key1.xml b/dom/media/test/bipbop-cenc-audio-key1.xml
new file mode 100644
index 000000000..a1672eece
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-audio-key1.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ This XML file describes the encryption applied to |bipbop_<res>-cenc*|. To
+ generate the encrypted files, run bipbop-cenc.sh
+-->
+
+<GPACDRM type="CENC AES-CTR">
+
+ <DRMInfo type="pssh" version="1">
+ <!--
+ SystemID specified in
+ https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
+ -->
+ <BS ID128="1077efecc0b24d02ace33c1e52e2fb4b" />
+ <!-- Number of KeyIDs = 1 -->
+ <BS bits="32" value="1" />
+ <!-- KeyID -->
+ <BS ID128="0x7e571d047e571d047e571d047e571d21" />
+ </DRMInfo>
+
+ <CrypTrack trackID="2" isEncrypted="1" IV_size="16" saiSavedBox="senc"
+ first_IV="0x00000000000000000000000000000000">
+ <key KID="0x7e571d047e571d047e571d047e571d21"
+ value="0x7e5744447e5744447e5744447e574421" />
+ </CrypTrack>
+
+</GPACDRM>
diff --git a/dom/media/test/bipbop-cenc-audio-key2.xml b/dom/media/test/bipbop-cenc-audio-key2.xml
new file mode 100644
index 000000000..b70660905
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-audio-key2.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ This XML file describes the encryption applied to |bipbop_<res>-cenc*|. To
+ generate the encrypted files, run bipbop-cenc.sh
+-->
+
+<GPACDRM type="CENC AES-CTR">
+
+ <DRMInfo type="pssh" version="1">
+ <!--
+ SystemID specified in
+ https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
+ -->
+ <BS ID128="1077efecc0b24d02ace33c1e52e2fb4b" />
+ <!-- Number of KeyIDs = 1 -->
+ <BS bits="32" value="1" />
+ <!-- KeyID -->
+ <BS ID128="0x7e571d047e571d047e571d047e571d22" />
+ </DRMInfo>
+
+ <CrypTrack trackID="2" isEncrypted="1" IV_size="16" saiSavedBox="senc"
+ first_IV="0x00000000000000000000000000000000">
+ <key KID="0x7e571d047e571d047e571d047e571d22"
+ value="0x7e5744447e5744447e5744447e574422" />
+ </CrypTrack>
+
+</GPACDRM>
diff --git a/dom/media/test/bipbop-cenc-audio1.m4s b/dom/media/test/bipbop-cenc-audio1.m4s
new file mode 100644
index 000000000..63cfd66f7
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-audio1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop-cenc-audio1.m4s^headers^ b/dom/media/test/bipbop-cenc-audio1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-audio1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop-cenc-audio2.m4s b/dom/media/test/bipbop-cenc-audio2.m4s
new file mode 100644
index 000000000..04a6cb6ff
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-audio2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop-cenc-audio2.m4s^headers^ b/dom/media/test/bipbop-cenc-audio2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-audio2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop-cenc-audio3.m4s b/dom/media/test/bipbop-cenc-audio3.m4s
new file mode 100644
index 000000000..ad0cd72f9
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-audio3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop-cenc-audio3.m4s^headers^ b/dom/media/test/bipbop-cenc-audio3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-audio3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop-cenc-audioinit.mp4 b/dom/media/test/bipbop-cenc-audioinit.mp4
new file mode 100644
index 000000000..b827aa49a
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-audioinit.mp4
Binary files differ
diff --git a/dom/media/test/bipbop-cenc-audioinit.mp4^headers^ b/dom/media/test/bipbop-cenc-audioinit.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-audioinit.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop-cenc-video-key1.xml b/dom/media/test/bipbop-cenc-video-key1.xml
new file mode 100644
index 000000000..f0d9878fa
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-video-key1.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ This XML file describes the encryption applied to |bipbop_<res>-cenc*|. To
+ generate the encrypted files, run bipbop-cenc.sh
+-->
+
+<GPACDRM type="CENC AES-CTR">
+
+ <DRMInfo type="pssh" version="1">
+ <!--
+ SystemID specified in
+ https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
+ -->
+ <BS ID128="1077efecc0b24d02ace33c1e52e2fb4b" />
+ <!-- Number of KeyIDs = 1 -->
+ <BS bits="32" value="1" />
+ <!-- KeyID -->
+ <BS ID128="0x7e571d037e571d037e571d037e571d11" />
+ </DRMInfo>
+
+ <CrypTrack trackID="1" isEncrypted="1" IV_size="16" saiSavedBox="senc"
+ first_IV="0x00000000000000000000000000000000">
+ <key KID="0x7e571d037e571d037e571d037e571d11"
+ value="0x7e5733337e5733337e5733337e573311" />
+ </CrypTrack>
+
+</GPACDRM>
diff --git a/dom/media/test/bipbop-cenc-video-key2.xml b/dom/media/test/bipbop-cenc-video-key2.xml
new file mode 100644
index 000000000..1f320e633
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-video-key2.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ This XML file describes the encryption applied to |bipbop_<res>-cenc*|. To
+ generate the encrypted files, run bipbop-cenc.sh
+-->
+
+<GPACDRM type="CENC AES-CTR">
+
+ <DRMInfo type="pssh" version="1">
+ <!--
+ SystemID specified in
+ https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
+ -->
+ <BS ID128="1077efecc0b24d02ace33c1e52e2fb4b" />
+ <!-- Number of KeyIDs = 1 -->
+ <BS bits="32" value="1" />
+ <!-- KeyID -->
+ <BS ID128="0x7e571d037e571d037e571d037e571d12" />
+ </DRMInfo>
+
+ <CrypTrack trackID="1" isEncrypted="1" IV_size="16" saiSavedBox="senc"
+ first_IV="0x00000000000000000000000000000000">
+ <key KID="0x7e571d037e571d037e571d037e571d12"
+ value="0x7e5733337e5733337e5733337e573312" />
+ </CrypTrack>
+
+</GPACDRM>
diff --git a/dom/media/test/bipbop-cenc-video1.m4s b/dom/media/test/bipbop-cenc-video1.m4s
new file mode 100644
index 000000000..755013c11
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-video1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop-cenc-video1.m4s^headers^ b/dom/media/test/bipbop-cenc-video1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-video1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop-cenc-video2.m4s b/dom/media/test/bipbop-cenc-video2.m4s
new file mode 100644
index 000000000..c884bd95f
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-video2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop-cenc-video2.m4s^headers^ b/dom/media/test/bipbop-cenc-video2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-video2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop-cenc-videoinit.mp4 b/dom/media/test/bipbop-cenc-videoinit.mp4
new file mode 100644
index 000000000..aa87d0bbe
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-videoinit.mp4
Binary files differ
diff --git a/dom/media/test/bipbop-cenc-videoinit.mp4^headers^ b/dom/media/test/bipbop-cenc-videoinit.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop-cenc-videoinit.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop-cenc.sh b/dom/media/test/bipbop-cenc.sh
new file mode 100755
index 000000000..a00c38ae8
--- /dev/null
+++ b/dom/media/test/bipbop-cenc.sh
@@ -0,0 +1,29 @@
+mkdir work.tmp
+
+for r in 225w_175kbps 300_215kbps 300wp_227kbps 360w_253kbps 480_624kbps 480wp_663kbps 480_959kbps 480wp_1001kbps
+do
+ for k in 1 2
+ do
+ # Encrypt bipbop_<res>.mp4 with the keys specified in this file,
+ # and output to |bipbop_<res>-cenc-{video,audio}.mp4|
+ MP4Box -crypt bipbop-cenc-audio-key${k}.xml -rem 1 -out work.tmp/bipbop_${r}-cenc-audio-key${k}.mp4 bipbop_${r}.mp4
+ MP4Box -crypt bipbop-cenc-video-key${k}.xml -rem 2 -out work.tmp/bipbop_${r}-cenc-video-key${k}.mp4 bipbop_${r}.mp4
+
+ # Fragment |bipbop_<res>-cenc-*.mp4| into 500ms segments:
+ MP4Box -dash 500 -rap -segment-name work.tmp/bipbop_${r}-cenc-audio-key${k}- -subsegs-per-sidx 5 work.tmp/bipbop_${r}-cenc-audio-key${k}.mp4
+ MP4Box -dash 500 -rap -segment-name work.tmp/bipbop_${r}-cenc-video-key${k}- -subsegs-per-sidx 5 work.tmp/bipbop_${r}-cenc-video-key${k}.mp4
+
+ # The above command will generate a set of fragments |bipbop_<res>-cenc-{video,audio}-*.m4s
+ # and |bipbop_<res>-cenc-{video,audio}-init.mp4| containing just the init segment.
+
+ # Remove unneeded mpd files.
+ rm bipbop_${r}-cenc-{audio,video}-key${k}_dash.mpd
+ done
+done
+
+# Only keep the first 4 audio & 2 video segments:
+cp work.tmp/*-init[.]mp4 ./
+cp work.tmp/*audio*-[1234][.]m4s ./
+cp work.tmp/*video*-[12][.]m4s ./
+
+rm -Rf work.tmp
diff --git a/dom/media/test/bipbop-frag-cenc.xml b/dom/media/test/bipbop-frag-cenc.xml
new file mode 100644
index 000000000..6f6a4d90a
--- /dev/null
+++ b/dom/media/test/bipbop-frag-cenc.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ This XML file describes the encryption applied to |bipbop-cenc*|. To
+ generate the bipbop-cenc files, run the following commands:
+
+ Encrypt bipbop-no-edts.mp4 with the keys specified in this file,
+ and output to |bipbop-cenc-{video,audio}.mp4|
+ MP4Box -crypt bipbop-frag-cenc.xml -rem 2 -out bipbop-cenc-video.mp4 bipbop-no-edts.mp4
+ MP4Box -crypt bipbop-frag-cenc.xml -rem 1 -out bipbop-cenc-audio.mp4 bipbop-no-edts.mp4
+
+ Fragment |bipbop-cenc-*.mp4| into 500ms segments:
+ MP4Box -dash 500 -rap -segment-name bipbop-cenc-video -subsegs-per-sidx 5 bipbop-cenc-video.mp4
+ MP4Box -dash 500 -rap -segment-name bipbop-cenc-audio -subsegs-per-sidx 5 bipbop-cenc-audio.mp4
+
+ The above command will generate a set of fragments in |bipbop-cenc-{video,audio}*.m4s
+ and |bipbop-cenc-{video,audio}init.mp4| containing just the init segment.
+
+ To cut down the duration, we throw out all but the first 3 audio & 2 video segments:
+ rm bipbop-cenc-audio{[^123],[123][^.]}.m4s
+ rm bipbop-cenc-video{[^12],[12][^.]}.m4s
+
+ MP4Box will also have generated some *.mpd files we don't need:
+ rm bipbop-cenc-*.mpd
+
+ Delete intermediate encrypted files:
+ rm bipbop-cenc-{audio,video}.mp4
+-->
+
+<GPACDRM type="CENC AES-CTR">
+
+ <DRMInfo type="pssh" version="1">
+ <!--
+ SystemID specified in
+ https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
+ -->
+ <BS ID128="1077efecc0b24d02ace33c1e52e2fb4b" />
+ <!-- Number of KeyIDs = 2 -->
+ <BS bits="32" value="2" />
+ <!-- KeyID -->
+ <BS ID128="0x7e571d037e571d037e571d037e571d03" />
+ <BS ID128="0x7e571d047e571d047e571d047e571d04" />
+ </DRMInfo>
+
+ <CrypTrack trackID="1" isEncrypted="1" IV_size="16" saiSavedBox="senc"
+ first_IV="0x00000000000000000000000000000000">
+ <key KID="0x7e571d037e571d037e571d037e571d03"
+ value="0x7e5733337e5733337e5733337e573333" />
+ </CrypTrack>
+
+ <CrypTrack trackID="2" isEncrypted="1" IV_size="16" saiSavedBox="senc"
+ first_IV="0x00000000000000000000000000000000">
+ <key KID="0x7e571d047e571d047e571d047e571d04"
+ value="0x7e5744447e5744447e5744447e574444" />
+ </CrypTrack>
+
+</GPACDRM>
diff --git a/dom/media/test/bipbop-lateaudio.mp4 b/dom/media/test/bipbop-lateaudio.mp4
new file mode 100644
index 000000000..5b4cc5709
--- /dev/null
+++ b/dom/media/test/bipbop-lateaudio.mp4
Binary files differ
diff --git a/dom/media/test/bipbop-lateaudio.mp4^headers^ b/dom/media/test/bipbop-lateaudio.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop-lateaudio.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop-no-edts.mp4 b/dom/media/test/bipbop-no-edts.mp4
new file mode 100644
index 000000000..63435887d
--- /dev/null
+++ b/dom/media/test/bipbop-no-edts.mp4
Binary files differ
diff --git a/dom/media/test/bipbop.mp4 b/dom/media/test/bipbop.mp4
new file mode 100644
index 000000000..017d658f3
--- /dev/null
+++ b/dom/media/test/bipbop.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-1.m4s b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-1.m4s
new file mode 100644
index 000000000..e2bd754c7
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-1.m4s^headers^ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-2.m4s b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-2.m4s
new file mode 100644
index 000000000..347835fee
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-2.m4s^headers^ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-3.m4s b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-3.m4s
new file mode 100644
index 000000000..64b0da69a
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-3.m4s^headers^ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-4.m4s b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-4.m4s
new file mode 100644
index 000000000..864f4248a
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-4.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-4.m4s^headers^ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-4.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-4.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-init.mp4 b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-init.mp4
new file mode 100644
index 000000000..40c3a7bb9
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-init.mp4^headers^ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key1-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-1.m4s b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-1.m4s
new file mode 100644
index 000000000..a8896e069
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-1.m4s^headers^ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-2.m4s b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-2.m4s
new file mode 100644
index 000000000..0f0a35ce7
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-2.m4s^headers^ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-3.m4s b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-3.m4s
new file mode 100644
index 000000000..fece52ff4
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-3.m4s^headers^ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-4.m4s b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-4.m4s
new file mode 100644
index 000000000..70e61e3d5
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-4.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-4.m4s^headers^ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-4.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-4.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-init.mp4 b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-init.mp4
new file mode 100644
index 000000000..986e5fb18
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-init.mp4^headers^ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-audio-key2-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-video-key1-1.m4s b/dom/media/test/bipbop_225w_175kbps-cenc-video-key1-1.m4s
new file mode 100644
index 000000000..547950e51
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-video-key1-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-video-key1-1.m4s^headers^ b/dom/media/test/bipbop_225w_175kbps-cenc-video-key1-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-video-key1-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-video-key1-init.mp4 b/dom/media/test/bipbop_225w_175kbps-cenc-video-key1-init.mp4
new file mode 100644
index 000000000..3214f131d
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-video-key1-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-video-key1-init.mp4^headers^ b/dom/media/test/bipbop_225w_175kbps-cenc-video-key1-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-video-key1-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-video-key2-1.m4s b/dom/media/test/bipbop_225w_175kbps-cenc-video-key2-1.m4s
new file mode 100644
index 000000000..08713078d
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-video-key2-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-video-key2-1.m4s^headers^ b/dom/media/test/bipbop_225w_175kbps-cenc-video-key2-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-video-key2-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-video-key2-init.mp4 b/dom/media/test/bipbop_225w_175kbps-cenc-video-key2-init.mp4
new file mode 100644
index 000000000..0b13fed5f
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-video-key2-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_225w_175kbps-cenc-video-key2-init.mp4^headers^ b/dom/media/test/bipbop_225w_175kbps-cenc-video-key2-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps-cenc-video-key2-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_225w_175kbps.mp4 b/dom/media/test/bipbop_225w_175kbps.mp4
new file mode 100644
index 000000000..abe37b9f9
--- /dev/null
+++ b/dom/media/test/bipbop_225w_175kbps.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-1.m4s b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-1.m4s
new file mode 100644
index 000000000..e2bd754c7
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-1.m4s^headers^ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-2.m4s b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-2.m4s
new file mode 100644
index 000000000..347835fee
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-2.m4s^headers^ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-3.m4s b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-3.m4s
new file mode 100644
index 000000000..64b0da69a
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-3.m4s^headers^ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-4.m4s b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-4.m4s
new file mode 100644
index 000000000..864f4248a
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-4.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-4.m4s^headers^ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-4.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-4.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-init.mp4 b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-init.mp4
new file mode 100644
index 000000000..21f386327
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-init.mp4^headers^ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key1-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-1.m4s b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-1.m4s
new file mode 100644
index 000000000..a8896e069
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-1.m4s^headers^ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-2.m4s b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-2.m4s
new file mode 100644
index 000000000..0f0a35ce7
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-2.m4s^headers^ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-3.m4s b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-3.m4s
new file mode 100644
index 000000000..fece52ff4
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-3.m4s^headers^ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-4.m4s b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-4.m4s
new file mode 100644
index 000000000..70e61e3d5
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-4.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-4.m4s^headers^ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-4.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-4.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-init.mp4 b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-init.mp4
new file mode 100644
index 000000000..bc741cdf8
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-init.mp4^headers^ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-audio-key2-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-video-key1-1.m4s b/dom/media/test/bipbop_300_215kbps-cenc-video-key1-1.m4s
new file mode 100644
index 000000000..9c6818d06
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-video-key1-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-video-key1-1.m4s^headers^ b/dom/media/test/bipbop_300_215kbps-cenc-video-key1-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-video-key1-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-video-key1-2.m4s b/dom/media/test/bipbop_300_215kbps-cenc-video-key1-2.m4s
new file mode 100644
index 000000000..f327aaa57
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-video-key1-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-video-key1-2.m4s^headers^ b/dom/media/test/bipbop_300_215kbps-cenc-video-key1-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-video-key1-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-video-key1-init.mp4 b/dom/media/test/bipbop_300_215kbps-cenc-video-key1-init.mp4
new file mode 100644
index 000000000..543f18c24
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-video-key1-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-video-key1-init.mp4^headers^ b/dom/media/test/bipbop_300_215kbps-cenc-video-key1-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-video-key1-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-video-key2-1.m4s b/dom/media/test/bipbop_300_215kbps-cenc-video-key2-1.m4s
new file mode 100644
index 000000000..f850ceaf0
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-video-key2-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-video-key2-1.m4s^headers^ b/dom/media/test/bipbop_300_215kbps-cenc-video-key2-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-video-key2-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-video-key2-2.m4s b/dom/media/test/bipbop_300_215kbps-cenc-video-key2-2.m4s
new file mode 100644
index 000000000..a28a106da
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-video-key2-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-video-key2-2.m4s^headers^ b/dom/media/test/bipbop_300_215kbps-cenc-video-key2-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-video-key2-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-video-key2-init.mp4 b/dom/media/test/bipbop_300_215kbps-cenc-video-key2-init.mp4
new file mode 100644
index 000000000..a05a87997
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-video-key2-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_300_215kbps-cenc-video-key2-init.mp4^headers^ b/dom/media/test/bipbop_300_215kbps-cenc-video-key2-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps-cenc-video-key2-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300_215kbps.mp4 b/dom/media/test/bipbop_300_215kbps.mp4
new file mode 100644
index 000000000..af01e5fa3
--- /dev/null
+++ b/dom/media/test/bipbop_300_215kbps.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-1.m4s b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-1.m4s
new file mode 100644
index 000000000..e2bd754c7
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-1.m4s^headers^ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-2.m4s b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-2.m4s
new file mode 100644
index 000000000..347835fee
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-2.m4s^headers^ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-3.m4s b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-3.m4s
new file mode 100644
index 000000000..64b0da69a
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-3.m4s^headers^ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-4.m4s b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-4.m4s
new file mode 100644
index 000000000..864f4248a
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-4.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-4.m4s^headers^ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-4.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-4.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-init.mp4 b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-init.mp4
new file mode 100644
index 000000000..40c3a7bb9
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-init.mp4^headers^ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key1-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-1.m4s b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-1.m4s
new file mode 100644
index 000000000..a8896e069
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-1.m4s^headers^ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-2.m4s b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-2.m4s
new file mode 100644
index 000000000..0f0a35ce7
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-2.m4s^headers^ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-3.m4s b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-3.m4s
new file mode 100644
index 000000000..fece52ff4
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-3.m4s^headers^ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-4.m4s b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-4.m4s
new file mode 100644
index 000000000..70e61e3d5
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-4.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-4.m4s^headers^ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-4.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-4.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-init.mp4 b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-init.mp4
new file mode 100644
index 000000000..986e5fb18
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-init.mp4^headers^ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-audio-key2-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-1.m4s b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-1.m4s
new file mode 100644
index 000000000..9c6818d06
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-1.m4s^headers^ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-2.m4s b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-2.m4s
new file mode 100644
index 000000000..ce2e64eb3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-2.m4s^headers^ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-init.mp4 b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-init.mp4
new file mode 100644
index 000000000..8592a5b0a
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-init.mp4^headers^ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key1-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-1.m4s b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-1.m4s
new file mode 100644
index 000000000..f850ceaf0
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-1.m4s^headers^ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-2.m4s b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-2.m4s
new file mode 100644
index 000000000..d07ce9753
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-2.m4s^headers^ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-init.mp4 b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-init.mp4
new file mode 100644
index 000000000..9d2fa23dd
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-init.mp4^headers^ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps-cenc-video-key2-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_300wp_227kbps.mp4 b/dom/media/test/bipbop_300wp_227kbps.mp4
new file mode 100644
index 000000000..149935531
--- /dev/null
+++ b/dom/media/test/bipbop_300wp_227kbps.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-1.m4s b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-1.m4s
new file mode 100644
index 000000000..e2bd754c7
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-1.m4s^headers^ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-2.m4s b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-2.m4s
new file mode 100644
index 000000000..347835fee
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-2.m4s^headers^ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-3.m4s b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-3.m4s
new file mode 100644
index 000000000..64b0da69a
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-3.m4s^headers^ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-4.m4s b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-4.m4s
new file mode 100644
index 000000000..864f4248a
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-4.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-4.m4s^headers^ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-4.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-4.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-init.mp4 b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-init.mp4
new file mode 100644
index 000000000..40c3a7bb9
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-init.mp4^headers^ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key1-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-1.m4s b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-1.m4s
new file mode 100644
index 000000000..a8896e069
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-1.m4s^headers^ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-2.m4s b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-2.m4s
new file mode 100644
index 000000000..0f0a35ce7
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-2.m4s^headers^ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-3.m4s b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-3.m4s
new file mode 100644
index 000000000..fece52ff4
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-3.m4s^headers^ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-4.m4s b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-4.m4s
new file mode 100644
index 000000000..70e61e3d5
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-4.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-4.m4s^headers^ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-4.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-4.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-init.mp4 b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-init.mp4
new file mode 100644
index 000000000..986e5fb18
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-init.mp4^headers^ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-audio-key2-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-video-key1-1.m4s b/dom/media/test/bipbop_360w_253kbps-cenc-video-key1-1.m4s
new file mode 100644
index 000000000..a571d47cf
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-video-key1-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-video-key1-1.m4s^headers^ b/dom/media/test/bipbop_360w_253kbps-cenc-video-key1-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-video-key1-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-video-key1-init.mp4 b/dom/media/test/bipbop_360w_253kbps-cenc-video-key1-init.mp4
new file mode 100644
index 000000000..42dbfec1e
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-video-key1-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-video-key1-init.mp4^headers^ b/dom/media/test/bipbop_360w_253kbps-cenc-video-key1-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-video-key1-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-video-key2-1.m4s b/dom/media/test/bipbop_360w_253kbps-cenc-video-key2-1.m4s
new file mode 100644
index 000000000..9e4224cac
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-video-key2-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-video-key2-1.m4s^headers^ b/dom/media/test/bipbop_360w_253kbps-cenc-video-key2-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-video-key2-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-video-key2-init.mp4 b/dom/media/test/bipbop_360w_253kbps-cenc-video-key2-init.mp4
new file mode 100644
index 000000000..21763ecbd
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-video-key2-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-cenc-video-key2-init.mp4^headers^ b/dom/media/test/bipbop_360w_253kbps-cenc-video-key2-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-cenc-video-key2-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps-clearkey-audio.webm b/dom/media/test/bipbop_360w_253kbps-clearkey-audio.webm
new file mode 100644
index 000000000..4be8f340c
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-clearkey-audio.webm
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-clearkey-audio.webm^headers^ b/dom/media/test/bipbop_360w_253kbps-clearkey-audio.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-clearkey-audio.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps-clearkey-video-vp8.webm b/dom/media/test/bipbop_360w_253kbps-clearkey-video-vp8.webm
new file mode 100644
index 000000000..56cf4c483
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-clearkey-video-vp8.webm
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-clearkey-video-vp8.webm^headers^ b/dom/media/test/bipbop_360w_253kbps-clearkey-video-vp8.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-clearkey-video-vp8.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps-clearkey-video-vp9.webm b/dom/media/test/bipbop_360w_253kbps-clearkey-video-vp9.webm
new file mode 100644
index 000000000..9f411d0e3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-clearkey-video-vp9.webm
Binary files differ
diff --git a/dom/media/test/bipbop_360w_253kbps-clearkey-video-vp9.webm^headers^ b/dom/media/test/bipbop_360w_253kbps-clearkey-video-vp9.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps-clearkey-video-vp9.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_360w_253kbps.mp4 b/dom/media/test/bipbop_360w_253kbps.mp4
new file mode 100644
index 000000000..6c796f4e1
--- /dev/null
+++ b/dom/media/test/bipbop_360w_253kbps.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-1.m4s b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-1.m4s
new file mode 100644
index 000000000..e2bd754c7
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-1.m4s^headers^ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-2.m4s b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-2.m4s
new file mode 100644
index 000000000..347835fee
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-2.m4s^headers^ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-3.m4s b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-3.m4s
new file mode 100644
index 000000000..64b0da69a
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-3.m4s^headers^ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-4.m4s b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-4.m4s
new file mode 100644
index 000000000..864f4248a
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-4.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-4.m4s^headers^ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-4.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-4.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-init.mp4 b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-init.mp4
new file mode 100644
index 000000000..e626fa456
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-init.mp4^headers^ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key1-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-1.m4s b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-1.m4s
new file mode 100644
index 000000000..a8896e069
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-1.m4s^headers^ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-2.m4s b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-2.m4s
new file mode 100644
index 000000000..0f0a35ce7
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-2.m4s^headers^ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-3.m4s b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-3.m4s
new file mode 100644
index 000000000..fece52ff4
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-3.m4s^headers^ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-4.m4s b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-4.m4s
new file mode 100644
index 000000000..70e61e3d5
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-4.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-4.m4s^headers^ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-4.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-4.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-init.mp4 b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-init.mp4
new file mode 100644
index 000000000..d7cbb2b6b
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-init.mp4^headers^ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-audio-key2-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-video-key1-1.m4s b/dom/media/test/bipbop_480_624kbps-cenc-video-key1-1.m4s
new file mode 100644
index 000000000..805f4bbf3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-video-key1-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-video-key1-1.m4s^headers^ b/dom/media/test/bipbop_480_624kbps-cenc-video-key1-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-video-key1-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-video-key1-2.m4s b/dom/media/test/bipbop_480_624kbps-cenc-video-key1-2.m4s
new file mode 100644
index 000000000..5bf999473
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-video-key1-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-video-key1-2.m4s^headers^ b/dom/media/test/bipbop_480_624kbps-cenc-video-key1-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-video-key1-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-video-key1-init.mp4 b/dom/media/test/bipbop_480_624kbps-cenc-video-key1-init.mp4
new file mode 100644
index 000000000..77c7daba5
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-video-key1-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-video-key1-init.mp4^headers^ b/dom/media/test/bipbop_480_624kbps-cenc-video-key1-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-video-key1-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-video-key2-1.m4s b/dom/media/test/bipbop_480_624kbps-cenc-video-key2-1.m4s
new file mode 100644
index 000000000..c5127beec
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-video-key2-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-video-key2-1.m4s^headers^ b/dom/media/test/bipbop_480_624kbps-cenc-video-key2-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-video-key2-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-video-key2-2.m4s b/dom/media/test/bipbop_480_624kbps-cenc-video-key2-2.m4s
new file mode 100644
index 000000000..b0ff51f74
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-video-key2-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-video-key2-2.m4s^headers^ b/dom/media/test/bipbop_480_624kbps-cenc-video-key2-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-video-key2-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-video-key2-init.mp4 b/dom/media/test/bipbop_480_624kbps-cenc-video-key2-init.mp4
new file mode 100644
index 000000000..cfa099c04
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-video-key2-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480_624kbps-cenc-video-key2-init.mp4^headers^ b/dom/media/test/bipbop_480_624kbps-cenc-video-key2-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps-cenc-video-key2-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_624kbps.mp4 b/dom/media/test/bipbop_480_624kbps.mp4
new file mode 100644
index 000000000..27928b85f
--- /dev/null
+++ b/dom/media/test/bipbop_480_624kbps.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-1.m4s b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-1.m4s
new file mode 100644
index 000000000..e2bd754c7
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-1.m4s^headers^ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-2.m4s b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-2.m4s
new file mode 100644
index 000000000..347835fee
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-2.m4s^headers^ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-3.m4s b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-3.m4s
new file mode 100644
index 000000000..64b0da69a
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-3.m4s^headers^ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-4.m4s b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-4.m4s
new file mode 100644
index 000000000..864f4248a
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-4.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-4.m4s^headers^ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-4.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-4.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-init.mp4 b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-init.mp4
new file mode 100644
index 000000000..c9106aad9
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-init.mp4^headers^ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key1-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-1.m4s b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-1.m4s
new file mode 100644
index 000000000..a8896e069
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-1.m4s^headers^ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-2.m4s b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-2.m4s
new file mode 100644
index 000000000..0f0a35ce7
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-2.m4s^headers^ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-3.m4s b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-3.m4s
new file mode 100644
index 000000000..fece52ff4
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-3.m4s^headers^ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-4.m4s b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-4.m4s
new file mode 100644
index 000000000..70e61e3d5
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-4.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-4.m4s^headers^ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-4.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-4.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-init.mp4 b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-init.mp4
new file mode 100644
index 000000000..888b20ab6
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-init.mp4^headers^ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-audio-key2-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-video-key1-1.m4s b/dom/media/test/bipbop_480_959kbps-cenc-video-key1-1.m4s
new file mode 100644
index 000000000..796ad1367
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-video-key1-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-video-key1-1.m4s^headers^ b/dom/media/test/bipbop_480_959kbps-cenc-video-key1-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-video-key1-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-video-key1-2.m4s b/dom/media/test/bipbop_480_959kbps-cenc-video-key1-2.m4s
new file mode 100644
index 000000000..d02be5319
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-video-key1-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-video-key1-2.m4s^headers^ b/dom/media/test/bipbop_480_959kbps-cenc-video-key1-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-video-key1-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-video-key1-init.mp4 b/dom/media/test/bipbop_480_959kbps-cenc-video-key1-init.mp4
new file mode 100644
index 000000000..6e0c60f98
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-video-key1-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-video-key1-init.mp4^headers^ b/dom/media/test/bipbop_480_959kbps-cenc-video-key1-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-video-key1-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-video-key2-1.m4s b/dom/media/test/bipbop_480_959kbps-cenc-video-key2-1.m4s
new file mode 100644
index 000000000..06778e6f2
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-video-key2-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-video-key2-1.m4s^headers^ b/dom/media/test/bipbop_480_959kbps-cenc-video-key2-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-video-key2-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-video-key2-2.m4s b/dom/media/test/bipbop_480_959kbps-cenc-video-key2-2.m4s
new file mode 100644
index 000000000..4c1c603e8
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-video-key2-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-video-key2-2.m4s^headers^ b/dom/media/test/bipbop_480_959kbps-cenc-video-key2-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-video-key2-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-video-key2-init.mp4 b/dom/media/test/bipbop_480_959kbps-cenc-video-key2-init.mp4
new file mode 100644
index 000000000..f4a98eca9
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-video-key2-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480_959kbps-cenc-video-key2-init.mp4^headers^ b/dom/media/test/bipbop_480_959kbps-cenc-video-key2-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps-cenc-video-key2-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480_959kbps.mp4 b/dom/media/test/bipbop_480_959kbps.mp4
new file mode 100644
index 000000000..4a9f2ee82
--- /dev/null
+++ b/dom/media/test/bipbop_480_959kbps.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-1.m4s b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-1.m4s
new file mode 100644
index 000000000..e2bd754c7
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-1.m4s^headers^ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-2.m4s b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-2.m4s
new file mode 100644
index 000000000..347835fee
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-2.m4s^headers^ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-3.m4s b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-3.m4s
new file mode 100644
index 000000000..64b0da69a
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-3.m4s^headers^ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-4.m4s b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-4.m4s
new file mode 100644
index 000000000..864f4248a
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-4.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-4.m4s^headers^ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-4.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-4.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-init.mp4 b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-init.mp4
new file mode 100644
index 000000000..416bc7a7c
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-init.mp4^headers^ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key1-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-1.m4s b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-1.m4s
new file mode 100644
index 000000000..a8896e069
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-1.m4s^headers^ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-2.m4s b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-2.m4s
new file mode 100644
index 000000000..0f0a35ce7
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-2.m4s^headers^ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-3.m4s b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-3.m4s
new file mode 100644
index 000000000..fece52ff4
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-3.m4s^headers^ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-4.m4s b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-4.m4s
new file mode 100644
index 000000000..70e61e3d5
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-4.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-4.m4s^headers^ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-4.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-4.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-init.mp4 b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-init.mp4
new file mode 100644
index 000000000..73d542cfe
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-init.mp4^headers^ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-audio-key2-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-1.m4s b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-1.m4s
new file mode 100644
index 000000000..796ad1367
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-1.m4s^headers^ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-2.m4s b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-2.m4s
new file mode 100644
index 000000000..80824e9ff
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-2.m4s^headers^ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-init.mp4 b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-init.mp4
new file mode 100644
index 000000000..5db21d091
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-init.mp4^headers^ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key1-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-1.m4s b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-1.m4s
new file mode 100644
index 000000000..06778e6f2
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-1.m4s^headers^ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-2.m4s b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-2.m4s
new file mode 100644
index 000000000..38a081187
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-2.m4s^headers^ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-init.mp4 b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-init.mp4
new file mode 100644
index 000000000..bc8bddf50
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-init.mp4^headers^ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps-cenc-video-key2-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_1001kbps.mp4 b/dom/media/test/bipbop_480wp_1001kbps.mp4
new file mode 100644
index 000000000..600376cf8
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_1001kbps.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-1.m4s b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-1.m4s
new file mode 100644
index 000000000..e2bd754c7
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-1.m4s^headers^ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-2.m4s b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-2.m4s
new file mode 100644
index 000000000..347835fee
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-2.m4s^headers^ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-3.m4s b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-3.m4s
new file mode 100644
index 000000000..64b0da69a
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-3.m4s^headers^ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-4.m4s b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-4.m4s
new file mode 100644
index 000000000..864f4248a
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-4.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-4.m4s^headers^ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-4.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-4.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-init.mp4 b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-init.mp4
new file mode 100644
index 000000000..416bc7a7c
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-init.mp4^headers^ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key1-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-1.m4s b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-1.m4s
new file mode 100644
index 000000000..a8896e069
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-1.m4s^headers^ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-2.m4s b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-2.m4s
new file mode 100644
index 000000000..0f0a35ce7
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-2.m4s^headers^ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-3.m4s b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-3.m4s
new file mode 100644
index 000000000..fece52ff4
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-3.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-3.m4s^headers^ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-3.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-3.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-4.m4s b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-4.m4s
new file mode 100644
index 000000000..70e61e3d5
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-4.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-4.m4s^headers^ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-4.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-4.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-init.mp4 b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-init.mp4
new file mode 100644
index 000000000..73d542cfe
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-init.mp4^headers^ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-audio-key2-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-1.m4s b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-1.m4s
new file mode 100644
index 000000000..805f4bbf3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-1.m4s^headers^ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-2.m4s b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-2.m4s
new file mode 100644
index 000000000..0a40d1cb7
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-2.m4s^headers^ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-init.mp4 b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-init.mp4
new file mode 100644
index 000000000..5db21d091
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-init.mp4^headers^ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key1-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-1.m4s b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-1.m4s
new file mode 100644
index 000000000..c5127beec
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-1.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-1.m4s^headers^ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-1.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-1.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-2.m4s b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-2.m4s
new file mode 100644
index 000000000..3f344022a
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-2.m4s
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-2.m4s^headers^ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-2.m4s^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-2.m4s^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-init.mp4 b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-init.mp4
new file mode 100644
index 000000000..bc8bddf50
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-init.mp4
Binary files differ
diff --git a/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-init.mp4^headers^ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-init.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps-cenc-video-key2-init.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bipbop_480wp_663kbps.mp4 b/dom/media/test/bipbop_480wp_663kbps.mp4
new file mode 100644
index 000000000..3cc1da69d
--- /dev/null
+++ b/dom/media/test/bipbop_480wp_663kbps.mp4
Binary files differ
diff --git a/dom/media/test/black100x100-aspect3to2.ogv b/dom/media/test/black100x100-aspect3to2.ogv
new file mode 100644
index 000000000..81fe51ffb
--- /dev/null
+++ b/dom/media/test/black100x100-aspect3to2.ogv
Binary files differ
diff --git a/dom/media/test/black100x100-aspect3to2.ogv^headers^ b/dom/media/test/black100x100-aspect3to2.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/black100x100-aspect3to2.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bogus.duh b/dom/media/test/bogus.duh
new file mode 100644
index 000000000..528ae275d
--- /dev/null
+++ b/dom/media/test/bogus.duh
@@ -0,0 +1,45 @@
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
diff --git a/dom/media/test/bogus.ogv b/dom/media/test/bogus.ogv
new file mode 100644
index 000000000..528ae275d
--- /dev/null
+++ b/dom/media/test/bogus.ogv
@@ -0,0 +1,45 @@
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
diff --git a/dom/media/test/bogus.ogv^headers^ b/dom/media/test/bogus.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bogus.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bogus.wav b/dom/media/test/bogus.wav
new file mode 100644
index 000000000..528ae275d
--- /dev/null
+++ b/dom/media/test/bogus.wav
@@ -0,0 +1,45 @@
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
+bogus bogus bogus
diff --git a/dom/media/test/bogus.wav^headers^ b/dom/media/test/bogus.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bogus.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug1066943.webm b/dom/media/test/bug1066943.webm
new file mode 100644
index 000000000..64a24ec89
--- /dev/null
+++ b/dom/media/test/bug1066943.webm
Binary files differ
diff --git a/dom/media/test/bug1066943.webm^headers^ b/dom/media/test/bug1066943.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug1066943.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug1301226-odd.wav b/dom/media/test/bug1301226-odd.wav
new file mode 100644
index 000000000..dd2df4e4d
--- /dev/null
+++ b/dom/media/test/bug1301226-odd.wav
Binary files differ
diff --git a/dom/media/test/bug1301226-odd.wav^headers^ b/dom/media/test/bug1301226-odd.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug1301226-odd.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug1301226.wav b/dom/media/test/bug1301226.wav
new file mode 100644
index 000000000..0128486f0
--- /dev/null
+++ b/dom/media/test/bug1301226.wav
Binary files differ
diff --git a/dom/media/test/bug1301226.wav^headers^ b/dom/media/test/bug1301226.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug1301226.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug461281.ogg b/dom/media/test/bug461281.ogg
new file mode 100644
index 000000000..d7f6a0ccf
--- /dev/null
+++ b/dom/media/test/bug461281.ogg
Binary files differ
diff --git a/dom/media/test/bug461281.ogg^headers^ b/dom/media/test/bug461281.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug461281.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug482461-theora.ogv b/dom/media/test/bug482461-theora.ogv
new file mode 100644
index 000000000..941b8d8ef
--- /dev/null
+++ b/dom/media/test/bug482461-theora.ogv
Binary files differ
diff --git a/dom/media/test/bug482461-theora.ogv^headers^ b/dom/media/test/bug482461-theora.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug482461-theora.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug482461.ogv b/dom/media/test/bug482461.ogv
new file mode 100644
index 000000000..6cf6aed33
--- /dev/null
+++ b/dom/media/test/bug482461.ogv
Binary files differ
diff --git a/dom/media/test/bug482461.ogv^headers^ b/dom/media/test/bug482461.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug482461.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug495129.ogv b/dom/media/test/bug495129.ogv
new file mode 100644
index 000000000..44eb9296f
--- /dev/null
+++ b/dom/media/test/bug495129.ogv
Binary files differ
diff --git a/dom/media/test/bug495129.ogv^headers^ b/dom/media/test/bug495129.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug495129.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug495794.ogg b/dom/media/test/bug495794.ogg
new file mode 100644
index 000000000..1c19a6406
--- /dev/null
+++ b/dom/media/test/bug495794.ogg
Binary files differ
diff --git a/dom/media/test/bug495794.ogg^headers^ b/dom/media/test/bug495794.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug495794.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug498380.ogv b/dom/media/test/bug498380.ogv
new file mode 100644
index 000000000..1179ecb70
--- /dev/null
+++ b/dom/media/test/bug498380.ogv
Binary files differ
diff --git a/dom/media/test/bug498380.ogv^headers^ b/dom/media/test/bug498380.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug498380.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug498855-1.ogv b/dom/media/test/bug498855-1.ogv
new file mode 100644
index 000000000..95a524da4
--- /dev/null
+++ b/dom/media/test/bug498855-1.ogv
Binary files differ
diff --git a/dom/media/test/bug498855-1.ogv^headers^ b/dom/media/test/bug498855-1.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug498855-1.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug498855-2.ogv b/dom/media/test/bug498855-2.ogv
new file mode 100644
index 000000000..795a308ae
--- /dev/null
+++ b/dom/media/test/bug498855-2.ogv
Binary files differ
diff --git a/dom/media/test/bug498855-2.ogv^headers^ b/dom/media/test/bug498855-2.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug498855-2.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug498855-3.ogv b/dom/media/test/bug498855-3.ogv
new file mode 100644
index 000000000..714858dfe
--- /dev/null
+++ b/dom/media/test/bug498855-3.ogv
Binary files differ
diff --git a/dom/media/test/bug498855-3.ogv^headers^ b/dom/media/test/bug498855-3.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug498855-3.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug499519.ogv b/dom/media/test/bug499519.ogv
new file mode 100644
index 000000000..62c0922d3
--- /dev/null
+++ b/dom/media/test/bug499519.ogv
Binary files differ
diff --git a/dom/media/test/bug499519.ogv^headers^ b/dom/media/test/bug499519.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug499519.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug500311.ogv b/dom/media/test/bug500311.ogv
new file mode 100644
index 000000000..2cf27ef1e
--- /dev/null
+++ b/dom/media/test/bug500311.ogv
Binary files differ
diff --git a/dom/media/test/bug500311.ogv^headers^ b/dom/media/test/bug500311.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug500311.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug501279.ogg b/dom/media/test/bug501279.ogg
new file mode 100644
index 000000000..e266f07ee
--- /dev/null
+++ b/dom/media/test/bug501279.ogg
Binary files differ
diff --git a/dom/media/test/bug501279.ogg^headers^ b/dom/media/test/bug501279.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug501279.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug504613.ogv b/dom/media/test/bug504613.ogv
new file mode 100644
index 000000000..5c7fd015e
--- /dev/null
+++ b/dom/media/test/bug504613.ogv
Binary files differ
diff --git a/dom/media/test/bug504613.ogv^headers^ b/dom/media/test/bug504613.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug504613.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug504644.ogv b/dom/media/test/bug504644.ogv
new file mode 100644
index 000000000..46fb4a876
--- /dev/null
+++ b/dom/media/test/bug504644.ogv
Binary files differ
diff --git a/dom/media/test/bug504644.ogv^headers^ b/dom/media/test/bug504644.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug504644.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug504843.ogv b/dom/media/test/bug504843.ogv
new file mode 100644
index 000000000..94b475086
--- /dev/null
+++ b/dom/media/test/bug504843.ogv
Binary files differ
diff --git a/dom/media/test/bug504843.ogv^headers^ b/dom/media/test/bug504843.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug504843.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug506094.ogv b/dom/media/test/bug506094.ogv
new file mode 100644
index 000000000..142b7b9ad
--- /dev/null
+++ b/dom/media/test/bug506094.ogv
Binary files differ
diff --git a/dom/media/test/bug506094.ogv^headers^ b/dom/media/test/bug506094.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug506094.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug516323.indexed.ogv b/dom/media/test/bug516323.indexed.ogv
new file mode 100644
index 000000000..7bd76eecc
--- /dev/null
+++ b/dom/media/test/bug516323.indexed.ogv
Binary files differ
diff --git a/dom/media/test/bug516323.indexed.ogv^headers^ b/dom/media/test/bug516323.indexed.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug516323.indexed.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug516323.ogv b/dom/media/test/bug516323.ogv
new file mode 100644
index 000000000..8f2f38b98
--- /dev/null
+++ b/dom/media/test/bug516323.ogv
Binary files differ
diff --git a/dom/media/test/bug516323.ogv^headers^ b/dom/media/test/bug516323.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug516323.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug520493.ogg b/dom/media/test/bug520493.ogg
new file mode 100644
index 000000000..6eb23198f
--- /dev/null
+++ b/dom/media/test/bug520493.ogg
Binary files differ
diff --git a/dom/media/test/bug520493.ogg^headers^ b/dom/media/test/bug520493.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug520493.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug520500.ogg b/dom/media/test/bug520500.ogg
new file mode 100644
index 000000000..b91d3dd97
--- /dev/null
+++ b/dom/media/test/bug520500.ogg
Binary files differ
diff --git a/dom/media/test/bug520500.ogg^headers^ b/dom/media/test/bug520500.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug520500.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug520908.ogv b/dom/media/test/bug520908.ogv
new file mode 100644
index 000000000..093158432
--- /dev/null
+++ b/dom/media/test/bug520908.ogv
Binary files differ
diff --git a/dom/media/test/bug520908.ogv^headers^ b/dom/media/test/bug520908.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug520908.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug523816.ogv b/dom/media/test/bug523816.ogv
new file mode 100644
index 000000000..ca9a31b6d
--- /dev/null
+++ b/dom/media/test/bug523816.ogv
Binary files differ
diff --git a/dom/media/test/bug523816.ogv^headers^ b/dom/media/test/bug523816.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug523816.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug533822.ogg b/dom/media/test/bug533822.ogg
new file mode 100644
index 000000000..a8e506910
--- /dev/null
+++ b/dom/media/test/bug533822.ogg
Binary files differ
diff --git a/dom/media/test/bug533822.ogg^headers^ b/dom/media/test/bug533822.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug533822.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug556821.ogv b/dom/media/test/bug556821.ogv
new file mode 100644
index 000000000..8d76fee45
--- /dev/null
+++ b/dom/media/test/bug556821.ogv
Binary files differ
diff --git a/dom/media/test/bug556821.ogv^headers^ b/dom/media/test/bug556821.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug556821.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug557094.ogv b/dom/media/test/bug557094.ogv
new file mode 100644
index 000000000..b4fc0799a
--- /dev/null
+++ b/dom/media/test/bug557094.ogv
Binary files differ
diff --git a/dom/media/test/bug557094.ogv^headers^ b/dom/media/test/bug557094.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug557094.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug580982.webm b/dom/media/test/bug580982.webm
new file mode 100644
index 000000000..802019f39
--- /dev/null
+++ b/dom/media/test/bug580982.webm
Binary files differ
diff --git a/dom/media/test/bug580982.webm^headers^ b/dom/media/test/bug580982.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug580982.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug603918.webm b/dom/media/test/bug603918.webm
new file mode 100644
index 000000000..c430e97f4
--- /dev/null
+++ b/dom/media/test/bug603918.webm
Binary files differ
diff --git a/dom/media/test/bug603918.webm^headers^ b/dom/media/test/bug603918.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug603918.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug604067.webm b/dom/media/test/bug604067.webm
new file mode 100644
index 000000000..86bdfdc91
--- /dev/null
+++ b/dom/media/test/bug604067.webm
Binary files differ
diff --git a/dom/media/test/bug604067.webm^headers^ b/dom/media/test/bug604067.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/bug604067.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/bug883173.vtt b/dom/media/test/bug883173.vtt
new file mode 100644
index 000000000..61f086bcc
--- /dev/null
+++ b/dom/media/test/bug883173.vtt
@@ -0,0 +1,16 @@
+WEBVTT
+
+00:03.000 --> 00:04.000
+Should display fifth.
+
+00:01.000 --> 00:02.000
+Should display first.
+
+00:01.000 --> 00:03.000
+Should display second.
+
+00:02.000 --> 00:04.000
+Should display forth.
+
+00:02.000 --> 00:03.000
+Should display third.
diff --git a/dom/media/test/can_play_type_dash.js b/dom/media/test/can_play_type_dash.js
new file mode 100644
index 000000000..ec5764be2
--- /dev/null
+++ b/dom/media/test/can_play_type_dash.js
@@ -0,0 +1,27 @@
+function check_dash(v, enabled) {
+ function check(type, expected) {
+ is(v.canPlayType(type), enabled ? expected : "", type);
+ }
+
+ // DASH types
+ check("application/dash+xml", "probably");
+
+ // Supported Webm codecs
+ check("application/dash+xml; codecs=vorbis", "probably");
+ check("application/dash+xml; codecs=vorbis", "probably");
+ check("application/dash+xml; codecs=vorbis,vp8", "probably");
+ check("application/dash+xml; codecs=vorbis,vp8.0", "probably");
+ check("application/dash+xml; codecs=\"vorbis,vp8\"", "probably");
+ check("application/dash+xml; codecs=\"vorbis,vp8.0\"", "probably");
+ check("application/dash+xml; codecs=\"vp8, vorbis\"", "probably");
+ check("application/dash+xml; codecs=\"vp8.0, vorbis\"", "probably");
+ check("application/dash+xml; codecs=vp8", "probably");
+ check("application/dash+xml; codecs=vp8.0", "probably");
+
+ // Unsupported codecs
+ check("application/dash+xml; codecs=xyz", "");
+ check("application/dash+xml; codecs=xyz,vorbis", "");
+ check("application/dash+xml; codecs=vorbis,xyz", "");
+ check("application/dash+xml; codecs=xyz,vp8.0", "");
+ check("application/dash+xml; codecs=vp8.0,xyz", "");
+}
diff --git a/dom/media/test/can_play_type_ogg.js b/dom/media/test/can_play_type_ogg.js
new file mode 100644
index 000000000..b9678bcac
--- /dev/null
+++ b/dom/media/test/can_play_type_ogg.js
@@ -0,0 +1,78 @@
+
+function check_ogg(v, enabled, finish) {
+ function check(type, expected) {
+ is(v.canPlayType(type), enabled ? expected : "", type);
+ }
+
+ function basic_test() {
+ return new Promise(function(resolve, reject) {
+ // Ogg types
+ check("video/ogg", "maybe");
+ check("audio/ogg", "maybe");
+ check("application/ogg", "maybe");
+
+ // Supported Ogg codecs
+ check("audio/ogg; codecs=vorbis", "probably");
+ check("video/ogg; codecs=vorbis", "probably");
+ check("video/ogg; codecs=vorbis,theora", "probably");
+ check("video/ogg; codecs=\"vorbis, theora\"", "probably");
+ check("video/ogg; codecs=theora", "probably");
+
+ resolve();
+ });
+ }
+
+ // Verify Opus support
+ function verify_opus_support() {
+ return new Promise(function(resolve, reject) {
+ var OpusEnabled = undefined;
+ try {
+ OpusEnabled = SpecialPowers.getBoolPref("media.opus.enabled");
+ } catch (ex) {
+ // SpecialPowers failed, perhaps because Opus isn't compiled in
+ console.log("media.opus.enabled pref not found; skipping Opus validation");
+ }
+ if (OpusEnabled != undefined) {
+ resolve();
+ } else {
+ reject();
+ }
+ });
+ }
+
+ function opus_enable() {
+ return new Promise(function(resolve, reject) {
+ SpecialPowers.pushPrefEnv({"set": [['media.opus.enabled', true]]},
+ function() {
+ check("audio/ogg; codecs=opus", "probably");
+ resolve();
+ });
+ });
+ }
+
+ function opus_disable() {
+ return new Promise(function(resolve, reject) {
+ SpecialPowers.pushPrefEnv({"set": [['media.opus.enabled', false]]},
+ function() {
+ check("audio/ogg; codecs=opus", "");
+ resolve();
+ });
+ });
+ }
+
+ function unspported_ogg() {
+ // Unsupported Ogg codecs
+ check("video/ogg; codecs=xyz", "");
+ check("video/ogg; codecs=xyz,vorbis", "");
+ check("video/ogg; codecs=vorbis,xyz", "");
+
+ finish.call();
+ }
+
+ basic_test()
+ .then(verify_opus_support)
+ .then(opus_enable)
+ .then(opus_disable)
+ .then(unspported_ogg, unspported_ogg);
+
+}
diff --git a/dom/media/test/can_play_type_wave.js b/dom/media/test/can_play_type_wave.js
new file mode 100644
index 000000000..d3ce534f9
--- /dev/null
+++ b/dom/media/test/can_play_type_wave.js
@@ -0,0 +1,29 @@
+function check_wave(v, enabled) {
+ function check(type, expected) {
+ is(v.canPlayType(type), enabled ? expected : "", type);
+ }
+
+ // Wave types
+ check("audio/wave", "maybe");
+ check("audio/wav", "maybe");
+ check("audio/x-wav", "maybe");
+ check("audio/x-pn-wav", "maybe");
+
+ // Supported Wave codecs
+ check("audio/wave; codecs=1", "probably");
+ check("audio/wave; codecs=6", "probably");
+ check("audio/wave; codecs=7", "probably");
+ // "no codecs" should be supported, I guess
+ check("audio/wave; codecs=", "probably");
+ check("audio/wave; codecs=\"\"", "probably");
+
+ // Unsupported Wave codecs
+ check("audio/wave; codecs=0", "");
+ check("audio/wave; codecs=2", "");
+ check("audio/wave; codecs=xyz,1", "");
+ check("audio/wave; codecs=1,xyz", "");
+ check("audio/wave; codecs=\"xyz, 1\"", "");
+ // empty codec names
+ check("audio/wave; codecs=,", "");
+ check("audio/wave; codecs=\"0, 1,\"", "");
+}
diff --git a/dom/media/test/can_play_type_webm.js b/dom/media/test/can_play_type_webm.js
new file mode 100644
index 000000000..eeb79b278
--- /dev/null
+++ b/dom/media/test/can_play_type_webm.js
@@ -0,0 +1,54 @@
+function check_webm(v, enabled) {
+ function check(type, expected) {
+ is(v.canPlayType(type), enabled ? expected : "", type);
+ }
+
+ // WebM types
+ check("video/webm", "maybe");
+ check("audio/webm", "maybe");
+
+ var video = ['vp8', 'vp8.0', 'vp9', 'vp9.0'];
+ var audio = ['vorbis', 'opus'];
+ // Check for FxOS case.
+ // Since we want to use OMX webm HW acceleration to speed up vp8 decoding,
+ // we enabled it after Android version 16(JB) as MOZ_OMX_WEBM_DECODER
+ // defined in moz.build. More information is on Bug 986381.
+ // Currently OMX (KK included) webm decoders can only support vp8 and vorbis,
+ // so only vp8 and vorbis will be tested when OMX webm decoder is enabled.
+ if (navigator.userAgent.indexOf("Mobile") != -1 &&
+ navigator.userAgent.indexOf("Android") == -1) {
+ // See nsSystemInfo.cpp, the getProperty('version') and
+ // getProperty('sdk_version') are different.
+ var androidSDKVer = SpecialPowers.Cc['@mozilla.org/system-info;1']
+ .getService(SpecialPowers.Ci.nsIPropertyBag2)
+ .getProperty('sdk_version');
+ info("android version:"+androidSDKVer);
+
+ // Since from Android KK, vp9 sw decoder is supported.
+ if (androidSDKVer > 18) {
+ video = ['vp8', 'vp8.0', 'vp9', 'vp9.0'];
+ audio = ['vorbis'];
+ } else if (androidSDKVer > 15) {
+ video = ['vp8', 'vp8.0'];
+ audio = ['vorbis'];
+ }
+
+ }
+
+ audio.forEach(function(acodec) {
+ check("audio/webm; codecs=" + acodec, "probably");
+ check("video/webm; codecs=" + acodec, "probably");
+ });
+ video.forEach(function(vcodec) {
+ check("video/webm; codecs=" + vcodec, "probably");
+ audio.forEach(function(acodec) {
+ check("video/webm; codecs=\"" + vcodec + ", " + acodec + "\"", "probably");
+ check("video/webm; codecs=\"" + acodec + ", " + vcodec + "\"", "probably");
+ });
+ });
+
+ // Unsupported WebM codecs
+ check("video/webm; codecs=xyz", "");
+ check("video/webm; codecs=xyz,vorbis", "");
+ check("video/webm; codecs=vorbis,xyz", "");
+}
diff --git a/dom/media/test/cancellable_request.sjs b/dom/media/test/cancellable_request.sjs
new file mode 100644
index 000000000..5b458e73c
--- /dev/null
+++ b/dom/media/test/cancellable_request.sjs
@@ -0,0 +1,154 @@
+function parseQuery(request, key) {
+ var params = request.queryString.split('&');
+ for (var j = 0; j < params.length; ++j) {
+ var p = params[j];
+ if (p == key)
+ return true;
+ if (p.indexOf(key + "=") == 0)
+ return p.substring(key.length + 1);
+ if (p.indexOf("=") < 0 && key == "")
+ return p;
+ }
+ return false;
+}
+
+function push32BE(array, input) {
+ array.push(String.fromCharCode((input >> 24) & 0xff));
+ array.push(String.fromCharCode((input >> 16) & 0xff));
+ array.push(String.fromCharCode((input >> 8) & 0xff));
+ array.push(String.fromCharCode((input) & 0xff));
+}
+
+function push32LE(array, input) {
+ array.push(String.fromCharCode((input) & 0xff));
+ array.push(String.fromCharCode((input >> 8) & 0xff));
+ array.push(String.fromCharCode((input >> 16) & 0xff));
+ array.push(String.fromCharCode((input >> 24) & 0xff));
+}
+
+function push16LE(array, input) {
+ array.push(String.fromCharCode((input) & 0xff));
+ array.push(String.fromCharCode((input >> 8) & 0xff));
+}
+
+function buildWave(samples, sample_rate) {
+ const RIFF_MAGIC = 0x52494646;
+ const WAVE_MAGIC = 0x57415645;
+ const FRMT_MAGIC = 0x666d7420;
+ const DATA_MAGIC = 0x64617461;
+ const RIFF_SIZE = 44;
+
+ var header = [];
+ push32BE(header, RIFF_MAGIC);
+ push32LE(header, RIFF_SIZE + samples.length * 2);
+ push32BE(header, WAVE_MAGIC);
+ push32BE(header, FRMT_MAGIC);
+ push32LE(header, 16);
+ push16LE(header, 1);
+ push16LE(header, 1);
+ push32LE(header, sample_rate);
+ push32LE(header, sample_rate);
+ push16LE(header, 2);
+ push16LE(header, 16);
+ push32BE(header, DATA_MAGIC);
+ push32LE(header, samples.length * 2);
+ for (var i = 0; i < samples.length; ++i) {
+ push16LE(header, samples[i], 2);
+ }
+ return header;
+}
+
+const Ci = Components.interfaces;
+const CC = Components.Constructor;
+const Timer = CC("@mozilla.org/timer;1", "nsITimer", "initWithCallback");
+const BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1",
+ "nsIBinaryOutputStream",
+ "setOutputStream");
+
+function poll(f) {
+ if (f()) {
+ return;
+ }
+ new Timer(function() { poll(f); }, 100, Ci.nsITimer.TYPE_ONE_SHOT);
+}
+
+function handleRequest(request, response)
+{
+ var cancel = parseQuery(request, "cancelkey");
+ if (cancel) {
+ setState(cancel[1], "cancelled");
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ response.write("Cancel approved!");
+ return;
+ }
+
+ var samples = [];
+ for (var i = 0; i < 1000000; ++i) {
+ samples.push(0);
+ }
+ var bytes = buildWave(samples, 44100).join("");
+
+ var key = parseQuery(request, "key");
+ response.setHeader("Content-Type", "audio/x-wav");
+ response.setHeader("Content-Length", ""+bytes.length, false);
+
+ var out = new BinaryOutputStream(response.bodyOutputStream);
+
+ var start = 0, end = bytes.length - 1;
+ if (request.hasHeader("Range"))
+ {
+ var rangeMatch = request.getHeader("Range").match(/^bytes=(\d+)?-(\d+)?$/);
+
+ if (rangeMatch[1] !== undefined)
+ start = parseInt(rangeMatch[1], 10);
+
+ if (rangeMatch[2] !== undefined)
+ end = parseInt(rangeMatch[2], 10);
+
+ // No start given, so the end is really the count of bytes from the
+ // end of the file.
+ if (start === undefined)
+ {
+ start = Math.max(0, bytes.length - end);
+ end = bytes.length - 1;
+ }
+
+ // start and end are inclusive
+ if (end === undefined || end >= bytes.length)
+ end = bytes.length - 1;
+
+ if (end < start)
+ {
+ response.setStatusLine(request.httpVersion, 200, "OK");
+ start = 0;
+ end = bytes.length - 1;
+ }
+ else
+ {
+ response.setStatusLine(request.httpVersion, 206, "Partial Content");
+ var contentRange = "bytes " + start + "-" + end + "/" + bytes.length;
+ response.setHeader("Content-Range", contentRange);
+ }
+ }
+
+ if (start > 0) {
+ // Send all requested data
+ out.write(bytes.slice(start, end + 1), end + 1 - start);
+ return;
+ }
+
+ // Write the first 1.2M of the Wave file. We know the cache size is set to
+ // 100K so this will fill the cache and and cause a "suspend" event on
+ // the loading element.
+ out.write(bytes, 1200000);
+
+ response.processAsync();
+ // Now wait for the message to cancel this response
+ poll(function() {
+ if (getState(key[1]) != "cancelled") {
+ return false;
+ }
+ response.finish();
+ return true;
+ });
+}
diff --git a/dom/media/test/chain.ogg b/dom/media/test/chain.ogg
new file mode 100644
index 000000000..3535b280f
--- /dev/null
+++ b/dom/media/test/chain.ogg
Binary files differ
diff --git a/dom/media/test/chain.ogg^headers^ b/dom/media/test/chain.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/chain.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/chain.ogv b/dom/media/test/chain.ogv
new file mode 100644
index 000000000..3e684b64a
--- /dev/null
+++ b/dom/media/test/chain.ogv
Binary files differ
diff --git a/dom/media/test/chain.ogv^headers^ b/dom/media/test/chain.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/chain.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/chain.opus b/dom/media/test/chain.opus
new file mode 100644
index 000000000..9fa67f94c
--- /dev/null
+++ b/dom/media/test/chain.opus
Binary files differ
diff --git a/dom/media/test/chain.opus^headers^ b/dom/media/test/chain.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/chain.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/chained-audio-video.ogg b/dom/media/test/chained-audio-video.ogg
new file mode 100644
index 000000000..adda68bb4
--- /dev/null
+++ b/dom/media/test/chained-audio-video.ogg
Binary files differ
diff --git a/dom/media/test/chained-audio-video.ogg^headers^ b/dom/media/test/chained-audio-video.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/chained-audio-video.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/chained-video.ogv b/dom/media/test/chained-video.ogv
new file mode 100644
index 000000000..a6288ef6c
--- /dev/null
+++ b/dom/media/test/chained-video.ogv
Binary files differ
diff --git a/dom/media/test/chained-video.ogv^headers^ b/dom/media/test/chained-video.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/chained-video.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/contentType.sjs b/dom/media/test/contentType.sjs
new file mode 100644
index 000000000..d79cdf034
--- /dev/null
+++ b/dom/media/test/contentType.sjs
@@ -0,0 +1,77 @@
+// Parse the query string, and give us the value for a certain key, or false if
+// it does not exist.
+function parseQuery(request, key) {
+ var params = request.queryString.split('?')[0].split('&');
+ for (var j = 0; j < params.length; ++j) {
+ var p = params[j];
+ if (p == key)
+ return true;
+ if (p.indexOf(key + "=") == 0)
+ return p.substring(key.length + 1);
+ if (p.indexOf("=") < 0 && key == "")
+ return p;
+ }
+ return false;
+}
+
+function handleRequest(request, response) {
+ try {
+ // Get the filename to send back.
+ var filename = parseQuery(request, "file");
+
+ const CC = Components.Constructor;
+ const BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1",
+ "nsIBinaryOutputStream",
+ "setOutputStream");
+ var file = Components.classes["@mozilla.org/file/directory_service;1"].
+ getService(Components.interfaces.nsIProperties).
+ get("CurWorkD", Components.interfaces.nsILocalFile);
+ var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
+ createInstance(Components.interfaces.nsIFileInputStream);
+ var bis = Components.classes["@mozilla.org/binaryinputstream;1"].
+ createInstance(Components.interfaces.nsIBinaryInputStream);
+ var paths = "tests/dom/media/test/" + filename;
+ dump(paths + '\n');
+ var split = paths.split("/");
+ for(var i = 0; i < split.length; ++i) {
+ file.append(split[i]);
+ }
+ fis.init(file, -1, -1, false);
+
+ // handle range requests
+ var partialstart = 0,
+ partialend = file.fileSize - 1;
+ if (request.hasHeader("Range")) {
+ var range = request.getHeader("Range");
+ var parts = range.replace(/bytes=/, "").split("-");
+ var partialstart = parts[0];
+ var partialend = parts[1];
+ if (!partialend.length) {
+ partialend = file.fileSize - 1;
+ }
+ response.setStatusLine(request.httpVersion, 206, "Partial Content");
+ var contentRange = "bytes " + partialstart + "-" + partialend + "/" + file.fileSize;
+ response.setHeader("Content-Range", contentRange);
+ }
+
+ fis.seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, partialstart);
+ bis.setInputStream(fis);
+
+ var sendContentType = parseQuery(request, "nomime");
+ if (sendContentType == false) {
+ var contentType = parseQuery(request, "type");
+ if (contentType == false) {
+ // This should not happen.
+ dump("No type specified without having \'nomime\' in parameters.");
+ return;
+ }
+ response.setHeader("Content-Type", contentType, false);
+ }
+ response.setHeader("Content-Length", ""+bis.available(), false);
+
+ var bytes = bis.readBytes(bis.available());
+ response.write(bytes, bytes.length);
+ } catch (e) {
+ dump ("ERROR : " + e + "\n");
+ }
+}
diff --git a/dom/media/test/crashtests/0-timescale.html b/dom/media/test/crashtests/0-timescale.html
new file mode 100644
index 000000000..db845096d
--- /dev/null
+++ b/dom/media/test/crashtests/0-timescale.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+</head>
+<body>
+<!-- This video file has a timescale of 0 in the mdhd atom -->
+<video src="0-timescale.mp4"
+ autoplay
+ onerror="document.documentElement.className=undefined"
+ onloadedmetadata="this.src=''; document.documentElement.className=undefined">
+<!-- Note we reset 'src' to release decoder resources and cubeb streams to prevent OOM or OpenCubeb() failures. -->
+</video>
+</body>
+</html>
diff --git a/dom/media/test/crashtests/0-timescale.mp4 b/dom/media/test/crashtests/0-timescale.mp4
new file mode 100644
index 000000000..32df5dc5a
--- /dev/null
+++ b/dom/media/test/crashtests/0-timescale.mp4
Binary files differ
diff --git a/dom/media/test/crashtests/1012609.html b/dom/media/test/crashtests/1012609.html
new file mode 100644
index 000000000..1dad783a0
--- /dev/null
+++ b/dom/media/test/crashtests/1012609.html
@@ -0,0 +1,9 @@
+<script>
+try{var r0=new AudioContext();}catch(e){}
+try{var r32=r0.createOscillator();}catch(e){}
+try{var r58=r0.createPeriodicWave(new Float32Array(1997),new Float32Array(1997));}catch(e){}
+try{r32.start(0);}catch(e){}
+try{r32.setPeriodicWave(r58);}catch(e){}
+try{r32.frequency.value=-1;}catch(e){}
+</script>
+
diff --git a/dom/media/test/crashtests/1015662.html b/dom/media/test/crashtests/1015662.html
new file mode 100644
index 000000000..20407c807
--- /dev/null
+++ b/dom/media/test/crashtests/1015662.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<body>
+<video><track src="javascript:5"></track></video>
+</body>
diff --git a/dom/media/test/crashtests/1020205.html b/dom/media/test/crashtests/1020205.html
new file mode 100644
index 000000000..e9efc4096
--- /dev/null
+++ b/dom/media/test/crashtests/1020205.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+var context = new window.AudioContext();
+var source = context.createBufferSource();
+source.connect(context.destination);
+source.playbackRate.value = 0.01;
+source.buffer = context.createBuffer(2, 32, context.sampleRate);
+source.start(0);
+
+setTimeout(
+ function() {
+ source.buffer = context.createBuffer(1, 10, context.sampleRate);
+ source.playbackRate.value = 1;
+ source.onended =
+ function() {
+ document.documentElement.removeAttribute("class");
+ };
+ }, 0);
+
+</script>
+</html>
diff --git a/dom/media/test/crashtests/1028458.html b/dom/media/test/crashtests/1028458.html
new file mode 100644
index 000000000..c78ac046b
--- /dev/null
+++ b/dom/media/test/crashtests/1028458.html
@@ -0,0 +1,23 @@
+<html class="reftest-wait">
+<audio id="testAudio" controls></audio>
+<script type="text/javascript">
+navigator.mozGetUserMedia({audio: true, fake: true}, function(stream) {
+ stream.getAudioTracks()[0].enabled = false;
+ var testAudio = document.getElementById('testAudio');
+ // Wait some time for good measure
+ var eventReceived = 0;
+ testAudio.addEventListener("timeupdate", function() {
+ if (++eventReceived == 3) {
+ document.querySelector("html").className = "";
+ }
+ })
+ testAudio.mozSrcObject = stream;
+ testAudio.play();
+ }, function(err) {
+ // Don't go orange if we can't get an audio input stream,
+ // as this is not what we are trying to test and can happen on Windows.
+ document.querySelector("html").className = "";
+ });
+</script>
+
+</html>
diff --git a/dom/media/test/crashtests/1041466.html b/dom/media/test/crashtests/1041466.html
new file mode 100644
index 000000000..0f064d186
--- /dev/null
+++ b/dom/media/test/crashtests/1041466.html
@@ -0,0 +1,21 @@
+<html>
+<script>
+try{var Context1= new (window.webkitAudioContext || window.AudioContext)()}catch(e){}
+try{var Delay0=Context1.createDelay();}catch(e){}
+try{var ScriptProcessor0=Context1.createScriptProcessor(512,26,7);}catch(e){}
+try{var ChannelSplitter0=Context1.createChannelSplitter(91);}catch(e){}
+try{var Gain1=Context1.createGain();}catch(e){}
+try{var WaveShaper0=Context1.createWaveShaper();}catch(e){}
+try{var Analyser1=Context1.createAnalyser();}catch(e){}
+try{Gain1.connect(Delay0);}catch(e){}
+try{Analyser1.connect(BiquadFilter0);}catch(e){}
+try{Gain1.connect(Context1.destination);}catch(e){}
+try{WaveShaper0.connect(ScriptProcessor0);}catch(e){}
+try{ChannelSplitter0.connect(BiquadFilter1);}catch(e){}
+try{Delay0.connect(Gain1);}catch(e){}
+try{ScriptProcessor0.connect(Context1.destination);}catch(e){}
+try{WaveShaper0.connect(Gain1);}catch(e){}
+try{WaveShaper0.connect(ChannelSplitter0);}catch(e){}
+try{ScriptProcessor0.connect(WaveShaper0);}catch(e){}
+</script>
+</html>
diff --git a/dom/media/test/crashtests/1045650.html b/dom/media/test/crashtests/1045650.html
new file mode 100644
index 000000000..32acd2ce7
--- /dev/null
+++ b/dom/media/test/crashtests/1045650.html
@@ -0,0 +1,18 @@
+<html><body><script>
+
+var r0=new AudioContext();
+
+var splitter=r0.createChannelSplitter();
+var delay=r0.createDelay();
+var scriptp=r0.createScriptProcessor();
+var cmerger=r0.createChannelMerger();
+var gain=r0.createGain();
+
+splitter.connect(delay,2);
+delay.connect(scriptp);
+scriptp.connect(cmerger);
+cmerger.connect(splitter);
+gain.connect(gain);
+gain.connect(cmerger);
+
+</script></body></html>
diff --git a/dom/media/test/crashtests/1080986.html b/dom/media/test/crashtests/1080986.html
new file mode 100644
index 000000000..1de307516
--- /dev/null
+++ b/dom/media/test/crashtests/1080986.html
@@ -0,0 +1,3 @@
+<html>
+<audio autoplay src="1080986.wav"></audio>
+</html>
diff --git a/dom/media/test/crashtests/1080986.wav b/dom/media/test/crashtests/1080986.wav
new file mode 100644
index 000000000..b96c59b7e
--- /dev/null
+++ b/dom/media/test/crashtests/1080986.wav
Binary files differ
diff --git a/dom/media/test/crashtests/1122218.html b/dom/media/test/crashtests/1122218.html
new file mode 100644
index 000000000..984487dd2
--- /dev/null
+++ b/dom/media/test/crashtests/1122218.html
@@ -0,0 +1,24 @@
+<html>
+<head>
+<script>
+function boom() {
+ var r0=new AudioContext();
+
+ var cm=r0.createChannelMerger(20);
+
+ var o1=r0.createOscillator();
+ var o2=r0.createOscillator();
+
+ var pw=r0.createPeriodicWave(new Float32Array(4),new Float32Array(4));
+ o2.setPeriodicWave(pw);
+
+ o1.connect(cm);
+ cm.connect(o2.frequency);
+
+ o1.start();
+ o2.start(0.476);
+}
+</script>
+</head>
+<body onload="boom();"></body>
+</html>
diff --git a/dom/media/test/crashtests/1127188.html b/dom/media/test/crashtests/1127188.html
new file mode 100644
index 000000000..650f07dd4
--- /dev/null
+++ b/dom/media/test/crashtests/1127188.html
@@ -0,0 +1,3 @@
+<script>
+ (new AudioContext).close();
+</script>
diff --git a/dom/media/test/crashtests/1157994.html b/dom/media/test/crashtests/1157994.html
new file mode 100644
index 000000000..2e3001302
--- /dev/null
+++ b/dom/media/test/crashtests/1157994.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+function boom()
+{
+ var ac = new AudioContext();
+ // first "suspended" -> "running" transition
+ ac.onstatechange = function() {
+ ac.onstatechange = null;
+ ac.suspend();
+ ac.close();
+ }
+}
+
+</script>
+</head>
+<body onload="boom();"></body>
+</html>
+
diff --git a/dom/media/test/crashtests/1158427.html b/dom/media/test/crashtests/1158427.html
new file mode 100644
index 000000000..b544a942a
--- /dev/null
+++ b/dom/media/test/crashtests/1158427.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+function boom()
+{
+ dump("before capture\n");
+ document.createElement("audio").mozCaptureStreamUntilEnded();
+ dump("before context\n");
+ new window.AudioContext();
+ dump("before gc\n");
+ SpecialPowers.forceCC();
+ dump("after gc\n");
+}
+
+</script>
+</head>
+<body onload="boom();"></body>
+</html>
+
diff --git a/dom/media/test/crashtests/1185176.html b/dom/media/test/crashtests/1185176.html
new file mode 100644
index 000000000..d5e9b68a2
--- /dev/null
+++ b/dom/media/test/crashtests/1185176.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<script>
+
+function boom()
+{
+ var ac = new window.AudioContext();
+ var oscillator = ac.createOscillator();
+ oscillator.start(0);
+ oscillator.stop(0.1);
+ setTimeout(function() {
+ oscillator.channelCount = 1;
+ oscillator.channelCountMode = "explicit";
+ oscillator.channelInterpretation = "speakers";
+ document.documentElement.removeAttribute("class");
+ }, 1000);
+}
+
+</script>
+</head>
+<body onload="boom();"></body>
+</html>
+
diff --git a/dom/media/test/crashtests/1185192.html b/dom/media/test/crashtests/1185192.html
new file mode 100644
index 000000000..46fa311aa
--- /dev/null
+++ b/dom/media/test/crashtests/1185192.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+function boom()
+{
+ new Audio().mozCaptureStreamUntilEnded();
+ var ac = new window.AudioContext();
+ ac.resume();
+ ac.close();
+}
+
+</script>
+</head>
+<body onload="boom();"></body>
+</html>
+
diff --git a/dom/media/test/crashtests/1223670.html b/dom/media/test/crashtests/1223670.html
new file mode 100644
index 000000000..94cad43e2
--- /dev/null
+++ b/dom/media/test/crashtests/1223670.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<script>
+
+function boom()
+{
+
+ var ac = new window.AudioContext("publicnotification");
+
+ setTimeout(function() {
+ document.documentElement.removeAttribute("class");
+ var htmlAudio = new Audio();
+ var stream = htmlAudio.mozCaptureStreamUntilEnded();
+ ac.createMediaStreamSource(stream);
+ }, 0);
+}
+
+</script>
+</head>
+<body onload="boom();">
+</body>
+</html>
diff --git a/dom/media/test/crashtests/1228484.html b/dom/media/test/crashtests/1228484.html
new file mode 100644
index 000000000..2b2e9b0f9
--- /dev/null
+++ b/dom/media/test/crashtests/1228484.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+var htmlAudio = new Audio(URL.createObjectURL(new window.MediaSource()));
+
+(new window.AudioContext("ringer")).createMediaElementSource(htmlAudio);
+(new window.AudioContext("alarm")).createMediaElementSource(htmlAudio);
+
+</script>
+</head>
+</html>
diff --git a/dom/media/test/crashtests/1236639.html b/dom/media/test/crashtests/1236639.html
new file mode 100644
index 000000000..5c4634a4d
--- /dev/null
+++ b/dom/media/test/crashtests/1236639.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Bug 1236639: Crash on audio playback due to invalid XING headers</title>
+</head>
+<body>
+<audio autoplay src="1236639.mp3"></audio>
+</body>
+</html>
diff --git a/dom/media/test/crashtests/1236639.mp3 b/dom/media/test/crashtests/1236639.mp3
new file mode 100644
index 000000000..8ef96e8cc
--- /dev/null
+++ b/dom/media/test/crashtests/1236639.mp3
Binary files differ
diff --git a/dom/media/test/crashtests/1291702.html b/dom/media/test/crashtests/1291702.html
new file mode 100644
index 000000000..facc52af7
--- /dev/null
+++ b/dom/media/test/crashtests/1291702.html
@@ -0,0 +1,72 @@
+<script>
+Logger={}; Logger.JSError=function(e){};
+try { o0 = new Audio("media/audio/mono-uncompressed-8bit-44100hz.wav") } catch(e) { Logger.JSError(e); }
+try { o1 = o0.mozCaptureStreamUntilEnded() } catch(e) { Logger.JSError(e); }
+try { o2 = new window.AudioContext(); } catch(e) { Logger.JSError(e); }
+try { o3 = o2.createBufferSource(); } catch(e) { Logger.JSError(e); }
+try { o5 = o2.createChannelMerger(3); } catch(e) { Logger.JSError(e); }
+try { o3.start(0) } catch(e) { Logger.JSError(e); }
+try { o2.listener.setPosition(0.0417049336344248, 0.9932504594310304, 32) } catch(e) { Logger.JSError(e); }
+try { o5.disconnect(0) } catch(e) { Logger.JSError(e); }
+try { o0.mozGetMetadata() } catch(e) { Logger.JSError(e); }
+try { o3.channelCount = 1; } catch(e) { Logger.JSError(e); }
+try { o3.buffer = function anonymous() {
+var buffer = o2.createBuffer(1, 512, o2.sampleRate);for(var c=0;c<1;c++) {var data = buffer.getChannelData(c);for(var i=0;i<512;i++) {data[i] = i % 512}}return buffer;
+}(); } catch(e) { Logger.JSError(e); }
+try { o3.loop = false; } catch(e) { Logger.JSError(e); }
+try { o0.mozPreservesPitch = false; } catch(e) { Logger.JSError(e); }
+try { o2.destination.channelCount = 1; } catch(e) { Logger.JSError(e); }
+try { o3.loopStart = 8; } catch(e) { Logger.JSError(e); }
+try { o3.playbackRate.value = 0.46271130895770884; } catch(e) { Logger.JSError(e); }
+try { o2.listener.setVelocity(0.34781960219792546, 4, 2048) } catch(e) { Logger.JSError(e); }
+try { o5.connect(o5, 0, 0) } catch(e) { Logger.JSError(e); }
+try { o3.loopStart = -0.24696638021780326; } catch(e) { Logger.JSError(e); }
+try { o0.mozSetup(1, 44100) } catch(e) { Logger.JSError(e); }
+try { o3.buffer.copyToChannel(function anonymous() {
+var buffer=new Float32Array(256);for(var i=0;i<256;i++){buffer[i]=i / 256}return buffer;
+}(), 1, 2048, 64) } catch(e) { Logger.JSError(e); }
+try { o3.loop = false; } catch(e) { Logger.JSError(e); }
+try { setInterval(function anonymous() {
+try { o0.pause() } catch(e) { Logger.JSError(e); }
+}, 12.902067779658143) } catch(e) { Logger.JSError(e); }
+try { o2.listener.setPosition(256, 256, 16) } catch(e) { Logger.JSError(e); }
+try { o3.playbackRate.setValueCurveAtTime(function anonymous() {
+var buffer=new Float32Array(4);for(var i=0;i<4;i++){buffer[i]=i / 4}return buffer;
+}(), 2, 0.40792575814014437) } catch(e) { Logger.JSError(e); }
+try { o3.playbackRate.value = 0.4997270553139334; } catch(e) { Logger.JSError(e); }
+try { o0.loop = true; } catch(e) { Logger.JSError(e); }
+try { o3.loopStart = 4; } catch(e) { Logger.JSError(e); }
+try { setInterval(function anonymous() {
+try { o3.buffer = function anonymous() {
+var buffer = o2.createBuffer(1, 1, o2.sampleRate);for(var c=0;c<1;c++) {var data = buffer.getChannelData(c);for(var i=0;i<1;i++) {data[i] = Math.sin(Math.sin(i))}}return buffer;
+}() } catch(e) { Logger.JSError(e); }
+}, 54.32078602859342) } catch(e) { Logger.JSError(e); }
+try { o3.connect(o2.destination); } catch(e) { Logger.JSError(e); }
+try { o3.channelCountMode = 'max'; } catch(e) { Logger.JSError(e); }
+try { setInterval(function anonymous() {
+try { o3.channelCount = 1; } catch(e) { Logger.JSError(e); }
+}, 55.448587039802966) } catch(e) { Logger.JSError(e); }
+try { o3.playbackRate.cancelScheduledValues(0.7190983131805198) } catch(e) { Logger.JSError(e); }
+try { o3.playbackRate.cancelScheduledValues(16) } catch(e) { Logger.JSError(e); }
+try { o3.connect(o5, 0, 2) } catch(e) { Logger.JSError(e); }
+try { o3.loopEnd = 0.5864771678080962; } catch(e) { Logger.JSError(e); }
+try { o0.playbackRate = 0.2781783298771312; } catch(e) { Logger.JSError(e); }
+try { o0.loop = false; } catch(e) { Logger.JSError(e); }
+try { setInterval(function anonymous() {
+try { o5.disconnect(0) } catch(e) { Logger.JSError(e); }
+}, 29.75776777646425) } catch(e) { Logger.JSError(e); }
+try { o3.playbackRate.setValueCurveAtTime(function anonymous() {
+var buffer=new Float32Array(8);for(var i=0;i<8;i++){buffer[i]=8 % 8}return buffer;
+}(), 0.4972710112336257, 64) } catch(e) { Logger.JSError(e); }
+try { setInterval(function anonymous() {
+try { o0.controls = false; } catch(e) { Logger.JSError(e); }
+}, 22.550249570567694) } catch(e) { Logger.JSError(e); }
+try { o2.listener.setOrientation(0.6531494410366634, 64, 0.5120918081402992, -64, 0.32912433155093446, 256) } catch(e) { Logger.JSError(e); }
+try { o3.loop = true; } catch(e) { Logger.JSError(e); }
+try { o3.connect(o5, 0, 0) } catch(e) { Logger.JSError(e); }
+try { o3.buffer = function anonymous() {
+var buffer = o2.createBuffer(1, 2048, 48000);for(var c=0;c<1;c++) {var data = buffer.getChannelData(c);for(var i=0;i<2048;i++) {data[i] = Math.sin(Math.sin(2048 * 0.2519529190035427))}}return buffer;
+}(); } catch(e) { Logger.JSError(e); }
+try { o3.disconnect(0) } catch(e) { Logger.JSError(e); }
+</script>
+
diff --git a/dom/media/test/crashtests/1304948.html b/dom/media/test/crashtests/1304948.html
new file mode 100644
index 000000000..667a13d06
--- /dev/null
+++ b/dom/media/test/crashtests/1304948.html
@@ -0,0 +1,33 @@
+<html class="reftest-wait">
+<head>
+ <title> Bug 1304948 : Crash if a texttrack remove a cue not belongs to it. </title>
+</head>
+<meta charset="utf-8">
+<script type="text/javascript">
+
+window.onload = function() {
+ var a = document.createElementNS('http://www.w3.org/1999/xhtml', 'video');
+ a.src = "";
+ document.body.appendChild(a);
+ var b = a.addTextTrack('chapters', "AAAAAAAAAAAAAAAA", "de");
+ var c = new VTTCue(0.6, 0.3, "AA");
+ b.addCue(c);
+ var d = document.createElementNS('http://www.w3.org/1999/xhtml', 'video');
+ var e = d.addTextTrack('chapters', "AAAA", "en-US");
+ a.currentTime = 2;
+ a.play();
+ try {
+ // This will queue a TimeMarchesOn task on mainthread, so use
+ // timer to wait the TimeMarchesOn crash.
+ e.removeCue(c);
+ } catch (e) {
+ if (e.name == "NotFoundError") {
+ setTimeout(function() {
+ document.documentElement.removeAttribute("class");}, 0);
+ }
+ }
+};
+
+</script>
+</body>
+</html>
diff --git a/dom/media/test/crashtests/1319486.html b/dom/media/test/crashtests/1319486.html
new file mode 100644
index 000000000..74bdb2147
--- /dev/null
+++ b/dom/media/test/crashtests/1319486.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title> Bug 1319486 : Crash if a texttrackcue added to different texttracks. </title>
+</head>
+<body>
+<video id=v1></video>
+<video id=v2></video>
+</body>
+<meta charset="utf-8">
+<script type="text/javascript">
+
+addEventListener('DOMContentLoaded', function(){
+ let cue,tt1,tt2;
+ v1.play();
+ tt1 = v1.addTextTrack('metadata', "", "");
+ v1.play();
+ v1.currentTime = 8;
+ cue = new VTTCue(0, 0.5, "");
+ tt1.addCue(cue);
+ tt2 = v2.addTextTrack('captions', "", "");
+ tt2.addCue(cue);
+ tt2.removeCue(cue);
+ tt1.addCue(new VTTCue(0.7, 2, ""));
+});
+</script>
+</html>
diff --git a/dom/media/test/crashtests/459439-1.html b/dom/media/test/crashtests/459439-1.html
new file mode 100644
index 000000000..7bb0131d5
--- /dev/null
+++ b/dom/media/test/crashtests/459439-1.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<script type="text/javascript">
+var i = 0;
+function boom()
+{
+ var div = document.getElementById("div");
+ var audio = document.getElementById("audio");
+
+ audio.onload = null;
+
+ div.textContent = "FAIL";
+ audio.src += "";
+ div.textContent = "PASS?";
+
+ ++i;
+
+ setTimeout(done, 1);
+}
+
+function done()
+{
+ // Note we reset 'src' to release decoder resources and cubeb streams to
+ // prevent OOM or OpenCubeb() failures.
+ var audio = document.getElementById("audio");
+ audio.src = "";
+ document.documentElement.removeAttribute("class");
+}
+</script>
+</head>
+<body>
+<audio id="audio" autoplay src="sound.ogg" oncanplaythrough="setTimeout(boom, 1);"></audio>
+<div id="div"></div>
+</body>
+</html>
diff --git a/dom/media/test/crashtests/466607-1.html b/dom/media/test/crashtests/466607-1.html
new file mode 100644
index 000000000..e154223ef
--- /dev/null
+++ b/dom/media/test/crashtests/466607-1.html
@@ -0,0 +1,14 @@
+<html>
+<head>
+<script type="text/javascript">
+
+function boom()
+{
+ document.body.appendChild(document.createElementNS("bar", "audio"));
+ document.body.appendChild(document.createElementNS("bar", "video"));
+}
+
+</script>
+</head>
+<body onload="boom();"></body>
+</html>
diff --git a/dom/media/test/crashtests/466945-1.html b/dom/media/test/crashtests/466945-1.html
new file mode 100644
index 000000000..ac1ba29e3
--- /dev/null
+++ b/dom/media/test/crashtests/466945-1.html
@@ -0,0 +1,25 @@
+<html class="reftest-wait">
+<head>
+<script type="text/javascript">
+
+var s;
+
+function boom()
+{
+ s = document.createElement("span");
+ s.innerHTML = "<video src='data:text/html,' autoplay='autoplay'><\/video>";
+ document.body.appendChild(document.createElement("iframe"));
+ setTimeout(boom2, 0);
+}
+
+function boom2()
+{
+ s.innerHTML = "";
+ document.documentElement.removeAttribute("class");
+}
+
+</script>
+</head>
+
+<body onload="setTimeout(boom, 0);"></body>
+</html>
diff --git a/dom/media/test/crashtests/468763-1.html b/dom/media/test/crashtests/468763-1.html
new file mode 100644
index 000000000..d21e5bc38
--- /dev/null
+++ b/dom/media/test/crashtests/468763-1.html
@@ -0,0 +1 @@
+<html><head></head><body><video src="nosuchprotocol:"></video></body></html> \ No newline at end of file
diff --git a/dom/media/test/crashtests/474744-1.html b/dom/media/test/crashtests/474744-1.html
new file mode 100644
index 000000000..8a7c70cf0
--- /dev/null
+++ b/dom/media/test/crashtests/474744-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script type="text/javascript">
+
+function boom()
+{
+ document.body.innerHTML += "<video src='aim:yaz'><\/video>";
+}
+
+</script>
+</head>
+<body onload="boom();">
+</body>
+</html>
diff --git a/dom/media/test/crashtests/481136-1.html b/dom/media/test/crashtests/481136-1.html
new file mode 100644
index 000000000..bd264058d
--- /dev/null
+++ b/dom/media/test/crashtests/481136-1.html
@@ -0,0 +1,3 @@
+<html>
+<div><object data='sound.ogg'></div>
+</html>
diff --git a/dom/media/test/crashtests/492286-1.xhtml b/dom/media/test/crashtests/492286-1.xhtml
new file mode 100644
index 000000000..627ac3872
--- /dev/null
+++ b/dom/media/test/crashtests/492286-1.xhtml
@@ -0,0 +1 @@
+<source xmlns="http://www.w3.org/1999/xhtml"/> \ No newline at end of file
diff --git a/dom/media/test/crashtests/493915-1.html b/dom/media/test/crashtests/493915-1.html
new file mode 100644
index 000000000..2a6ae9bd6
--- /dev/null
+++ b/dom/media/test/crashtests/493915-1.html
@@ -0,0 +1,18 @@
+<html>
+<head>
+<script type="text/javascript">
+
+function boom()
+{
+ s = document.createElement("span");
+ a = document.createElement("audio");
+ a['src'] = "javascript:4";
+ a['loopend'] = 3;
+ s.appendChild(a);
+}
+
+</script>
+</head>
+
+<body onload="boom();"></body>
+</html>
diff --git a/dom/media/test/crashtests/495794-1.html b/dom/media/test/crashtests/495794-1.html
new file mode 100644
index 000000000..2db69206a
--- /dev/null
+++ b/dom/media/test/crashtests/495794-1.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <body>
+ <audio src="495794-1.ogg" autoplay onended="this.src=''; document.documentElement.className=undefined"></audio>
+ <!-- Note we reset 'src' to release decoder resources and cubeb streams to prevent OOM or OpenCubeb() failures. -->
+ </body>
+</html>
+
diff --git a/dom/media/test/crashtests/495794-1.ogg b/dom/media/test/crashtests/495794-1.ogg
new file mode 100644
index 000000000..1c19a6406
--- /dev/null
+++ b/dom/media/test/crashtests/495794-1.ogg
Binary files differ
diff --git a/dom/media/test/crashtests/576612-1.html b/dom/media/test/crashtests/576612-1.html
new file mode 100644
index 000000000..04f993e78
--- /dev/null
+++ b/dom/media/test/crashtests/576612-1.html
@@ -0,0 +1,15 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script>
+function boom()
+{
+
+ var v = document.getElementById("v");
+ v.src = "data:text/plain,_";
+ document.documentElement.appendChild(v);
+
+}
+</script>
+</head>
+<body onload="boom();"><video id="v" src="data:video/ogg;codecs=&quot;theora,vorbis&quot;,1"></video></body>
+</html>
diff --git a/dom/media/test/crashtests/691096-1.html b/dom/media/test/crashtests/691096-1.html
new file mode 100644
index 000000000..3c3ebfc12
--- /dev/null
+++ b/dom/media/test/crashtests/691096-1.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<script>
+var ITERATIONS = 200;
+
+function stoptest (evt)
+{
+ if (evt) {
+ // Note we reset 'src' to release decoder resources and cubeb streams to
+ // prevent OOM or OpenCubeb() failures.
+ evt.target.src = "";
+ }
+ document.documentElement.removeAttribute("class");
+}
+
+function boom()
+{
+ for (var i = 0; i < ITERATIONS; ++i) {
+ a = document.createElementNS("http://www.w3.org/1999/xhtml", "audio");
+ a.addEventListener("loadedmetadata", stoptest);
+ a.setAttributeNS(null, "autoplay", "");
+ a.setAttributeNS(null, "src", "sound.ogg");
+ }
+ setTimeout(stoptest, 250);
+}
+
+</script>
+</head>
+<body onload="boom();"></body>
+</html>
diff --git a/dom/media/test/crashtests/752784-1.html b/dom/media/test/crashtests/752784-1.html
new file mode 100644
index 000000000..4644eeb89
--- /dev/null
+++ b/dom/media/test/crashtests/752784-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+function boom()
+{
+ document.getElementById("a").mozCaptureStream();
+}
+</script>
+</head>
+
+<body onload="boom();">
+<audio id="a" src="sound.ogg">
+</body>
+</html>
diff --git a/dom/media/test/crashtests/789075-1.html b/dom/media/test/crashtests/789075-1.html
new file mode 100644
index 000000000..6f857573a
--- /dev/null
+++ b/dom/media/test/crashtests/789075-1.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+</head>
+<body>
+<video src="789075.webm" preload="metadata" onloadedmetadata="this.src=''; document.documentElement.className=undefined"></video>
+<!-- Note we reset 'src' to release decoder resources and cubeb streams to prevent OOM or OpenCubeb() failures. -->
+</body>
+</html>
diff --git a/dom/media/test/crashtests/789075.webm b/dom/media/test/crashtests/789075.webm
new file mode 100644
index 000000000..602e53fca
--- /dev/null
+++ b/dom/media/test/crashtests/789075.webm
Binary files differ
diff --git a/dom/media/test/crashtests/795892-1.html b/dom/media/test/crashtests/795892-1.html
new file mode 100644
index 000000000..d73cea7f2
--- /dev/null
+++ b/dom/media/test/crashtests/795892-1.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<script>
+function boom()
+{
+ var a = document.getElementById("a");
+ a.play();
+ a.onplaying = function () {
+ a.onplaying = null;
+ // Note we reset 'src' to release decoder resources and cubeb streams to
+ // prevent OOM or OpenCubeb() failures.
+ a.src = "";
+ document.documentElement.className = "";
+ }
+}
+</script>
+</head>
+
+<body>
+<video id="a" src="cors.webm" crossorigin preload="metadata" onloadedmetadata="boom();">
+</body>
+</html>
diff --git a/dom/media/test/crashtests/844563.html b/dom/media/test/crashtests/844563.html
new file mode 100644
index 000000000..7f9365511
--- /dev/null
+++ b/dom/media/test/crashtests/844563.html
@@ -0,0 +1,5 @@
+<script>
+var a = document.createElementNS("http://www.w3.org/1999/xhtml", "audio");
+a.mozPreservesPitch = a;
+</script>
+
diff --git a/dom/media/test/crashtests/846612.html b/dom/media/test/crashtests/846612.html
new file mode 100644
index 000000000..070c37538
--- /dev/null
+++ b/dom/media/test/crashtests/846612.html
@@ -0,0 +1,8 @@
+<script>
+document.addEventListener("DOMContentLoaded", function() {
+ var a = document.querySelector("audio");
+ a.playbackRate = 2;
+ a.play();
+});
+</script>
+<audio src="495794-1.ogg"></audio>
diff --git a/dom/media/test/crashtests/852838.html b/dom/media/test/crashtests/852838.html
new file mode 100644
index 000000000..0bea29351
--- /dev/null
+++ b/dom/media/test/crashtests/852838.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <script>
+ var o0 = new window.AudioContext();
+ var o1 = o0.createBuffer(536870912, 1, 8192);
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/dom/media/test/crashtests/865537-1.html b/dom/media/test/crashtests/865537-1.html
new file mode 100644
index 000000000..4065eb360
--- /dev/null
+++ b/dom/media/test/crashtests/865537-1.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+<html>
+<body onload="doTest()">
+<base href="../unknown">
+<div id="test3"></div>
+<video id="test4"><source src="white.webm"></video>
+<script>
+function doTest() {
+ test3.appendChild(test4);
+}
+</script>
+</body>
+</html>
diff --git a/dom/media/test/crashtests/868504.html b/dom/media/test/crashtests/868504.html
new file mode 100644
index 000000000..94090c1c0
--- /dev/null
+++ b/dom/media/test/crashtests/868504.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+function boom()
+{
+ new AudioContext().createBufferSource().playbackRate.linearRampToValueAtTime(0, -1);
+}
+
+</script>
+</head>
+<body onload="boom();"></body>
+</html>
diff --git a/dom/media/test/crashtests/874869.html b/dom/media/test/crashtests/874869.html
new file mode 100644
index 000000000..1fe3dbd2f
--- /dev/null
+++ b/dom/media/test/crashtests/874869.html
@@ -0,0 +1,15 @@
+<script>
+var Context0= new AudioContext()
+var Panner0=Context0.createPanner();
+var BufferSource3=Context0.createBufferSource();
+Panner0.channelCount=0;
+BufferSource3.connect(Panner0);
+BufferSource3.buffer=function(){
+ var length=1;
+ var Buffer=Context0.createBuffer(1,length,'44200');
+ var bufferData= Buffer.getChannelData(0);
+ for (var i = 0; i < length; ++i) { bufferData[i] = 255;};
+ return Buffer;
+}();
+
+</script> \ No newline at end of file
diff --git a/dom/media/test/crashtests/874915.html b/dom/media/test/crashtests/874915.html
new file mode 100644
index 000000000..59218b3da
--- /dev/null
+++ b/dom/media/test/crashtests/874915.html
@@ -0,0 +1,24 @@
+<script>
+var Context0= new AudioContext()
+var BufferSource6=Context0.createBufferSource();
+
+setInterval(function(){
+BufferSource6.buffer=function(){
+ var length=11283;
+ var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
+ var bufferData= Buffer.getChannelData(0);
+ for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(624))};
+ return Buffer;
+}();
+},0)
+
+BufferSource6.start(0.15831333969254047,0.23571860056836158,0.529235512483865);
+
+BufferSource6.buffer=function(){
+ var length=48517;
+ var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
+ var bufferData= Buffer.getChannelData(0);
+ for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(365))};
+ return Buffer;
+}();
+</script> \ No newline at end of file
diff --git a/dom/media/test/crashtests/874934.html b/dom/media/test/crashtests/874934.html
new file mode 100644
index 000000000..350ce2810
--- /dev/null
+++ b/dom/media/test/crashtests/874934.html
@@ -0,0 +1,23 @@
+<script>
+var Context0= new AudioContext()
+var BufferSource0=Context0.createBufferSource();
+BufferSource0.start(0.01932738965842873,0.33345631847623736,0.3893404237460345);
+BufferSource0.buffer=function(){
+ var length=35887;
+ var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
+ var bufferData= Buffer.getChannelData(0);
+ for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(0.39765272522345185))};
+ return Buffer;
+}();
+
+BufferSource0.buffer=function(){
+ var length=15952;
+ var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
+ var bufferData= Buffer.getChannelData(0);
+ for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(85))};
+ return Buffer;
+}();
+
+BufferSource0.playbackRate.value=20.401213286832185;
+
+</script>
diff --git a/dom/media/test/crashtests/874952.html b/dom/media/test/crashtests/874952.html
new file mode 100644
index 000000000..a9a398fdb
--- /dev/null
+++ b/dom/media/test/crashtests/874952.html
@@ -0,0 +1,11 @@
+<script>
+var Context0= new AudioContext()
+var ChannelSplitter0=Context0.createChannelSplitter();
+var BiquadFilter0=Context0.createBiquadFilter();
+var WaveShaper0=Context0.createWaveShaper();
+
+ChannelSplitter0.connect(BiquadFilter0,3,0);
+ChannelSplitter0.connect(WaveShaper0);
+BiquadFilter0.disconnect();
+WaveShaper0.connect(ChannelSplitter0);
+</script>
diff --git a/dom/media/test/crashtests/875144.html b/dom/media/test/crashtests/875144.html
new file mode 100644
index 000000000..bf5d0d086
--- /dev/null
+++ b/dom/media/test/crashtests/875144.html
@@ -0,0 +1,81 @@
+<script>
+Logger = {}
+Logger.error = function(e) {}
+Logger.comment = function(e) {}
+
+try { o0 = document.createElement('audio'); } catch(e) { Logger.error(Logger.comment(e)); }
+try { (document.body || document.documentElement).appendChild(o0); } catch(e) { Logger.error(Logger.comment(e)); }
+try { o1 = new AudioContext(); } catch(e) { Logger.error(Logger.comment(e)); }
+try { o2 = o1.createGain(); } catch(e) { Logger.error(Logger.comment(e)); }
+try { o3 = o1.createBufferSource(); } catch(e) { Logger.error(Logger.comment(e)); }
+try { o3.buffer = function() { o4 = o1.createBuffer(1, 3, 52970);
+o5 = o4.getChannelData(0);
+for(var i=0; i<3; ++i) {
+o5[i] = Math.sin(i * 63);
+}
+return o4;
+}(); } catch(e) { Logger.error(Logger.comment(e)); }
+try { o3.buffer = function() { o6 = o1.createBuffer(1, 15, 41218);
+o7 = o6.getChannelData(0);
+for(var i=0; i<15; ++i) {
+o7[i] = Math.sin(i * 0);
+}
+return o6;
+}(); } catch(e) { Logger.error(Logger.comment(e)); }
+try { o3.buffer = function() { o8 = o1.createBuffer(1, 0, 49074);
+o9 = o8.getChannelData(0);
+for(var i=0; i<0; ++i) {
+o9[i] = Math.sin(i * 0);
+}
+return o8;
+}(); } catch(e) { Logger.error(Logger.comment(e)); }
+try { o3.buffer = function() { o10 = o1.createBuffer(1, 31, 86527);
+o11 = o10.getChannelData(0);
+for(var i=0; i<31; ++i) {
+o11[i] = Math.sin(i * 127);
+}
+return o10;
+}(); } catch(e) { Logger.error(Logger.comment(e)); }
+try { o3.stop(-1) } catch(e) { Logger.error(Logger.comment(e)); }
+/* [Exception... "An attempt was made to use an object that is not, or is no longer, usable" code: "11" nsresult: "0x8053000b (InvalidStateError)" location: "file:///Users/cdiehl/dev/projects/peach/Peach/Utilities/JS/undefined.js Line: 602"] */
+try { o3.channelCountMode = 'explicit'; } catch(e) { Logger.error(Logger.comment(e)); }
+try { o12 = o1.createBiquadFilter(); } catch(e) { Logger.error(Logger.comment(e)); }
+try { o3.buffer = function() { o13 = o1.createBuffer(1, 63, 28347);
+o14 = o13.getChannelData(0);
+for(var i=0; i<63; ++i) {
+o14[i] = Math.sin(i * 15);
+}
+return o13;
+}(); } catch(e) { Logger.error(Logger.comment(e)); }
+try { o12.channelCount = 1; } catch(e) { Logger.error(Logger.comment(e)); }
+try { o12.connect(GainNode, 65536, 0) } catch(e) { Logger.error(Logger.comment(e)); }
+/* TypeError: Value does not implement interface AudioNode. */
+try { o3.buffer = function() { o15 = o1.createBuffer(1, 1, 72540);
+o16 = o15.getChannelData(0);
+for(var i=0; i<1; ++i) {
+o16[i] = Math.sin(i * 7);
+}
+return o15;
+}(); } catch(e) { Logger.error(Logger.comment(e)); }
+try { o12.getFrequencyResponse(new Float32Array(7), new Float32Array(127), new Float32Array(7)) } catch(e) { Logger.error(Logger.comment(e)); }
+try { o12.getFrequencyResponse(new Float32Array(15), new Float32Array(127), new Float32Array(7)) } catch(e) { Logger.error(Logger.comment(e)); }
+try { o17 = document.createElement('audio'); } catch(e) { Logger.error(Logger.comment(e)); }
+try { (document.body || document.documentElement).appendChild(o0); } catch(e) { Logger.error(Logger.comment(e)); }
+try { o3.buffer = function() { o18 = o1.createBuffer(1, 7, 91261);
+o19 = o18.getChannelData(0);
+for(var i=0; i<7; ++i) {
+o19[i] = Math.sin(i * 7);
+}
+return o18;
+}(); } catch(e) { Logger.error(Logger.comment(e)); }
+try { o12.getFrequencyResponse(new Float32Array(31), new Float32Array(31), new Float32Array(127)) } catch(e) { Logger.error(Logger.comment(e)); }
+try { o20 = o1.createChannelSplitter(1, 2, 4, 16, 32); } catch(e) { Logger.error(Logger.comment(e)); }
+try { o12.channelCountMode = 'explicit'; } catch(e) { Logger.error(Logger.comment(e)); }
+try { o3.buffer = function() { o21 = o1.createBuffer(1, 0, 14451);
+o22 = o21.getChannelData(0);
+for(var i=0; i<0; ++i) {
+o22[i] = Math.sin(i * 63);
+}
+return o21;
+}(); } catch(e) { Logger.error(Logger.comment(e)); }
+</script>
diff --git a/dom/media/test/crashtests/875596.html b/dom/media/test/crashtests/875596.html
new file mode 100644
index 000000000..7bac09dab
--- /dev/null
+++ b/dom/media/test/crashtests/875596.html
@@ -0,0 +1,12 @@
+<script>
+try { o1 = new AudioContext(); } catch(e) { }
+try { o6 = o1.createGain(); } catch(e) { }
+try { o8 = o1.createBufferSource(); } catch(e) { }
+try { o6.gain.setValueCurveAtTime(new Float32Array(7), 0, 0) } catch(e) { }
+try { o8.connect(o6, 0, 0) } catch(e) { }
+try { o8.buffer = function() {
+ o19 = o1.createBuffer(1, 1, 76309);
+ for(var i=0; i<1; ++i) { }
+ return o19;
+}(); } catch(e) { }
+</script>
diff --git a/dom/media/test/crashtests/875911.html b/dom/media/test/crashtests/875911.html
new file mode 100644
index 000000000..fbc52642b
--- /dev/null
+++ b/dom/media/test/crashtests/875911.html
@@ -0,0 +1,3 @@
+<script>
+ new OfflineAudioContext(1, 10, 48000);
+</script>
diff --git a/dom/media/test/crashtests/876024-1.html b/dom/media/test/crashtests/876024-1.html
new file mode 100644
index 000000000..5502d8e42
--- /dev/null
+++ b/dom/media/test/crashtests/876024-1.html
@@ -0,0 +1,5 @@
+<script>
+o1 = new window.AudioContext(2, 8, 44100);
+o4 = o1.createBiquadFilter();
+o4.detune.setValueAtTime(0.0843, 1.7976931348623157e+308);
+</script>
diff --git a/dom/media/test/crashtests/876024-2.html b/dom/media/test/crashtests/876024-2.html
new file mode 100644
index 000000000..4b9beb745
--- /dev/null
+++ b/dom/media/test/crashtests/876024-2.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+
+function boom()
+{
+ var bufferSource = new AudioContext().createScriptProcessor().context.createBufferSource();
+ bufferSource.start(0, 0, 0);
+ bufferSource.stop(562949953421313);
+}
+
+</script></head>
+
+<body onload="boom();"></body>
+</html>
diff --git a/dom/media/test/crashtests/876118.html b/dom/media/test/crashtests/876118.html
new file mode 100644
index 000000000..bc0630350
--- /dev/null
+++ b/dom/media/test/crashtests/876118.html
@@ -0,0 +1,16 @@
+<script>
+var Context0= new AudioContext()
+var BufferSource7=Context0.createBufferSource();
+
+BufferSource7.connect(Context0.destination);
+BufferSource7.buffer=function(){
+ var length=7;
+ var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
+ var bufferData= Buffer.getChannelData(0);for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(-1))};
+ return Buffer;
+}();
+
+
+Context0.destination.channelCountMode="explicit";
+Context0.destination.channelCount=519910189000000;
+</script>
diff --git a/dom/media/test/crashtests/876207.html b/dom/media/test/crashtests/876207.html
new file mode 100644
index 000000000..7bfcb096b
--- /dev/null
+++ b/dom/media/test/crashtests/876207.html
@@ -0,0 +1,30 @@
+<script>
+try { o1 = new window.OfflineAudioContext(1, 10, 44100); } catch(e) { }
+try { o2 = o1.createChannelSplitter(1); } catch(e) { }
+try { o3 = o1.createAnalyser(); } catch(e) { }
+try { o4 = o1.createWaveShaper(); } catch(e) { }
+try { o5 = o1.createChannelSplitter(6); } catch(e) { }
+try { o6 = o1.createAnalyser(); } catch(e) { }
+try { o7 = o1.createBufferSource(); } catch(e) { }
+try { o7.connect(o1.destination); } catch(e) { }
+try { o7.buffer = function() {
+o8 = o1.createBuffer(1, 3, o1.sampleRate);
+o9 = o8.getChannelData(0);
+for(var i = 0; i < 3; ++i) {
+o9[i] = Math.sin(i * 127);
+}
+return o8;
+}()
+; } catch(e) { }
+try { o7.playbackRate.cancelScheduledValues(0) } catch(e) { }
+try { o7.channelInterpretation = 'speakers'; } catch(e) { }
+try { o1.destination.channelInterpretation = 'speakers'; } catch(e) { }
+try { o5.connect(o1.destination, 1, 1) } catch(e) { }
+try { o1.listener.setOrientation(0, 1073741824, 1073741824, 4194304, 1, 0) } catch(e) { }
+try { o4.curve = new Float32Array(127); } catch(e) { }
+try { o6.getByteFrequencyData(new Uint8Array(12)) } catch(e) { }
+try { o6.disconnect() } catch(e) { }
+try { o1.destination.channelCount = 33554432; } catch(e) { }
+try { o7.playbackRate.setTargetAtTime(0, 8388608, 1) } catch(e) { }
+try { o6.getByteTimeDomainData(new Uint8Array(12)) } catch(e) { }
+</script>
diff --git a/dom/media/test/crashtests/876215.html b/dom/media/test/crashtests/876215.html
new file mode 100644
index 000000000..07135e362
--- /dev/null
+++ b/dom/media/test/crashtests/876215.html
@@ -0,0 +1,14 @@
+<script>
+try { o1 = new window.OfflineAudioContext(1, 10, 44100); } catch(e) { }
+try { o6 = o1.createScriptProcessor(0, 0, 2); } catch(e) { }
+try { o8 = o1.createBufferSource(); } catch(e) { }
+try { o8.connect(o1.destination); } catch(e) { }
+try { o8.connect(o6) } catch(e) { }
+try { o3.disconnect() } catch(e) { }
+try { o8.buffer = function() {
+o21 = o1.createBuffer(1, 3, o1.sampleRate);
+o22 = o21.getChannelData(0);
+return o21;
+}()
+; } catch(e) { }
+</script>
diff --git a/dom/media/test/crashtests/876249.html b/dom/media/test/crashtests/876249.html
new file mode 100644
index 000000000..6f72b40bc
--- /dev/null
+++ b/dom/media/test/crashtests/876249.html
@@ -0,0 +1,27 @@
+<script>
+var Context0= new AudioContext()
+var BufferSource0=Context0.createBufferSource();
+var BiquadFilter0=Context0.createBiquadFilter();
+BufferSource0.start(0,0.6167310480959713,0.7142638498917222);
+BiquadFilter0.connect(Context0.destination);
+BufferSource0.buffer=function(){
+ var length=86333;
+ var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
+ var bufferData= Buffer.getChannelData(0);
+ for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(-1))};
+ return Buffer;
+}();
+
+BufferSource0.connect(BiquadFilter0);
+
+BufferSource0.buffer=function(){
+ var length=21989;
+ var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
+ var bufferData= Buffer.getChannelData(0);
+ for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(0))};
+ return Buffer;
+}();
+
+BufferSource0.stop(0.04184641852043569);
+
+</script>
diff --git a/dom/media/test/crashtests/876252.html b/dom/media/test/crashtests/876252.html
new file mode 100644
index 000000000..cb9cb63ed
--- /dev/null
+++ b/dom/media/test/crashtests/876252.html
@@ -0,0 +1,23 @@
+<script>
+var Context0= new AudioContext()
+var BufferSource4=Context0.createBufferSource();
+BufferSource4.start(0.05386466556228697,0.397192713804543,0.48810303467325866);
+
+BufferSource4.buffer=function(){
+ var length=109076;
+ var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
+ var bufferData= Buffer.getChannelData(0);
+ for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(370))};
+ return Buffer;
+}();
+
+BufferSource4.buffer=function(){
+ var length=19339;
+ var Buffer=Context0.createBuffer(1,length,53362);
+ var bufferData= Buffer.getChannelData(0);
+ for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(-0.16235407581552863))};
+ return Buffer;
+}();
+
+BufferSource4.stop(0.46482366253621876);
+</script>
diff --git a/dom/media/test/crashtests/876834.html b/dom/media/test/crashtests/876834.html
new file mode 100644
index 000000000..f4ca6ee55
--- /dev/null
+++ b/dom/media/test/crashtests/876834.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<script>
+new OfflineAudioContext(0, 0, 3229622);
+</script>
diff --git a/dom/media/test/crashtests/877527.html b/dom/media/test/crashtests/877527.html
new file mode 100644
index 000000000..c639d501b
--- /dev/null
+++ b/dom/media/test/crashtests/877527.html
@@ -0,0 +1,37 @@
+<script>
+try { o1 = new window.AudioContext(2, 5, 44100); } catch(e) { }
+try { o2 = o1.createChannelMerger(1); } catch(e) { }
+try { o3 = o1.createDelay(10); } catch(e) { }
+try { o4 = o1.createBuffer(2, 2048, 8000); } catch(e) { }
+try { o5 = o1.createPanner(); } catch(e) { }
+try { o6 = o1.createBufferSource(); } catch(e) { }
+try { o7 = (function() {
+var buf = o1.createBuffer(1, 50000, o1.sampleRate);
+for(var j=0; j<1; ++j) {
+for(var i=0; i<50000; ++i) { buf.getChannelData(j)[i] = Math.sin(i * (9.8));}
+}
+return buf;
+})(); } catch(e) { }
+try { o6.buffer = o7; } catch(e) { }
+try { o6.connect(o5); } catch(e) { }
+try { o5.connect(o1.destination); } catch(e) { }
+try { o1.listener.speedOfSound = 0.0000019073486328125; } catch(e) { }
+try { o6.loop = true; } catch(e) { }
+try { o8 = (function() {
+var buf = o1.createBuffer(2, 1000, o1.sampleRate);
+for(var j=0; j<2; ++j) {
+for(var i=0; i<1000; ++i) { buf.getChannelData(j)[i] = Math.sin(i * (1));}
+}
+return buf;
+})(); } catch(e) { }
+try { o6.buffer = o7; } catch(e) { }
+try { o6.connect(o5); } catch(e) { }
+try { o5.connect(o1.destination); } catch(e) { }
+try { o6.loopEnd = 1.4901161193847656e-8; } catch(e) { }
+try { o6.connect(o1.destination); } catch(e) { }
+try { o6.buffer = o8; } catch(e) { }
+try { o5.setPosition(0.36, o1.destination.context.destination.channelCountMode, o1.destination.context.destination.channelInterpretation) } catch(e) { }
+try { o2.channelCountMode = 'explicit'; } catch(e) { }
+try { o1.listener.speedOfSound = 4; } catch(e) { }
+try { o1.startRendering(); } catch(e) { }
+</script>
diff --git a/dom/media/test/crashtests/877820.html b/dom/media/test/crashtests/877820.html
new file mode 100644
index 000000000..6d65c1e9d
--- /dev/null
+++ b/dom/media/test/crashtests/877820.html
@@ -0,0 +1,4 @@
+<script>
+o1 = new window.OfflineAudioContext(2, 5, 0.39);
+window.location.reload();
+</script> \ No newline at end of file
diff --git a/dom/media/test/crashtests/878014.html b/dom/media/test/crashtests/878014.html
new file mode 100644
index 000000000..4a0ca6dce
--- /dev/null
+++ b/dom/media/test/crashtests/878014.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+try { o2 = new window.AudioContext(1, 15, 44100); } catch(e) { }
+try { o5 = o2.createDelay(0.1); } catch(e) { }
+try { o6 = o2.createPanner(); } catch(e) { }
+try { o8 = o2.createBufferSource(); } catch(e) { }
+try { o9 = (function() {
+var buf = o2.createBuffer(1, 12134, o2.sampleRate);
+for(var j=0; j<1; ++j) {
+for(var i=0; i<12134; ++i) { buf.getChannelData(j)[i] = Math.sin(i * (-127));}
+}
+return buf;
+})(); } catch(e) { }
+try { o8.buffer = o9; } catch(e) { }
+try { o8.connect(o6); } catch(e) { }
+try { o6.connect(o5, 0, 0) } catch(e) { }
+try { o8.buffer = (function() {
+var buf = o2.createBuffer(1, 5409, o2.sampleRate);
+for(var j=0; j<1; ++j) {
+for(var i=0; i<5409; ++i) { buf.getChannelData(j)[i] = Math.sin(i * (-1));}
+}
+return buf;
+})(); } catch(e) { }
+setTimeout(function() { try { o5.delayTime.setValueAtTime(0.78, 121560862.56366833); } catch(e) { } setTimeout(done, 0); },128)
+try { o5.delayTime.value = 0.4283; } catch(e) { }
+
+function done() {
+ document.documentElement.removeAttribute("class");
+}
+</script>
diff --git a/dom/media/test/crashtests/878328.html b/dom/media/test/crashtests/878328.html
new file mode 100644
index 000000000..ec7b39871
--- /dev/null
+++ b/dom/media/test/crashtests/878328.html
@@ -0,0 +1,5 @@
+<script>
+o1 = new window.AudioContext(2, 7, 44100);
+o5 = o1.createDelay(1);
+o5.delayTime.setValueCurveAtTime(new Float32Array(3), 1.7976931348623157e+308, 0.64);
+</script> \ No newline at end of file
diff --git a/dom/media/test/crashtests/878407.html b/dom/media/test/crashtests/878407.html
new file mode 100644
index 000000000..ae2918dc8
--- /dev/null
+++ b/dom/media/test/crashtests/878407.html
@@ -0,0 +1,11 @@
+<script>
+o1 = new window.AudioContext();
+o4 = o1.createDelay(0.4468);
+o6 = o1.createPanner();
+o7 = (function() {var buf = o1.createBuffer(1, 1000, o1.sampleRate);for(var j=0; j<1; ++j) {for(var i=0; i<1000; ++i) {buf.getChannelData(j)[i] = Math.sin(i * (-15));}}return buf;})();
+o8 = o1.createBufferSource();
+o8.buffer = o7;
+o8.connect(o6);
+o6.connect(o4)
+o4.delayTime.setValueAtTime(0.6019893103749466289898, 0.26)
+</script>
diff --git a/dom/media/test/crashtests/878478.html b/dom/media/test/crashtests/878478.html
new file mode 100644
index 000000000..89a47ddb5
--- /dev/null
+++ b/dom/media/test/crashtests/878478.html
@@ -0,0 +1,30 @@
+<script>
+var Context0= new AudioContext()
+var BufferSource0=Context0.createBufferSource();
+
+BufferSource0.loop=true;
+
+BufferSource0.buffer=function(){
+ var channels=3;
+ var length=97252;
+ var Buffer=Context0.createBuffer(channels,length,Context0.sampleRate);
+ for(var y=0;y<channels;y++){
+ var bufferData= Buffer.getChannelData(y);
+ for (var i = 0; i < length; ++i) { bufferData[i] = 1;}
+ };
+ return Buffer;
+}();
+
+BufferSource0.playbackRate.cancelScheduledValues(0.4);
+
+BufferSource0.loopEnd=5e-324;
+
+BufferSource0.buffer=function(){
+ var length=26590;
+ var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
+ var bufferData= Buffer.getChannelData(0);
+ for (var i = 0; i < length; ++i) { bufferData[i] = 1};
+ return Buffer;
+}();
+
+</script>
diff --git a/dom/media/test/crashtests/880129.html b/dom/media/test/crashtests/880129.html
new file mode 100644
index 000000000..775e9d80b
--- /dev/null
+++ b/dom/media/test/crashtests/880129.html
@@ -0,0 +1,9 @@
+<script>
+try { o1 = new window.AudioContext(3, 2, 44100); } catch(e) { }
+try { o6 = o1.createBufferSource(); } catch(e) { }
+try { o15 = o1.createAnalyser(); } catch(e) { }
+try { o15.fftSize = 32; } catch(e) { }
+try { o6.connect(o15,0,0) } catch(e) { }
+try { o27 = o1.createPanner(); } catch(e) { }
+try { o6.buffer = function(){var buffer = o1.createBuffer(2, 1148, o1.sampleRate);for(var c=0; c<2; c++) {for(var i=0; i<1148; i++) {buffer.getChannelData(c)[i] = 0;}}return buffer;}() } catch(e) { }
+</script> \ No newline at end of file
diff --git a/dom/media/test/crashtests/880202.html b/dom/media/test/crashtests/880202.html
new file mode 100644
index 000000000..dc0fade9d
--- /dev/null
+++ b/dom/media/test/crashtests/880202.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+var Context0= new window.OfflineAudioContext(15,12119,44100)
+var BufferSource1=Context0.createBufferSource();
+var Gain0=Context0.createGain();
+var Panner0=Context0.createPanner();
+Context0.listener.setPosition(29,135,158);
+
+BufferSource1.connect(Gain0);
+
+BufferSource1.buffer=function(){
+ var channels=3;
+ var length=53325;
+ var Buffer=Context0.createBuffer(channels,length,Context0.sampleRate);
+ for(var y=0;y<channels;y++){
+ var bufferData= Buffer.getChannelData(y);
+ for (var i = 0; i < length; ++i) {
+ bufferData[i] = i*(270);
+ }
+ };
+ return Buffer;
+}();
+
+Gain0.connect(Panner0);
+Panner0.panningModel="equalpower";
+
+
+setTimeout(function(){
+document.documentElement.removeAttribute("class");
+},500)
+
+</script>
diff --git a/dom/media/test/crashtests/880342-1.html b/dom/media/test/crashtests/880342-1.html
new file mode 100644
index 000000000..7d1aa0c3e
--- /dev/null
+++ b/dom/media/test/crashtests/880342-1.html
@@ -0,0 +1,208 @@
+<script>
+try { o1 = new window.AudioContext(2, 10, 1019159); } catch(e) { }
+try { o2 = o1.createBufferSource(); } catch(e) { }
+try { o3 = o1.createConvolver(); } catch(e) { }
+try { o4 = o1.createChannelMerger(2); } catch(e) { }
+try { o5 = o1.createAnalyser(); } catch(e) { }
+try { o6 = o1.createPanner(); } catch(e) { }
+try { o7 = o1.createDynamicsCompressor(); } catch(e) { }
+try { o8 = o1.createWaveShaper(); } catch(e) { }
+try { o9 = o1.createChannelSplitter(6); } catch(e) { }
+try { o10 = o1.createScriptProcessor(8192, 2, 3); } catch(e) { }
+try { o1.listener.setPosition(-144115188075855870, 0, -5e-324) } catch(e) { }
+try { o3.buffer = function(){var buffer = o1.createBuffer(2, 741, o1.sampleRate);for(var c=0; c<2; c++) {for(var i=0; i<741; i++) {buffer.getChannelData(c)[i] = 1;}}return buffer;}(); } catch(e) { }
+try { o10.onaudioprocess = function(e) { /* onEvent */ }; } catch(e) { }
+try { o3.connect(o5,0,0) } catch(e) { }
+try { o9.channelCountMode = 'max'; } catch(e) { }
+try { o10.onaudioprocess = function(e) { /* onEvent */ }; } catch(e) { }
+try { o7.channelInterpretation = 'speakers'; } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(2, 1887, 63346);for(var c=0; c<2; c++) {for(var i=0; i<1887; i++) {buffer.getChannelData(c)[i] = 1;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o2.playbackRate.exponentialRampToValueAtTime(3.819464020334534, 32) } catch(e) { }
+try { o5.connect(o9,2,0) } catch(e) { }
+try { o9.channelCountMode = 'explicit'; } catch(e) { }
+try { o1.listener.speedOfSound = 72057594037927940; } catch(e) { }
+try { o1.destination.channelCountMode = 'explicit'; } catch(e) { }
+try { o7.threshold.value = 0.0646435404346891590021684237399313133209944; } catch(e) { }
+try { o7.connect(o10,0,0) } catch(e) { }
+try { o1.destination.channelInterpretation = 'speakers'; } catch(e) { }
+try { o3.connect(o4,0,0) } catch(e) { }
+try { o7.release.value = 23.030355486273447; } catch(e) { }
+try { o9.connect(o9,4,0) } catch(e) { }
+try { o6.channelCountMode = 'max'; } catch(e) { }
+try { o7.threshold.value = 0.6395867363641939418172910336579661816358566284179687500; } catch(e) { }
+try { o2.connect(o9,3,0) } catch(e) { }
+try { o10.onaudioprocess = function(e) { /* onEvent */ }; } catch(e) { }
+try { o7.connect(o10,0,0) } catch(e) { }
+try { o5.connect(o5,0,0) } catch(e) { }
+try { o2.playbackRate.value = 5e-324; } catch(e) { }
+try { o4.channelInterpretation = 'discrete'; } catch(e) { }
+try { o2.playbackRate.value = 1.2211628339508704; } catch(e) { }
+try { o2.channelCountMode = 'clamped-max'; } catch(e) { }
+try { o1.listener.dopplerFactor = 32; } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(22, 1811, 21177);for(var c=0; c<22; c++) {for(var i=0; i<1811; i++) {buffer.getChannelData(c)[i] = 1;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o5.channelCountMode = 'max'; } catch(e) { }
+try { o1.listener.speedOfSound = 1024; } catch(e) { }
+try { o2.playbackRate.value = 9.999999999999998e-91; } catch(e) { }
+try { o1.listener.speedOfSound = 16; } catch(e) { }
+try { o8.curve = new Float32Array(256); } catch(e) { }
+try { o1.listener.setVelocity(0, 128, 4) } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(23, 483, o1.sampleRate);for(var c=0; c<23; c++) {for(var i=0; i<483; i++) {buffer.getChannelData(c)[i] = 0.026;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(3, 945, 43803);for(var c=0; c<3; c++) {for(var i=0; i<945; i++) {buffer.getChannelData(c)[i] = -1;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(19, 997, 23781);for(var c=0; c<19; c++) {for(var i=0; i<997; i++) {buffer.getChannelData(c)[i] = -1;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o1.listener.speedOfSound = -8; } catch(e) { }
+try { o3.channelCountMode = 'explicit'; } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(3, 1740, o1.sampleRate);for(var c=0; c<3; c++) {for(var i=0; i<1740; i++) {buffer.getChannelData(c)[i] = 8;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(1, 1057, 30602);for(var c=0; c<1; c++) {for(var i=0; i<1057; i++) {buffer.getChannelData(c)[i] = -1;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(3, 78, o1.sampleRate);for(var c=0; c<3; c++) {for(var i=0; i<78; i++) {buffer.getChannelData(c)[i] = 10;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o1.listener.setPosition(9.999999999999995e-275, 0.0001, 2) } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(1, 863, o1.sampleRate);for(var c=0; c<1; c++) {for(var i=0; i<863; i++) {buffer.getChannelData(c)[i] = 1;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o8.channelCount = 3; } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(2, 1821, o1.sampleRate);for(var c=0; c<2; c++) {for(var i=0; i<1821; i++) {buffer.getChannelData(c)[i] = 0.3655;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o6.connect(o6,0,0) } catch(e) { }
+try { o1.listener.setOrientation(128, -0.479527496, 128, 1, 1, -16) } catch(e) { }
+try { o4.connect(o8,0,0) } catch(e) { }
+try { o7.reduction.exponentialRampToValueAtTime(1.7976931348623157e+308, 2048) } catch(e) { }
+try { o1.listener.dopplerFactor = 0.5754; } catch(e) { }
+try { o7.release.value = 0; } catch(e) { }
+try { o5.getFloatFrequencyData(new Float32Array(2048)) } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(2, 120, 42419);for(var c=0; c<2; c++) {for(var i=0; i<120; i++) {buffer.getChannelData(c)[i] = -1;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o3.buffer = function(){var buffer = o1.createBuffer(1, 1620, o1.sampleRate);for(var c=0; c<1; c++) {for(var i=0; i<1620; i++) {buffer.getChannelData(c)[i] = -1;}}return buffer;}(); } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(1, 823, 77239);for(var c=0; c<1; c++) {for(var i=0; i<823; i++) {buffer.getChannelData(c)[i] = -1;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o1.destination.channelInterpretation = 'speakers'; } catch(e) { }
+try { o1.listener.setPosition(2048, 0.000522899209, -4503599627370495) } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(3, 84028, 75483);for(var c=0; c<3; c++) {for(var i=0; i<84028; i++) {buffer.getChannelData(c)[i] = -1;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o2.playbackRate.setTargetAtTime(5e-324, 9.999999999999998e-104, 0) } catch(e) { }
+try { o7.attack.value = 9.999999999999994e-236; } catch(e) { }
+try { o1.listener.dopplerFactor = 1024; } catch(e) { }
+try { o3.connect(o7,0,0) } catch(e) { }
+try { o2.playbackRate.linearRampToValueAtTime(0, 0) } catch(e) { }
+try { o4.connect(o10,0,0) } catch(e) { }
+try { o1.listener.setVelocity(0.682, 32, 1e-76) } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(3, 201, o1.sampleRate);for(var c=0; c<3; c++) {for(var i=0; i<201; i++) {buffer.getChannelData(c)[i] = 4;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o2.connect(o6,0,0) } catch(e) { }
+try { o5.getByteFrequencyData(new Uint8Array(32)) } catch(e) { }
+try { o3.connect(o6,0,0) } catch(e) { }
+try { o7.channelCount = 1; } catch(e) { }
+try { o2.playbackRate.setValueCurveAtTime(new Float32Array(512), 8, 1) } catch(e) { }
+try { o3.connect(o4,0,1) } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(3, 1996, o1.sampleRate);for(var c=0; c<3; c++) {for(var i=0; i<1996; i++) {buffer.getChannelData(c)[i] = -1;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o1.listener.dopplerFactor = 2; } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(2, 983, 60517);for(var c=0; c<2; c++) {for(var i=0; i<983; i++) {buffer.getChannelData(c)[i] = 1;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o6.coneInnerAngle = 360; } catch(e) { }
+try { o8.curve = new Float32Array(512); } catch(e) { }
+try { o1.listener.setPosition(32, 16, 9.999999999999995e-280) } catch(e) { }
+try { o6.connect(o6,0,0) } catch(e) { }
+try { o1.listener.setPosition(2097151, 512, 5e-324) } catch(e) { }
+try { o7.channelCountMode = 'clamped-max'; } catch(e) { }
+try { o1.destination.channelCountMode = 'max'; } catch(e) { }
+try { o1.listener.setPosition(0, 1000000, 64) } catch(e) { }
+try { o4.connect(o5,0,0) } catch(e) { }
+try { o9.connect(o4,0,1) } catch(e) { }
+try { o7.attack.setValueCurveAtTime(new Float32Array(8), 256, 2048) } catch(e) { }
+try { o9.channelCountMode = 'explicit'; } catch(e) { }
+try { o1.listener.dopplerFactor = 5e-324; } catch(e) { }
+try { o4.connect(o10,0,0) } catch(e) { }
+try { o7.ratio.cancelScheduledValues(1) } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(1, 1590, 9733);for(var c=0; c<1; c++) {for(var i=0; i<1590; i++) {buffer.getChannelData(c)[i] = 2;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o1.destination.channelCount = 2; } catch(e) { }
+try { o1.destination.channelInterpretation = 'speakers'; } catch(e) { }
+try { o5.channelCountMode = 'max'; } catch(e) { }
+try { o9.channelCountMode = 'clamped-max'; } catch(e) { }
+try { o7.attack.setTargetAtTime(0.11499421161482907549622467513472656719386577606201171875000, 1, 1.7976931348623157e+308) } catch(e) { }
+try { o2.playbackRate.value = 1; } catch(e) { }
+try { o3.normalize = false; } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(2, 1866, o1.sampleRate);for(var c=0; c<2; c++) {for(var i=0; i<1866; i++) {buffer.getChannelData(c)[i] = 0.174908422905697580329587026426452212035655975341797;}}return buffer;}(); } catch(e) { }
+try { o2.playbackRate.value = 1.0; } catch(e) { }
+try { o7.threshold.value = 100; } catch(e) { }
+try { o1.listener.setVelocity(961.4441892370145, 9.999999999999999e-157, 1) } catch(e) { }
+try { o5.getByteFrequencyData(new Uint8Array(2)) } catch(e) { }
+try { o6.connect(o10,0,0) } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(3, 1176, o1.sampleRate);for(var c=0; c<3; c++) {for(var i=0; i<1176; i++) {buffer.getChannelData(c)[i] = 9.753993292300242;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o2.playbackRate.linearRampToValueAtTime(0.8687, 32) } catch(e) { }
+try { o5.channelCountMode = 'explicit'; } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(13, 703, 12723);for(var c=0; c<13; c++) {for(var i=0; i<703; i++) {buffer.getChannelData(c)[i] = -1;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o2.loopEnd = 1.7976931348623157e+308; } catch(e) { }
+try { o3.connect(o7,0,0) } catch(e) { }
+try { o1.destination.channelCountMode = 'clamped-max'; } catch(e) { }
+try { o1.destination.channelInterpretation = 'discrete'; } catch(e) { }
+try { o2.connect(o10,0,0) } catch(e) { }
+try { o3.normalize = false; } catch(e) { }
+try { /* switch-case did not return anything. */ } catch(e) { }
+try { o10.connect(o8,0,0) } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(3, 132, 88507);for(var c=0; c<3; c++) {for(var i=0; i<132; i++) {buffer.getChannelData(c)[i] = 1.7976931348623157e+308;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o2.loopStart = 1.7976931348623157e+308; } catch(e) { }
+try { o1.listener.dopplerFactor = 1024; } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(1, 40, o1.sampleRate);for(var c=0; c<1; c++) {for(var i=0; i<40; i++) {buffer.getChannelData(c)[i] = 1.3785770335346594;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o4.connect(o9,5,0) } catch(e) { }
+try { o8.curve = new Float32Array(16); } catch(e) { }
+try { o10.onaudioprocess = function(e) { /* onEvent */ }; } catch(e) { }
+try { o6.channelCountMode = 'explicit'; } catch(e) { }
+try { o2.playbackRate.value = 0; } catch(e) { }
+try { o4.channelCount = 3; } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(3, 220, o1.sampleRate);for(var c=0; c<3; c++) {for(var i=0; i<220; i++) {buffer.getChannelData(c)[i] = -1;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o1.destination.channelInterpretation = 'discrete'; } catch(e) { }
+try { o1.listener.setPosition(70368744177664, 2048, 1.7976931348623157e+308) } catch(e) { }
+try { o2.playbackRate.setValueCurveAtTime(new Float32Array(128), 1.7976931348623157e+308, 0.75) } catch(e) { }
+try { o5.fftSize = 118; } catch(e) { }
+try { o5.minDecibels = 1; } catch(e) { }
+try { o7.release.value = 5e-324; } catch(e) { }
+try { o2.channelCount = 3; } catch(e) { }
+try { o2.channelCountMode = 'clamped-max'; } catch(e) { }
+try { o3.normalize = false; } catch(e) { }
+try { o1.listener.speedOfSound = 2; } catch(e) { }
+try { o2.loopStart = 32; } catch(e) { }
+try { o3.channelCountMode = 'max'; } catch(e) { }
+try { o1.listener.setPosition(0.37976588317653304, -274877906943, 64) } catch(e) { }
+try { o8.curve = new Float32Array(4); } catch(e) { }
+try { o1.listener.setVelocity(16, -1024, 0) } catch(e) { }
+try { o5.minDecibels = 10000; } catch(e) { }
+try { o2.playbackRate.value = 5e-324; } catch(e) { }
+try { o3.connect(o9,1,0) } catch(e) { }
+try { o10.onaudioprocess = function(e) { /* onEvent */ }; } catch(e) { }
+try { o5.connect(o8,0,0) } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(3, 554, o1.sampleRate);for(var c=0; c<3; c++) {for(var i=0; i<554; i++) {buffer.getChannelData(c)[i] = 0.000001;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o7.release.value = 0; } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(1, 1289, 29583);for(var c=0; c<1; c++) {for(var i=0; i<1289; i++) {buffer.getChannelData(c)[i] = 5e-324;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o1.listener.setOrientation(1024, 64, 16, 1024, 1, 68719476735) } catch(e) { }
+try { o1.listener.setOrientation(512, 10000000, 274877906944, 9.999999999999998e-113, -8, 3.6191134923595274) } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(1, 1453, 15258);for(var c=0; c<1; c++) {for(var i=0; i<1453; i++) {buffer.getChannelData(c)[i] = -1;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o8.channelInterpretation = 'discrete'; } catch(e) { }
+try { o5.channelInterpretation = 'discrete'; } catch(e) { }
+try { o7.connect(o9,4,0) } catch(e) { }
+try { o8.connect(o10,0,0) } catch(e) { }
+try { o1.listener.setPosition(18014398509481984, 16, 0.505129302503804056279079759406158700585365295410156250000) } catch(e) { }
+try { o10.connect(o9,5,0) } catch(e) { }
+try { o2.loop = false; } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(11, 1673, o1.sampleRate);for(var c=0; c<11; c++) {for(var i=0; i<1673; i++) {buffer.getChannelData(c)[i] = 0;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(2, 577, o1.sampleRate);for(var c=0; c<2; c++) {for(var i=0; i<577; i++) {buffer.getChannelData(c)[i] = 0.5611;}}return buffer;}() } catch(e) { }
+try { o2.connect(o1.destination); } catch(e) { }
+try { o1.listener.setOrientation(64, 2049, 5e-324, 0.1777, 2, 7) } catch(e) { }
+try { o5.maxDecibels = 128; } catch(e) { }
+try { o2.start(0) } catch(e) { }
+</script> \ No newline at end of file
diff --git a/dom/media/test/crashtests/880342-2.html b/dom/media/test/crashtests/880342-2.html
new file mode 100644
index 000000000..a8ef88ae7
--- /dev/null
+++ b/dom/media/test/crashtests/880342-2.html
@@ -0,0 +1,8 @@
+<script>
+try { o1 = new window.AudioContext(2, 10, 1019159); } catch(e) { }
+try { o2 = o1.createBufferSource(); } catch(e) { }
+try { o3 = o1.createConvolver(); } catch(e) { }
+try { o3.buffer = function(){var buffer = o1.createBuffer(2, 741, o1.sampleRate);for(var c=0; c<2; c++) {for(var i=0; i<741; i++) {buffer.getChannelData(c)[i] = 1;}}return buffer;}(); } catch(e) { }
+try { o2.buffer = function(){var buffer = o1.createBuffer(2, 120, 42419);for(var c=0; c<2; c++) {for(var i=0; i<120; i++) {buffer.getChannelData(c)[i] = -1;}}return buffer;}() } catch(e) { }
+try { o3.buffer = function(){var buffer = o1.createBuffer(1, 1620, o1.sampleRate);for(var c=0; c<1; c++) {for(var i=0; i<1620; i++) {buffer.getChannelData(c)[i] = -1;}}return buffer;}(); } catch(e) { }
+</script> \ No newline at end of file
diff --git a/dom/media/test/crashtests/880384.html b/dom/media/test/crashtests/880384.html
new file mode 100644
index 000000000..798fbf133
--- /dev/null
+++ b/dom/media/test/crashtests/880384.html
@@ -0,0 +1,8 @@
+<script>
+o1 = new window.AudioContext(3, 256, 44100);
+o2 = o1.createBufferSource();
+o3 = o1.createConvolver();
+o3.normalize = false;
+o3.buffer = function(){var buffer = o1.createBuffer(2, 1051, o1.sampleRate);for(var c=0; c<2; c++) {for(var i=0; i<1051; i++) {buffer.getChannelData(c)[i] = 1;}}return buffer;}();
+o3.buffer = function(){var buffer = o1.createBuffer(2, 1112, o1.sampleRate);for(var c=0; c<2; c++) {for(var i=0; i<1112; i++) {buffer.getChannelData(c)[i] = 1;}}return buffer;}();
+</script>
diff --git a/dom/media/test/crashtests/880404.html b/dom/media/test/crashtests/880404.html
new file mode 100644
index 000000000..bf3493238
--- /dev/null
+++ b/dom/media/test/crashtests/880404.html
@@ -0,0 +1,6 @@
+<script>
+o1 = new window.OfflineAudioContext(2, 32, 44100);
+o12 = o1.createConvolver();
+o12.buffer = function(){var buffer = o1.createBuffer(1, 78, o1.sampleRate);for(var c=0; c<1; c++) {for(var i=0; i<78; i++) {buffer.getChannelData(c)[i] = 1;}}return buffer;}();
+o1.startRendering();
+</script> \ No newline at end of file
diff --git a/dom/media/test/crashtests/880724.html b/dom/media/test/crashtests/880724.html
new file mode 100644
index 000000000..b57b5f996
--- /dev/null
+++ b/dom/media/test/crashtests/880724.html
@@ -0,0 +1,13 @@
+<script>
+o1 = new window.AudioContext();
+o5 = o1.createConvolver();
+o5.buffer = function() {
+ var buffer = o1.createBuffer(2, 3, 33120);
+ for(var c=0; c<2; c++) {
+ for(var i=0; i<3; i++) {
+ buffer.getChannelData(c)[i] = -1;
+ }
+ }
+ return buffer;
+}();
+</script> \ No newline at end of file
diff --git a/dom/media/test/crashtests/881775.html b/dom/media/test/crashtests/881775.html
new file mode 100644
index 000000000..d55c45d17
--- /dev/null
+++ b/dom/media/test/crashtests/881775.html
@@ -0,0 +1,25 @@
+<script>
+o1 = new window.AudioContext(2, 16, 44100);
+o2 = o1.createBufferSource();
+o12 = o1.createBiquadFilter();
+o1.destination.channelCountMode = 'max';
+o2.buffer = function(){
+ var buffer = o1.createBuffer(2, 326, 77632);
+ for(var c=0; c<2; c++) {
+ for(var i=0; i<326; i++) {
+ buffer.getChannelData(c)[i] = -1;
+ }
+ }
+ return buffer;
+}();
+o2.connect(o1.destination);
+o2.buffer = function(){
+ var buffer = o1.createBuffer(3, 405, o1.sampleRate);
+ for(var c=0; c<3; c++) {
+ for(var i=0; i<405; i++) {
+ buffer.getChannelData(c)[i] = 1;
+ }
+ }
+ return buffer;
+}();
+</script>
diff --git a/dom/media/test/crashtests/882549.html b/dom/media/test/crashtests/882549.html
new file mode 100644
index 000000000..8a720c3e1
--- /dev/null
+++ b/dom/media/test/crashtests/882549.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <script>
+ var o0 = new VTTCue(0.000, 1.000, 'Bug882549');
+ var o1 = o0.getCueAsHTML();
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
+<script>
+</script>
diff --git a/dom/media/test/crashtests/882956.html b/dom/media/test/crashtests/882956.html
new file mode 100644
index 000000000..ae7b441f9
--- /dev/null
+++ b/dom/media/test/crashtests/882956.html
@@ -0,0 +1,15 @@
+<script>
+o1 = new window.AudioContext(1, 2048, 44100);
+o2 = o1.createBufferSource();
+o1.destination.channelCountMode = 'max';
+o2.connect(o1.destination);
+o2.buffer = function(){
+ var buffer = o1.createBuffer(30, 442, 94933);
+ for(var c=0; c<30; c++) {
+ for(var i=0; i<442; i++) {
+ buffer.getChannelData(c)[i] = 1;
+ }
+ }
+ return buffer;
+}();
+</script>
diff --git a/dom/media/test/crashtests/884459.html b/dom/media/test/crashtests/884459.html
new file mode 100644
index 000000000..e321d569f
--- /dev/null
+++ b/dom/media/test/crashtests/884459.html
@@ -0,0 +1,12 @@
+<script>
+var Context0= new window.OfflineAudioContext(14,191531,44100)
+var BufferSource1=Context0.createBufferSource();
+
+setInterval(function(){
+BufferSource1.playbackRate.setTargetAtTime(0xC8F461D3EE6B2,(Context0.currentTime+0.0677539280615747),0.826130285160616);
+BufferSource1.playbackRate.setValueAtTime(35467.63924283907536607336193,0);
+},1)
+
+Context0.startRendering();
+
+</script>
diff --git a/dom/media/test/crashtests/889042.html b/dom/media/test/crashtests/889042.html
new file mode 100644
index 000000000..9f74979c5
--- /dev/null
+++ b/dom/media/test/crashtests/889042.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<script>
+ (new AudioContext()).createConvolver().buffer = null;
+</script>
diff --git a/dom/media/test/crashtests/894104.html b/dom/media/test/crashtests/894104.html
new file mode 100644
index 000000000..d021994e7
--- /dev/null
+++ b/dom/media/test/crashtests/894104.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+
+function boom()
+{
+ var frame = document.getElementById("f");
+ var frameWin = frame.contentWindow;
+ frameWin.VTTCue;
+ document.body.removeChild(frame);
+ new frameWin.VTTCue(0, 1, "Bug 894104").getCueAsHTML();
+}
+
+</script>
+</head>
+
+<body onload="boom();"><iframe id="f" src="data:text/html,1"></iframe></body>
+</html>
diff --git a/dom/media/test/crashtests/907986-1.html b/dom/media/test/crashtests/907986-1.html
new file mode 100644
index 000000000..320b8eadd
--- /dev/null
+++ b/dom/media/test/crashtests/907986-1.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+var context = new window.OfflineAudioContext(1, 100, 48000);
+context.oncomplete = function(e) {
+ document.documentElement.removeAttribute("class");
+};
+// zero front vector
+context.listener.setOrientation(0, 0, 0, 6.311749985202524e+307, 0, 0);
+var panner = context.createPanner();
+panner.setPosition(6.311749985202524e+307, 4, 6.311749985202524e+307);
+panner.connect(context.destination);
+var source = context.createOscillator();
+source.connect(panner);
+source.start(0);
+context.startRendering();
+</script>
diff --git a/dom/media/test/crashtests/907986-2.html b/dom/media/test/crashtests/907986-2.html
new file mode 100644
index 000000000..e0626ba2c
--- /dev/null
+++ b/dom/media/test/crashtests/907986-2.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+var context = new window.OfflineAudioContext(1, 100, 48000);
+context.oncomplete = function(e) {
+ document.documentElement.removeAttribute("class");
+};
+// zero up vector
+context.listener.setOrientation(0, 6.311749985202524e+307, 0, 0, 0, 0);
+var panner = context.createPanner();
+panner.setPosition(1, 2, 3);
+panner.connect(context.destination);
+var source = context.createOscillator();
+source.connect(panner);
+source.start(0);
+context.startRendering();
+</script>
diff --git a/dom/media/test/crashtests/907986-3.html b/dom/media/test/crashtests/907986-3.html
new file mode 100644
index 000000000..75b756c36
--- /dev/null
+++ b/dom/media/test/crashtests/907986-3.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+var context = new window.OfflineAudioContext(1, 100, 48000);
+context.oncomplete = function(e) {
+ document.documentElement.removeAttribute("class");
+};
+// linearly dependent
+context.listener.setOrientation(0, 0, -6.311749985202524e+307, 0, 0, 6.311749985202524e+307);
+var panner = context.createPanner();
+panner.setPosition(1, 2, 3);
+panner.connect(context.destination);
+var source = context.createOscillator();
+source.connect(panner);
+source.start(0);
+context.startRendering();
+</script>
diff --git a/dom/media/test/crashtests/907986-4.html b/dom/media/test/crashtests/907986-4.html
new file mode 100644
index 000000000..a73500efc
--- /dev/null
+++ b/dom/media/test/crashtests/907986-4.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+var context = new window.OfflineAudioContext(1, 100, 48000);
+context.oncomplete = function(e) {
+ document.documentElement.removeAttribute("class");
+};
+var panner = context.createPanner();
+panner.setPosition(0, 3, 0); // directly overhead
+panner.connect(context.destination);
+var source = context.createOscillator();
+source.connect(panner);
+source.start(0);
+context.startRendering();
+</script>
diff --git a/dom/media/test/crashtests/910171-1.html b/dom/media/test/crashtests/910171-1.html
new file mode 100644
index 000000000..9f3ec831b
--- /dev/null
+++ b/dom/media/test/crashtests/910171-1.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+var context = new window.OfflineAudioContext(1, 4096, 48000);
+context.oncomplete = function(e) {
+ document.documentElement.removeAttribute("class");
+};
+var delay = context.createDelay();
+delay.connect(context.destination);
+delay.delayTime.value = 1.0;
+var buffer = context.createBuffer(1, 2048, context.sampleRate);
+var source = context.createBufferSource();
+source.buffer = buffer;
+source.connect(delay);
+source.start();
+context.startRendering();
+</script>
diff --git a/dom/media/test/crashtests/920987.html b/dom/media/test/crashtests/920987.html
new file mode 100644
index 000000000..6e8b2992a
--- /dev/null
+++ b/dom/media/test/crashtests/920987.html
@@ -0,0 +1,6 @@
+<script>
+var ctx = new AudioContext();
+var buffer = ctx.createBuffer(1, 1000, ctx.sampleRate);
+var array = new Float32Array(900);
+buffer.copyToChannel(array, 0, 0xfffffff8);
+</script>
diff --git a/dom/media/test/crashtests/925619-1.html b/dom/media/test/crashtests/925619-1.html
new file mode 100644
index 000000000..146c531f9
--- /dev/null
+++ b/dom/media/test/crashtests/925619-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+// 1024 > 89478.5 * 48000 - (1 << 32)
+var context = new window.OfflineAudioContext(1, 1024, 48000);
+context.oncomplete = function(e) {
+ document.documentElement.removeAttribute("class");
+};
+var buffer = context.createBuffer(1, 2048, context.sampleRate);
+var source = context.createBufferSource();
+source.buffer = buffer;
+source.start(89478.5); // 89478.5 is a little greater than 2^32 / 48000.
+context.startRendering();
+</script>
diff --git a/dom/media/test/crashtests/925619-2.html b/dom/media/test/crashtests/925619-2.html
new file mode 100644
index 000000000..e734b8bca
--- /dev/null
+++ b/dom/media/test/crashtests/925619-2.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+var context = new window.OfflineAudioContext(1, 2048, 48000);
+// 1024 > 89478.5 * 48000 - (1 << 32)
+var buffer = context.createBuffer(1, 1024, context.sampleRate);
+var source = context.createBufferSource();
+source.buffer = buffer;
+source.onended = function(e) {
+ document.documentElement.removeAttribute("class");
+};
+source.start(0);
+source.stop(89478.5); // 89478.5 is a little greater than 2^32 / 48000.
+context.startRendering();
+</script>
diff --git a/dom/media/test/crashtests/926619.html b/dom/media/test/crashtests/926619.html
new file mode 100644
index 000000000..2ead02af4
--- /dev/null
+++ b/dom/media/test/crashtests/926619.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+
+function boom()
+{
+ var ac = new window.AudioContext();
+
+ var _ChannelMergerNode = ac.createChannelMerger(4);
+
+ var _MediaStreamAudioDestinationNode = ac.createMediaStreamDestination();
+ var _MediaStream = _MediaStreamAudioDestinationNode.stream;
+ var _MediaStreamAudioSourceNode = ac.createMediaStreamSource(_MediaStream);
+
+ _ChannelMergerNode.connect(_MediaStreamAudioDestinationNode, 0, 0);
+ _MediaStreamAudioSourceNode.connect(_ChannelMergerNode, 0, 0);
+}
+
+</script>
+</head>
+<body onload="boom();"></body>
+</html>
diff --git a/dom/media/test/crashtests/933151.html b/dom/media/test/crashtests/933151.html
new file mode 100644
index 000000000..3d45f7af3
--- /dev/null
+++ b/dom/media/test/crashtests/933151.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+function boom()
+{
+ var ac = new window.AudioContext();
+ var buffer = ac.createBuffer(1, 24313, 47250);
+ buffer.copyFromChannel(buffer.getChannelData(0), '');
+}
+
+</script>
+</head>
+<body onload="boom();"></body>
+</html>
diff --git a/dom/media/test/crashtests/933156.html b/dom/media/test/crashtests/933156.html
new file mode 100644
index 000000000..b89445a43
--- /dev/null
+++ b/dom/media/test/crashtests/933156.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+function boom()
+{
+ var ac = new window.AudioContext();
+
+ var panner = ac.createPanner();
+ panner.setPosition(8, 0.7643051305237005, 0.10292575673733972);
+
+ var oscillator = ac.createOscillator();
+ oscillator.connect(panner);
+ oscillator.start(0);
+
+ setTimeout(function() {
+ panner.panningModel = 'equalpower';
+ oscillator.stop(0);
+ document.documentElement.removeAttribute("class");
+ }, 0.5);
+}
+boom();
+</script>
+</html>
diff --git a/dom/media/test/crashtests/944851.html b/dom/media/test/crashtests/944851.html
new file mode 100644
index 000000000..4f663accc
--- /dev/null
+++ b/dom/media/test/crashtests/944851.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+
+var ac = new AudioContext(1, 1354, 44100);
+var shaper = ac.createWaveShaper();
+var biquad = ac.createBiquadFilter();
+shaper.connect(biquad.frequency);
+biquad.getFrequencyResponse(new Float32Array(55785),
+ new Float32Array(62876),
+ new Float32Array(45111));
+
+</script>
+</head>
+</html>
diff --git a/dom/media/test/crashtests/952756.html b/dom/media/test/crashtests/952756.html
new file mode 100644
index 000000000..ffced2e40
--- /dev/null
+++ b/dom/media/test/crashtests/952756.html
@@ -0,0 +1,19 @@
+<script>
+var Context0= new AudioContext()
+var BufferSource0=Context0.createBufferSource();
+BufferSource0.buffer=function(){
+ var length=35887;
+ var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
+ var bufferData= Buffer.getChannelData(0);
+ for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(0.39765272522345185))};
+ return Buffer;
+}();
+BufferSource0.start(0.01932738965842873,0.33345631847623736,0.3893404237460345);
+BufferSource0.buffer=function(){
+ var length=15952;
+ var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
+ var bufferData= Buffer.getChannelData(0);
+ for (var i = 0; i < length; ++i) { bufferData[i] = Math.sin(i*(85))};
+ return Buffer;
+}();
+</script>
diff --git a/dom/media/test/crashtests/966636.html b/dom/media/test/crashtests/966636.html
new file mode 100644
index 000000000..acc9758c8
--- /dev/null
+++ b/dom/media/test/crashtests/966636.html
@@ -0,0 +1,45 @@
+<html class="reftest-wait">
+<head>
+<script>
+function boom() {
+ var Context0= new window.AudioContext();
+ var BufferSource0=Context0.createBufferSource();
+ BufferSource0.start(0);
+ BufferSource0.playbackRate.value = 1.0/128.0;
+
+ setTimeout(
+ function(){
+ BufferSource0.buffer=
+ function(){
+ var length=1;
+ var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
+ var bufferData= Buffer.getChannelData(0);
+ for (var i = 0; i < length; ++i) {
+ bufferData[i] = Math.sin(i*(626))
+ };return Buffer;
+ }();
+ setTimeout(
+ function(){
+ document.documentElement.removeAttribute("class");
+ }, 0)
+ },4)
+
+ BufferSource0.buffer=
+ function(){
+ const resample_filter_length = 64;
+ // Small enough so that resampler tail latency is triggered immediately,
+ // but large enough that skip_zeros does not consume resampler tail
+ // latency.
+ var length=resample_filter_length/2 + 1;
+ var Buffer=Context0.createBuffer(1,length,Context0.sampleRate);
+ var bufferData= Buffer.getChannelData(0);
+ for (var i = 0; i < length; ++i) {
+ bufferData[i] = Math.sin(i*(311980))
+ };
+ return Buffer;
+ }();
+}
+</script>
+</head>
+<body onload="boom();">
+</body>
diff --git a/dom/media/test/crashtests/986901.html b/dom/media/test/crashtests/986901.html
new file mode 100644
index 000000000..343df2c0e
--- /dev/null
+++ b/dom/media/test/crashtests/986901.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+ var ac = new window.AudioContext();
+ var delay1 = ac.createDelay(0.02);
+ var delay2 = ac.createDelay(0.002);
+ var source = ac.createOscillator();
+ source.start(0);
+ source.connect(delay1, 0, 0);
+ delay2.connect(delay1, 0, 0);
+ delay1.connect(delay2, 0, 0);
+</script>
+</head>
+</html>
diff --git a/dom/media/test/crashtests/990794.html b/dom/media/test/crashtests/990794.html
new file mode 100644
index 000000000..8b40088b1
--- /dev/null
+++ b/dom/media/test/crashtests/990794.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<script>
+var ctx = new AudioContext();
+var source = ctx.createOscillator();
+source.start(0);
+
+function appendMerger(src) {
+ const inputCount = 18;
+
+ var merger = ctx.createChannelMerger(32);
+
+ for (var i = 0; i < inputCount; ++i) {
+ src.connect(merger, 0, i);
+ }
+
+ return merger;
+}
+
+for (var i = 0; i < 6; ++i) {
+ source = appendMerger(source);
+}
+</script>
diff --git a/dom/media/test/crashtests/995289.html b/dom/media/test/crashtests/995289.html
new file mode 100644
index 000000000..c988f41fa
--- /dev/null
+++ b/dom/media/test/crashtests/995289.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<script>
+var r0=new AudioContext();
+var r5=r0.createOscillator();
+var r6=r0.createPeriodicWave(new Float32Array(1),new Float32Array(1));
+r5.frequency.value = 4294967295;
+r5.start(0);
+r5.setPeriodicWave(r6);
+</script>
diff --git a/dom/media/test/crashtests/analyser-channels-1.html b/dom/media/test/crashtests/analyser-channels-1.html
new file mode 100644
index 000000000..2f3133cf1
--- /dev/null
+++ b/dom/media/test/crashtests/analyser-channels-1.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+ var context = new window.OfflineAudioContext(1, 256, 48000);
+ var analyser = context.createAnalyser();
+ analyser.channelCount = 2;
+ analyser.channelCountMode = "explicit";
+ analyser.fftSize = 32;
+ var source = context.createOscillator();
+ source.connect(analyser);
+ source.start(0);
+ context.startRendering().
+ then(function() {
+ document.documentElement.removeAttribute("class");
+ });
+</script>
diff --git a/dom/media/test/crashtests/audiocontext-double-suspend.html b/dom/media/test/crashtests/audiocontext-double-suspend.html
new file mode 100644
index 000000000..98399549b
--- /dev/null
+++ b/dom/media/test/crashtests/audiocontext-double-suspend.html
@@ -0,0 +1,5 @@
+<script>
+var ac = new AudioContext();
+ac.resume();
+ac.resume();
+</script>
diff --git a/dom/media/test/crashtests/buffer-source-duration-1.html b/dom/media/test/crashtests/buffer-source-duration-1.html
new file mode 100644
index 000000000..df8d7a37d
--- /dev/null
+++ b/dom/media/test/crashtests/buffer-source-duration-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+const rate = 44100;
+var context = new window.OfflineAudioContext(1, 512, rate);
+var buffer = context.createBuffer(1, 128, rate);
+var source = context.createBufferSource();
+source.buffer = buffer;
+source.start(0, 0, 86400);
+context.startRendering().
+ then(function() {
+ document.documentElement.removeAttribute("class");
+ });
+</script>
diff --git a/dom/media/test/crashtests/buffer-source-ended-1.html b/dom/media/test/crashtests/buffer-source-ended-1.html
new file mode 100644
index 000000000..de8546316
--- /dev/null
+++ b/dom/media/test/crashtests/buffer-source-ended-1.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+var context = new AudioContext();
+
+var source = context.createBufferSource();
+source.buffer = context.createBuffer(1, 2.0 * context.sampleRate, context.sampleRate);
+source.onended = function(e) {
+ document.documentElement.removeAttribute("class");
+}
+source.start(0.0, 1.0);
+setTimeout(
+ function() {
+ source.buffer = context.createBuffer(1, 1, context.sampleRate);
+ }, 0);
+</script>
diff --git a/dom/media/test/crashtests/buffer-source-resampling-start-1.html b/dom/media/test/crashtests/buffer-source-resampling-start-1.html
new file mode 100644
index 000000000..55db8591e
--- /dev/null
+++ b/dom/media/test/crashtests/buffer-source-resampling-start-1.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+const rate = 44101; // not divisible by 2
+var context = new window.OfflineAudioContext(1, 512, rate);
+var buffer = context.createBuffer(1, 128, rate);
+buffer.getChannelData(0)[0] = 1.0;
+var source = context.createBufferSource();
+source.buffer = buffer;
+source.playbackRate.value = rate / (Math.pow(2, 30) * 1.0000001);
+source.start(512 / rate);
+context.startRendering().
+ then(function() {
+ document.documentElement.removeAttribute("class");
+ });
+</script>
diff --git a/dom/media/test/crashtests/cors.webm b/dom/media/test/crashtests/cors.webm
new file mode 100644
index 000000000..72b029723
--- /dev/null
+++ b/dom/media/test/crashtests/cors.webm
Binary files differ
diff --git a/dom/media/test/crashtests/cors.webm^headers^ b/dom/media/test/crashtests/cors.webm^headers^
new file mode 100644
index 000000000..cb762eff8
--- /dev/null
+++ b/dom/media/test/crashtests/cors.webm^headers^
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/dom/media/test/crashtests/crashtests.list b/dom/media/test/crashtests/crashtests.list
new file mode 100644
index 000000000..496fe5ee5
--- /dev/null
+++ b/dom/media/test/crashtests/crashtests.list
@@ -0,0 +1,103 @@
+load 0-timescale.html # bug 1229166
+skip-if(Android) load 459439-1.html # bug 888557
+load 466607-1.html
+load 466945-1.html
+load 468763-1.html
+load 474744-1.html
+HTTP load 481136-1.html # needs to be HTTP to recognize the ogg as an audio file?
+load 492286-1.xhtml
+load 493915-1.html
+load 495794-1.html
+load 576612-1.html
+load 752784-1.html
+load 789075-1.html
+HTTP load 795892-1.html
+load 844563.html
+load 846612.html
+load 852838.html
+load 865537-1.html
+load 868504.html
+load 874869.html
+load 874915.html
+load 874934.html
+load 874952.html
+load 875144.html
+load 875596.html
+load 875911.html
+load 876024-1.html
+load 876024-2.html
+load 876118.html
+load 876207.html
+load 876215.html
+load 876249.html
+load 876252.html
+load 876834.html
+load 877527.html
+load 877820.html
+load 878014.html
+load 878328.html
+load 878407.html
+load 878478.html
+load 880129.html
+load 880202.html
+load 880342-1.html
+load 880342-2.html
+load 880384.html
+load 880404.html
+load 880724.html
+load 881775.html
+load 882549.html
+load 882956.html
+load 884459.html
+load 889042.html
+load 894104.html
+load 907986-1.html
+load 907986-2.html
+load 907986-3.html
+load 907986-4.html
+load 910171-1.html
+load 920987.html
+load 925619-1.html
+load 925619-2.html
+load 926619.html
+load 933151.html
+load 933156.html
+load 944851.html
+load 952756.html
+load 966636.html
+load 986901.html
+load 990794.html
+load 995289.html
+load 1012609.html
+load 1015662.html
+load 1020205.html
+skip-if(Android) test-pref(media.navigator.permission.disabled,true) load 1028458.html # bug 1048863
+load 1041466.html
+load 1045650.html
+load 1080986.html
+load 1122218.html
+load 1127188.html
+load 1157994.html
+load 1158427.html
+load 1185176.html
+load 1185192.html
+load 1223670.html
+load 1228484.html
+load 1304948.html
+load 1319486.html
+load 1291702.html
+load disconnect-wrong-destination.html
+load analyser-channels-1.html
+load audiocontext-double-suspend.html
+load buffer-source-duration-1.html
+load buffer-source-ended-1.html
+load buffer-source-resampling-start-1.html
+load doppler-1.html
+HTTP load media-element-source-seek-1.html
+load offline-buffer-source-ended-1.html
+load oscillator-ended-1.html
+load oscillator-ended-2.html
+load video-replay-after-audio-end.html
+# This needs to run at the end to avoid leaking busted state into other tests.
+load 691096-1.html
+load 1236639.html
diff --git a/dom/media/test/crashtests/disconnect-wrong-destination.html b/dom/media/test/crashtests/disconnect-wrong-destination.html
new file mode 100644
index 000000000..515ca3c87
--- /dev/null
+++ b/dom/media/test/crashtests/disconnect-wrong-destination.html
@@ -0,0 +1,13 @@
+<script>
+ var oc = new OfflineAudioContext(1, 1, 44100);
+ var splitter = oc.createChannelSplitter(2);
+ var merger0 = oc.createChannelMerger(2);
+ var merger1 = oc.createChannelMerger(2);
+ splitter.connect(merger0, 0);
+ splitter.connect(merger0, 1);
+ splitter.connect(merger1, 0);
+ splitter.connect(merger1, 1);
+
+ splitter.disconnect(merger0, 0);
+ splitter.disconnect(merger1, 1);
+</script>
diff --git a/dom/media/test/crashtests/doppler-1.html b/dom/media/test/crashtests/doppler-1.html
new file mode 100644
index 000000000..2af3c8f46
--- /dev/null
+++ b/dom/media/test/crashtests/doppler-1.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+var context = new window.AudioContext();
+var source = context.createBufferSource();
+source.buffer = context.createBuffer(1, 1, context.sampleRate);
+source.onended =
+ function(e) {
+ setTimeout(
+ function() {
+ var panner = context.createPanner();
+ source.connect(panner);
+ panner.setVelocity(1.0, 0.0, 0.0);
+ setTimeout(
+ function() {
+ document.documentElement.removeAttribute("class");
+ },
+ 0);
+ },
+ 0);
+ };
+source.start(0);
+</script>
diff --git a/dom/media/test/crashtests/media-element-source-seek-1.html b/dom/media/test/crashtests/media-element-source-seek-1.html
new file mode 100644
index 000000000..5c3aed5ae
--- /dev/null
+++ b/dom/media/test/crashtests/media-element-source-seek-1.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+var audioElement = document.createElement("audio");
+audioElement.autoplay = true;
+audioElement.src = "sound.ogg";
+audioElement.onplaying =
+ function() {
+ audioElement.onplaying = null;
+ setTimeout(
+ function() {
+ audioElement.onseeked =
+ function() {
+ // Note we reset 'src' to release decoder resources and cubeb
+ // streams to prevent OOM or OpenCubeb() failures.
+ audioElement.src = "";
+ document.documentElement.removeAttribute("class");
+ };
+ audioElement.currentTime = 0;
+ }, 100);
+ };
+
+var context = new window.AudioContext();
+var source = context.createMediaElementSource(audioElement);
+source.connect(context.destination);
+</script>
+</html>
diff --git a/dom/media/test/crashtests/offline-buffer-source-ended-1.html b/dom/media/test/crashtests/offline-buffer-source-ended-1.html
new file mode 100644
index 000000000..063102112
--- /dev/null
+++ b/dom/media/test/crashtests/offline-buffer-source-ended-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+var context = new window.OfflineAudioContext(1, 12001, 12000);
+
+var source = context.createBufferSource();
+source.buffer = context.createBuffer(1, 12000, context.sampleRate);
+source.onended = function(e) {
+ document.documentElement.removeAttribute("class");
+}
+source.connect(context.destination);
+source.start(0);
+
+context.startRendering();
+</script>
diff --git a/dom/media/test/crashtests/oscillator-ended-1.html b/dom/media/test/crashtests/oscillator-ended-1.html
new file mode 100644
index 000000000..831111261
--- /dev/null
+++ b/dom/media/test/crashtests/oscillator-ended-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+function createContext() {
+ var context = new window.AudioContext();
+ var source = context.createOscillator();
+ source.onended = function(e) {
+ document.documentElement.removeAttribute("class");
+ };
+ source.connect(context.destination);
+ source.start(0.49);
+ source.stop(0.5);
+}
+createContext();
+</script>
diff --git a/dom/media/test/crashtests/oscillator-ended-2.html b/dom/media/test/crashtests/oscillator-ended-2.html
new file mode 100644
index 000000000..ee9b8cf30
--- /dev/null
+++ b/dom/media/test/crashtests/oscillator-ended-2.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+function createContext() {
+ var context = new window.AudioContext();
+ var source = context.createOscillator();
+ source.onended = function(e) {
+ document.documentElement.removeAttribute("class");
+ };
+ source.connect(context.destination);
+ source.start(60);
+ source.stop(0.5);
+}
+createContext();
+</script>
diff --git a/dom/media/test/crashtests/sound.ogg b/dom/media/test/crashtests/sound.ogg
new file mode 100644
index 000000000..edda4e912
--- /dev/null
+++ b/dom/media/test/crashtests/sound.ogg
Binary files differ
diff --git a/dom/media/test/crashtests/video-crash.webm b/dom/media/test/crashtests/video-crash.webm
new file mode 100644
index 000000000..9532113d8
--- /dev/null
+++ b/dom/media/test/crashtests/video-crash.webm
Binary files differ
diff --git a/dom/media/test/crashtests/video-replay-after-audio-end.html b/dom/media/test/crashtests/video-replay-after-audio-end.html
new file mode 100644
index 000000000..9ffd6078d
--- /dev/null
+++ b/dom/media/test/crashtests/video-replay-after-audio-end.html
@@ -0,0 +1,43 @@
+<html class="reftest-wait">
+<head>
+ <title> Bug 1242774 : video crashed if pause and play again after audio track ends </title>
+</head>
+<body>
+<script type="text/javascript">
+function assert(value, msg) {
+ if (!value) {
+ dump("### Error : " + msg + "\n");
+ }
+}
+
+var AUDIO_END_TIME = 4.5;
+var video = document.createElement('video');
+video.src = "video-crash.webm";
+video.play();
+
+video.ontimeupdate = function () {
+ assert(AUDIO_END_TIME < video.duration,
+ "AUDIO_END_TIME should be smaller than the duration!");
+
+ if (video.currentTime > AUDIO_END_TIME) {
+ dump("### Pause video during silent part.\n");
+ video.ontimeupdate = null;
+ video.pause();
+ }
+
+ video.onpause = function () {
+ video.onpause = null;
+ setTimeout(function() {
+ dump("### Re-play after pausing during silent part.\n");
+ video.play();
+ video.onended = function () {
+ video.onended = null;
+ dump("### Video is ended.\n");
+ document.documentElement.removeAttribute("class");
+ }
+ }, 1000);
+ }
+}
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/media/test/dash/dash-manifest-garbled-webm.mpd b/dom/media/test/dash/dash-manifest-garbled-webm.mpd
new file mode 100644
index 000000000..aa78ded3e
--- /dev/null
+++ b/dom/media/test/dash/dash-manifest-garbled-webm.mpd
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<MPD
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="urn:mpeg:DASH:schema:MPD:2011"
+ xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011"
+ type="static"
+ mediaPresentationDuration="PT3.958S"
+ minBufferTime="PT1S"
+ profiles="urn:webm:dash:profile:webm-on-demand:2012">
+ <BaseURL>./</BaseURL>
+ <Period id="0" start="PT0S" duration="PT3.958S" >
+ <AdaptationSet id="0" mimeType="video/webm" codecs="vp8" lang="eng" subsegmentAlignment="true" subsegmentStartsWithSAP="1" bitstreamSwitching="true">
+ <Representation id="0" bandwidth="54207" width="320" height="180">
+ <BaseURL>garbled.webm</BaseURL>
+ <SegmentBase indexRange="35090-35123">
+ <Initialization range="0-228" />
+ </SegmentBase>
+ </Representation>
+ <Representation id="1" bandwidth="78006" width="428" height="240">
+ <BaseURL>dash-webm-video-428x240.webm</BaseURL>
+ <SegmentBase indexRange="50173-50206">
+ <Initialization range="0-228" />
+ </SegmentBase>
+ </Representation>
+ </AdaptationSet>
+ <AdaptationSet id="1" mimeType="audio/webm" codecs="vorbis" lang="eng" audioSamplingRate="48000" subsegmentStartsWithSAP="1">
+ <Representation id="2" bandwidth="57264">
+ <BaseURL>dash-webm-audio-128k.webm</BaseURL>
+ <SegmentBase indexRange="41927-41946">
+ <Initialization range="0-4521" />
+ </SegmentBase>
+ </Representation>
+ </AdaptationSet>
+ </Period>
+</MPD>
diff --git a/dom/media/test/dash/dash-manifest-garbled.mpd b/dom/media/test/dash/dash-manifest-garbled.mpd
new file mode 100644
index 000000000..ac8eadbdd
--- /dev/null
+++ b/dom/media/test/dash/dash-manifest-garbled.mpd
@@ -0,0 +1 @@
+PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxNUEQgbWVkaWFQcmVzZW50YXRpb25EdXJhdGlvbj0iUFQxOS41MVMiIG1pbkJ1ZmZlclRpbWU9IlBUMVMiIHByb2ZpbGVzPSJ1cm46d2VibTpkYXNoOnByb2ZpbGU6d2VibS1vbi1kZW1hbmQ6MjAxMiIgdHlwZT0ic3RhdGljIiB4bWxucz0idXJuOm1wZWc6REFTSDpzY2hlbWE6TVBEOjIwMTEiIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhzaTpzY2hlbWFMb2NhdGlvbj0idXJuOm1wZWc6REFTSDpzY2hlbWE6TVBEOjIwMTEiPjxCYXNlVVJMPmh0dHA6Ly93d3cuZ29vZ2xlLmNvbTwvQmFzZVVSTD48UGVyaW9kIGR1cmF0aW9uPSJQVDE5LjUxUyIgaWQ9IjAiIHN0YXJ0PSJQVDBTIj48QWRhcHRhdGlvblNldCBhdWRpb1NhbXBsaW5nUmF0ZT0iNDgwMDAiIGNvZGVjcz0idm9yYmlzIiBpZD0iMSIgbGFuZz0iZW5nIiBtaW1lVHlwZT0iYXVkaW8vd2VibSIgc3Vic2VnbWVudFN0YXJ0c1dpdGhTQVA9IjEiPjxSZXByZXNlbnRhdGlvbiBiYW5kd2lkdGg9IjIwMTA5IiBpZD0iMiI+PEJhc2VVUkwvPjxTZWdtZW50QmFzZSBpbmRleFJhbmdlPSIzMTk3ODAtMzIwNjEyIj48SW5pdGlhbGl6YXRpb24gcmFuZ2U9IjAtMjA4NzAiLz48L1NlZ21lbnRCYXNlPjwvUmVwcmVzZW50YXRpb24+PC9BZGFwdGF0aW9uU2V0PjwvUGVyaW9kPjwvTVBEPg
diff --git a/dom/media/test/dash/dash-manifest-sjs.mpd b/dom/media/test/dash/dash-manifest-sjs.mpd
new file mode 100644
index 000000000..c7ecba3c6
--- /dev/null
+++ b/dom/media/test/dash/dash-manifest-sjs.mpd
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<MPD
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="urn:mpeg:DASH:schema:MPD:2011"
+ xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011"
+ type="static"
+ mediaPresentationDuration="PT3.958S"
+ minBufferTime="PT1S"
+ profiles="urn:webm:dash:profile:webm-on-demand:2012">
+ <BaseURL>./dash_detect_stream_switch.sjs?name=</BaseURL>
+ <Period id="0" start="PT0S" duration="PT3.958S" >
+ <AdaptationSet id="0" mimeType="video/webm" codecs="vp8" lang="eng" subsegmentAlignment="true" subsegmentStartsWithSAP="1" bitstreamSwitching="true">
+ <Representation id="0" bandwidth="54207" width="320" height="180">
+ <BaseURL>dash-webm-video-320x180.webm</BaseURL>
+ <SegmentBase indexRange="35090-35123">
+ <Initialization range="0-228" />
+ </SegmentBase>
+ </Representation>
+ <Representation id="1" bandwidth="78006" width="428" height="240">
+ <BaseURL>dash-webm-video-428x240.webm</BaseURL>
+ <SegmentBase indexRange="50173-50206">
+ <Initialization range="0-228" />
+ </SegmentBase>
+ </Representation>
+ </AdaptationSet>
+ <AdaptationSet id="1" mimeType="audio/webm" codecs="vorbis" lang="eng" audioSamplingRate="48000" subsegmentStartsWithSAP="1">
+ <Representation id="2" bandwidth="57264">
+ <BaseURL>dash-webm-audio-128k.webm</BaseURL>
+ <SegmentBase indexRange="41927-41946">
+ <Initialization range="0-4521" />
+ </SegmentBase>
+ </Representation>
+ </AdaptationSet>
+ </Period>
+</MPD>
diff --git a/dom/media/test/dash/dash-manifest.mpd b/dom/media/test/dash/dash-manifest.mpd
new file mode 100644
index 000000000..98c7a9048
--- /dev/null
+++ b/dom/media/test/dash/dash-manifest.mpd
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<MPD
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="urn:mpeg:DASH:schema:MPD:2011"
+ xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011"
+ type="static"
+ mediaPresentationDuration="PT3.958S"
+ minBufferTime="PT1S"
+ profiles="urn:webm:dash:profile:webm-on-demand:2012">
+ <BaseURL>./</BaseURL>
+ <Period id="0" start="PT0S" duration="PT3.958S" >
+ <AdaptationSet id="0" mimeType="video/webm" codecs="vp8" lang="eng" subsegmentAlignment="true" subsegmentStartsWithSAP="1" bitstreamSwitching="true">
+ <Representation id="0" bandwidth="54207" width="320" height="180">
+ <BaseURL>dash-webm-video-320x180.webm</BaseURL>
+ <SegmentBase indexRange="35090-35123">
+ <Initialization range="0-228" />
+ </SegmentBase>
+ </Representation>
+ <Representation id="1" bandwidth="78006" width="428" height="240">
+ <BaseURL>dash-webm-video-428x240.webm</BaseURL>
+ <SegmentBase indexRange="50173-50206">
+ <Initialization range="0-228" />
+ </SegmentBase>
+ </Representation>
+ </AdaptationSet>
+ <AdaptationSet id="1" mimeType="audio/webm" codecs="vorbis" lang="eng" audioSamplingRate="48000" subsegmentStartsWithSAP="1">
+ <Representation id="2" bandwidth="57264">
+ <BaseURL>dash-webm-audio-128k.webm</BaseURL>
+ <SegmentBase indexRange="41927-41946">
+ <Initialization range="0-4521" />
+ </SegmentBase>
+ </Representation>
+ </AdaptationSet>
+ </Period>
+</MPD>
diff --git a/dom/media/test/dash/dash-webm-audio-128k.webm b/dom/media/test/dash/dash-webm-audio-128k.webm
new file mode 100644
index 000000000..f56c04205
--- /dev/null
+++ b/dom/media/test/dash/dash-webm-audio-128k.webm
Binary files differ
diff --git a/dom/media/test/dash/dash-webm-video-320x180.webm b/dom/media/test/dash/dash-webm-video-320x180.webm
new file mode 100644
index 000000000..282e6a2cc
--- /dev/null
+++ b/dom/media/test/dash/dash-webm-video-320x180.webm
Binary files differ
diff --git a/dom/media/test/dash/dash-webm-video-428x240.webm b/dom/media/test/dash/dash-webm-video-428x240.webm
new file mode 100644
index 000000000..23f2c8961
--- /dev/null
+++ b/dom/media/test/dash/dash-webm-video-428x240.webm
Binary files differ
diff --git a/dom/media/test/dash/garbled.webm b/dom/media/test/dash/garbled.webm
new file mode 100644
index 000000000..ac8eadbdd
--- /dev/null
+++ b/dom/media/test/dash/garbled.webm
@@ -0,0 +1 @@
+PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxNUEQgbWVkaWFQcmVzZW50YXRpb25EdXJhdGlvbj0iUFQxOS41MVMiIG1pbkJ1ZmZlclRpbWU9IlBUMVMiIHByb2ZpbGVzPSJ1cm46d2VibTpkYXNoOnByb2ZpbGU6d2VibS1vbi1kZW1hbmQ6MjAxMiIgdHlwZT0ic3RhdGljIiB4bWxucz0idXJuOm1wZWc6REFTSDpzY2hlbWE6TVBEOjIwMTEiIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhzaTpzY2hlbWFMb2NhdGlvbj0idXJuOm1wZWc6REFTSDpzY2hlbWE6TVBEOjIwMTEiPjxCYXNlVVJMPmh0dHA6Ly93d3cuZ29vZ2xlLmNvbTwvQmFzZVVSTD48UGVyaW9kIGR1cmF0aW9uPSJQVDE5LjUxUyIgaWQ9IjAiIHN0YXJ0PSJQVDBTIj48QWRhcHRhdGlvblNldCBhdWRpb1NhbXBsaW5nUmF0ZT0iNDgwMDAiIGNvZGVjcz0idm9yYmlzIiBpZD0iMSIgbGFuZz0iZW5nIiBtaW1lVHlwZT0iYXVkaW8vd2VibSIgc3Vic2VnbWVudFN0YXJ0c1dpdGhTQVA9IjEiPjxSZXByZXNlbnRhdGlvbiBiYW5kd2lkdGg9IjIwMTA5IiBpZD0iMiI+PEJhc2VVUkwvPjxTZWdtZW50QmFzZSBpbmRleFJhbmdlPSIzMTk3ODAtMzIwNjEyIj48SW5pdGlhbGl6YXRpb24gcmFuZ2U9IjAtMjA4NzAiLz48L1NlZ21lbnRCYXNlPjwvUmVwcmVzZW50YXRpb24+PC9BZGFwdGF0aW9uU2V0PjwvUGVyaW9kPjwvTVBEPg
diff --git a/dom/media/test/dash_detect_stream_switch.sjs b/dom/media/test/dash_detect_stream_switch.sjs
new file mode 100644
index 000000000..378db10ca
--- /dev/null
+++ b/dom/media/test/dash_detect_stream_switch.sjs
@@ -0,0 +1,114 @@
+/* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* dash_detect_stream_switch.sjs
+ *
+ * Parses requests for DASH manifests and ensures stream switching takes place
+ * by verifying the subsegments downloaded and the streams they belong to.
+ * If unexpected subsegments (byte ranges) are requested, the script will
+ * will respond with a 404.
+ */
+
+var DEBUG = false;
+
+function parseQuery(request, key) {
+ var params = request.queryString.split('&');
+ if (DEBUG) {
+ dump("DASH-SJS: request params = \"" + params + "\"\n");
+ }
+ for (var j = 0; j < params.length; ++j) {
+ var p = params[j];
+ if (p == key)
+ return true;
+ if (p.indexOf(key + "=") === 0)
+ return p.substring(key.length + 1);
+ if (p.indexOf("=") < 0 && key === "")
+ return p;
+ }
+ return false;
+}
+
+function handleRequest(request, response)
+{
+ try {
+ var name = parseQuery(request, "name");
+ var range = request.hasHeader("Range") ? request.getHeader("Range")
+ : undefined;
+
+ // Should not get request for 1st subsegment from 2nd stream, nor 2nd
+ // subsegment from 1st stream.
+ if (name == "dash-webm-video-320x180.webm" && range == "bytes=25514-32767" ||
+ name == "dash-webm-video-428x240.webm" && range == "bytes=228-35852")
+ {
+ throw "Should not request " + name + " with byte-range " + range;
+ } else {
+ var rangeSplit = range.split("=");
+ if (rangeSplit.length != 2) {
+ throw "DASH-SJS: ERROR: invalid number of tokens (" + rangeSplit.length +
+ ") delimited by \'=\' in \'Range\' header.";
+ }
+ var offsets = rangeSplit[1].split("-");
+ if (offsets.length != 2) {
+ throw "DASH-SJS: ERROR: invalid number of tokens (" + offsets.length +
+ ") delimited by \'-\' in \'Range\' header.";
+ }
+ var startOffset = parseInt(offsets[0]);
+ var endOffset = parseInt(offsets[1]);
+ var file = Components.classes["@mozilla.org/file/directory_service;1"].
+ getService(Components.interfaces.nsIProperties).
+ get("CurWorkD", Components.interfaces.nsILocalFile);
+ var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
+ createInstance(Components.interfaces.nsIFileInputStream);
+ var bis = Components.classes["@mozilla.org/binaryinputstream;1"].
+ createInstance(Components.interfaces.nsIBinaryInputStream);
+
+ var paths = "tests/dom/media/test/" + name;
+ var split = paths.split("/");
+ for (var i = 0; i < split.length; ++i) {
+ file.append(split[i]);
+ }
+
+ fis.init(file, -1, -1, false);
+ // Exception: start offset should be within file bounds.
+ if (startOffset > file.fileSize) {
+ throw "Starting offset [" + startOffset + "] is after end of file [" +
+ file.fileSize + "].";
+ }
+ // End offset may be too large in the MPD. Real world HTTP servers just
+ // return what data they can; do the same here - reduce the end offset.
+ if (endOffset >= file.fileSize) {
+ if (DEBUG) {
+ dump("DASH-SJS: reducing endOffset [" + endOffset + "] to fileSize [" +
+ (file.fileSize-1) + "]\n");
+ }
+ endOffset = file.fileSize-1;
+ }
+ fis.seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, startOffset);
+ bis.setInputStream(fis);
+
+ var byteLengthToRead = endOffset + 1 - startOffset;
+ var totalBytesExpected = byteLengthToRead + startOffset;
+ if (DEBUG) {
+ dump("DASH-SJS: byteLengthToRead = " + byteLengthToRead +
+ " byteLengthToRead+startOffset = " + totalBytesExpected +
+ " fileSize = " + file.fileSize + "\n");
+ }
+
+ var bytes = bis.readBytes(byteLengthToRead);
+ response.setStatusLine(request.httpVersion, 206, "Partial Content");
+ response.setHeader("Content-Length", ""+bytes.length, false);
+ response.setHeader("Content-Type", "application/dash+xml", false);
+ var contentRange = "bytes " + startOffset + "-" + endOffset + "/" +
+ file.fileSize;
+ response.setHeader("Content-Range", contentRange, false);
+ response.write(bytes, bytes.length);
+ bis.close();
+ }
+ } catch (e) {
+ dump ("DASH-SJS-ERROR: " + e + "\n");
+ response.setStatusLine(request.httpVersion, 404, "Not found");
+ }
+}
diff --git a/dom/media/test/detodos-recorder-test.opus b/dom/media/test/detodos-recorder-test.opus
new file mode 100644
index 000000000..88b2eab0f
--- /dev/null
+++ b/dom/media/test/detodos-recorder-test.opus
Binary files differ
diff --git a/dom/media/test/detodos-recorder-test.opus^headers^ b/dom/media/test/detodos-recorder-test.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/detodos-recorder-test.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/detodos-short.opus b/dom/media/test/detodos-short.opus
new file mode 100644
index 000000000..8bda283fc
--- /dev/null
+++ b/dom/media/test/detodos-short.opus
Binary files differ
diff --git a/dom/media/test/detodos-short.opus^headers^ b/dom/media/test/detodos-short.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/detodos-short.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/detodos-short.webm b/dom/media/test/detodos-short.webm
new file mode 100644
index 000000000..45af2675a
--- /dev/null
+++ b/dom/media/test/detodos-short.webm
Binary files differ
diff --git a/dom/media/test/detodos-short.webm^headers^ b/dom/media/test/detodos-short.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/detodos-short.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/detodos.opus b/dom/media/test/detodos.opus
new file mode 100644
index 000000000..6c7ba88a6
--- /dev/null
+++ b/dom/media/test/detodos.opus
Binary files differ
diff --git a/dom/media/test/detodos.opus^headers^ b/dom/media/test/detodos.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/detodos.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/detodos.webm b/dom/media/test/detodos.webm
new file mode 100644
index 000000000..39cfa7f53
--- /dev/null
+++ b/dom/media/test/detodos.webm
Binary files differ
diff --git a/dom/media/test/detodos.webm^headers^ b/dom/media/test/detodos.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/detodos.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/dirac.ogg b/dom/media/test/dirac.ogg
new file mode 100644
index 000000000..2986cf1e8
--- /dev/null
+++ b/dom/media/test/dirac.ogg
Binary files differ
diff --git a/dom/media/test/dirac.ogg^headers^ b/dom/media/test/dirac.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/dirac.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/dynamic_redirect.sjs b/dom/media/test/dynamic_redirect.sjs
new file mode 100644
index 000000000..4e43dfae2
--- /dev/null
+++ b/dom/media/test/dynamic_redirect.sjs
@@ -0,0 +1,67 @@
+function parseQuery(query, key) {
+ for (let p of query.split('&')) {
+ if (p == key) {
+ return true;
+ }
+ if (p.startsWith(key + "=")) {
+ return p.substring(key.length + 1);
+ }
+ }
+}
+
+// Return seek.ogv file content for the first request with a given key.
+// All subsequent requests return a redirect to a different-origin resource.
+function handleRequest(request, response)
+{
+ var query = request.queryString;
+ var key = parseQuery(query, "key");
+ var resource = parseQuery(query, "res");
+ var nested = parseQuery(query, "nested") || false;
+
+ dump("Received request for key = "+ key +"\n");
+ if (!nested) {
+ if (getState(key) == "redirect") {
+ var origin = request.host == "mochi.test" ? "example.org" : "mochi.test:8888";
+ response.setStatusLine(request.httpVersion, 303, "See Other");
+ let url = "http://" + origin +
+ "/tests/dom/media/test/dynamic_redirect.sjs?nested&" + query;
+ dump("Redirecting to "+ url + "\n");
+ response.setHeader("Location", url);
+ response.setHeader("Content-Type", "text/html");
+ return;
+ }
+ setState(key, "redirect");
+ }
+ var file = Components.classes["@mozilla.org/file/directory_service;1"].
+ getService(Components.interfaces.nsIProperties).
+ get("CurWorkD", Components.interfaces.nsILocalFile);
+ var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
+ createInstance(Components.interfaces.nsIFileInputStream);
+ var bis = Components.classes["@mozilla.org/binaryinputstream;1"].
+ createInstance(Components.interfaces.nsIBinaryInputStream);
+ var paths = "tests/dom/media/test/" + resource;
+ var split = paths.split("/");
+ for (var i = 0; i < split.length; ++i) {
+ file.append(split[i]);
+ }
+ fis.init(file, -1, -1, false);
+
+ bis.setInputStream(fis);
+ var bytes = bis.readBytes(bis.available());
+ let [from, to] = request.getHeader("range").split("=")[1].split("-").map(s => parseInt(s));
+ to = to || Math.max(from, bytes.length - 1);
+ byterange = bytes.substring(from, to + 1);
+
+ let contentRange = "bytes "+ from +"-"+ to +"/"+ bytes.length;
+ let contentLength = (to - from + 1).toString();
+ dump("Response Content-Range = "+ contentRange +"\n");
+ dump("Response Content-Length = "+ contentLength +"\n");
+
+ response.setStatusLine(request.httpVersion, 206, "Partial Content");
+ response.setHeader("Content-Range", contentRange);
+ response.setHeader("Content-Length", contentLength, false);
+ response.setHeader("Content-Type", "video/ogg", false);
+ response.setHeader("Accept-Ranges", "bytes", false);
+ response.write(byterange, byterange.length);
+ bis.close();
+}
diff --git a/dom/media/test/dynamic_resource.sjs b/dom/media/test/dynamic_resource.sjs
new file mode 100644
index 000000000..12a43f92a
--- /dev/null
+++ b/dom/media/test/dynamic_resource.sjs
@@ -0,0 +1,48 @@
+function parseQuery(request, key) {
+ var params = request.queryString.split('&');
+ for (var j = 0; j < params.length; ++j) {
+ var p = params[j];
+ if (p == key)
+ return true;
+ if (p.indexOf(key + "=") == 0)
+ return p.substring(key.length + 1);
+ if (p.indexOf("=") < 0 && key == "")
+ return p;
+ }
+ return false;
+}
+
+// Return resource1 file content for the first request with a given key.
+// All subsequent requests return resource2. Both must be video/ogg.
+function handleRequest(request, response)
+{
+ var key = parseQuery(request, "key");
+ var resource1 = parseQuery(request, "res1");
+ var resource2 = parseQuery(request, "res2");
+
+ var resource = getState(key) == "2" ? resource2 : resource1;
+ setState(key, "2");
+
+ var file = Components.classes["@mozilla.org/file/directory_service;1"].
+ getService(Components.interfaces.nsIProperties).
+ get("CurWorkD", Components.interfaces.nsILocalFile);
+ var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
+ createInstance(Components.interfaces.nsIFileInputStream);
+ var bis = Components.classes["@mozilla.org/binaryinputstream;1"].
+ createInstance(Components.interfaces.nsIBinaryInputStream);
+ var paths = "tests/dom/media/test/" + resource;
+ var split = paths.split("/");
+ for(var i = 0; i < split.length; ++i) {
+ file.append(split[i]);
+ }
+ fis.init(file, -1, -1, false);
+ dump("file=" + file + "\n");
+ bis.setInputStream(fis);
+ var bytes = bis.readBytes(bis.available());
+ response.setStatusLine(request.httpVersion, 206, "Partial Content");
+ response.setHeader("Content-Range", "bytes 0-" + (bytes.length - 1) + "/" + bytes.length);
+ response.setHeader("Content-Length", ""+bytes.length, false);
+ response.setHeader("Content-Type", "video/ogg", false);
+ response.write(bytes, bytes.length);
+ bis.close();
+}
diff --git a/dom/media/test/eme.js b/dom/media/test/eme.js
new file mode 100644
index 000000000..81f679762
--- /dev/null
+++ b/dom/media/test/eme.js
@@ -0,0 +1,495 @@
+const CLEARKEY_KEYSYSTEM = "org.w3.clearkey";
+
+const gCencMediaKeySystemConfig = [{
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{ contentType: 'video/mp4' }],
+ audioCapabilities: [{ contentType: 'audio/mp4' }],
+}];
+
+function IsMacOSSnowLeopardOrEarlier() {
+ var re = /Mac OS X (\d+)\.(\d+)/;
+ var ver = navigator.userAgent.match(re);
+ if (!ver || ver.length != 3) {
+ return false;
+ }
+ var major = ver[1] | 0;
+ var minor = ver[2] | 0;
+ return major == 10 && minor <= 6;
+}
+
+function bail(message)
+{
+ return function(err) {
+ if (err) {
+ message += "; " + String(err)
+ }
+ ok(false, message);
+ if (err) {
+ info(String(err));
+ }
+ SimpleTest.finish();
+ }
+}
+
+function ArrayBufferToString(arr)
+{
+ var str = '';
+ var view = new Uint8Array(arr);
+ for (var i = 0; i < view.length; i++) {
+ str += String.fromCharCode(view[i]);
+ }
+ return str;
+}
+
+function StringToArrayBuffer(str)
+{
+ var arr = new ArrayBuffer(str.length);
+ var view = new Uint8Array(arr);
+ for (var i = 0; i < str.length; i++) {
+ view[i] = str.charCodeAt(i);
+ }
+ return arr;
+}
+
+function StringToHex(str){
+ var res = "";
+ for (var i = 0; i < str.length; ++i) {
+ res += ("0" + str.charCodeAt(i).toString(16)).slice(-2);
+ }
+ return res;
+}
+
+function Base64ToHex(str)
+{
+ var bin = window.atob(str.replace(/-/g, "+").replace(/_/g, "/"));
+ var res = "";
+ for (var i = 0; i < bin.length; i++) {
+ res += ("0" + bin.charCodeAt(i).toString(16)).substr(-2);
+ }
+ return res;
+}
+
+function HexToBase64(hex)
+{
+ var bin = "";
+ for (var i = 0; i < hex.length; i += 2) {
+ bin += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
+ }
+ return window.btoa(bin).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
+}
+
+function TimeRangesToString(trs)
+{
+ var l = trs.length;
+ if (l === 0) { return "-"; }
+ var s = "";
+ var i = 0;
+ for (;;) {
+ s += trs.start(i) + "-" + trs.end(i);
+ if (++i === l) { return s; }
+ s += ",";
+ }
+}
+
+function SourceBufferToString(sb)
+{
+ return ("SourceBuffer{"
+ + "AppendMode=" + (sb.AppendMode || "-")
+ + ", updating=" + (sb.updating ? "true" : "false")
+ + ", buffered=" + TimeRangesToString(sb.buffered)
+ + ", audioTracks=" + (sb.audioTracks ? sb.audioTracks.length : "-")
+ + ", videoTracks=" + (sb.videoTracks ? sb.videoTracks.length : "-")
+ + "}");
+}
+
+function SourceBufferListToString(sbl)
+{
+ return "SourceBufferList[" + sbl.map(SourceBufferToString).join(", ") + "]";
+}
+
+function UpdateSessionFunc(test, token, sessionType, resolve, reject) {
+ return function(ev) {
+ var msgStr = ArrayBufferToString(ev.message);
+ var msg = JSON.parse(msgStr);
+
+ Log(token, "got message from CDM: " + msgStr);
+ is(msg.type, sessionType, TimeStamp(token) + " key session type should match");
+ ok(msg.kids, TimeStamp(token) + " message event should contain key ID array");
+
+ var outKeys = [];
+
+ for (var i = 0; i < msg.kids.length; i++) {
+ var id64 = msg.kids[i];
+ var idHex = Base64ToHex(msg.kids[i]).toLowerCase();
+ var key = test.keys[idHex];
+
+ if (key) {
+ Log(token, "found key " + key + " for key id " + idHex);
+ outKeys.push({
+ "kty":"oct",
+ "kid":id64,
+ "k":HexToBase64(key)
+ });
+ } else {
+ bail(token + " couldn't find key for key id " + idHex);
+ }
+ }
+
+ var update = JSON.stringify({
+ "keys" : outKeys,
+ "type" : msg.type
+ });
+ Log(token, "sending update message to CDM: " + update);
+
+ ev.target.update(StringToArrayBuffer(update)).then(function() {
+ Log(token, "MediaKeySession update ok!");
+ resolve(ev.target);
+ }).catch(function(reason) {
+ bail(token + " MediaKeySession update failed")(reason);
+ reject();
+ });
+ }
+}
+
+function MaybeCrossOriginURI(test, uri)
+{
+ if (test.crossOrigin) {
+ return "http://test2.mochi.test:8888/tests/dom/media/test/allowed.sjs?" + uri;
+ } else {
+ return uri;
+ }
+}
+
+function AppendTrack(test, ms, track, token, loadParams)
+{
+ return new Promise(function(resolve, reject) {
+ var sb;
+ var curFragment = 0;
+ var resolved = false;
+ var fragments = track.fragments;
+ var fragmentFile;
+
+ if (loadParams && loadParams.onlyLoadFirstFragments) {
+ fragments = fragments.slice(0, loadParams.onlyLoadFirstFragments);
+ }
+
+ function addNextFragment() {
+ if (curFragment >= fragments.length) {
+ Log(token, track.name + ": end of track");
+ resolve();
+ resolved = true;
+ return;
+ }
+
+ fragmentFile = MaybeCrossOriginURI(test, fragments[curFragment++]);
+
+ var req = new XMLHttpRequest();
+ req.open("GET", fragmentFile);
+ req.responseType = "arraybuffer";
+
+ req.addEventListener("load", function() {
+ Log(token, track.name + ": fetch of " + fragmentFile + " complete, appending");
+ sb.appendBuffer(new Uint8Array(req.response));
+ });
+
+ req.addEventListener("error", function(){info(token + " error fetching " + fragmentFile);});
+ req.addEventListener("abort", function(){info(token + " aborted fetching " + fragmentFile);});
+
+ Log(token, track.name + ": addNextFragment() fetching next fragment " + fragmentFile);
+ req.send(null);
+ }
+
+ Log(token, track.name + ": addSourceBuffer(" + track.type + ")");
+ sb = ms.addSourceBuffer(track.type);
+ sb.addEventListener("updateend", function() {
+ if (ms.readyState == "ended") {
+ /* We can get another updateevent as a result of calling ms.endOfStream() if
+ the highest end time of our source buffers is different from that of the
+ media source duration. Due to bug 1065207 this can happen because of
+ inaccuracies in the frame duration calculations. Check if we are already
+ "ended" and ignore the update event */
+ Log(token, track.name + ": updateend when readyState already 'ended'");
+ if (!resolved) {
+ // Needed if decoder knows this was the last fragment and ended by itself.
+ Log(token, track.name + ": but promise not resolved yet -> end of track");
+ resolve();
+ resolved = true;
+ }
+ return;
+ }
+ Log(token, track.name + ": updateend for " + fragmentFile + ", " + SourceBufferToString(sb));
+ addNextFragment();
+ });
+
+ addNextFragment();
+ });
+}
+
+//Returns a promise that is resolved when the media element is ready to have
+//its play() function called; when it's loaded MSE fragments.
+function LoadTest(test, elem, token, loadParams)
+{
+ if (!test.tracks) {
+ ok(false, token + " test does not have a tracks list");
+ return Promise.reject();
+ }
+
+ var ms = new MediaSource();
+ elem.src = URL.createObjectURL(ms);
+
+ return new Promise(function (resolve, reject) {
+ var firstOpen = true;
+ ms.addEventListener("sourceopen", function () {
+ if (!firstOpen) {
+ Log(token, "sourceopen again?");
+ return;
+ }
+
+ firstOpen = false;
+ Log(token, "sourceopen");
+ return Promise.all(test.tracks.map(function(track) {
+ return AppendTrack(test, ms, track, token, loadParams);
+ })).then(function() {
+ if (loadParams && loadParams.noEndOfStream) {
+ Log(token, "Tracks loaded");
+ } else {
+ Log(token, "Tracks loaded, calling MediaSource.endOfStream()");
+ ms.endOfStream();
+ }
+ resolve();
+ }).catch(function() {
+ Log(token, "error while loading tracks");
+ });
+ })
+ });
+}
+
+// Same as LoadTest, but manage a token+"_load" start&finished.
+// Also finish main token if loading fails.
+function LoadTestWithManagedLoadToken(test, elem, manager, token, loadParams)
+{
+ manager.started(token + "_load");
+ return LoadTest(test, elem, token, loadParams)
+ .catch(function (reason) {
+ ok(false, TimeStamp(token) + " - Error during load: " + reason);
+ manager.finished(token + "_load");
+ manager.finished(token);
+ })
+ .then(function () {
+ manager.finished(token + "_load");
+ });
+}
+
+function SetupEME(test, token, params)
+{
+ var v = document.createElement("video");
+ v.crossOrigin = test.crossOrigin || false;
+ v.sessions = [];
+
+ v.closeSessions = function() {
+ return Promise.all(v.sessions.map(s => s.close().then(() => s.closed))).then(
+ () => {
+ v.setMediaKeys(null);
+ if (v.parentNode) {
+ v.parentNode.removeChild(v);
+ }
+ v.onerror = null;
+ v.src = null;
+ });
+ };
+
+ // Log events dispatched to make debugging easier...
+ [ "canplay", "canplaythrough", "ended", "error", "loadeddata",
+ "loadedmetadata", "loadstart", "pause", "play", "playing", "progress",
+ "stalled", "suspend", "waiting", "waitingforkey",
+ ].forEach(function (e) {
+ v.addEventListener(e, function(event) {
+ Log(token, "" + e);
+ }, false);
+ });
+
+ // Finish the test when error is encountered.
+ v.onerror = bail(token + " got error event");
+
+ var onSetKeysFail = (params && params.onSetKeysFail)
+ ? params.onSetKeysFail
+ : bail(token + " Failed to set MediaKeys on <video> element");
+
+ // null: No session management in progress, just go ahead and update the session.
+ // [...]: Session management in progress, add {initDataType, initData} to
+ // this queue to get it processed when possible.
+ var initDataQueue = [];
+ function pushInitData(ev)
+ {
+ if (initDataQueue === null) {
+ initDataQueue = [];
+ }
+ initDataQueue.push(ev);
+ if (params && params.onInitDataQueued) {
+ params.onInitDataQueued(ev, ev.initDataType, StringToHex(ArrayBufferToString(ev.initData)));
+ }
+ }
+
+ function processInitDataQueue()
+ {
+ if (initDataQueue === null) { return; }
+ // If we're processed all our init data null the queue to indicate encrypted event handled.
+ if (initDataQueue.length === 0) {
+ initDataQueue = null;
+ return;
+ }
+ var ev = initDataQueue.shift();
+
+ var sessionType = (params && params.sessionType) ? params.sessionType : "temporary";
+ Log(token, "createSession(" + sessionType + ") for (" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ")");
+ var session = v.mediaKeys.createSession(sessionType);
+ if (params && params.onsessioncreated) {
+ params.onsessioncreated(session);
+ }
+ v.sessions.push(session);
+
+ return new Promise(function (resolve, reject) {
+ session.addEventListener("message", UpdateSessionFunc(test, token, sessionType, resolve, reject));
+ Log(token, "session[" + session.sessionId + "].generateRequest(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ")");
+ session.generateRequest(ev.initDataType, ev.initData).catch(function(reason) {
+ // Reject the promise if generateRequest() failed. Otherwise it will
+ // be resolve in UpdateSessionFunc().
+ bail(token + ": session[" + session.sessionId + "].generateRequest(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") failed")(reason);
+ reject();
+ });
+ })
+
+ .then(function(aSession) {
+ Log(token, "session[" + session.sessionId + "].generateRequest(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") succeeded");
+ if (params && params.onsessionupdated) {
+ params.onsessionupdated(aSession);
+ }
+ processInitDataQueue();
+ });
+ }
+
+ function streamType(type) {
+ var x = test.tracks.find(o => o.name == type);
+ return x ? x.type : undefined;
+ }
+
+ // If sessions are to be delayed we won't peform any processing until the
+ // callback the assigned here is called by the test.
+ if (params && params.delaySessions) {
+ params.ProcessSessions = processInitDataQueue;
+ }
+
+ // Is this the first piece of init data we're processing?
+ var firstInitData = true;
+ v.addEventListener("encrypted", function(ev) {
+ if (firstInitData) {
+ Log(token, "got first encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + "), setup session");
+ firstInitData = false;
+ pushInitData(ev);
+
+ function chain(promise, onReject) {
+ return promise.then(function(value) {
+ return Promise.resolve(value);
+ }).catch(function(reason) {
+ onReject(reason);
+ return Promise.reject();
+ })
+ }
+
+ var options = { initDataTypes: [ev.initDataType] };
+ if (streamType("video")) {
+ options.videoCapabilities = [{contentType: streamType("video")}];
+ }
+ if (streamType("audio")) {
+ options.audioCapabilities = [{contentType: streamType("audio")}];
+ }
+
+ var p = navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, [options]);
+ var r = bail(token + " Failed to request key system access.");
+ chain(p, r)
+ .then(function(keySystemAccess) {
+ var p = keySystemAccess.createMediaKeys();
+ var r = bail(token + " Failed to create MediaKeys object");
+ return chain(p, r);
+ })
+
+ .then(function(mediaKeys) {
+ Log(token, "created MediaKeys object ok");
+ mediaKeys.sessions = [];
+ var p = v.setMediaKeys(mediaKeys);
+ return chain(p, onSetKeysFail);
+ })
+
+ .then(function() {
+ Log(token, "set MediaKeys on <video> element ok");
+ if (params && params.onMediaKeysSet) {
+ params.onMediaKeysSet();
+ }
+ if (!(params && params.delaySessions)) {
+ processInitDataQueue();
+ }
+ })
+ } else {
+ if (params && params.delaySessions) {
+ Log(token, "got encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") event, queue it in because we're delaying sessions");
+ pushInitData(ev);
+ } else if (initDataQueue !== null) {
+ Log(token, "got encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") event, queue it for later session update");
+ pushInitData(ev);
+ } else {
+ Log(token, "got encrypted(" + ev.initDataType + ", " + StringToHex(ArrayBufferToString(ev.initData)) + ") event, update session now");
+ pushInitData(ev);
+ processInitDataQueue();
+ }
+ }
+ });
+ return v;
+}
+
+function SetupEMEPref(callback) {
+ var prefs = [
+ [ "media.mediasource.enabled", true ],
+ [ "media.eme.apiVisible", true ],
+ [ "media.mediasource.webm.enabled", true ],
+ ];
+
+ if (SpecialPowers.Services.appinfo.name == "B2G" ||
+ !manifestVideo().canPlayType("video/mp4")) {
+ // XXX remove once we have mp4 PlatformDecoderModules on all platforms.
+ prefs.push([ "media.use-blank-decoder", true ]);
+ }
+
+ SpecialPowers.pushPrefEnv({ "set" : prefs }, callback);
+}
+
+function fetchWithXHR(uri, onLoadFunction) {
+ var p = new Promise(function(resolve, reject) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", uri, true);
+ xhr.responseType = "arraybuffer";
+ xhr.addEventListener("load", function () {
+ is(xhr.status, 200, "fetchWithXHR load uri='" + uri + "' status=" + xhr.status);
+ resolve(xhr.response);
+ });
+ xhr.send();
+ });
+
+ if (onLoadFunction) {
+ p.then(onLoadFunction);
+ }
+
+ return p;
+};
+
+function once(target, name, cb) {
+ var p = new Promise(function(resolve, reject) {
+ target.addEventListener(name, function onceEvent(arg) {
+ target.removeEventListener(name, onceEvent);
+ resolve(arg);
+ });
+ });
+ if (cb) {
+ p.then(cb);
+ }
+ return p;
+}
diff --git a/dom/media/test/external/MANIFEST.in b/dom/media/test/external/MANIFEST.in
new file mode 100644
index 000000000..fe0b96e77
--- /dev/null
+++ b/dom/media/test/external/MANIFEST.in
@@ -0,0 +1,4 @@
+exclude MANIFEST.in
+include requirements.txt
+recursive-include external_media_harness *
+recursive-include external_media_tests *
diff --git a/dom/media/test/external/README.md b/dom/media/test/external/README.md
new file mode 100644
index 000000000..e806f03bc
--- /dev/null
+++ b/dom/media/test/external/README.md
@@ -0,0 +1,5 @@
+external-media-tests
+===================
+
+Documentation for this library has moved to https://developer.mozilla.org/en-US/docs/Mozilla/QA/external-media-tests.
+
diff --git a/dom/media/test/external/docs/Makefile b/dom/media/test/external/docs/Makefile
new file mode 100644
index 000000000..78c1b7379
--- /dev/null
+++ b/dom/media/test/external/docs/Makefile
@@ -0,0 +1,216 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " applehelp to make an Apple Help Book"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " xml to make Docutils-native XML files"
+ @echo " pseudoxml to make pseudoxml-XML files for display purposes"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+ @echo " coverage to run coverage check of the documentation (if enabled)"
+
+.PHONY: clean
+clean:
+ rm -rf $(BUILDDIR)/*
+
+.PHONY: html
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+.PHONY: dirhtml
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+.PHONY: singlehtml
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+.PHONY: pickle
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+.PHONY: json
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+.PHONY: htmlhelp
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+.PHONY: qthelp
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ExternalMediaTests.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ExternalMediaTests.qhc"
+
+.PHONY: applehelp
+applehelp:
+ $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
+ @echo
+ @echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
+ @echo "N.B. You won't be able to view it unless you put it in" \
+ "~/Library/Documentation/Help or install it in your application" \
+ "bundle."
+
+.PHONY: devhelp
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/ExternalMediaTests"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ExternalMediaTests"
+ @echo "# devhelp"
+
+.PHONY: epub
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+.PHONY: latex
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+.PHONY: latexpdf
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: latexpdfja
+latexpdfja:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through platex and dvipdfmx..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: text
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+.PHONY: man
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+.PHONY: texinfo
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+.PHONY: info
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+.PHONY: gettext
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+.PHONY: changes
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+.PHONY: linkcheck
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+.PHONY: doctest
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
+
+.PHONY: coverage
+coverage:
+ $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
+ @echo "Testing of coverage in the sources finished, look at the " \
+ "results in $(BUILDDIR)/coverage/python.txt."
+
+.PHONY: xml
+xml:
+ $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+ @echo
+ @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+.PHONY: pseudoxml
+pseudoxml:
+ $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+ @echo
+ @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
diff --git a/dom/media/test/external/docs/conf.py b/dom/media/test/external/docs/conf.py
new file mode 100644
index 000000000..09b15a3fd
--- /dev/null
+++ b/dom/media/test/external/docs/conf.py
@@ -0,0 +1,297 @@
+# -*- coding: utf-8 -*-
+#
+# External Media Tests documentation build configuration file, created by
+# sphinx-quickstart on Tue Mar 15 15:58:18 2016.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys
+import os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.viewcode',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'External Media Tests'
+copyright = u'2015-2016, Mozilla, Inc.'
+author = u'Syd Polk and Maja Frydrychowicz'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = u'0.1'
+# The full version, including alpha/beta/rc tags.
+release = u'0.1'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
+
+if not on_rtd:
+ try:
+ import sphinx_rtd_theme
+ html_theme = 'sphinx_rtd_theme'
+ html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
+ except ImportError:
+ pass
+
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (relative to this directory) to use as a favicon of
+# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Language to be used for generating the HTML full-text search index.
+# Sphinx supports the following languages:
+# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
+# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
+#html_search_language = 'en'
+
+# A dictionary with options for the search language support, empty by default.
+# Now only 'ja' uses this config value
+#html_search_options = {'type': 'default'}
+
+# The name of a javascript file (relative to the configuration directory) that
+# implements a search results scorer. If empty, the default will be used.
+#html_search_scorer = 'scorer.js'
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'ExternalMediaTestsdoc'
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+
+# Latex figure (float) alignment
+#'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ (master_doc, 'ExternalMediaTests.tex', u'External Media Tests Documentation',
+ u'Syd Polk and Maja Frydrychowicz', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ (master_doc, 'externalmediatests', u'External Media Tests Documentation',
+ [author], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ (master_doc, 'ExternalMediaTests', u'External Media Tests Documentation',
+ author, 'ExternalMediaTests', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
diff --git a/dom/media/test/external/docs/external_media_harness.rst b/dom/media/test/external/docs/external_media_harness.rst
new file mode 100644
index 000000000..b484ce68c
--- /dev/null
+++ b/dom/media/test/external/docs/external_media_harness.rst
@@ -0,0 +1,19 @@
+external_media_harness package
+==============================
+
+Test case classes for use in video tests
+
+external_media_harness.testcase module
+--------------------------------------
+
+.. autoclass:: external_media_harness.testcase.MediaTestCase
+ :members:
+ :show-inheritance:
+
+.. autoclass:: external_media_harness.testcase.NetworkBandwidthTestCase
+ :members:
+ :show-inheritance:
+
+.. autoclass:: external_media_harness.testcase.VideoPlaybackTestsMixin
+ :members:
+ :show-inheritance:
diff --git a/dom/media/test/external/docs/external_media_tests.media_tests.video_puppeteer.rst b/dom/media/test/external/docs/external_media_tests.media_tests.video_puppeteer.rst
new file mode 100644
index 000000000..92b8749c8
--- /dev/null
+++ b/dom/media/test/external/docs/external_media_tests.media_tests.video_puppeteer.rst
@@ -0,0 +1,27 @@
+VideoPuppeteer
+==============
+
+
+video_puppeteer.VideoPuppeteer
+------------------------------
+
+.. autoclass:: external_media_tests.media_utils.video_puppeteer.VideoPuppeteer
+ :members:
+ :show-inheritance:
+
+video_puppeteer.VideoException
+------------------------------
+
+.. autoexception:: external_media_tests.media_utils.video_puppeteer.VideoException
+
+video_puppeteer.playback_started
+--------------------------------
+
+.. autofunction:: external_media_tests.media_utils.video_puppeteer.playback_started
+
+video_puppeteer.playback_done
+-----------------------------
+
+.. autofunction:: external_media_tests.media_utils.video_puppeteer.playback_done
+
+
diff --git a/dom/media/test/external/docs/external_media_tests.media_tests.youtube_puppeteer.rst b/dom/media/test/external/docs/external_media_tests.media_tests.youtube_puppeteer.rst
new file mode 100644
index 000000000..613823e6e
--- /dev/null
+++ b/dom/media/test/external/docs/external_media_tests.media_tests.youtube_puppeteer.rst
@@ -0,0 +1,26 @@
+YoutubePuppeteer
+================
+
+youtube_puppeteer.YouTubePuppeteer
+----------------------------------
+
+.. autoclass:: external_media_tests.media_utils.youtube_puppeteer.YouTubePuppeteer
+ :members:
+ :show-inheritance:
+
+youtube_puppeteer.playback_started
+----------------------------------
+
+.. autofunction:: external_media_tests.media_utils.youtube_puppeteer.playback_started
+
+youtube_puppeteer.playback_done
+-------------------------------
+
+.. autofunction:: external_media_tests.media_utils.youtube_puppeteer.playback_done
+
+youtbue_puppeteer.wait_for_almost_done
+--------------------------------------
+
+.. autofunction:: external_media_tests.media_utils.youtube_puppeteer.wait_for_almost_done
+
+
diff --git a/dom/media/test/external/docs/external_media_tests.rst b/dom/media/test/external/docs/external_media_tests.rst
new file mode 100644
index 000000000..619fc5343
--- /dev/null
+++ b/dom/media/test/external/docs/external_media_tests.rst
@@ -0,0 +1,26 @@
+
+external_media_tests package
+============================
+
+This document highlights the utility classes for tests. In general, the indvidiual tests are not documented here.
+
+Test pacakges
+-------------
+
+.. toctree::
+
+ external_media_tests.media_tests.video_puppeteer
+ external_media_tests.media_tests.youtube_puppeteer
+
+
+external_media_tests.utils.verbose_until
+----------------------------------------
+
+.. autofunction:: external_media_tests.utils.verbose_until
+
+external_media_tests.utils.save_memory_report
+---------------------------------------------
+
+.. autofunction:: external_media_tests.utils.save_memory_report
+
+
diff --git a/dom/media/test/external/docs/index.rst b/dom/media/test/external/docs/index.rst
new file mode 100644
index 000000000..7891346c5
--- /dev/null
+++ b/dom/media/test/external/docs/index.rst
@@ -0,0 +1,33 @@
+.. py:currentmodule:: external_media_tests
+
+External Media Tests
+====================
+
+External Media Tests is a library built on top of `Firefox Puppeter`_ and the `Marionette python client`_. It is designed to test playback of video elements embedded in web pages, independent of vendor. Using this library, you can write tests which play, pause, and stop videos, as well as inspect properties such as currentTime().
+
+.. _Marionette python client: http://marionette-client.readthedocs.org/en/latest
+.. _Firefox Puppeter: http://firefox-puppeteer.readthedocs.org/en/latest/
+
+Installation
+------------
+
+External Media Tests lives in `External Media Tests Source`_. Documentation for installation and usage lives on `External Media Tests`_; this documentation is API documentation for the various pieces of the test library.
+
+.. _External Media Tests Source: https://hg.mozilla.org/dom/media/test/external
+.. _External Media Tests: https://developer.mozilla.org/en-US/docs/Mozilla/QA/external-media-tests
+
+Contents
+--------
+
+.. toctree::
+
+ external_media_harness
+ external_media_tests
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/dom/media/test/external/docs/make.bat b/dom/media/test/external/docs/make.bat
new file mode 100644
index 000000000..79bf88203
--- /dev/null
+++ b/dom/media/test/external/docs/make.bat
@@ -0,0 +1,263 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. texinfo to make Texinfo files
+ echo. gettext to make PO message catalogs
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. xml to make Docutils-native XML files
+ echo. pseudoxml to make pseudoxml-XML files for display purposes
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ echo. coverage to run coverage check of the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+
+REM Check if sphinx-build is available and fallback to Python version if any
+%SPHINXBUILD% 1>NUL 2>NUL
+if errorlevel 9009 goto sphinx_python
+goto sphinx_ok
+
+:sphinx_python
+
+set SPHINXBUILD=python -m sphinx.__init__
+%SPHINXBUILD% 2> nul
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.http://sphinx-doc.org/
+ exit /b 1
+)
+
+:sphinx_ok
+
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\ExternalMediaTests.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\ExternalMediaTests.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "latexpdf" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ cd %BUILDDIR%/latex
+ make all-pdf
+ cd %~dp0
+ echo.
+ echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "latexpdfja" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ cd %BUILDDIR%/latex
+ make all-pdf-ja
+ cd %~dp0
+ echo.
+ echo.Build finished; the PDF files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "texinfo" (
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+ goto end
+)
+
+if "%1" == "gettext" (
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+if "%1" == "coverage" (
+ %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of coverage in the sources finished, look at the ^
+results in %BUILDDIR%/coverage/python.txt.
+ goto end
+)
+
+if "%1" == "xml" (
+ %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The XML files are in %BUILDDIR%/xml.
+ goto end
+)
+
+if "%1" == "pseudoxml" (
+ %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
+ goto end
+)
+
+:end
diff --git a/dom/media/test/external/external_media_harness/__init__.py b/dom/media/test/external/external_media_harness/__init__.py
new file mode 100644
index 000000000..906473f0b
--- /dev/null
+++ b/dom/media/test/external/external_media_harness/__init__.py
@@ -0,0 +1,5 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from runtests import cli
diff --git a/dom/media/test/external/external_media_harness/runtests.py b/dom/media/test/external/external_media_harness/runtests.py
new file mode 100644
index 000000000..08d1a323b
--- /dev/null
+++ b/dom/media/test/external/external_media_harness/runtests.py
@@ -0,0 +1,103 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+import sys
+
+import mozlog
+
+from manifestparser import read_ini
+from marionette_harness import (
+ BaseMarionetteTestRunner,
+ BaseMarionetteArguments,
+ BrowserMobProxyArguments,
+)
+from marionette_harness.runtests import MarionetteHarness, cli as mn_cli
+
+import external_media_tests
+from testcase import MediaTestCase
+from external_media_tests.media_utils.video_puppeteer import debug_script
+
+
+class MediaTestArgumentsBase(object):
+ name = 'Firefox Media Tests'
+ args = [
+ [['--urls'], {
+ 'help': 'ini file of urls to make available to all tests',
+ 'default': os.path.join(external_media_tests.urls, 'default.ini'),
+ }],
+ ]
+
+ def verify_usage_handler(self, args):
+ if args.urls:
+ if not os.path.isfile(args.urls):
+ raise ValueError('--urls must provide a path to an ini file')
+ else:
+ path = os.path.abspath(args.urls)
+ args.video_urls = MediaTestArgumentsBase.get_urls(path)
+ if not args.video_urls:
+ raise ValueError('list of video URLs cannot be empty')
+
+ def parse_args_handler(self, args):
+ if not args.tests:
+ args.tests = [external_media_tests.manifest]
+
+
+ @staticmethod
+ def get_urls(manifest):
+ with open(manifest, 'r'):
+ return [line[0] for line in read_ini(manifest)]
+
+
+class MediaTestArguments(BaseMarionetteArguments):
+ def __init__(self, **kwargs):
+ BaseMarionetteArguments.__init__(self, **kwargs)
+ self.register_argument_container(MediaTestArgumentsBase())
+ self.register_argument_container(BrowserMobProxyArguments())
+
+
+class MediaTestRunner(BaseMarionetteTestRunner):
+ def __init__(self, **kwargs):
+ BaseMarionetteTestRunner.__init__(self, **kwargs)
+ if not self.server_root:
+ self.server_root = external_media_tests.resources
+ # pick up prefs from marionette_driver.geckoinstance.DesktopInstance
+ self.app = 'fxdesktop'
+ self.test_handlers = [MediaTestCase]
+
+ # Used in HTML report (--log-html)
+ def gather_media_debug(test, status):
+ rv = {}
+ marionette = test._marionette_weakref()
+
+ if marionette.session is not None:
+ try:
+ with marionette.using_context(marionette.CONTEXT_CHROME):
+ debug_lines = marionette.execute_script(debug_script)
+ if debug_lines:
+ name = 'mozMediaSourceObject.mozDebugReaderData'
+ rv[name] = '\n'.join(debug_lines)
+ else:
+ logger = mozlog.get_default_logger()
+ logger.info('No data available about '
+ 'mozMediaSourceObject')
+ except:
+ logger = mozlog.get_default_logger()
+ logger.warning('Failed to gather test failure media debug',
+ exc_info=True)
+ return rv
+
+ self.result_callbacks.append(gather_media_debug)
+
+
+class FirefoxMediaHarness(MarionetteHarness):
+ def parse_args(self, *args, **kwargs):
+ return MarionetteHarness.parse_args(self, {'mach': sys.stdout})
+
+
+def cli():
+ mn_cli(MediaTestRunner, MediaTestArguments, FirefoxMediaHarness)
+
+if __name__ == '__main__':
+ cli()
diff --git a/dom/media/test/external/external_media_harness/testcase.py b/dom/media/test/external/external_media_harness/testcase.py
new file mode 100644
index 000000000..56350ccd9
--- /dev/null
+++ b/dom/media/test/external/external_media_harness/testcase.py
@@ -0,0 +1,362 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import re
+import os
+
+from marionette_driver import Wait
+from marionette_driver.errors import TimeoutException
+from marionette_harness import (
+ BrowserMobProxyTestCaseMixin,
+ MarionetteTestCase,
+ Marionette,
+ SkipTest,
+)
+
+from firefox_puppeteer import PuppeteerMixin
+from external_media_tests.utils import (timestamp_now, verbose_until)
+from external_media_tests.media_utils.video_puppeteer import (
+ VideoException,
+ VideoPuppeteer
+)
+
+
+class MediaTestCase(PuppeteerMixin, MarionetteTestCase):
+
+ """
+ Necessary methods for MSE playback
+
+ :param video_urls: Urls you are going to play as part of the tests.
+ """
+
+ def __init__(self, *args, **kwargs):
+ self.video_urls = kwargs.pop('video_urls', False)
+ super(MediaTestCase, self).__init__(*args, **kwargs)
+
+ def save_screenshot(self):
+ """
+ Make a screenshot of the window that is currently playing the video
+ element.
+ """
+ screenshot_dir = os.path.join(self.marionette.instance.workspace or '',
+ 'screenshots')
+ filename = ''.join([self.id().replace(' ', '-'),
+ '_',
+ str(timestamp_now()),
+ '.png'])
+ path = os.path.join(screenshot_dir, filename)
+ if not os.path.exists(screenshot_dir):
+ os.makedirs(screenshot_dir)
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ img_data = self.marionette.screenshot()
+ with open(path, 'wb') as f:
+ f.write(img_data.decode('base64'))
+ self.marionette.log('Screenshot saved in {}'
+ .format(os.path.abspath(path)))
+
+ def log_video_debug_lines(self, video):
+ """
+ Log the debugging information that Firefox provides for video elements.
+ """
+ with self.marionette.using_context(Marionette.CONTEXT_CHROME):
+ debug_lines = video.get_debug_lines()
+ if debug_lines:
+ self.marionette.log('\n'.join(debug_lines))
+
+ def run_playback(self, video):
+ """
+ Play the video all of the way through, or for the requested duration,
+ whichever comes first. Raises if the video stalls for too long.
+
+ :param video: VideoPuppeteer instance to play.
+ """
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ self.logger.info(video.test_url)
+ try:
+ verbose_until(Wait(video, interval=video.interval,
+ timeout=video.expected_duration * 1.3 +
+ video.stall_wait_time),
+ video, VideoPuppeteer.playback_done)
+ except VideoException as e:
+ raise self.failureException(e)
+
+ def check_playback_starts(self, video):
+ """
+ Check to see if a given video will start. Raises if the video does not
+ start.
+
+ :param video: VideoPuppeteer instance to play.
+ """
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ self.logger.info(video.test_url)
+ try:
+ verbose_until(Wait(video, timeout=video.timeout),
+ video, VideoPuppeteer.playback_started)
+ except TimeoutException as e:
+ raise self.failureException(e)
+
+ def skipTest(self, reason):
+ """
+ Skip this test.
+
+ Skip with marionette.marionette_test import SkipTest so that it
+ gets recognized a skip in marionette.marionette_test.CommonTestCase.run
+ """
+ raise SkipTest(reason)
+
+
+class NetworkBandwidthTestCase(MediaTestCase):
+ """
+ Test MSE playback while network bandwidth is limited. Uses browsermobproxy
+ (https://bmp.lightbody.net/). Please see
+ https://developer.mozilla.org/en-US/docs/Mozilla/QA/external-media-tests
+ for more information on setting up browsermob_proxy.
+ """
+
+ def __init__(self, *args, **kwargs):
+ super(NetworkBandwidthTestCase, self).__init__(*args, **kwargs)
+ BrowserMobProxyTestCaseMixin.__init__(self, *args, **kwargs)
+ self.proxy = None
+
+ def setUp(self):
+ super(NetworkBandwidthTestCase, self).setUp()
+ BrowserMobProxyTestCaseMixin.setUp(self)
+ self.proxy = self.create_browsermob_proxy()
+
+ def tearDown(self):
+ super(NetworkBandwidthTestCase, self).tearDown()
+ BrowserMobProxyTestCaseMixin.tearDown(self)
+ self.proxy = None
+
+ def run_videos(self, timeout=60):
+ """
+ Run each of the videos in the video list. Raises if something goes
+ wrong in playback.
+ """
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ for url in self.video_urls:
+ video = VideoPuppeteer(self.marionette, url, stall_wait_time=60,
+ set_duration=60, timeout=timeout)
+ self.run_playback(video)
+
+
+class VideoPlaybackTestsMixin(object):
+
+ """
+ Test MSE playback in HTML5 video element.
+
+ These tests should pass on any site where a single video element plays
+ upon loading and is uninterrupted (by ads, for example).
+
+ This tests both starting videos and performing partial playback at one
+ minute each, and is the test that should be run frequently in automation.
+ """
+
+ def test_playback_starts(self):
+ """
+ Test to make sure that playback of the video element starts for each
+ video.
+ """
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ for url in self.video_urls:
+ try:
+ video = VideoPuppeteer(self.marionette, url, timeout=60)
+ # Second playback_started check in case video._start_time
+ # is not 0
+ self.check_playback_starts(video)
+ video.pause()
+ except TimeoutException as e:
+ raise self.failureException(e)
+
+ def test_video_playback_partial(self):
+ """
+ Test to make sure that playback of 60 seconds works for each video.
+ """
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ for url in self.video_urls:
+ video = VideoPuppeteer(self.marionette, url,
+ stall_wait_time=10,
+ set_duration=60)
+ self.run_playback(video)
+
+
+class NetworkBandwidthTestsMixin(object):
+
+ """
+ Test video urls with various bandwidth settings.
+ """
+
+ def test_playback_limiting_bandwidth_250(self):
+ self.proxy.limits({'downstream_kbps': 250})
+ self.run_videos(timeout=120)
+
+ def test_playback_limiting_bandwidth_500(self):
+ self.proxy.limits({'downstream_kbps': 500})
+ self.run_videos(timeout=120)
+
+ def test_playback_limiting_bandwidth_1000(self):
+ self.proxy.limits({'downstream_kbps': 1000})
+ self.run_videos(timeout=120)
+
+
+reset_adobe_gmp_script = """
+navigator.requestMediaKeySystemAccess('com.adobe.primetime',
+[{initDataTypes: ['cenc']}]).then(
+ function(access) {
+ marionetteScriptFinished('success');
+ },
+ function(ex) {
+ marionetteScriptFinished(ex);
+ }
+);
+"""
+
+
+reset_widevine_gmp_script = """
+navigator.requestMediaKeySystemAccess('com.widevine.alpha',
+[{initDataTypes: ['cenc']}]).then(
+ function(access) {
+ marionetteScriptFinished('success');
+ },
+ function(ex) {
+ marionetteScriptFinished(ex);
+ }
+);
+"""
+
+
+class EMESetupMixin(object):
+
+ """
+ An object that needs to use the Adobe or Widevine GMP system must inherit
+ from this class, and then call check_eme_system() to insure that everything
+ is setup correctly.
+ """
+
+ version_needs_reset = True
+
+ def check_eme_system(self):
+ """
+ Download the most current version of the Adobe and Widevine GMP
+ Plugins. Verify that all MSE and EME prefs are set correctly. Raises
+ if things are not OK.
+ """
+ self.set_eme_prefs()
+ self.reset_GMP_version()
+ assert(self.check_eme_prefs())
+
+ def set_eme_prefs(self):
+ with self.marionette.using_context(Marionette.CONTEXT_CHROME):
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1187471#c28
+ # 2015-09-28 cpearce says this is no longer necessary, but in case
+ # we are working with older firefoxes...
+ self.marionette.set_pref('media.gmp.trial-create.enabled', False)
+
+ def reset_GMP_version(self):
+ if EMESetupMixin.version_needs_reset:
+ with self.marionette.using_context(Marionette.CONTEXT_CHROME):
+ if self.marionette.get_pref('media.gmp-eme-adobe.version'):
+ self.marionette.reset_pref('media.gmp-eme-adobe.version')
+ if self.marionette.get_pref('media.gmp-widevinecdm.version'):
+ self.marionette.reset_pref('media.gmp-widevinecdm.version')
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ adobe_result = self.marionette.execute_async_script(
+ reset_adobe_gmp_script,
+ script_timeout=60000)
+ widevine_result = self.marionette.execute_async_script(
+ reset_widevine_gmp_script,
+ script_timeout=60000)
+ if not adobe_result == 'success':
+ raise VideoException(
+ 'ERROR: Resetting Adobe GMP failed {}'
+ .format(adobe_result))
+ if not widevine_result == 'success':
+ raise VideoException(
+ 'ERROR: Resetting Widevine GMP failed {}'
+ .format(widevine_result))
+
+ EMESetupMixin.version_needs_reset = False
+
+ def check_and_log_boolean_pref(self, pref_name, expected_value):
+ with self.marionette.using_context(Marionette.CONTEXT_CHROME):
+ pref_value = self.marionette.get_pref(pref_name)
+
+ if pref_value is None:
+ self.logger.info('Pref {} has no value.'.format(pref_name))
+ return False
+ else:
+ self.logger.info('Pref {} = {}'.format(pref_name, pref_value))
+ if pref_value != expected_value:
+ self.logger.info('Pref {} has unexpected value.'
+ .format(pref_name))
+ return False
+
+ return True
+
+ def check_and_log_integer_pref(self, pref_name, minimum_value=0):
+ with self.marionette.using_context(Marionette.CONTEXT_CHROME):
+ pref_value = self.marionette.get_pref(pref_name)
+
+ if pref_value is None:
+ self.logger.info('Pref {} has no value.'.format(pref_name))
+ return False
+ else:
+ self.logger.info('Pref {} = {}'.format(pref_name, pref_value))
+
+ match = re.search('^\d+$', pref_value)
+ if not match:
+ self.logger.info('Pref {} is not an integer'
+ .format(pref_name))
+ return False
+
+ return pref_value >= minimum_value
+
+ def chceck_and_log_version_string_pref(self, pref_name, minimum_value='0'):
+ """
+ Compare a pref made up of integers separated by stops .s, with a
+ version string of the same format. The number of integers in each
+ string does not need to match. The comparison is done by converting
+ each to an integer array and comparing those. Both version strings
+ must be made up of only integers, or this method will raise an
+ unhandled exception of type ValueError when the conversion to int
+ fails.
+ """
+ with self.marionette.using_context(Marionette.CONTEXT_CHROME):
+ pref_value = self.marionette.get_pref(pref_name)
+
+ if pref_value is None:
+ self.logger.info('Pref {} has no value.'.format(pref_name))
+ return False
+ else:
+ self.logger.info('Pref {} = {}'.format(pref_name, pref_value))
+
+ match = re.search('^\d(.\d+)*$', pref_value)
+ if not match:
+ self.logger.info('Pref {} is not a version string'
+ .format(pref_name))
+ return False
+
+ pref_ints = [int(n) for n in pref_value.split('.')]
+ minumum_ints = [int(n) for n in minimum_value.split('.')]
+
+ return pref_ints >= minumum_ints
+
+ def check_eme_prefs(self):
+ with self.marionette.using_context(Marionette.CONTEXT_CHROME):
+ return all([
+ self.check_and_log_boolean_pref(
+ 'media.mediasource.enabled', True),
+ self.check_and_log_boolean_pref(
+ 'media.eme.enabled', True),
+ self.check_and_log_boolean_pref(
+ 'media.mediasource.mp4.enabled', True),
+ self.check_and_log_boolean_pref(
+ 'media.gmp-eme-adobe.enabled', True),
+ self.check_and_log_integer_pref(
+ 'media.gmp-eme-adobe.version', 1),
+ self.check_and_log_boolean_pref(
+ 'media.gmp-widevinecdm.enabled', True),
+ self.chceck_and_log_version_string_pref(
+ 'media.gmp-widevinecdm.version', '1.0.0.0')
+ ])
diff --git a/dom/media/test/external/external_media_tests/__init__.py b/dom/media/test/external/external_media_tests/__init__.py
new file mode 100644
index 000000000..bf7ceec47
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/__init__.py
@@ -0,0 +1,10 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+
+root = os.path.abspath(os.path.dirname(__file__))
+manifest = os.path.join(root, 'manifest.ini')
+resources = os.path.join(root, 'resources')
+urls = os.path.join(root, 'urls')
diff --git a/dom/media/test/external/external_media_tests/manifest.ini b/dom/media/test/external/external_media_tests/manifest.ini
new file mode 100644
index 000000000..e370fd679
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/manifest.ini
@@ -0,0 +1 @@
+[include:playback/manifest.ini]
diff --git a/dom/media/test/external/external_media_tests/media_utils/__init__.py b/dom/media/test/external/external_media_tests/media_utils/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/media_utils/__init__.py
diff --git a/dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py b/dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py
new file mode 100644
index 000000000..b904267dd
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py
@@ -0,0 +1,448 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from collections import namedtuple
+from time import clock, sleep
+
+from marionette_driver import By, expected, Wait
+from marionette_harness import Marionette
+
+from external_media_tests.utils import verbose_until
+
+
+# Adapted from
+# https://github.com/gavinsharp/aboutmedia/blob/master/chrome/content/aboutmedia.xhtml
+debug_script = """
+var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIWebNavigation)
+ .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
+ .rootTreeItem
+ .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindow);
+var tabbrowser = mainWindow.gBrowser;
+for (var i=0; i < tabbrowser.browsers.length; ++i) {
+ var b = tabbrowser.getBrowserAtIndex(i);
+ var media = b.contentDocumentAsCPOW.getElementsByTagName('video');
+ for (var j=0; j < media.length; ++j) {
+ var ms = media[j].mozMediaSourceObject;
+ if (ms) {
+ debugLines = ms.mozDebugReaderData.split(\"\\n\");
+ return debugLines;
+ }
+ }
+}"""
+
+
+class VideoPuppeteer(object):
+ """
+ Wrapper to control and introspect HTML5 video elements.
+
+ A note about properties like current_time and duration:
+ These describe whatever stream is playing when the state is checked.
+ It is possible that many different streams are dynamically spliced
+ together, so the video stream that is currently playing might be the main
+ video or it might be something else, like an ad, for example.
+
+ :param marionette: The marionette instance this runs in.
+ :param url: the URL of the page containing the video element.
+ :param video_selector: the selector of the element that we want to watch.
+ This is set by default to 'video', which is what most sites use, but
+ others should work.
+ :param interval: The polling interval that is used to check progress.
+ :param set_duration: When set to >0, the polling and checking will stop at
+ the number of seconds specified. Otherwise, this will stop at the end
+ of the video.
+ :param stall_wait_time: The amount of time to wait to see if a stall has
+ cleared. If 0, do not check for stalls.
+ :param timeout: The amount of time to wait until the video starts.
+ """
+
+ _video_var_script = (
+ 'var video = arguments[0];'
+ 'var baseURI = arguments[0].baseURI;'
+ 'var currentTime = video.wrappedJSObject.currentTime;'
+ 'var duration = video.wrappedJSObject.duration;'
+ 'var buffered = video.wrappedJSObject.buffered;'
+ 'var bufferedRanges = [];'
+ 'for (var i = 0; i < buffered.length; i++) {'
+ 'bufferedRanges.push([buffered.start(i), buffered.end(i)]);'
+ '}'
+ 'var played = video.wrappedJSObject.played;'
+ 'var playedRanges = [];'
+ 'for (var i = 0; i < played.length; i++) {'
+ 'playedRanges.push([played.start(i), played.end(i)]);'
+ '}'
+ 'var totalFrames = '
+ 'video.getVideoPlaybackQuality()["totalVideoFrames"];'
+ 'var droppedFrames = '
+ 'video.getVideoPlaybackQuality()["droppedVideoFrames"];'
+ 'var corruptedFrames = '
+ 'video.getVideoPlaybackQuality()["corruptedVideoFrames"];'
+ )
+ """
+ A string containing JS that assigns video state to variables.
+ The purpose of this string script is to be appended to by this and
+ any inheriting classes to return these and other variables. In the case
+ of an inheriting class the script can be added to in order to fetch
+ further relevant variables -- keep in mind we only want one script
+ execution to prevent races, so it wouldn't do to have child classes
+ run this script then their own, as there is potential for lag in
+ between.
+
+ This script assigns a subset of the vars used later by the
+ `_video_state_named_tuple` function. Please see that function's
+ documentation for further information on these variables.
+ """
+
+ def __init__(self, marionette, url, video_selector='video', interval=1,
+ set_duration=0, stall_wait_time=0, timeout=60,
+ autostart=True):
+ self.marionette = marionette
+ self.test_url = url
+ self.interval = interval
+ self.stall_wait_time = stall_wait_time
+ self.timeout = timeout
+ self._set_duration = set_duration
+ self.video = None
+ self.expected_duration = 0
+ self._first_seen_time = 0
+ self._first_seen_wall_time = 0
+ self._fetch_state_script_string = None
+ self._last_seen_video_state = None
+ wait = Wait(self.marionette, timeout=self.timeout)
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ self.marionette.navigate(self.test_url)
+ self.marionette.execute_script("""
+ log('URL: {0}');""".format(self.test_url))
+ verbose_until(wait, self,
+ expected.element_present(By.TAG_NAME, 'video'))
+ videos_found = self.marionette.find_elements(By.CSS_SELECTOR,
+ video_selector)
+ if len(videos_found) > 1:
+ self.marionette.log(type(self).__name__ + ': multiple video '
+ 'elements found. '
+ 'Using first.')
+ if len(videos_found) <= 0:
+ self.marionette.log(type(self).__name__ + ': no video '
+ 'elements found.')
+ return
+ self.video = videos_found[0]
+ self.marionette.execute_script("log('video element obtained');")
+ if autostart:
+ self.start()
+
+ def start(self):
+ # To get an accurate expected_duration, playback must have started
+ self._refresh_state()
+ wait = Wait(self, timeout=self.timeout)
+ verbose_until(wait, self, VideoPuppeteer.playback_started,
+ "Check if video has played some range")
+ self._first_seen_time = self._last_seen_video_state.current_time
+ self._first_seen_wall_time = clock()
+ self._update_expected_duration()
+
+ def get_debug_lines(self):
+ """
+ Get Firefox internal debugging for the video element.
+
+ :return: A text string that has Firefox-internal debugging information.
+ """
+ with self.marionette.using_context('chrome'):
+ debug_lines = self.marionette.execute_script(debug_script)
+ return debug_lines
+
+ def play(self):
+ """
+ Tell the video element to Play.
+ """
+ self._execute_video_script('arguments[0].wrappedJSObject.play();')
+
+ def pause(self):
+ """
+ Tell the video element to Pause.
+ """
+ self._execute_video_script('arguments[0].wrappedJSObject.pause();')
+
+ def playback_started(self):
+ """
+ Determine if video has started
+
+ :param self: The VideoPuppeteer instance that we are interested in.
+
+ :return: True if is playing; False otherwise
+ """
+ self._refresh_state()
+ try:
+ played_ranges = self._last_seen_video_state.played
+ return (
+ played_ranges.length > 0 and
+ played_ranges.start(0) < played_ranges.end(0) and
+ played_ranges.end(0) > 0.0
+ )
+ except Exception as e:
+ print ('Got exception {}'.format(e))
+ return False
+
+ def playback_done(self):
+ """
+ If we are near the end and there is still a video element, then
+ we are essentially done. If this happens to be last time we are polled
+ before the video ends, we won't get another chance.
+
+ :param self: The VideoPuppeteer instance that we are interested in.
+
+ :return: True if we are close enough to the end of playback; False
+ otherwise.
+ """
+ self._refresh_state()
+
+ if self._last_seen_video_state.remaining_time < self.interval:
+ return True
+
+ # Check to see if the video has stalled. Accumulate the amount of lag
+ # since the video started, and if it is too high, then raise.
+ if (self.stall_wait_time and
+ self._last_seen_video_state.lag > self.stall_wait_time):
+ raise VideoException('Video {} stalled.\n{}'
+ .format(self._last_seen_video_state.video_uri,
+ self))
+
+ # We are cruising, so we are not done.
+ return False
+
+ def _update_expected_duration(self):
+ """
+ Update the duration of the target video at self.test_url (in seconds).
+ This is based on the last seen state, so the state should be,
+ refreshed at least once before this is called.
+
+ expected_duration represents the following: how long do we expect
+ playback to last before we consider the video to be 'complete'?
+ If we only want to play the first n seconds of the video,
+ expected_duration is set to n.
+ """
+
+ # self._last_seen_video_state.duration is the duration of whatever was
+ # playing when the state was checked. In this case, we assume the video
+ # element always shows the same stream throughout playback (i.e. the
+ # are no ads spliced into the main video, for example), so
+ # self._last_seen_video_state.duration is the duration of the main
+ # video.
+ video_duration = self._last_seen_video_state.duration
+ # Do our best to figure out where the video started playing
+ played_ranges = self._last_seen_video_state.played
+ if played_ranges.length > 0:
+ # If we have a range we should only have on continuous range
+ assert played_ranges.length == 1
+ start_position = played_ranges.start(0)
+ else:
+ # If we don't have a range we should have a current time
+ start_position = self._first_seen_time
+ # In case video starts at t > 0, adjust target time partial playback
+ remaining_video = video_duration - start_position
+ if 0 < self._set_duration < remaining_video:
+ self.expected_duration = self._set_duration
+ else:
+ self.expected_duration = remaining_video
+
+ @staticmethod
+ def _video_state_named_tuple():
+ """
+ Create a named tuple class that can be used to store state snapshots
+ of the wrapped element. The fields in the tuple should be used as
+ follows:
+
+ base_uri: the baseURI attribute of the wrapped element.
+ current_time: the current time of the wrapped element.
+ duration: the duration of the wrapped element.
+ buffered: the buffered ranges of the wrapped element. In its raw form
+ this is as a list where the first element is the length and the second
+ element is a list of 2 item lists, where each two items are a buffered
+ range. Once assigned to the tuple this data should be wrapped in the
+ TimeRanges class.
+ played: the played ranges of the wrapped element. In its raw form this
+ is as a list where the first element is the length and the second
+ element is a list of 2 item lists, where each two items are a played
+ range. Once assigned to the tuple this data should be wrapped in the
+ TimeRanges class.
+ lag: the difference in real world time and wrapped element time.
+ Calculated as real world time passed - element time passed.
+ totalFrames: number of total frames for the wrapped element
+ droppedFrames: number of dropped frames for the wrapped element.
+ corruptedFrames: number of corrupted frames for the wrapped.
+ video_src: the src attribute of the wrapped element.
+
+ :return: A 'video_state_info' named tuple class.
+ """
+ return namedtuple('video_state_info',
+ ['base_uri',
+ 'current_time',
+ 'duration',
+ 'remaining_time',
+ 'buffered',
+ 'played',
+ 'lag',
+ 'total_frames',
+ 'dropped_frames',
+ 'corrupted_frames',
+ 'video_src'])
+
+ def _create_video_state_info(self, **video_state_info_kwargs):
+ """
+ Create an instance of the video_state_info named tuple. This function
+ expects a dictionary populated with the following keys: current_time,
+ duration, raw_played_ranges, total_frames, dropped_frames, and
+ corrupted_frames.
+
+ Aside from raw_played_ranges, see `_video_state_named_tuple` for more
+ information on the above keys and values. For raw_played_ranges a
+ list is expected that can be consumed to make a TimeRanges object.
+
+ :return: A named tuple 'video_state_info' derived from arguments and
+ state information from the puppeteer.
+ """
+ raw_buffered_ranges = video_state_info_kwargs['raw_buffered_ranges']
+ raw_played_ranges = video_state_info_kwargs['raw_played_ranges']
+ # Remove raw ranges from dict as they are not used in the final named
+ # tuple and will provide an unexpected kwarg if kept.
+ del video_state_info_kwargs['raw_buffered_ranges']
+ del video_state_info_kwargs['raw_played_ranges']
+ # Create buffered ranges
+ video_state_info_kwargs['buffered'] = (
+ TimeRanges(raw_buffered_ranges[0], raw_buffered_ranges[1]))
+ # Create played ranges
+ video_state_info_kwargs['played'] = (
+ TimeRanges(raw_played_ranges[0], raw_played_ranges[1]))
+ # Calculate elapsed times
+ elapsed_current_time = (video_state_info_kwargs['current_time'] -
+ self._first_seen_time)
+ elapsed_wall_time = clock() - self._first_seen_wall_time
+ # Calculate lag
+ video_state_info_kwargs['lag'] = (
+ elapsed_wall_time - elapsed_current_time)
+ # Calculate remaining time
+ if video_state_info_kwargs['played'].length > 0:
+ played_duration = (video_state_info_kwargs['played'].end(0) -
+ video_state_info_kwargs['played'].start(0))
+ video_state_info_kwargs['remaining_time'] = (
+ self.expected_duration - played_duration)
+ else:
+ # No playback has happened yet, remaining time is duration
+ video_state_info_kwargs['remaining_time'] = self.expected_duration
+ # Fetch non time critical source information
+ video_state_info_kwargs['video_src'] = self.video.get_attribute('src')
+ # Create video state snapshot
+ state_info = self._video_state_named_tuple()
+ return state_info(**video_state_info_kwargs)
+
+ @property
+ def _fetch_state_script(self):
+ if not self._fetch_state_script_string:
+ self._fetch_state_script_string = (
+ self._video_var_script +
+ 'return ['
+ 'baseURI,'
+ 'currentTime,'
+ 'duration,'
+ '[buffered.length, bufferedRanges],'
+ '[played.length, playedRanges],'
+ 'totalFrames,'
+ 'droppedFrames,'
+ 'corruptedFrames];')
+ return self._fetch_state_script_string
+
+ def _refresh_state(self):
+ """
+ Refresh the snapshot of the underlying video state. We do this all
+ in one so that the state doesn't change in between queries.
+
+ We also store information that can be derived from the snapshotted
+ information, such as lag. This is stored in the last seen state to
+ stress that it's based on the snapshot.
+ """
+ keys = ['base_uri', 'current_time', 'duration', 'raw_buffered_ranges',
+ 'raw_played_ranges', 'total_frames', 'dropped_frames',
+ 'corrupted_frames']
+ values = self._execute_video_script(self._fetch_state_script)
+ self._last_seen_video_state = (
+ self._create_video_state_info(**dict(zip(keys, values))))
+
+ def _measure_progress(self):
+ self._refresh_state()
+ initial = self._last_seen_video_state.current_time
+ sleep(1)
+ self._refresh_state()
+ return self._last_seen_video_state.current_time - initial
+
+ def _execute_video_script(self, script):
+ """
+ Execute JS script in content context with access to video element.
+
+ :param script: script to be executed
+ :return: value returned by script
+ """
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ return self.marionette.execute_script(script,
+ script_args=[self.video])
+
+ def __str__(self):
+ messages = ['{} - test url: {}: '
+ .format(type(self).__name__, self.test_url)]
+ if not self.video:
+ messages += ['\tvideo: None']
+ return '\n'.join(messages)
+ if not self._last_seen_video_state:
+ messages += ['\tvideo: No last seen state']
+ return '\n'.join(messages)
+ # Have video and state info
+ messages += [
+ '{',
+ '\t(video)'
+ ]
+ messages += ['\tinterval: {}'.format(self.interval)]
+ messages += ['\texpected duration: {}'.format(self.expected_duration)]
+ messages += ['\tstall wait time: {}'.format(self.stall_wait_time)]
+ messages += ['\ttimeout: {}'.format(self.timeout)]
+ # Print each field on its own line
+ for field in self._last_seen_video_state._fields:
+ # For compatibility with different test environments we force ascii
+ field_ascii = (
+ unicode(getattr(self._last_seen_video_state, field))
+ .encode('ascii','replace'))
+ messages += [('\t{}: {}'.format(field, field_ascii))]
+ messages += '}'
+ return '\n'.join(messages)
+
+
+class VideoException(Exception):
+ """
+ Exception class to use for video-specific error processing.
+ """
+ pass
+
+
+class TimeRanges:
+ """
+ Class to represent the TimeRanges data returned by played(). Exposes a
+ similar interface to the JavaScript TimeRanges object.
+ """
+ def __init__(self, length, ranges):
+ # These should be the same,. Theoretically we don't need the length,
+ # but since this should be used to consume data coming back from
+ # JS exec, this is a valid sanity check.
+ assert length == len(ranges)
+ self.length = length
+ self.ranges = [(pair[0], pair[1]) for pair in ranges]
+
+ def __repr__(self):
+ return (
+ 'TimeRanges: length: {}, ranges: {}'
+ .format(self.length, self.ranges)
+ )
+
+ def start(self, index):
+ return self.ranges[index][0]
+
+ def end(self, index):
+ return self.ranges[index][1]
diff --git a/dom/media/test/external/external_media_tests/media_utils/youtube_puppeteer.py b/dom/media/test/external/external_media_tests/media_utils/youtube_puppeteer.py
new file mode 100644
index 000000000..e42bbcc87
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/media_utils/youtube_puppeteer.py
@@ -0,0 +1,496 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import re
+
+from collections import namedtuple
+from json import loads
+from time import sleep
+
+from marionette_driver import By, expected, Wait
+from marionette_driver.errors import TimeoutException, NoSuchElementException
+from marionette_harness import Marionette
+
+from video_puppeteer import VideoPuppeteer, VideoException
+from external_media_tests.utils import verbose_until
+
+
+class YouTubePuppeteer(VideoPuppeteer):
+ """
+ Wrapper around a YouTube .html5-video-player element.
+
+ Can be used with youtube videos or youtube videos at embedded URLS. E.g.
+ both https://www.youtube.com/watch?v=AbAACm1IQE0 and
+ https://www.youtube.com/embed/AbAACm1IQE0 should work.
+
+ Using an embedded video has the advantage of not auto-playing more videos
+ while a test is running.
+
+ Compared to video puppeteer, this class has the benefit of accessing the
+ youtube player object as well as the video element. The YT player will
+ report information for the underlying video even if an add is playing (as
+ opposed to the video element behaviour, which will report on whatever
+ is play at the time of query), and can also report if an ad is playing.
+
+ Partial reference: https://developers.google.com/youtube/iframe_api_reference.
+ This reference is useful for site-specific features such as interacting
+ with ads, or accessing YouTube's debug data.
+ """
+
+ _player_var_script = (
+ 'var player_duration = arguments[1].wrappedJSObject.getDuration();'
+ 'var player_current_time = '
+ 'arguments[1].wrappedJSObject.getCurrentTime();'
+ 'var player_playback_quality = '
+ 'arguments[1].wrappedJSObject.getPlaybackQuality();'
+ 'var player_movie_id = '
+ 'arguments[1].wrappedJSObject.getVideoData()["video_id"];'
+ 'var player_movie_title = '
+ 'arguments[1].wrappedJSObject.getVideoData()["title"];'
+ 'var player_url = '
+ 'arguments[1].wrappedJSObject.getVideoUrl();'
+ 'var player_state = '
+ 'arguments[1].wrappedJSObject.getPlayerState();'
+ 'var player_ad_state = arguments[1].wrappedJSObject.getAdState();'
+ 'var player_breaks_count = '
+ 'arguments[1].wrappedJSObject.getOption("ad", "breakscount");'
+ )
+ """
+ A string containing JS that will assign player state to
+ variables. This is similar to `_video_var_script` from
+ `VideoPuppeteer`. See `_video_var_script` for more information on the
+ motivation for this method.
+
+ This script assigns a subset of the vars used later by the
+ `_yt_state_named_tuple` function. Please see that functions
+ documentation for further information on these variables.
+ """
+
+ _yt_player_state = {
+ 'UNSTARTED': -1,
+ 'ENDED': 0,
+ 'PLAYING': 1,
+ 'PAUSED': 2,
+ 'BUFFERING': 3,
+ 'CUED': 5
+ }
+ _yt_player_state_name = {v: k for k, v in _yt_player_state.items()}
+ _time_pattern = re.compile('(?P<minute>\d+):(?P<second>\d+)')
+
+ def __init__(self, marionette, url, autostart=True, **kwargs):
+ self.player = None
+ self._last_seen_player_state = None
+ super(YouTubePuppeteer,
+ self).__init__(marionette, url,
+ video_selector='.html5-video-player video',
+ autostart=False,
+ **kwargs)
+ wait = Wait(self.marionette, timeout=30)
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ verbose_until(wait, self,
+ expected.element_present(By.CLASS_NAME,
+ 'html5-video-player'))
+ self.player = self.marionette.find_element(By.CLASS_NAME,
+ 'html5-video-player')
+ self.marionette.execute_script("log('.html5-video-player "
+ "element obtained');")
+ # When an ad is playing, self.player_duration indicates the duration
+ # of the spliced-in ad stream, not the duration of the main video, so
+ # we attempt to skip the ad first.
+ for attempt in range(5):
+ sleep(1)
+ self.process_ad()
+ if (self._last_seen_player_state.player_ad_inactive and
+ self._last_seen_video_state.duration and not
+ self._last_seen_player_state.player_buffering):
+ break
+ self._update_expected_duration()
+ if autostart:
+ self.start()
+
+ def player_play(self):
+ """
+ Play via YouTube API.
+ """
+ self._execute_yt_script('arguments[1].wrappedJSObject.playVideo();')
+
+ def player_pause(self):
+ """
+ Pause via YouTube API.
+ """
+ self._execute_yt_script('arguments[1].wrappedJSObject.pauseVideo();')
+
+ def _player_measure_progress(self):
+ """
+ Determine player progress. Refreshes state.
+
+ :return: Playback progress in seconds via YouTube API with snapshots.
+ """
+ self._refresh_state()
+ initial = self._last_seen_player_state.player_current_time
+ sleep(1)
+ self._refresh_state()
+ return self._last_seen_player_state.player_current_time - initial
+
+ def _get_player_debug_dict(self):
+ text = self._execute_yt_script('return arguments[1].'
+ 'wrappedJSObject.getDebugText();')
+ if text:
+ try:
+ return loads(text)
+ except ValueError:
+ self.marionette.log('Error loading json: DebugText',
+ level='DEBUG')
+
+ def _execute_yt_script(self, script):
+ """
+ Execute JS script in content context with access to video element and
+ YouTube .html5-video-player element.
+
+ :param script: script to be executed.
+
+ :return: value returned by script
+ """
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ return self.marionette.execute_script(script,
+ script_args=[self.video,
+ self.player])
+
+ def _check_if_ad_ended(self):
+ self._refresh_state()
+ return self._last_seen_player_state.player_ad_ended
+
+ def process_ad(self):
+ """
+ Wait for this ad to finish. Refreshes state.
+ """
+ self._refresh_state()
+ if self._last_seen_player_state.player_ad_inactive:
+ return
+ ad_timeout = (self._search_ad_duration() or 30) + 5
+ wait = Wait(self, timeout=ad_timeout, interval=1)
+ try:
+ self.marionette.log('process_ad: waiting {} s for ad'
+ .format(ad_timeout))
+ verbose_until(wait,
+ self,
+ YouTubePuppeteer._check_if_ad_ended,
+ "Check if ad ended")
+ except TimeoutException:
+ self.marionette.log('Waiting for ad to end timed out',
+ level='WARNING')
+
+ def _search_ad_duration(self):
+ """
+ Try and determine ad duration. Refreshes state.
+
+ :return: ad duration in seconds, if currently displayed in player
+ """
+ self._refresh_state()
+ if not (self._last_seen_player_state.player_ad_playing or
+ self._player_measure_progress() == 0):
+ return None
+ if (self._last_seen_player_state.player_ad_playing and
+ self._last_seen_video_state.duration):
+ return self._last_seen_video_state.duration
+ selector = '.html5-video-player .videoAdUiAttribution'
+ wait = Wait(self.marionette, timeout=5)
+ try:
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ wait.until(expected.element_present(By.CSS_SELECTOR,
+ selector))
+ countdown = self.marionette.find_element(By.CSS_SELECTOR,
+ selector)
+ ad_time = self._time_pattern.search(countdown.text)
+ if ad_time:
+ ad_minutes = int(ad_time.group('minute'))
+ ad_seconds = int(ad_time.group('second'))
+ return 60 * ad_minutes + ad_seconds
+ except (TimeoutException, NoSuchElementException):
+ self.marionette.log('Could not obtain '
+ 'element: {}'.format(selector),
+ level='WARNING')
+ return None
+
+ def _player_stalled(self):
+ """
+ Checks if the player has stalled. Refreshes state.
+
+ :return: True if playback is not making progress for 4-9 seconds. This
+ excludes ad breaks. Note that the player might just be busy with
+ buffering due to a slow network.
+ """
+
+ # `current_time` stands still while ad is playing
+ def condition():
+ # no ad is playing and current_time stands still
+ return (not self._last_seen_player_state.player_ad_playing and
+ self._measure_progress() < 0.1 and
+ self._player_measure_progress() < 0.1 and
+ (self._last_seen_player_state.player_playing or
+ self._last_seen_player_state.player_buffering))
+
+ if condition():
+ sleep(2)
+ self._refresh_state()
+ if self._last_seen_player_state.player_buffering:
+ sleep(5)
+ self._refresh_state()
+ return condition()
+ else:
+ return False
+
+ @staticmethod
+ def _yt_state_named_tuple():
+ """
+ Create a named tuple class that can be used to store state snapshots
+ of the wrapped youtube player. The fields in the tuple should be used
+ as follows:
+
+ player_duration: the duration as fetched from the wrapped player.
+ player_current_time: the current playback time as fetched from the
+ wrapped player.
+ player_remaining_time: the remaining time as calculated based on the
+ puppeteers expected time and the players current time.
+ player_playback_quality: the playback quality as fetched from the
+ wrapped player. See:
+ https://developers.google.com/youtube/js_api_reference#Playback_quality
+ player_movie_id: the movie id fetched from the wrapped player.
+ player_movie_title: the title fetched from the wrapped player.
+ player_url: the self reported url fetched from the wrapped player.
+ player_state: the current state of playback as fetch from the wrapped
+ player. See:
+ https://developers.google.com/youtube/js_api_reference#Playback_status
+ player_unstarted, player_ended, player_playing, player_paused,
+ player_buffering, and player_cued: these are all shortcuts to the
+ player state, only one should be true at any time.
+ player_ad_state: as player_state, but reports for the current ad.
+ player_ad_state, player_ad_inactive, player_ad_playing, and
+ player_ad_ended: these are all shortcuts to the ad state, only one
+ should be true at any time.
+ player_breaks_count: the number of ads as fetched from the wrapped
+ player. This includes both played and unplayed ads, and includes
+ streaming ads as well as pop up ads.
+
+ :return: A 'player_state_info' named tuple class.
+ """
+ return namedtuple('player_state_info',
+ ['player_duration',
+ 'player_current_time',
+ 'player_remaining_time',
+ 'player_playback_quality',
+ 'player_movie_id',
+ 'player_movie_title',
+ 'player_url',
+ 'player_state',
+ 'player_unstarted',
+ 'player_ended',
+ 'player_playing',
+ 'player_paused',
+ 'player_buffering',
+ 'player_cued',
+ 'player_ad_state',
+ 'player_ad_inactive',
+ 'player_ad_playing',
+ 'player_ad_ended',
+ 'player_breaks_count'
+ ])
+
+ def _create_player_state_info(self, **player_state_info_kwargs):
+ """
+ Create an instance of the state info named tuple. This function
+ expects a dictionary containing the following keys:
+ player_duration, player_current_time, player_playback_quality,
+ player_movie_id, player_movie_title, player_url, player_state,
+ player_ad_state, and player_breaks_count.
+
+ For more information on the above keys and their values see
+ `_yt_state_named_tuple`.
+
+ :return: A named tuple 'yt_state_info', derived from arguments and
+ state information from the puppeteer.
+ """
+ player_state_info_kwargs['player_remaining_time'] = (
+ self.expected_duration -
+ player_state_info_kwargs['player_current_time'])
+ # Calculate player state convenience info
+ player_state = player_state_info_kwargs['player_state']
+ player_state_info_kwargs['player_unstarted'] = (
+ player_state == self._yt_player_state['UNSTARTED'])
+ player_state_info_kwargs['player_ended'] = (
+ player_state == self._yt_player_state['ENDED'])
+ player_state_info_kwargs['player_playing'] = (
+ player_state == self._yt_player_state['PLAYING'])
+ player_state_info_kwargs['player_paused'] = (
+ player_state == self._yt_player_state['PAUSED'])
+ player_state_info_kwargs['player_buffering'] = (
+ player_state == self._yt_player_state['BUFFERING'])
+ player_state_info_kwargs['player_cued'] = (
+ player_state == self._yt_player_state['CUED'])
+ # Calculate ad state convenience info
+ player_ad_state = player_state_info_kwargs['player_ad_state']
+ player_state_info_kwargs['player_ad_inactive'] = (
+ player_ad_state == self._yt_player_state['UNSTARTED'])
+ player_state_info_kwargs['player_ad_playing'] = (
+ player_ad_state == self._yt_player_state['PLAYING'])
+ player_state_info_kwargs['player_ad_ended'] = (
+ player_ad_state == self._yt_player_state['ENDED'])
+ # Create player snapshot
+ state_info = self._yt_state_named_tuple()
+ return state_info(**player_state_info_kwargs)
+
+ @property
+ def _fetch_state_script(self):
+ if not self._fetch_state_script_string:
+ self._fetch_state_script_string = (
+ self._video_var_script +
+ self._player_var_script +
+ 'return ['
+ 'baseURI,'
+ 'currentTime,'
+ 'duration,'
+ '[buffered.length, bufferedRanges],'
+ '[played.length, playedRanges],'
+ 'totalFrames,'
+ 'droppedFrames,'
+ 'corruptedFrames,'
+ 'player_duration,'
+ 'player_current_time,'
+ 'player_playback_quality,'
+ 'player_movie_id,'
+ 'player_movie_title,'
+ 'player_url,'
+ 'player_state,'
+ 'player_ad_state,'
+ 'player_breaks_count];')
+ return self._fetch_state_script_string
+
+ def _refresh_state(self):
+ """
+ Refresh the snapshot of the underlying video and player state. We do
+ this allin one so that the state doesn't change in between queries.
+
+ We also store information that can be derived from the snapshotted
+ information, such as lag. This is stored in the last seen state to
+ stress that it's based on the snapshot.
+ """
+ values = self._execute_yt_script(self._fetch_state_script)
+ video_keys = ['base_uri', 'current_time', 'duration',
+ 'raw_buffered_ranges', 'raw_played_ranges',
+ 'total_frames', 'dropped_frames', 'corrupted_frames']
+ player_keys = ['player_duration', 'player_current_time',
+ 'player_playback_quality', 'player_movie_id',
+ 'player_movie_title', 'player_url', 'player_state',
+ 'player_ad_state', 'player_breaks_count']
+ # Get video state
+ self._last_seen_video_state = (
+ self._create_video_state_info(**dict(
+ zip(video_keys, values[:len(video_keys)]))))
+ # Get player state
+ self._last_seen_player_state = (
+ self._create_player_state_info(**dict(
+ zip(player_keys, values[-len(player_keys):]))))
+
+ def mse_enabled(self):
+ """
+ Check if the video source indicates mse usage for current video.
+ Refreshes state.
+
+ :return: True if MSE is being used, False if not.
+ """
+ self._refresh_state()
+ return self._last_seen_video_state.video_src.startswith('blob')
+
+ def playback_started(self):
+ """
+ Check whether playback has started. Refreshes state.
+
+ :return: True if play back has started, False if not.
+ """
+ self._refresh_state()
+ # usually, ad is playing during initial buffering
+ if (self._last_seen_player_state.player_playing or
+ self._last_seen_player_state.player_buffering):
+ return True
+ if (self._last_seen_video_state.current_time > 0 or
+ self._last_seen_player_state.player_current_time > 0):
+ return True
+ return False
+
+ def playback_done(self):
+ """
+ Check whether playback is done. Refreshes state.
+
+ :return: True if play back has ended, False if not.
+ """
+ # in case ad plays at end of video
+ self._refresh_state()
+ if self._last_seen_player_state.player_ad_playing:
+ return False
+ return (self._last_seen_player_state.player_ended or
+ self._last_seen_player_state.player_remaining_time < 1)
+
+ def wait_for_almost_done(self, final_piece=120):
+ """
+ Allow the given video to play until only `final_piece` seconds remain,
+ skipping ads mid-way as much as possible.
+ `final_piece` should be short enough to not be interrupted by an ad.
+
+ Depending on the length of the video, check the ad status every 10-30
+ seconds, skip an active ad if possible.
+
+ This call refreshes state.
+
+ :param final_piece: The length in seconds of the desired remaining time
+ to wait until.
+ """
+ self._refresh_state()
+ rest = 10
+ duration = remaining_time = self.expected_duration
+ if duration < final_piece:
+ # video is short so don't attempt to skip more ads
+ return duration
+ elif duration > 600:
+ # for videos that are longer than 10 minutes
+ # wait longer between checks
+ rest = duration / 50
+
+ while remaining_time > final_piece:
+ if self._player_stalled():
+ if self._last_seen_player_state.player_buffering:
+ # fall back on timeout in 'wait' call that comes after this
+ # in test function
+ self.marionette.log('Buffering and no playback progress.')
+ break
+ else:
+ message = '\n'.join(['Playback stalled', str(self)])
+ raise VideoException(message)
+ if self._last_seen_player_state.player_breaks_count > 0:
+ self.process_ad()
+ if remaining_time > 1.5 * rest:
+ sleep(rest)
+ else:
+ sleep(rest / 2)
+ # TODO during an ad, remaining_time will be based on ad's current_time
+ # rather than current_time of target video
+ remaining_time = self._last_seen_player_state.player_remaining_time
+ return remaining_time
+
+ def __str__(self):
+ messages = [super(YouTubePuppeteer, self).__str__()]
+ if not self.player:
+ messages += ['\t.html5-media-player: None']
+ return '\n'.join(messages)
+ if not self._last_seen_player_state:
+ messages += ['\t.html5-media-player: No last seen state']
+ return '\n'.join(messages)
+ messages += ['.html5-media-player: {']
+ for field in self._last_seen_player_state._fields:
+ # For compatibility with different test environments we force ascii
+ field_ascii = (
+ unicode(getattr(self._last_seen_player_state, field))
+ .encode('ascii', 'replace'))
+ messages += [('\t{}: {}'.format(field, field_ascii))]
+ messages += '}'
+ return '\n'.join(messages)
diff --git a/dom/media/test/external/external_media_tests/playback/eme.ini b/dom/media/test/external/external_media_tests/playback/eme.ini
new file mode 100644
index 000000000..6f08919bf
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/playback/eme.ini
@@ -0,0 +1 @@
+[test_eme_playback.py]
diff --git a/dom/media/test/external/external_media_tests/playback/limiting_bandwidth.ini b/dom/media/test/external/external_media_tests/playback/limiting_bandwidth.ini
new file mode 100644
index 000000000..77c144d80
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/playback/limiting_bandwidth.ini
@@ -0,0 +1,2 @@
+[test_playback_limiting_bandwidth.py]
+[test_ultra_low_bandwidth.py]
diff --git a/dom/media/test/external/external_media_tests/playback/manifest.ini b/dom/media/test/external/external_media_tests/playback/manifest.ini
new file mode 100644
index 000000000..f7271cbfb
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/playback/manifest.ini
@@ -0,0 +1 @@
+[test_video_playback.py]
diff --git a/dom/media/test/external/external_media_tests/playback/netflix_limiting_bandwidth.ini b/dom/media/test/external/external_media_tests/playback/netflix_limiting_bandwidth.ini
new file mode 100644
index 000000000..dd0ce3601
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/playback/netflix_limiting_bandwidth.ini
@@ -0,0 +1 @@
+[test_eme_playback_limiting_bandwidth.py]
diff --git a/dom/media/test/external/external_media_tests/playback/test_eme_playback.py b/dom/media/test/external/external_media_tests/playback/test_eme_playback.py
new file mode 100644
index 000000000..9c7eb6725
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/playback/test_eme_playback.py
@@ -0,0 +1,18 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from external_media_harness.testcase import (
+ MediaTestCase,
+ VideoPlaybackTestsMixin,
+ EMESetupMixin
+)
+
+
+class TestEMEPlayback(MediaTestCase, VideoPlaybackTestsMixin, EMESetupMixin):
+
+ def setUp(self):
+ super(TestEMEPlayback, self).setUp()
+ self.check_eme_system()
+
+ # Tests are implemented in VideoPlaybackTestsMixin
diff --git a/dom/media/test/external/external_media_tests/playback/test_eme_playback_limiting_bandwidth.py b/dom/media/test/external/external_media_tests/playback/test_eme_playback_limiting_bandwidth.py
new file mode 100644
index 000000000..44cbb44f1
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/playback/test_eme_playback_limiting_bandwidth.py
@@ -0,0 +1,24 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from marionette_harness import BrowserMobProxyTestCaseMixin
+
+from external_media_harness.testcase import (
+ EMESetupMixin,
+ NetworkBandwidthTestCase,
+ NetworkBandwidthTestsMixin,
+)
+
+
+class TestEMEPlaybackLimitingBandwidth(NetworkBandwidthTestCase,
+ BrowserMobProxyTestCaseMixin,
+ NetworkBandwidthTestsMixin,
+ EMESetupMixin):
+
+
+ def setUp(self):
+ super(TestEMEPlaybackLimitingBandwidth, self).setUp()
+ self.check_eme_system()
+
+ # Tests in NetworkBandwidthTestsMixin
diff --git a/dom/media/test/external/external_media_tests/playback/test_full_playback.py b/dom/media/test/external/external_media_tests/playback/test_full_playback.py
new file mode 100644
index 000000000..0db504682
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/playback/test_full_playback.py
@@ -0,0 +1,25 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from marionette_harness import Marionette
+
+from external_media_harness.testcase import MediaTestCase
+from external_media_tests.media_utils.video_puppeteer import VideoPuppeteer
+
+
+class TestFullPlayback(MediaTestCase):
+ """ Test MSE playback in HTML5 video element.
+
+ These tests should pass on any site where a single video element plays
+ upon loading and is uninterrupted (by ads, for example). This will play
+ the full videos, so it could take a while depending on the videos playing.
+ It should be run much less frequently in automated systems.
+ """
+
+ def test_video_playback_full(self):
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ for url in self.video_urls:
+ video = VideoPuppeteer(self.marionette, url,
+ stall_wait_time=10)
+ self.run_playback(video)
diff --git a/dom/media/test/external/external_media_tests/playback/test_playback_limiting_bandwidth.py b/dom/media/test/external/external_media_tests/playback/test_playback_limiting_bandwidth.py
new file mode 100644
index 000000000..81f1e8a59
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/playback/test_playback_limiting_bandwidth.py
@@ -0,0 +1,17 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from marionette_harness import BrowserMobProxyTestCaseMixin
+
+from external_media_harness.testcase import (
+ NetworkBandwidthTestCase, NetworkBandwidthTestsMixin
+)
+
+
+class TestPlaybackLimitingBandwidth(NetworkBandwidthTestCase,
+ NetworkBandwidthTestsMixin,
+ BrowserMobProxyTestCaseMixin):
+
+ # Tests are in NetworkBandwidthTestsMixin
+ pass
diff --git a/dom/media/test/external/external_media_tests/playback/test_shaka_playback.py b/dom/media/test/external/external_media_tests/playback/test_shaka_playback.py
new file mode 100644
index 000000000..a2ecb4a2c
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/playback/test_shaka_playback.py
@@ -0,0 +1,42 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from marionette_harness import Marionette
+
+from external_media_harness.testcase import MediaTestCase
+from external_media_tests.media_utils.video_puppeteer import VideoPuppeteer
+
+
+class TestShakaPlayback(MediaTestCase):
+ """ Test Widevine playback in shaka-player
+
+ This test takes manifest URLs rather than URLs for pages with videos. These
+ manifests are loaded with shaka-player
+ """
+
+ def test_video_playback_partial(self):
+ """ Plays 60 seconds of the video from the manifest URLs given
+ """
+ shakaUrl = "http://shaka-player-demo.appspot.com"
+ self.marionette.set_pref('media.mediasource.webm.enabled', True)
+
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ for manifestUrl in self.video_urls:
+ vp = VideoPuppeteer(self.marionette,
+ shakaUrl,
+ stall_wait_time=10,
+ set_duration=60,
+ video_selector="video#video",
+ autostart=False)
+
+
+ manifestInput = self.marionette.find_element("id",
+ "manifestUrlInput")
+ manifestInput.clear()
+ manifestInput.send_keys(manifestUrl)
+ loadButton = self.marionette.find_element("id", "loadButton")
+ loadButton.click()
+
+ vp.start()
+ self.run_playback(vp)
diff --git a/dom/media/test/external/external_media_tests/playback/test_ultra_low_bandwidth.py b/dom/media/test/external/external_media_tests/playback/test_ultra_low_bandwidth.py
new file mode 100644
index 000000000..d49ff7d94
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/playback/test_ultra_low_bandwidth.py
@@ -0,0 +1,15 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from marionette_harness import BrowserMobProxyTestCaseMixin
+
+from external_media_harness.testcase import NetworkBandwidthTestCase
+
+
+class TestUltraLowBandwidth(NetworkBandwidthTestCase,
+ BrowserMobProxyTestCaseMixin):
+
+ def test_playback_limiting_bandwidth_160(self):
+ self.proxy.limits({'downstream_kbps': 160})
+ self.run_videos(timeout=120)
diff --git a/dom/media/test/external/external_media_tests/playback/test_video_playback.py b/dom/media/test/external/external_media_tests/playback/test_video_playback.py
new file mode 100644
index 000000000..b841ec08c
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/playback/test_video_playback.py
@@ -0,0 +1,15 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from external_media_harness.testcase import (
+ MediaTestCase,
+ VideoPlaybackTestsMixin
+)
+
+
+class TestVideoPlayback(MediaTestCase, VideoPlaybackTestsMixin):
+
+ # Tests are actually implemented in VideoPlaybackTestsMixin.
+
+ pass
diff --git a/dom/media/test/external/external_media_tests/playback/youtube/manifest.ini b/dom/media/test/external/external_media_tests/playback/youtube/manifest.ini
new file mode 100644
index 000000000..d9ad7eb19
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/playback/youtube/manifest.ini
@@ -0,0 +1 @@
+[test_basic_playback.py ]
diff --git a/dom/media/test/external/external_media_tests/playback/youtube/test_basic_playback.py b/dom/media/test/external/external_media_tests/playback/youtube/test_basic_playback.py
new file mode 100644
index 000000000..edd0afc5e
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/playback/youtube/test_basic_playback.py
@@ -0,0 +1,74 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from marionette_driver import Wait
+from marionette_driver.errors import TimeoutException
+from marionette_harness import Marionette
+
+from external_media_tests.utils import verbose_until
+from external_media_harness.testcase import MediaTestCase
+from external_media_tests.media_utils.video_puppeteer import VideoException
+from external_media_tests.media_utils.youtube_puppeteer import YouTubePuppeteer
+
+
+class TestBasicYouTubePlayback(MediaTestCase):
+ def test_mse_is_enabled_by_default(self):
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ youtube = YouTubePuppeteer(self.marionette, self.video_urls[0],
+ timeout=60)
+ wait = Wait(youtube,
+ timeout=min(300, youtube.expected_duration * 1.3),
+ interval=1)
+ try:
+ verbose_until(wait, youtube,
+ YouTubePuppeteer.mse_enabled,
+ "Failed to find 'blob' in video src url.")
+ except TimeoutException as e:
+ raise self.failureException(e)
+
+ def test_video_playing_in_one_tab(self):
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ for url in self.video_urls:
+ self.logger.info(url)
+ youtube = YouTubePuppeteer(self.marionette, url)
+ self.logger.info('Expected duration: {}'
+ .format(youtube.expected_duration))
+
+ final_piece = 60
+ try:
+ time_left = youtube.wait_for_almost_done(
+ final_piece=final_piece)
+ except VideoException as e:
+ raise self.failureException(e)
+ duration = abs(youtube.expected_duration) + 1
+ if duration > 1:
+ self.logger.info('Almost done: {} - {} seconds left.'
+ .format(url, time_left))
+ if time_left > final_piece:
+ self.marionette.log('time_left greater than '
+ 'final_piece - {}'
+ .format(time_left),
+ level='WARNING')
+ self.save_screenshot()
+ else:
+ self.marionette.log('Duration close to 0 - {}'
+ .format(youtube),
+ level='WARNING')
+ self.save_screenshot()
+ try:
+ verbose_until(Wait(youtube,
+ timeout=max(100, time_left) * 1.3,
+ interval=1),
+ youtube,
+ YouTubePuppeteer.playback_done)
+ except TimeoutException as e:
+ raise self.failureException(e)
+
+ def test_playback_starts(self):
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ for url in self.video_urls:
+ try:
+ YouTubePuppeteer(self.marionette, url, timeout=60)
+ except TimeoutException as e:
+ raise self.failureException(e)
diff --git a/dom/media/test/external/external_media_tests/playback/youtube/test_prefs.py b/dom/media/test/external/external_media_tests/playback/youtube/test_prefs.py
new file mode 100644
index 000000000..4c07ca008
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/playback/youtube/test_prefs.py
@@ -0,0 +1,46 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from external_media_harness.testcase import MediaTestCase
+from marionette_driver import Wait
+
+from external_media_tests.utils import verbose_until
+from external_media_tests.media_utils.youtube_puppeteer import YouTubePuppeteer
+
+
+class TestMediaSourcePrefs(MediaTestCase):
+ def setUp(self):
+ MediaTestCase.setUp(self)
+ self.test_urls = self.video_urls[:2]
+ self.max_timeout = 60
+
+ def tearDown(self):
+ MediaTestCase.tearDown(self)
+
+ def test_mse_prefs(self):
+ """ mediasource should only be used if MSE prefs are enabled."""
+ self.set_mse_enabled_prefs(False)
+ self.check_mse_src(False, self.test_urls[0])
+
+ self.set_mse_enabled_prefs(True)
+ self.check_mse_src(True, self.test_urls[0])
+
+ def set_mse_enabled_prefs(self, value):
+ with self.marionette.using_context('chrome'):
+ self.marionette.set_pref('media.mediasource.enabled', value)
+ self.marionette.set_pref('media.mediasource.mp4.enabled', value)
+ self.marionette.set_pref('media.mediasource.webm.enabled', value)
+
+ def check_mse_src(self, mse_expected, url):
+ with self.marionette.using_context('content'):
+ youtube = YouTubePuppeteer(self.marionette, url)
+ wait = Wait(youtube,
+ timeout=min(self.max_timeout,
+ youtube.expected_duration * 1.3),
+ interval=1)
+
+ def cond(y):
+ return y.mse_enabled == mse_expected
+
+ verbose_until(wait, youtube, cond)
diff --git a/dom/media/test/external/external_media_tests/resources/mozilla.html b/dom/media/test/external/external_media_tests/resources/mozilla.html
new file mode 100644
index 000000000..1cdf0fb4f
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/resources/mozilla.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html lang="en" dir="ltr">
+<head>
+ <title>Mozilla</title>
+ <link rel="shortcut icon" type="image/ico" href="../images/mozilla_favicon.ico" />
+</head>
+
+<body>
+ <a href="mozilla.html">
+ <img id="mozilla_logo" src="../images/mozilla_logo.jpg" />
+ </a>
+
+ <a href="#community">RARARARARARA</a> |
+ <a href="#project">Project</a> |
+ <a href="#organization">Organization</a>
+
+ <div id="content">
+ <h1 id="page-title">
+ <strong>RARARARARARA</strong> that the internet should be public,
+ open and accessible.
+ </h1>
+
+ <h2><a name="community">RARARARARARA</a></h2>
+ <p id="community">
+ We're a global community of thousands who believe in the power
+ of technology to enrich people's lives.
+ <a href="mozilla_community.html">More</a>
+ </p>
+
+ <h2><a name="project">Project</a></h2>
+ <p id="project">
+ We're an open source project whose code is used for some of the
+ Internet's most innovative applications.
+ <a href="mozilla_projects.html">More</a>
+ </p>
+
+ <h2><a name="organization">Organization</a></h2>
+ <p id="organization">
+ We're a public benefit organization dedicated to making the
+ Internet better for everyone.
+ <a href="mozilla_mission.html">More</a>
+ </p>
+ </div>
+</body>
+</html>
diff --git a/dom/media/test/external/external_media_tests/test_example.py b/dom/media/test/external/external_media_tests/test_example.py
new file mode 100644
index 000000000..99782014f
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/test_example.py
@@ -0,0 +1,21 @@
+from marionette_harness import Marionette
+
+from external_media_harness.testcase import MediaTestCase
+
+
+class TestSomethingElse(MediaTestCase):
+ def setUp(self):
+ MediaTestCase.setUp(self)
+ self.test_urls = [
+ 'mozilla.html',
+ ]
+ self.test_urls = [self.marionette.absolute_url(t)
+ for t in self.test_urls]
+
+ def tearDown(self):
+ MediaTestCase.tearDown(self)
+
+ def test_foo(self):
+ self.logger.info('foo!')
+ with self.marionette.using_context(Marionette.CONTEXT_CONTENT):
+ self.marionette.navigate(self.test_urls[0])
diff --git a/dom/media/test/external/external_media_tests/urls/default.ini b/dom/media/test/external/external_media_tests/urls/default.ini
new file mode 100644
index 000000000..b1e26abbd
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/urls/default.ini
@@ -0,0 +1,9 @@
+# short videos; no ads; embedded; max 5 minutes
+# 0:12
+[https://youtube.com/embed/AbAACm1IQE0?autoplay=1]
+# 2:18
+[https://youtube.com/embed/yOQQCoxs8-k?autoplay=1]
+# 0:08
+[https://youtube.com/embed/1visYpIREUM?autoplay=1]
+# 2:09
+[https://youtube.com/embed/rjmuKV9BTkE?autoplay=1]
diff --git a/dom/media/test/external/external_media_tests/urls/netflix/default.ini b/dom/media/test/external/external_media_tests/urls/netflix/default.ini
new file mode 100644
index 000000000..ed14b69b8
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/urls/netflix/default.ini
@@ -0,0 +1,8 @@
+# YouTube test
+#[https://www.youtube.com/watch?v=AbAACm1IQE0]
+# ClearKey - 11:07
+[http://www.netflix.com/watch/70136810]
+# NoDRM - 2:24:xx
+[http://www.netflix.com/watch/70304192]
+# DRM - 24:47
+[http://www.netflix.com/watch/80015538]
diff --git a/dom/media/test/external/external_media_tests/urls/shaka-player/default.ini b/dom/media/test/external/external_media_tests/urls/shaka-player/default.ini
new file mode 100644
index 000000000..8a42d7603
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/urls/shaka-player/default.ini
@@ -0,0 +1,30 @@
+# The Shaka-player tests take manifest URLs rather than URLs for a page that
+# plays a video (since shaka-player is the page that plays the video)
+# This file contains the manifest URLs that shaka-player provides in it's
+# dropdown
+
+# "Angel One" (TNG clip) - multilingual, subtitles, VP8
+[http://shaka-player-demo.appspot.com/assets/angel_one.mpd]
+# "Car" (YT DASH test) - MP4
+[http://shaka-player-demo.appspot.com/assets/car-20120827-manifest.mpd]
+# "Car/CENC" (YT DASH EME test) - MP4, ClearKey
+[http://shaka-player-demo.appspot.com/assets/car_cenc-20120827-manifest.mpd]
+# "Feelings" (YT DASH test) - VP9
+[http://shaka-player-demo.appspot.com/assets/feelings_vp9-20130806-manifest.mpd]
+# "Feelings" (YT DASH test) - Audio only
+[http://shaka-player-demo.appspot.com/assets/feelings_audio_only-20130806-manifest.mpd]
+# "Car/SegmentTemplate" (Chromecast test) - MP4 (no SIDX, video only), Widevine
+[http://shaka-player-demo.appspot.com/assets/car_segmenttemplate.mpd]
+# "GPAC/SegmentList" (conformance test)
+[http://download.tsi.telecom-paristech.fr/gpac/DASH_CONFORMANCE/TelecomParisTech/mp4-main-multi/mp4-main-multi-mpd-AV-NBS.mpd]
+# "Oops" (modified YT DASH EME test) - MP4, multi-DRM
+[http://shaka-player-demo.appspot.com/assets/oops_cenc-20121114-signedlicenseurl-manifest.mpd]
+# "Oops" (modified YT DASH EME test) - MP4, Widevine, PSSH in MPD
+# This stream currently does not load
+#[http://shaka-player-demo.appspot.com/assets/oops_cenc_pssh.mpd]
+# "Sintel" (1080p high bitrate test) - MP4
+[http://storage.googleapis.com/widevine-demo-media/sintel-1080p/dash.mpd]
+# "Sintel" (4k) - MP4, VP8, VP9
+[http://storage.googleapis.com/widevine-demo-media/sintel-multicodec-4k/dash.mpd]
+# "Sintel" (4k) - MP4, Widevine
+[http://storage.googleapis.com/widevine-demo-media/sintel-4k-widevine/sintel.mpd]
diff --git a/dom/media/test/external/external_media_tests/urls/youtube/archive/crash_videos.ini b/dom/media/test/external/external_media_tests/urls/youtube/archive/crash_videos.ini
new file mode 100644
index 000000000..e7d420254
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/urls/youtube/archive/crash_videos.ini
@@ -0,0 +1,25 @@
+[https://www.youtube.com/watch?v=2GfaRuIMdos]
+[https://www.youtube.com/watch?v=9vKvcCNt40g]
+[https://www.youtube.com/watch?v=SHLLHya2pNo]
+[https://www.youtube.com/watch?v=isMEMDE2enU]
+[https://www.youtube.com/watch?v=H81M_MebLsk]
+[https://www.youtube.com/watch?v=yopNkcDzQQw]
+[https://www.youtube.com/watch?v=r_bG5beSqw0]
+[https://www.youtube.com/watch?v=Ki9sSZKClO0]
+[https://www.youtube.com/watch?v=gNS04P8djk4]
+[https://www.youtube.com/watch?v=DwC_6fIBW0w]
+[https://www.youtube.com/watch?v=g1D3A14o0NA]
+[https://www.youtube.com/watch?v=cs-XZ_dN4Hc]
+[https://www.youtube.com/watch?v=ZEWZ3AAH98c]
+[https://www.youtube.com/watch?v=hwbVGE4GBJI]
+[https://www.youtube.com/watch?v=cvcMnbkasIs]
+[https://www.youtube.com/watch?v=cHaBuoHwQ0Y]
+[https://www.youtube.com/watch?v=VKIYoAG9MZ0]
+[https://www.youtube.com/watch?v=WWDb2_unEJc]
+[https://www.youtube.com/watch?v=ybw5zonQffE]
+[https://www.youtube.com/watch?v=hS6ps2Xph_o]
+[https://www.youtube.com/watch?v=Bjb3xhgIqv4]
+[https://www.youtube.com/watch?v=fOzvEhX4Kvk]
+[https://www.youtube.com/watch?v=_TNsUxp_BxM]
+[https://www.youtube.com/watch?v=QRdwCSHF3oo]
+[https://www.youtube.com/watch?v=VwaHFcKJSYA]
diff --git a/dom/media/test/external/external_media_tests/urls/youtube/archive/other_videos.ini b/dom/media/test/external/external_media_tests/urls/youtube/archive/other_videos.ini
new file mode 100644
index 000000000..732d2405c
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/urls/youtube/archive/other_videos.ini
@@ -0,0 +1,19 @@
+# backlog of videos
+[http://youtu.be/2iVAvSnofy8]
+
+# 300s <= duration <= 1200s (5-20min)
+[http://youtu.be/9bZkp7q19f0]
+[http://youtu.be/KQ6zr6kCPj8]
+
+# duration > 1200s (>20min)
+[http://youtu.be/wZZ7oFKsKzY]
+[http://youtu.be/eHUrC_UiZwY]
+[http://youtu.be/FLX64H5FYa8]
+[http://youtu.be/Fu2DcHzokew]
+
+#no_ad_tests_youtube
+#[http://youtu.be/pWI8RB2dmfU]
+#[http://youtu.be/6GBtEmtVObw]
+
+#playlist_tests_youtube
+#[http://youtu.be/R6KJjPqlPz4?list=PL75_HhpYGJQ1Fzv9a46FlHfiy-fJusKBZ]
diff --git a/dom/media/test/external/external_media_tests/urls/youtube/archive/video_data.ini b/dom/media/test/external/external_media_tests/urls/youtube/archive/video_data.ini
new file mode 100644
index 000000000..ff8f58866
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/urls/youtube/archive/video_data.ini
@@ -0,0 +1,21 @@
+# duration < 300s (5min)
+[http://youtu.be/065dlrJoHcw]
+[http://youtu.be/1visYpIREUM]
+[http://youtu.be/mDf7CR5QKcE]
+[http://youtu.be/Aebs62bX0dA]
+[http://youtu.be/6SFp1z7uA6g]
+[http://youtu.be/tDDVAErOI5U]
+
+# ad testing
+[https://www.youtube.com/watch?v=l5ODwR6FPRQ]
+[https://www.youtube.com/watch?v=7RMQksXpQSk]
+
+# duration > 5 min
+# video with ad in the middle
+[https://www.youtube.com/watch?v=cht9Xq9suGg]
+
+# long video (>30 min), no ads
+[https://www.youtube.com/watch?v=-qXxNPvqHtQ]
+
+# bug 1144172, duration ~ 1hr
+#[https://www.youtube.com/watch?v=AYYDshv8C4g]
diff --git a/dom/media/test/external/external_media_tests/urls/youtube/archive/youtube.ini b/dom/media/test/external/external_media_tests/urls/youtube/archive/youtube.ini
new file mode 100644
index 000000000..0676b9ef4
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/urls/youtube/archive/youtube.ini
@@ -0,0 +1,38 @@
+# < 1 no ads
+[https://youtu.be/AbAACm1IQE0]
+[https://www.youtube.com/watch?v=KdHZwWQWNyM]
+[https://www.youtube.com/watch?v=-hVmkA_I9EE]
+[https://www.youtube.com/watch?v=1visYpIREUM]
+
+# 1 < t <= 5 no ads
+[https://www.youtube.com/watch?v=rpYRAs6ePY8]
+[https://www.youtube.com/watch?v=xcgUKzwg0Mo]
+[https://youtu.be/sEAT2EFIJow]
+[https://www.youtube.com/watch?v=SSgnbQ5UC48]
+[https://youtu.be/4oQu26IhiaA]
+[https://youtu.be/IbND63HOb0M]
+[https://youtu.be/-9sJp9wrdAk]
+[https://www.youtube.com/watch?v=yIQGH4aQWI0]
+
+# 1 < t <= 5
+[https://www.youtube.com/watch?v=-hVmkA_I9EE]
+[https://www.youtube.com/watch?v=l5ODwR6FPRQ]
+[https://www.youtube.com/watch?v=7RMQksXpQSk]
+[https://www.youtube.com/watch?v=TsXMe8H6iyc]
+[https://www.youtube.com/watch?v=tDDVAErOI5U]
+
+# 5 < t <= 10
+[https://youtu.be/Tl-hI2IsCo0] # no ad
+[https://www.youtube.com/watch?v=IX_d_vMKswE] #no ad
+[https://www.youtube.com/watch?v=YVQeTY-Ayko] #no ad
+[https://www.youtube.com/watch?v=rE3j_RHkqJc]
+[https://www.youtube.com/watch?v=l4bmZ1gRqCc]
+
+# 10 < t <= 30
+[https://www.youtube.com/watch?v=RvymAHt3nPc] # no ads
+[https://www.youtube.com/watch?v=8XQ1onjXJK0]
+[https://www.youtube.com/watch?v=6Lm9EHhbJAY]
+[https://www.youtube.com/watch?v=cht9Xq9suGg]
+
+# long video (>30 min), no ads
+[https://www.youtube.com/watch?v=-qXxNPvqHtQ]
diff --git a/dom/media/test/external/external_media_tests/urls/youtube/long1-720.ini b/dom/media/test/external/external_media_tests/urls/youtube/long1-720.ini
new file mode 100644
index 000000000..cabb823b1
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/urls/youtube/long1-720.ini
@@ -0,0 +1,5 @@
+# a couple of very long videos, < 12 hours total
+# 6:00:00 - can't embed due to copyright
+[https://www.youtube.com/watch?v=5N8sUccRiTA]
+# 2:09:00
+[https://www.youtube.com/embed/b6q5N16dje4?autoplay=1]
diff --git a/dom/media/test/external/external_media_tests/urls/youtube/long2-crashes-720.ini b/dom/media/test/external/external_media_tests/urls/youtube/long2-crashes-720.ini
new file mode 100644
index 000000000..de449f882
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/urls/youtube/long2-crashes-720.ini
@@ -0,0 +1,39 @@
+# It appears these are not currently used by tests. They are left here as they
+# reference failure scenarios. If tese are fixed that can be removed.
+
+# videos from crashes, < 12 hours
+
+# hang | NtUserMessageCall | SendMessageW
+# 1:10:00
+[https://www.youtube.com/watch?v=Ztie4DqeOak]
+
+# nsPluginInstanceOwner::GetDocument(nsIDocument**)
+# 22:40
+[https://www.youtube.com/watch?v=D4cLM_JRrAU]
+# 16:47
+[https://www.youtube.com/watch?v=3C2r05Lxsrk]
+
+# F1398665248_____________________________
+# 1:06:00
+[https://www.youtube.com/watch?v=59gTMBss8o0]
+# 50:58
+[https://www.youtube.com/watch?v=_7VFIZhR744]
+# 44:54
+[https://www.youtube.com/watch?v=d6ro4Oq5msA]
+
+# hang | WaitForMultipleObjectsEx | RealMsgWaitForMultipleObjectsEx | MsgWaitForMultipleObjects | F_1152915508___________________________________
+#1:07:12
+[https://www.youtube.com/watch?v=Ffkf3tosmKw]
+# 1:02:00
+[https://www.youtube.com/watch?v=dC3AHEao2MI]
+
+# hang | BaseGetNamedObjectDirectory | RealMsgWaitForMultipleObjectsEx | MsgWaitForMultipleObjects | F_1152915508___________________________________
+# 10:00
+[https://www.youtube.com/watch?v=fn3Qb56ujNQ]
+# 5:00
+[https://www.youtube.com/watch?v=gBsh1bT8ltI]
+# 03:50:12
+[https://www.youtube.com/watch?v=TdW4S8zbmJQ]
+
+
+
diff --git a/dom/media/test/external/external_media_tests/urls/youtube/long3-crashes-900.ini b/dom/media/test/external/external_media_tests/urls/youtube/long3-crashes-900.ini
new file mode 100644
index 000000000..70081b986
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/urls/youtube/long3-crashes-900.ini
@@ -0,0 +1,86 @@
+# It appears these are not currently used by tests. They are left here as they
+# reference failure scenarios. If tese are fixed that can be removed.
+
+# Total time: about 12-13 hours + unskippable ads
+#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=50&platform=Windows&version=37.0&date=%3E2015-03-26
+
+#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3Dhang+%7C+NtUserMessageCall+%7C+SendMessageW&date=%3E2015-03-26
+
+#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3DOOM+%7C+small&date=%3E2015-03-26
+
+#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3Dmozilla%3A%3Alayers%3A%3ACompositorD3D11%3A%3AHandleError%28long%2C+mozilla%3A%3Alayers%3A%3ACompositorD3D11%3A%3ASeverity%29+%7C+mozilla%3A%3Alayers%3A%3ACompositorD3D11%3A%3AFailed%28long%2C+mozilla%3A%3Alayers%3A%3ACompositorD3D11%3A%3ASeverity%29+%7C+mozilla%3A%3Alayers%3A%3ACompositorD3D11%3A%3AUpdateRenderTarget%28%29&date=%3E2015-03-26
+
+#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3DOOM+%7C+large+%7C+mozalloc_abort%28char+const%2A+const%29+%7C+mozalloc_handle_oom%28unsigned+int%29+%7C+moz_xmalloc+%7C+nsTArray_base%3CnsTArrayInfallibleAllocator%2C+nsTArray_CopyWithMemutils%3E%3A%3AEnsureCapacity%28unsigned+int%2C+unsigned+int%29+%7C+nsTArray_base%3CnsTArrayInfallibleAllo...&date=%3E2015-03-26
+
+#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3Dshutdownhang+%7C+WaitForSingleObjectEx+%7C+WaitForSingleObject+%7C+PR_Wait+%7C+nsThread%3A%3AProcessNextEvent%28bool%2C+bool%2A%29+%7C+NS_ProcessNextEvent%28nsIThread%2A%2C+bool%29+%7C+mozilla%3A%3AMediaShutdownManager%3A%3AShutdown%28%29&date=%3E2015-03-26
+
+#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3Dmozilla%3A%3Alayers%3A%3ACompositorD3D11%3A%3AUpdateConstantBuffers%28%29&date=%3E2015-03-26
+
+#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3Dmsvcr120.dll%400xf20c&date=%3E2015-03-26
+
+#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3Djs%3A%3AGCMarker%3A%3AprocessMarkStackTop%28js%3A%3ASliceBudget%26%29&date=%3E2015-03-26
+
+#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3Dshutdownhang+%7C+WaitForSingleObjectEx+%7C+WaitForSingleObject+%7C+PR_Wait+%7C+nsThread%3A%3AProcessNextEvent%28bool%2C+bool%2A%29+%7C+NS_ProcessNextEvent%28nsIThread%2A%2C+bool%29+%7C+mozilla%3A%3Alayers%3A%3ACompositorParent%3A%3AShutDown%28%29&date=%3E2015-03-26
+
+#Request url: https://crash-stats.mozilla.com/api/SuperSearchUnredacted/?product=Firefox&url=%24https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D&url=%21~list&url=%21~index&_results_number=5&platform=Windows&version=37.0&signature=%3Dshutdownhang+%7C+WaitForSingleObjectEx+%7C+WaitForSingleObject+%7C+PR_Wait+%7C+mozilla%3A%3AReentrantMonitor%3A%3AWait%28unsigned+int%29+%7C+mozilla%3A%3Alayers%3A%3AImageBridgeChild%3A%3AShutDown%28%29&date=%3E2015-03-26
+
+# shutdownhang | WaitForSingleObjectEx | WaitForSingleObject | PR_Wait | nsThread::ProcessNextEvent(bool, bool*) | NS_ProcessNextEvent(nsIThread*, bool) | mozilla::MediaShutdownManager::Shutdown()
+[https://www.youtube.com/watch?v=PnwS01Yu9bs]
+[https://www.youtube.com/watch?v=6hNOMhEqI9g]
+[https://www.youtube.com/watch?v=gK9eCjYEwH4]
+#[https://www.youtube.com/watch?v=E9DFupLEV7c] Geographic restriction
+[https://www.youtube.com/watch?v=sLEVm0OGImU]
+# hang | NtUserMessageCall | SendMessageW
+[https://www.youtube.com/watch?v=kt0g4dWxEBo]
+[https://www.youtube.com/watch?v=cvwMS6UmesQ]
+[https://www.youtube.com/watch?v=Bj3YSTu3jUs]
+[https://www.youtube.com/watch?v=J9bgaoXLbFI]
+[https://www.youtube.com/watch?v=d5GUd6IElIw]
+# shutdownhang | WaitForSingleObjectEx | WaitForSingleObject | PR_Wait | mozilla::ReentrantMonitor::Wait(unsigned int) | mozilla::layers::ImageBridgeChild::ShutDown()
+[https://www.youtube.com/watch?v=6FMNFvKEy4c]
+[https://www.youtube.com/watch?v=w4RNIyJw9RI]
+#[https://www.youtube.com/watch?v=tKB5S1yp5MA] Account terminated
+[https://www.youtube.com/watch?v=Tct2Iv1QRUU]
+[https://www.youtube.com/watch?v=zDHOW9PdQYE]
+# shutdownhang | WaitForSingleObjectEx | WaitForSingleObject | PR_Wait | nsThread::ProcessNextEvent(bool, bool*) | NS_ProcessNextEvent(nsIThread*, bool) | mozilla::layers::CompositorParent::ShutDown()
+[https://www.youtube.com/watch?v=AGo24nC3_HU]
+[https://www.youtube.com/watch?v=GsVaCnud57U]
+[https://www.youtube.com/watch?v=zFg55zva7ok]
+#[https://www.youtube.com/watch?v=5VSk7bwPPOM] Policy violation
+[https://www.youtube.com/watch?v=2OYa5kR5EQ4]
+# OOM | large | mozalloc_abort(char const* const) | mozalloc_handle_oom(unsigned int) | moz_xmalloc | nsTArray_base<nsTArrayInfallibleAllocator, nsTArray_CopyWithMemutils>::EnsureCapacity(unsigned int, unsigned int) | nsTArray_base<nsTArrayInfallibleAllo...
+#[https://www.youtube.com/watch?v=1g91CAubt1c] Policy violation
+[https://www.youtube.com/watch?v=HE_7UFHPfQ0]
+# [https://www.youtube.com/watch?v=vhrM1JXG8-k] Live stream, Flash only
+[https://www.youtube.com/watch?v=ERWFf0JS94E]
+#[https://www.youtube.com/watch?v=8tmiawwVreE] Age restriction
+# mozilla::layers::CompositorD3D11::UpdateConstantBuffers()
+[https://www.youtube.com/watch?v=7azYa518LvE]
+[https://www.youtube.com/watch?v=Zg5JvdXHUqg]
+[https://www.youtube.com/watch?v=Q_kcoEY2wNw]
+[https://www.youtube.com/watch?v=eNzUJa0WjfU]
+[https://www.youtube.com/watch?v=B5V12xYb7hE]
+# OOM | small
+[https://www.youtube.com/watch?v=TS9Z8dN4OPo]
+[https://www.youtube.com/watch?v=EpngdStzhmQ]
+[https://www.youtube.com/watch?v=dUiDCX3BnM0]
+[https://www.youtube.com/watch?v=Ii4Su6Z8pCw]
+[https://www.youtube.com/watch?v=vviBJS6WQno]
+# msvcr120.dll@0xf20c
+[https://www.youtube.com/watch?v=hRE2VO9oa_g]
+[https://www.youtube.com/watch?v=qLL8VanC3zI]
+[https://www.youtube.com/watch?v=YX2LIztg2EI]
+[https://www.youtube.com/watch?v=-7Eh28eatBo]
+[https://www.youtube.com/watch?v=a32AMX55sZM]
+# js::GCMarker::processMarkStackTop(js::SliceBudget&)
+[https://www.youtube.com/watch?v=f0L2RzygE5k]
+[https://www.youtube.com/watch?v=-1RGIDgwHgM]
+[https://www.youtube.com/watch?v=iL1CEn7SQfQ]
+[https://www.youtube.com/watch?v=450p7goxZqg]
+[https://www.youtube.com/watch?v=Eo8c2sZ2eOY]
+# mozilla::layers::CompositorD3D11::HandleError(long, mozilla::layers::CompositorD3D11::Severity) | mozilla::layers::CompositorD3D11::Failed(long, mozilla::layers::CompositorD3D11::Severity) | mozilla::layers::CompositorD3D11::UpdateRenderTarget()
+[https://www.youtube.com/watch?v=a79R7bPhVhw]
+[https://www.youtube.com/watch?v=JRNCgvZs5v4]
+[https://www.youtube.com/watch?v=q8y58dWKfY8]
+[https://www.youtube.com/watch?v=Ns9M6sUvqxs]
+[https://www.youtube.com/watch?v=Ii-PCeTgR-A]
diff --git a/dom/media/test/external/external_media_tests/urls/youtube/medium1-60.ini b/dom/media/test/external/external_media_tests/urls/youtube/medium1-60.ini
new file mode 100644
index 000000000..65ccef11a
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/urls/youtube/medium1-60.ini
@@ -0,0 +1,18 @@
+# mix of shorter/longer videos with/without ads, < 60 min
+# 4:59 - can't embed
+[https://www.youtube.com/watch?v=pWI8RB2dmfU]
+# 0:46 ad at start
+[https://www.youtube.com/embed/6SFp1z7uA6g?autoplay=1]
+# 0:58 ad at start
+[https://www.youtube.com/embed/Aebs62bX0dA?autoplay=1]
+# 1:43 ad
+[https://www.youtube.com/embed/l5ODwR6FPRQ?autoplay=1]
+# 8:00 ad - can't embed
+[https://www.youtube.com/watch?v=KlyXNRrsk4A]
+# video with ad in beginning and in the middle 20:00
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1176815
+[https://www.youtube.com/embed/cht9Xq9suGg?autoplay=1]
+# 1:35 ad
+[https://www.youtube.com/embed/orybDrUj4vA?autoplay=1]
+# 3:02 ad
+[https://www.youtube.com/embed/tDDVAErOI5U?autoplay=1]
diff --git a/dom/media/test/external/external_media_tests/urls/youtube/short1-10.ini b/dom/media/test/external/external_media_tests/urls/youtube/short1-10.ini
new file mode 100644
index 000000000..a8b4016dc
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/urls/youtube/short1-10.ini
@@ -0,0 +1,13 @@
+# short videos; no ads; max 10 minutes
+# 0:12
+[https://youtu.be/AbAACm1IQE0]
+# 0:30
+[https://www.youtube.com/watch?v=KdHZwWQWNyM]
+# 0:08
+[https://www.youtube.com/watch?v=1visYpIREUM]
+# 3:27
+[https://www.youtube.com/watch?v=xcgUKzwg0Mo]
+# 1:21
+[https://youtu.be/sEAT2EFIJow]
+# 1:23
+[https://www.youtube.com/watch?v=SSgnbQ5UC48]
diff --git a/dom/media/test/external/external_media_tests/urls/youtube/short2-crashes-15.ini b/dom/media/test/external/external_media_tests/urls/youtube/short2-crashes-15.ini
new file mode 100644
index 000000000..bfcba4101
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/urls/youtube/short2-crashes-15.ini
@@ -0,0 +1,17 @@
+# It appears these are not currently used by tests. They are left here as they
+# reference failure scenarios. If tese are fixed that can be removed.
+
+# crash-data videos, < 15 minutes total
+
+# hang | NtUserMessageCall | SendMessageW
+# 5:40
+[https://www.youtube.com/watch?v=UIobdRNLNek]
+
+# F1398665248_____________________________
+# 3:59
+[https://www.youtube.com/watch?v=XGotQYd-X6o]
+
+# hang | WaitForMultipleObjectsEx | RealMsgWaitForMultipleObjectsEx | MsgWaitForMultipleObjects | F_1152915508___________________________________
+# 4:07
+[https://www.youtube.com/watch?v=wQgppPHXJSs]
+
diff --git a/dom/media/test/external/external_media_tests/utils.py b/dom/media/test/external/external_media_tests/utils.py
new file mode 100644
index 000000000..4ac0d5f62
--- /dev/null
+++ b/dom/media/test/external/external_media_tests/utils.py
@@ -0,0 +1,68 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import datetime
+import time
+import types
+
+from marionette_driver.errors import TimeoutException
+
+
+def timestamp_now():
+ return int(time.mktime(datetime.datetime.now().timetuple()))
+
+
+def verbose_until(wait, target, condition, message=""):
+ """
+ Performs a `wait`.until(condition)` and adds information about the state of
+ `target` to any resulting `TimeoutException`.
+
+ :param wait: a `marionette.Wait` instance
+ :param target: the object you want verbose output about if a
+ `TimeoutException` is raised
+ This is usually the input value provided to the `condition` used by
+ `wait`. Ideally, `target` should implement `__str__`
+ :param condition: callable function used by `wait.until()`
+ :param message: optional message to log when exception occurs
+
+ :return: the result of `wait.until(condition)`
+ """
+ if isinstance(condition, types.FunctionType):
+ name = condition.__name__
+ else:
+ name = str(condition)
+ err_message = '\n'.join([message,
+ 'condition: ' + name,
+ str(target)])
+
+ return wait.until(condition, message=err_message)
+
+
+
+def save_memory_report(marionette):
+ """
+ Saves memory report (like about:memory) to current working directory.
+
+ :param marionette: Marionette instance to use for executing.
+ """
+ with marionette.using_context('chrome'):
+ marionette.execute_async_script("""
+ Components.utils.import("resource://gre/modules/Services.jsm");
+ let Cc = Components.classes;
+ let Ci = Components.interfaces;
+ let dumper = Cc["@mozilla.org/memory-info-dumper;1"].
+ getService(Ci.nsIMemoryInfoDumper);
+ // Examples of dirs: "CurProcD" usually 'browser' dir in
+ // current FF dir; "DfltDwnld" default download dir
+ let file = Services.dirsvc.get("CurProcD", Ci.nsIFile);
+ file.append("media-memory-report");
+ file.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0777);
+ file.append("media-memory-report.json.gz");
+ dumper.dumpMemoryReportsToNamedFile(file.path, null, null, false);
+ log('Saved memory report to ' + file.path);
+ // for dmd-enabled build
+ dumper.dumpMemoryInfoToTempDir("media", false, false);
+ marionetteScriptFinished(true);
+ return;
+ """, script_timeout=30000)
diff --git a/dom/media/test/external/mach_commands.py b/dom/media/test/external/mach_commands.py
new file mode 100644
index 000000000..e309f3c55
--- /dev/null
+++ b/dom/media/test/external/mach_commands.py
@@ -0,0 +1,74 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import absolute_import, unicode_literals
+
+import os
+import sys
+
+from mozbuild.base import (
+ MachCommandBase,
+ MachCommandConditions as conditions,
+)
+
+from mach.decorators import (
+ CommandProvider,
+ Command,
+)
+
+def setup_argument_parser():
+ from external_media_harness.runtests import MediaTestArguments
+ from mozlog.structured import commandline
+ parser = MediaTestArguments()
+ commandline.add_logging_group(parser)
+ return parser
+
+
+def run_external_media_test(tests, testtype=None, topsrcdir=None, **kwargs):
+ from external_media_harness.runtests import (
+ FirefoxMediaHarness,
+ MediaTestArguments,
+ MediaTestRunner,
+ mn_cli,
+ )
+
+ from mozlog.structured import commandline
+
+ from argparse import Namespace
+
+ parser = setup_argument_parser()
+
+ if not tests:
+ tests = [os.path.join(topsrcdir,
+ 'dom/media/test/external/external_media_tests/manifest.ini')]
+
+ args = Namespace(tests=tests)
+
+ for k, v in kwargs.iteritems():
+ setattr(args, k, v)
+
+ parser.verify_usage(args)
+
+ args.logger = commandline.setup_logging("Firefox External Media Tests",
+ args,
+ {"mach": sys.stdout})
+ failed = mn_cli(MediaTestRunner, MediaTestArguments, FirefoxMediaHarness,
+ args=vars(args))
+
+ if failed > 0:
+ return 1
+ else:
+ return 0
+
+
+@CommandProvider
+class MachCommands(MachCommandBase):
+ @Command('external-media-tests', category='testing',
+ description='Run Firefox external media tests.',
+ conditions=[conditions.is_firefox],
+ parser=setup_argument_parser,
+ )
+ def run_external_media_test(self, tests, **kwargs):
+ kwargs['binary'] = kwargs['binary'] or self.get_binary_path('app')
+ return run_external_media_test(tests, topsrcdir=self.topsrcdir, **kwargs)
diff --git a/dom/media/test/external/requirements-docs.txt b/dom/media/test/external/requirements-docs.txt
new file mode 100644
index 000000000..a5109fff1
--- /dev/null
+++ b/dom/media/test/external/requirements-docs.txt
@@ -0,0 +1,5 @@
+sphinx
+sphinx-rtd-theme
+
+-e dom/media/test/external
+
diff --git a/dom/media/test/external/requirements.txt b/dom/media/test/external/requirements.txt
new file mode 100644
index 000000000..07133ca9f
--- /dev/null
+++ b/dom/media/test/external/requirements.txt
@@ -0,0 +1,5 @@
+firefox-puppeteer >= 52.1.0, <53.0.0
+manifestparser==1.1
+marionette-driver==2.2.0
+marionette-harness==4.0.0
+mozlog==3.3
diff --git a/dom/media/test/external/setup.py b/dom/media/test/external/setup.py
new file mode 100644
index 000000000..8520f9c8a
--- /dev/null
+++ b/dom/media/test/external/setup.py
@@ -0,0 +1,42 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+from setuptools import setup, find_packages
+
+PACKAGE_VERSION = '2.1'
+
+THIS_DIR = os.path.dirname(os.path.realpath(__name__))
+
+
+def read(*parts):
+ with open(os.path.join(THIS_DIR, *parts)) as f:
+ return f.read()
+
+setup(name='external-media-tests',
+ version=PACKAGE_VERSION,
+ description=('A collection of Mozilla Firefox media playback tests run '
+ 'with Marionette'),
+ classifiers=[
+ 'Environment :: Console',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)',
+ 'Natural Language :: English',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Topic :: Software Development :: Libraries :: Python Modules',
+ ],
+ keywords='mozilla',
+ author='Mozilla Automation and Tools Team',
+ author_email='tools@lists.mozilla.org',
+ url='https://hg.mozilla.org/mozilla-central/dom/media/test/external/',
+ license='MPL 2.0',
+ packages=find_packages(),
+ zip_safe=False,
+ install_requires=read('requirements.txt').splitlines(),
+ include_package_data=True,
+ entry_points="""
+ [console_scripts]
+ external-media-tests = external_media_harness:cli
+ """)
diff --git a/dom/media/test/file_access_controls.html b/dom/media/test/file_access_controls.html
new file mode 100644
index 000000000..ae55154c0
--- /dev/null
+++ b/dom/media/test/file_access_controls.html
@@ -0,0 +1,156 @@
+<html>
+<head>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body onload="setTimeout(load, 0);" onunload="done()">
+<script>
+
+// Page URL: http://example.org/tests/dom/media/test/file_access_controls.html
+
+var gResource = getPlayableVideo(gSmallTests).name;
+
+var gTests = [
+ {
+ // Test 0
+ url: "redirect.sjs?domain=example.com&file="+ gResource,
+ result: "error",
+ description: "Won't load when redirected to different domain",
+ },{
+ // Test 1
+ url: "redirect.sjs?domain=example.com&allowed&file=" + gResource,
+ result: "loadeddata",
+ description: "Can load when redirected to different domain with allow-origin",
+ },{
+ // Test 2
+ url: "redirect.sjs?domain=test1.example.org&file=" + gResource,
+ result: "error",
+ description: "Won't load when redirected to subdomain",
+ },{
+ // Test 3
+ url: "redirect.sjs?domain=test1.example.org&allowed&file=" + gResource,
+ result: "loadeddata",
+ description: "Can load when redirected to subdomain with allow-origin",
+ },{
+ // Test 4
+ url: "redirect.sjs?domain=example.org&file=" + gResource,
+ result: "loadeddata",
+ description: "Can load when redirected to same domain",
+ },{
+ // Test 5
+ url: "http://example.org/tests/dom/media/test/" + gResource,
+ result: "loadeddata",
+ description: "Can load from same domain"
+ },{
+ // Test 6
+ url: "http://example.org:8000/tests/dom/media/test/" + gResource,
+ result: "error",
+ description: "Won't load from different port on same domain"
+ },{
+ // Test 7
+ url: "http://example.org:8000/tests/dom/media/test/allowed.sjs?" + gResource,
+ result: "loadeddata",
+ description: "Can load from different port on same domain with allow-origin",
+ },{
+ // Test 8
+ url: "http://example.com/tests/dom/media/test/" + gResource,
+ result: "error",
+ description: "Won't load cross domain",
+ },{
+ // Test 9
+ url: "http://example.com/tests/dom/media/test/allowed.sjs?" + gResource,
+ result: "loadeddata",
+ description: "Can load cross domain with allow-origin",
+ },{
+ // Test 10
+ url: "http://test1.example.org/tests/dom/media/test/allowed.sjs?" + gResource,
+ result: "loadeddata",
+ description: "Can load from subdomain with allow-origin",
+ },{
+ // Test 11
+ url: "http://test1.example.org/tests/dom/media/test/" + gResource,
+ result: "error",
+ description: "Won't load from subdomain",
+ }
+];
+
+var gTestNum = 0;
+var gVideo = null;
+var gTestedRemoved = false;
+
+function eventHandler(event) {
+ //dump((gTestNum - 1) + ": " + event.type + "\n");
+ var video = event.target;
+ opener.postMessage({"result": (event.type == video.expectedResult),
+ "message": video.testDescription + (gTestedRemoved ? " (element not in document)" : " (element in document)")},
+ "http://mochi.test:8888");
+ // Make sure any extra events cause an error
+ video.expectedResult = "<none>";
+ nextTest();
+}
+
+function createVideo() {
+ var v = document.createElement('video');
+ v.addEventListener('loadeddata', eventHandler, false);
+ v.addEventListener('error', eventHandler, false);
+ v.crossOrigin = 'anonymous';
+ return v;
+}
+
+function load() {
+ opener.postMessage({"result": (window.location.href == "http://example.org/tests/dom/media/test/file_access_controls.html"),
+ "message": "We must be on a example.org:80"},
+ "http://mochi.test:8888");
+
+ nextTest();
+}
+
+function nextTest() {
+ //dump("nextTest() called, gTestNum="+gTestNum+" gTestedRemoved="+gTestedRemoved+"\n");
+ if (gTestNum == gTests.length) {
+ //dump("gTestNum == gTests.length\n");
+ if (!gTestedRemoved) {
+ // Repeat all tests with element removed from doc, should get same result.
+ gTestedRemoved = true;
+ gTestNum = 0;
+ } else {
+ //dump("Exiting...\n");
+ // We're done, exit the test.
+ window.close();
+ return;
+ }
+ }
+
+ if (gVideo && gVideo.parentNode)
+ gVideo.parentNode.removeChild(gVideo);
+
+ gVideo = null;
+ SpecialPowers.forceGC();
+
+ gVideo = createVideo();
+ gVideo.expectedResult = gTests[gTestNum].result;
+ gVideo.testDescription = gTests[gTestNum].description;
+ // Uniquify the resource URL to ensure that the resources loaded by earlier or subsequent tests
+ // don't overlap with the resources we load here, which are loaded with non-default preferences set.
+ // We also want to make sure that an HTTP fetch actually happens for each testcase.
+ var url = gTests[gTestNum].url;
+ var random = Math.floor(Math.random()*1000000000);
+ url += (url.search(/\?/) < 0 ? "?" : "&") + "rand=" + random;
+ gVideo.src = url;
+ //dump("Starting test " + gTestNum + " at " + gVideo.src + " expecting:" + gVideo.expectedResult + "\n");
+ if (!gTestedRemoved) {
+ document.body.appendChild(gVideo);
+ // Will cause load() to be invoked.
+ } else {
+ gVideo.load();
+ }
+ gTestNum++;
+}
+
+function done() {
+ opener.postMessage({"done": "true"}, "http://mochi.test:8888");
+}
+
+</script>
+</body>
+</html>
+
diff --git a/dom/media/test/flac-noheader-s16.flac b/dom/media/test/flac-noheader-s16.flac
new file mode 100755
index 000000000..01152142a
--- /dev/null
+++ b/dom/media/test/flac-noheader-s16.flac
Binary files differ
diff --git a/dom/media/test/flac-noheader-s16.flac^headers^ b/dom/media/test/flac-noheader-s16.flac^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/flac-noheader-s16.flac^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/flac-s24.flac b/dom/media/test/flac-s24.flac
new file mode 100644
index 000000000..1ba5e27a1
--- /dev/null
+++ b/dom/media/test/flac-s24.flac
Binary files differ
diff --git a/dom/media/test/flac-s24.flac^headers^ b/dom/media/test/flac-s24.flac^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/flac-s24.flac^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/fragment_noplay.js b/dom/media/test/fragment_noplay.js
new file mode 100644
index 000000000..9c761b1b3
--- /dev/null
+++ b/dom/media/test/fragment_noplay.js
@@ -0,0 +1,14 @@
+function test_fragment_noplay(v, start, end, is, ok, finish) {
+
+function onLoadedMetadata() {
+ var s = start == null ? 0 : start;
+ var e = end == null ? v.duration : end;
+ var a = s - 0.15;
+ var b = s + 0.15;
+ ok(v.currentTime >= a && v.currentTime <= b, "loadedmetadata currentTime is " + a + " < " + v.currentTime + " < " + b);
+ ok(v.mozFragmentEnd == e, "mozFragmentEnd (" + v.mozFragmentEnd + ") == end Time (" + e + ")");
+ finish();
+}
+
+v.addEventListener("loadedmetadata", onLoadedMetadata, false);
+}
diff --git a/dom/media/test/fragment_play.js b/dom/media/test/fragment_play.js
new file mode 100644
index 000000000..df98f6b09
--- /dev/null
+++ b/dom/media/test/fragment_play.js
@@ -0,0 +1,67 @@
+function test_fragment_play(v, start, end, is, ok, finish) {
+
+var completed = false;
+var loadedMetadataRaised = false;
+var seekedRaised = false;
+var pausedRaised = false;
+
+function onLoadedMetadata() {
+ var s = start == null ? 0 : start;
+ var e = end == null ? v.duration : end;
+ ok(v.currentTime == s, "loadedmetadata currentTime is " + v.currentTime + " != " + s);
+ ok(v.mozFragmentEnd == e, "mozFragmentEnd (" + v.mozFragmentEnd + ") == end Time (" + e + ")");
+ loadedMetadataRaised = true;
+ v.play();
+}
+
+function onSeeked() {
+ if (completed)
+ return;
+
+ var s = start == null ? 0 : start;
+ ok(v.currentTime - s < 0.1, "seeked currentTime is " + v.currentTime + " != " + s + " (fuzzy compare +-0.1)");
+
+ seekedRaised = true;
+}
+
+function onTimeUpdate() {
+ if (completed)
+ return;
+
+ v._lastTimeUpdate = v.currentTime;
+}
+
+function onPause() {
+ if (completed)
+ return;
+
+ var e = end == null ? v.duration : end;
+ var a = e - 0.05;
+ var b = e + 0.05;
+ ok(v.currentTime >= a && v.currentTime <= b, "paused currentTime is " + a + " < " + v.currentTime + " < " + b + " ? " + v._lastTimeUpdate);
+ pausedRaised = true;
+ v.play();
+}
+
+
+function onEnded() {
+ if (completed)
+ return;
+
+ completed = true;
+ ok(loadedMetadataRaised, "loadedmetadata event");
+ if (start) {
+ ok(seekedRaised, "seeked event");
+ }
+ if (end) {
+ ok(pausedRaised, "paused event: " + end + " " + v.duration);
+ }
+ finish();
+}
+
+v.addEventListener("ended", onEnded, false);
+v.addEventListener("loadedmetadata", onLoadedMetadata, false);
+v.addEventListener("seeked", onSeeked, false);
+v.addEventListener("pause", onPause, false);
+v.addEventListener("timeupdate", onTimeUpdate, false);
+}
diff --git a/dom/media/test/gizmo-frag.mp4 b/dom/media/test/gizmo-frag.mp4
new file mode 100644
index 000000000..f6980663c
--- /dev/null
+++ b/dom/media/test/gizmo-frag.mp4
Binary files differ
diff --git a/dom/media/test/gizmo-noaudio.mp4 b/dom/media/test/gizmo-noaudio.mp4
new file mode 100644
index 000000000..24732a406
--- /dev/null
+++ b/dom/media/test/gizmo-noaudio.mp4
Binary files differ
diff --git a/dom/media/test/gizmo-noaudio.mp4^headers^ b/dom/media/test/gizmo-noaudio.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/gizmo-noaudio.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/gizmo-noaudio.webm b/dom/media/test/gizmo-noaudio.webm
new file mode 100644
index 000000000..9f412cb6e
--- /dev/null
+++ b/dom/media/test/gizmo-noaudio.webm
Binary files differ
diff --git a/dom/media/test/gizmo-noaudio.webm^headers^ b/dom/media/test/gizmo-noaudio.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/gizmo-noaudio.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/gizmo-short.mp4 b/dom/media/test/gizmo-short.mp4
new file mode 100644
index 000000000..f8caec741
--- /dev/null
+++ b/dom/media/test/gizmo-short.mp4
Binary files differ
diff --git a/dom/media/test/gizmo-short.mp4^headers^ b/dom/media/test/gizmo-short.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/gizmo-short.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/gizmo.mp4 b/dom/media/test/gizmo.mp4
new file mode 100644
index 000000000..87efad5ad
--- /dev/null
+++ b/dom/media/test/gizmo.mp4
Binary files differ
diff --git a/dom/media/test/gizmo.mp4^headers^ b/dom/media/test/gizmo.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/gizmo.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/gizmo.webm b/dom/media/test/gizmo.webm
new file mode 100644
index 000000000..518531a93
--- /dev/null
+++ b/dom/media/test/gizmo.webm
Binary files differ
diff --git a/dom/media/test/gizmo.webm^headers^ b/dom/media/test/gizmo.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/gizmo.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/graph_latency.py b/dom/media/test/graph_latency.py
new file mode 100644
index 000000000..576f58d86
--- /dev/null
+++ b/dom/media/test/graph_latency.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+# graph_latency.py - graph media latency
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# needs matplotlib (sudo aptitude install python-matplotlib)
+
+import matplotlib.pyplot as plt
+from matplotlib import rc
+import sys
+from pprint import pprint
+import re
+
+
+# FIX! needs to be sum of a single mediastreamtrack and any output overhead for it
+# So there is one sum per MST
+def compute_sum(data):
+ 'Compute the sum for each timestamp. This expects the output of parse_data.'
+ last_values = {}
+ out = ([],[])
+
+ for i in data:
+ if i[0] not in last_values.keys():
+ last_values[i[0]] = 0
+ last_values[i[0]] = float(i[3])
+ print last_values
+ out[0].append(i[2])
+ out[1].append(sum(last_values.values()))
+ return out
+
+
+def clean_data(raw_data):
+ '''
+ Remove the PR_LOG cruft at the beginning of each line and returns a list of
+ tuple.
+ '''
+ out = []
+ for line in raw_data:
+ match = re.match(r'(.*)#(.*)', line)
+ if match:
+ continue
+ else:
+ out.append(line.split(": ")[1])
+ return out
+
+# returns a list of tuples
+def parse_data(raw_lines):
+ '''
+ Split each line by , and put every bit in a tuple.
+ '''
+ out = []
+ for line in raw_lines:
+ out.append(line.split(','))
+ return out
+
+if len(sys.argv) == 3:
+ name = sys.argv[1]
+ channels = int(sys.argv[2])
+else:
+ print sys.argv[0] + "latency_log"
+
+try:
+ f = open(sys.argv[1])
+except:
+ print "cannot open " + name
+
+raw_lines = f.readlines()
+lines = clean_data(raw_lines)
+data = parse_data(lines)
+
+final_data = {}
+
+for tupl in data:
+ name = tupl[0]
+ if tupl[1] != 0:
+ name = name+tupl[1]
+ if name not in final_data.keys():
+ final_data[name] = ([], [])
+# sanity-check values
+ if float(tupl[3]) < 10*1000:
+ final_data[name][0].append(float(tupl[2]))
+ final_data[name][1].append(float(tupl[3]))
+
+#overall = compute_sum(data)
+#final_data["overall"] = overall
+
+pprint(final_data)
+
+fig = plt.figure()
+for i in final_data.keys():
+ plt.plot(final_data[i][0], final_data[i][1], label=i)
+
+plt.legend()
+plt.suptitle("Latency in ms (y-axis) against time in ms (x-axis).")
+
+size = fig.get_size_inches()
+# make it gigantic so we can see things. sometimes, if the graph is too big,
+# this errors. reduce the factor so it stays under 2**15.
+fig.set_size_inches((size[0]*10, size[1]*2))
+name = sys.argv[1][:-4] + ".pdf"
+fig.savefig(name)
+
diff --git a/dom/media/test/huge-id3.mp3 b/dom/media/test/huge-id3.mp3
new file mode 100644
index 000000000..41cb93d80
--- /dev/null
+++ b/dom/media/test/huge-id3.mp3
Binary files differ
diff --git a/dom/media/test/huge-id3.mp3^headers^ b/dom/media/test/huge-id3.mp3^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/huge-id3.mp3^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/id3tags.mp3 b/dom/media/test/id3tags.mp3
new file mode 100644
index 000000000..bad506cf1
--- /dev/null
+++ b/dom/media/test/id3tags.mp3
Binary files differ
diff --git a/dom/media/test/id3tags.mp3^headers^ b/dom/media/test/id3tags.mp3^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/id3tags.mp3^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/invalid-cmap-s0c0.opus b/dom/media/test/invalid-cmap-s0c0.opus
new file mode 100644
index 000000000..0b9958786
--- /dev/null
+++ b/dom/media/test/invalid-cmap-s0c0.opus
Binary files differ
diff --git a/dom/media/test/invalid-cmap-s0c0.opus^headers^ b/dom/media/test/invalid-cmap-s0c0.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/invalid-cmap-s0c0.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/invalid-cmap-s0c2.opus b/dom/media/test/invalid-cmap-s0c2.opus
new file mode 100644
index 000000000..a921894fe
--- /dev/null
+++ b/dom/media/test/invalid-cmap-s0c2.opus
Binary files differ
diff --git a/dom/media/test/invalid-cmap-s0c2.opus^headers^ b/dom/media/test/invalid-cmap-s0c2.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/invalid-cmap-s0c2.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/invalid-cmap-s1c2.opus b/dom/media/test/invalid-cmap-s1c2.opus
new file mode 100644
index 000000000..95a84f523
--- /dev/null
+++ b/dom/media/test/invalid-cmap-s1c2.opus
Binary files differ
diff --git a/dom/media/test/invalid-cmap-s1c2.opus^headers^ b/dom/media/test/invalid-cmap-s1c2.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/invalid-cmap-s1c2.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/invalid-cmap-short.opus b/dom/media/test/invalid-cmap-short.opus
new file mode 100644
index 000000000..fcd7eb506
--- /dev/null
+++ b/dom/media/test/invalid-cmap-short.opus
Binary files differ
diff --git a/dom/media/test/invalid-cmap-short.opus^headers^ b/dom/media/test/invalid-cmap-short.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/invalid-cmap-short.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/invalid-discard_on_multi_blocks.webm b/dom/media/test/invalid-discard_on_multi_blocks.webm
new file mode 100644
index 000000000..f39ab5bcb
--- /dev/null
+++ b/dom/media/test/invalid-discard_on_multi_blocks.webm
Binary files differ
diff --git a/dom/media/test/invalid-discard_on_multi_blocks.webm^headers^ b/dom/media/test/invalid-discard_on_multi_blocks.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/invalid-discard_on_multi_blocks.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/invalid-excess_discard.webm b/dom/media/test/invalid-excess_discard.webm
new file mode 100644
index 000000000..5b34aca1a
--- /dev/null
+++ b/dom/media/test/invalid-excess_discard.webm
Binary files differ
diff --git a/dom/media/test/invalid-excess_discard.webm^headers^ b/dom/media/test/invalid-excess_discard.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/invalid-excess_discard.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/invalid-excess_neg_discard.webm b/dom/media/test/invalid-excess_neg_discard.webm
new file mode 100644
index 000000000..2bfad6ed2
--- /dev/null
+++ b/dom/media/test/invalid-excess_neg_discard.webm
Binary files differ
diff --git a/dom/media/test/invalid-excess_neg_discard.webm^headers^ b/dom/media/test/invalid-excess_neg_discard.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/invalid-excess_neg_discard.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/invalid-m0c0.opus b/dom/media/test/invalid-m0c0.opus
new file mode 100644
index 000000000..86555f60e
--- /dev/null
+++ b/dom/media/test/invalid-m0c0.opus
Binary files differ
diff --git a/dom/media/test/invalid-m0c0.opus^headers^ b/dom/media/test/invalid-m0c0.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/invalid-m0c0.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/invalid-m0c3.opus b/dom/media/test/invalid-m0c3.opus
new file mode 100644
index 000000000..2c681a8c0
--- /dev/null
+++ b/dom/media/test/invalid-m0c3.opus
Binary files differ
diff --git a/dom/media/test/invalid-m0c3.opus^headers^ b/dom/media/test/invalid-m0c3.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/invalid-m0c3.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/invalid-m1c0.opus b/dom/media/test/invalid-m1c0.opus
new file mode 100644
index 000000000..c7728f79e
--- /dev/null
+++ b/dom/media/test/invalid-m1c0.opus
Binary files differ
diff --git a/dom/media/test/invalid-m1c0.opus^headers^ b/dom/media/test/invalid-m1c0.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/invalid-m1c0.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/invalid-m1c9.opus b/dom/media/test/invalid-m1c9.opus
new file mode 100644
index 000000000..1ef6e9f9c
--- /dev/null
+++ b/dom/media/test/invalid-m1c9.opus
Binary files differ
diff --git a/dom/media/test/invalid-m1c9.opus^headers^ b/dom/media/test/invalid-m1c9.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/invalid-m1c9.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/invalid-m2c0.opus b/dom/media/test/invalid-m2c0.opus
new file mode 100644
index 000000000..5c3f97e2a
--- /dev/null
+++ b/dom/media/test/invalid-m2c0.opus
Binary files differ
diff --git a/dom/media/test/invalid-m2c0.opus^headers^ b/dom/media/test/invalid-m2c0.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/invalid-m2c0.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/invalid-m2c1.opus b/dom/media/test/invalid-m2c1.opus
new file mode 100644
index 000000000..5ecb95ee2
--- /dev/null
+++ b/dom/media/test/invalid-m2c1.opus
Binary files differ
diff --git a/dom/media/test/invalid-m2c1.opus^headers^ b/dom/media/test/invalid-m2c1.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/invalid-m2c1.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/invalid-neg_discard.webm b/dom/media/test/invalid-neg_discard.webm
new file mode 100644
index 000000000..3f665c0b5
--- /dev/null
+++ b/dom/media/test/invalid-neg_discard.webm
Binary files differ
diff --git a/dom/media/test/invalid-neg_discard.webm^headers^ b/dom/media/test/invalid-neg_discard.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/invalid-neg_discard.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/invalid-preskip.webm b/dom/media/test/invalid-preskip.webm
new file mode 100644
index 000000000..99b4f2ca7
--- /dev/null
+++ b/dom/media/test/invalid-preskip.webm
Binary files differ
diff --git a/dom/media/test/invalid-preskip.webm^headers^ b/dom/media/test/invalid-preskip.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/invalid-preskip.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/long.vtt b/dom/media/test/long.vtt
new file mode 100644
index 000000000..23984b0c8
--- /dev/null
+++ b/dom/media/test/long.vtt
@@ -0,0 +1,8001 @@
+WEBVTT
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
+
+1
+00:00.500 --> 00:00.700
+This
+
+2
+00:01.200 --> 00:02.400
+Is
+
+3
+00:02.710 --> 00:02.910
+A
+
+4
+00:03.217 --> 00:03.989
+Test
diff --git a/dom/media/test/make-headers.sh b/dom/media/test/make-headers.sh
new file mode 100644
index 000000000..35d9bd90f
--- /dev/null
+++ b/dom/media/test/make-headers.sh
@@ -0,0 +1,18 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Script to generate ^header^ files for all media files we use.
+# This is to ensure that our media files are not cached by necko,
+# so that our detection as to whether the server supports byte range
+# requests is not interferred with by Necko's cache. See bug 977398
+# for details. Necko will fix this in bug 977314.
+
+FILES=(`ls *.ogg *.ogv *.webm *.mp3 *.opus *.mp4 *.m4s *.wav`)
+
+rm -f *.ogg^headers^ *.ogv^headers^ *.webm^headers^ *.mp3^headers^ *.opus^headers^ *.mp4^headers^ *.m4s^headers^ *.wav^headers^
+
+for i in "${FILES[@]}"
+do
+ echo "Cache-Control: no-store" >> $i^headers^
+done
diff --git a/dom/media/test/manifest.js b/dom/media/test/manifest.js
new file mode 100644
index 000000000..c6d533c1b
--- /dev/null
+++ b/dom/media/test/manifest.js
@@ -0,0 +1,1725 @@
+// In each list of tests below, test file types that are not supported should
+// be ignored. To make sure tests respect that, we include a file of type
+// "bogus/duh" in each list.
+
+// Make sure to not touch navigator in here, since we want to push prefs that
+// will affect the APIs it exposes, but the set of exposed APIs is determined
+// when Navigator.prototype is created. So if we touch navigator before pushing
+// the prefs, the APIs it exposes will not take those prefs into account. We
+// work around this by using a navigator object from a different global for our
+// UA string testing.
+var gManifestNavigatorSource = document.documentElement.appendChild(document.createElement("iframe"));
+gManifestNavigatorSource.style.display = "none";
+function manifestNavigator() {
+ return gManifestNavigatorSource.contentWindow.navigator;
+}
+
+// Similarly, use a <video> element from a different global for canPlayType or
+// other feature testing. If we used one from our global and did so before our
+// prefs are pushed, then we'd instantiate HTMLMediaElement.prototype before the
+// prefs are pushed and APIs we expect to be on that object would not be there.
+function manifestVideo() {
+ return gManifestNavigatorSource.contentDocument.createElement('video');
+}
+
+// These are small test files, good for just seeing if something loads. We
+// really only need one test file per backend here.
+var gSmallTests = [
+ { name:"small-shot.ogg", type:"audio/ogg", duration:0.276 },
+ { name:"small-shot.m4a", type:"audio/mp4", duration:0.29 },
+ { name:"small-shot.mp3", type:"audio/mpeg", duration:0.27 },
+ { name:"small-shot-mp3.mp4", type:"audio/mp4; codecs=mp3", duration:0.34 },
+ { name:"small-shot.flac", type:"audio/flac", duration:0.197 },
+ { name:"r11025_s16_c1-short.wav", type:"audio/x-wav", duration:0.37 },
+ { name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266 },
+ { name:"seek-short.webm", type:"video/webm", width:320, height:240, duration:0.23 },
+ { name:"vp9-short.webm", type:"video/webm", width:320, height:240, duration:0.20 },
+ { name:"detodos-short.opus", type:"audio/ogg; codecs=opus", duration:0.22 },
+ { name:"gizmo-short.mp4", type:"video/mp4", width:560, height:320, duration:0.27 },
+ { name:"flac-s24.flac", type:"audio/flac", duration:4.04 },
+ { name:"bogus.duh", type:"bogus/duh" }
+];
+
+if (SpecialPowers.Services.appinfo.name != "B2G") {
+ // We only run mochitests on b2g desktop and b2g emulator. The 3gp codecs
+ // aren't present on desktop, and the emulator codecs (which are different
+ // from the real device codecs) don't pass all of our tests, so we need
+ // to disable them.
+
+ gSmallTests = gSmallTests.concat([
+ { name:"sample.3gp", type:"video/3gpp", duration:4.933 },
+ { name:"sample.3g2", type:"video/3gpp2", duration:4.933 }
+ ]);
+}
+
+// Used by test_bug654550.html, for videoStats preference
+var gVideoTests = [
+ { name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266 },
+ { name:"seek-short.webm", type:"video/webm", width:320, height:240, duration:0.23 },
+ { name:"bogus.duh", type:"bogus/duh" }
+];
+
+// Temp hack for trackIDs and captureStream() -- bug 1215769
+var gLongerTests = [
+ { name:"seek.webm", type:"video/webm", width:320, height:240, duration:3.966 },
+ { name:"gizmo.mp4", type:"video/mp4", width:560, height:320, duration:5.56 },
+];
+
+// Used by test_progress to ensure we get the correct progress information
+// during resource download.
+var gProgressTests = [
+ { name:"r11025_u8_c1.wav", type:"audio/x-wav", duration:1.0, size:11069 },
+ { name:"big-short.wav", type:"audio/x-wav", duration:1.11, size:12366 },
+ { name:"seek-short.ogv", type:"video/ogg", duration:1.03, size:79921 },
+ { name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266, size:28942 },
+ { name:"seek-short.webm", type:"video/webm", duration:0.23, size:19267 },
+ { name:"gizmo-short.mp4", type:"video/mp4", duration:0.27, size:29905 },
+ { name:"bogus.duh", type:"bogus/duh" }
+];
+
+// Used by test_played.html
+var gPlayedTests = [
+ { name:"big-short.wav", type:"audio/x-wav", duration:1.11 },
+ { name:"seek-short.ogv", type:"video/ogg", duration:1.03 },
+ { name:"seek-short.webm", type:"video/webm", duration:0.23 },
+ { name:"gizmo-short.mp4", type:"video/mp4", duration:0.27 },
+ { name:"owl-short.mp3", type:"audio/mpeg", duration:0.52 },
+ // Disable vbr.mp3 to see if it reduces the error of AUDCLNT_E_CPUUSAGE_EXCEEDED.
+ // See bug 1110922 comment 26.
+ //{ name:"vbr.mp3", type:"audio/mpeg", duration:10.0 },
+ { name:"bug495794.ogg", type:"audio/ogg", duration:0.3 },
+];
+
+// Used by test_mozLoadFrom. Need one test file per decoder backend, plus
+// anything for testing clone-specific bugs.
+var cloneKey = Math.floor(Math.random()*100000000);
+var gCloneTests = gSmallTests.concat([
+ { name:"bug520908.ogv", type:"video/ogg", duration:0.2 },
+ // short-video is more like 1s, so if you load this twice you'll get an unexpected duration
+ { name:"dynamic_resource.sjs?key=" + cloneKey + "&res1=320x240.ogv&res2=short-video.ogv",
+ type:"video/ogg", duration:0.266 },
+]);
+
+// Used by test_play_twice. Need one test file per decoder backend, plus
+// anything for testing bugs that occur when replying a played file.
+var gReplayTests = gSmallTests.concat([
+ { name:"bug533822.ogg", type:"audio/ogg" },
+]);
+
+// Used by test_paused_after_ended. Need one test file per decoder backend, plus
+// anything for testing bugs that occur when replying a played file.
+var gPausedAfterEndedTests = gSmallTests.concat([
+ { name:"r11025_u8_c1.wav", type:"audio/x-wav", duration:1.0 },
+ { name:"small-shot.ogg", type:"video/ogg", duration:0.276 }
+]);
+
+// Test the mozHasAudio property, and APIs that detect different kinds of
+// tracks
+var gTrackTests = [
+ { name:"big-short.wav", type:"audio/x-wav", duration:1.11, size:12366, hasAudio:true, hasVideo:false },
+ { name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266, size:28942, hasAudio:false, hasVideo:true },
+ { name:"short-video.ogv", type:"video/ogg", duration:1.081, hasAudio:true, hasVideo:true },
+ { name:"seek-short.webm", type:"video/webm", duration:0.23, size:19267, hasAudio:false, hasVideo:true },
+ { name:"flac-s24.flac", type:"audio/flac", duration:4.04, hasAudio:true, hasVideo:false },
+ { name:"bogus.duh", type:"bogus/duh" }
+];
+
+var gClosingConnectionsTest = [
+ { name:"seek-short.ogv", type:"video/ogg", duration:1.03 },
+];
+
+// Used by any media recorder test. Need one test file per decoder backend
+// currently supported by the media encoder.
+var gMediaRecorderTests = [
+ // Duration should be greater than 500ms because we will record 2
+ // time slices (250ms per slice)
+ { name:"detodos-recorder-test.opus", type:"audio/ogg; codecs=opus", duration:0.62 }
+];
+
+// Used by video media recorder tests
+var gMediaRecorderVideoTests = [
+ { name:"seek-short.webm", type:"video/webm", width:320, height:240, duration:0.23 },
+];
+
+// These are files that we want to make sure we can play through. We can
+// also check metadata. Put files of the same type together in this list so if
+// something crashes we have some idea of which backend is responsible.
+// Used by test_playback, which expects no error event and one ended event.
+var gPlayTests = [
+ // Test playback of a WebM file with vp9 video
+ { name:"vp9cake-short.webm", type:"video/webm", duration:1.00 },
+
+ // 8-bit samples
+ { name:"r11025_u8_c1.wav", type:"audio/x-wav", duration:1.0 },
+ // 8-bit samples, file is truncated
+ { name:"r11025_u8_c1_trunc.wav", type:"audio/x-wav", duration:1.8 },
+ // file has trailing non-PCM data
+ { name:"r11025_s16_c1_trailing.wav", type:"audio/x-wav", duration:1.0 },
+ // file with list chunk
+ { name:"r16000_u8_c1_list.wav", type:"audio/x-wav", duration:4.2 },
+ // file with 2 extra bytes of metadata
+ { name:"16bit_wave_extrametadata.wav", type:"audio/x-wav", duration:1.108 },
+ // 24-bit samples
+ { name:"wavedata_s24.wav", type:"audio/x-wav", duration:1.0 },
+ // aLaw compressed wave file
+ { name:"wavedata_alaw.wav", type:"audio/x-wav", duration:1.0 },
+ // uLaw compressed wave file
+ { name:"wavedata_ulaw.wav", type:"audio/x-wav", duration:1.0 },
+ // Data length 0xFFFFFFFF
+ { name:"bug1301226.wav", type:"audio/x-wav", duration:0.003673 },
+ // Data length 0xFFFFFFFF and odd chunk lengths.
+ { name:"bug1301226-odd.wav", type:"audio/x-wav", duration:0.003673 },
+
+ // Ogg stream without eof marker
+ { name:"bug461281.ogg", type:"application/ogg", duration:2.208 },
+
+ // oggz-chop stream
+ { name:"bug482461.ogv", type:"video/ogg", duration:4.34 },
+ // Theora only oggz-chop stream
+ { name:"bug482461-theora.ogv", type:"video/ogg", duration:4.138 },
+ // With first frame a "duplicate" (empty) frame.
+ { name:"bug500311.ogv", type:"video/ogg", duration:1.96 },
+ // Small audio file
+ { name:"small-shot.ogg", type:"audio/ogg", duration:0.276 },
+ // More audio in file than video.
+ { name:"short-video.ogv", type:"video/ogg", duration:1.081 },
+ // First Theora data packet is zero bytes.
+ { name:"bug504613.ogv", type:"video/ogg", duration:Number.NaN },
+ // Multiple audio streams.
+ { name:"bug516323.ogv", type:"video/ogg", duration:4.208 },
+ // oggz-chop with non-keyframe as first frame
+ { name:"bug556821.ogv", type:"video/ogg", duration:2.936 },
+
+ // Encoded with vorbis beta1, includes unusually sized codebooks
+ { name:"beta-phrasebook.ogg", type:"audio/ogg", duration:4.01 },
+ // Small file, only 1 frame with audio only.
+ { name:"bug520493.ogg", type:"audio/ogg", duration:0.458 },
+ // Small file with vorbis comments with 0 length values and names.
+ { name:"bug520500.ogg", type:"audio/ogg", duration:0.123 },
+
+ // Various weirdly formed Ogg files
+ { name:"bug499519.ogv", type:"video/ogg", duration:0.24 },
+ { name:"bug506094.ogv", type:"video/ogg", duration:0 },
+ { name:"bug498855-1.ogv", type:"video/ogg", duration:0.24 },
+ { name:"bug498855-2.ogv", type:"video/ogg", duration:0.24 },
+ { name:"bug498855-3.ogv", type:"video/ogg", duration:0.24 },
+ { name:"bug504644.ogv", type:"video/ogg", duration:1.6 },
+ { name:"chain.ogv", type:"video/ogg", duration:Number.NaN },
+ { name:"bug523816.ogv", type:"video/ogg", duration:0.766 },
+ { name:"bug495129.ogv", type:"video/ogg", duration:2.41 },
+ { name:"bug498380.ogv", type:"video/ogg", duration:0.7663 },
+ { name:"bug495794.ogg", type:"audio/ogg", duration:0.3 },
+ { name:"bug557094.ogv", type:"video/ogg", duration:0.24 },
+ { name:"multiple-bos.ogg", type:"video/ogg", duration:0.431 },
+ { name:"audio-overhang.ogg", type:"audio/ogg", duration:2.3 },
+ { name:"video-overhang.ogg", type:"audio/ogg", duration:3.966 },
+
+ // bug461281.ogg with the middle second chopped out.
+ { name:"audio-gaps.ogg", type:"audio/ogg", duration:2.208 },
+
+ // Test playback/metadata work after a redirect
+ { name:"redirect.sjs?domain=mochi.test:8888&file=320x240.ogv",
+ type:"video/ogg", duration:0.266 },
+
+ // Test playback of a webm file
+ { name:"seek-short.webm", type:"video/webm", duration:0.23 },
+
+ // Test playback of a WebM file with non-zero start time.
+ { name:"split.webm", type:"video/webm", duration:1.967 },
+
+ // Test playback of a WebM file with resolution changes.
+ { name:"resolution-change.webm", type:"video/webm", duration:6.533 },
+
+ // Test playback of a raw file
+ { name:"seek.yuv", type:"video/x-raw-yuv", duration:1.833 },
+
+ // A really short, low sample rate, single channel file. This tests whether
+ // we can handle playing files when only push very little audio data to the
+ // hardware.
+ { name:"spacestorm-1000Hz-100ms.ogg", type:"audio/ogg", duration:0.099 },
+
+ // Opus data in an ogg container
+ { name:"detodos-short.opus", type:"audio/ogg; codecs=opus", duration:0.22 },
+ // Opus data in a webm container
+ { name:"detodos-short.webm", type:"audio/webm; codecs=opus", duration:0.26 },
+ { name:"bug1066943.webm", type:"audio/webm; codecs=opus", duration:1.383 },
+
+ // Multichannel Opus in an ogg container
+ { name:"test-1-mono.opus", type:"audio/ogg; codecs=opus", duration:1.044 },
+ { name:"test-2-stereo.opus", type:"audio/ogg; codecs=opus", duration:2.925 },
+ { name:"test-3-LCR.opus", type:"audio/ogg; codecs=opus", duration:4.214 },
+ { name:"test-4-quad.opus", type:"audio/ogg; codecs=opus", duration:6.234 },
+ { name:"test-5-5.0.opus", type:"audio/ogg; codecs=opus", duration:7.558 },
+ { name:"test-6-5.1.opus", type:"audio/ogg; codecs=opus", duration:10.333 },
+ { name:"test-7-6.1.opus", type:"audio/ogg; codecs=opus", duration:11.690 },
+ { name:"test-8-7.1.opus", type:"audio/ogg; codecs=opus", duration:13.478 },
+
+ { name:"gizmo-short.mp4", type:"video/mp4", duration:0.27 },
+ // Test playback of a MP4 file with a non-zero start time (and audio starting
+ // a second later).
+ { name:"bipbop-lateaudio.mp4", type:"video/mp4" },
+
+ { name:"small-shot.m4a", type:"audio/mp4", duration:0.29 },
+ { name:"small-shot.mp3", type:"audio/mpeg", duration:0.27 },
+ { name:"owl.mp3", type:"audio/mpeg", duration:3.343 },
+ // owl.mp3 as above, but with something funny going on in the ID3v2 tag
+ // that causes DirectShow to fail.
+ { name:"owl-funny-id3.mp3", type:"audio/mpeg", duration:3.343 },
+ // owl.mp3 as above, but with something even funnier going on in the ID3v2 tag
+ // that causes DirectShow to fail.
+ { name:"owl-funnier-id3.mp3", type:"audio/mpeg", duration:3.343 },
+ // One second of silence with ~140KB of ID3 tags. Usually when the first MP3
+ // frame is at such a high offset into the file, MP3FrameParser will give up
+ // and report that the stream is not MP3. However, it does not count ID3 tags
+ // in that offset. This test case makes sure that ID3 exclusion holds.
+ { name:"huge-id3.mp3", type:"audio/mpeg", duration:1.00 },
+ // A truncated VBR MP3 with just enough frames to keep most decoders happy.
+ // The Xing header reports the length of the file to be around 10 seconds, but
+ // there is really only one second worth of data. We want MP3FrameParser to
+ // trust the header, so this should be reported as 10 seconds.
+ { name:"vbr-head.mp3", type:"audio/mpeg", duration:10.00 },
+
+ // A flac file where the STREAMINFO block was removed.
+ // It is necessary to parse the file to find an audio frame instead.
+ { name:"flac-noheader-s16.flac", type:"audio/flac", duration:4.0 },
+ { name:"flac-s24.flac", type:"audio/flac", duration:4.04 },
+ // Ogg with theora video and flac audio.
+ { name:"A4.ogv", type:"video/ogg", width:320, height:240, duration:3.13 },
+
+ // Invalid file
+ { name:"bogus.duh", type:"bogus/duh", duration:Number.NaN },
+];
+
+var gSeekToNextFrameTests = [
+ // Test playback of a WebM file with vp9 video
+ { name:"vp9-short.webm", type:"video/webm", duration:0.20 },
+ { name:"vp9cake-short.webm", type:"video/webm", duration:1.00 },
+ // oggz-chop stream
+ { name:"bug482461.ogv", type:"video/ogg", duration:4.34 },
+ // Theora only oggz-chop stream
+ { name:"bug482461-theora.ogv", type:"video/ogg", duration:4.138 },
+ // With first frame a "duplicate" (empty) frame.
+ { name:"bug500311.ogv", type:"video/ogg", duration:1.96 },
+
+ // More audio in file than video.
+ { name:"short-video.ogv", type:"video/ogg", duration:1.081 },
+ // First Theora data packet is zero bytes.
+ { name:"bug504613.ogv", type:"video/ogg", duration:Number.NaN },
+ // Multiple audio streams.
+ { name:"bug516323.ogv", type:"video/ogg", duration:4.208 },
+ // oggz-chop with non-keyframe as first frame
+ { name:"bug556821.ogv", type:"video/ogg", duration:2.936 },
+ // Various weirdly formed Ogg files
+ { name:"bug498855-1.ogv", type:"video/ogg", duration:0.24 },
+ { name:"bug498855-2.ogv", type:"video/ogg", duration:0.24 },
+ { name:"bug498855-3.ogv", type:"video/ogg", duration:0.24 },
+ { name:"bug504644.ogv", type:"video/ogg", duration:1.6 },
+
+ { name:"bug523816.ogv", type:"video/ogg", duration:0.766 },
+
+ { name:"bug498380.ogv", type:"video/ogg", duration:0.766 },
+ { name:"bug557094.ogv", type:"video/ogg", duration:0.24 },
+ { name:"multiple-bos.ogg", type:"video/ogg", duration:0.431 },
+ // Test playback/metadata work after a redirect
+ { name:"redirect.sjs?domain=mochi.test:8888&file=320x240.ogv",
+ type:"video/ogg", duration:0.266 },
+ // Test playback of a webm file
+ { name:"seek-short.webm", type:"video/webm", duration:0.23 },
+ // Test playback of a WebM file with non-zero start time.
+ { name:"split.webm", type:"video/webm", duration:1.967 },
+ // Test playback of a raw file
+ { name:"seek.yuv", type:"video/x-raw-yuv", duration:1.833 },
+
+ { name:"gizmo-short.mp4", type:"video/mp4", duration:0.27 },
+
+ // Test playback of a MP4 file with a non-zero start time (and audio starting
+ // a second later).
+ { name:"bipbop-lateaudio.mp4", type:"video/mp4" },
+];
+
+// A file for each type we can support.
+var gSnifferTests = [
+ { name:"big.wav", type:"audio/x-wav", duration:9.278982, size:102444 },
+ { name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.233, size:28942 },
+ { name:"seek.webm", type:"video/webm", duration:3.966, size:215529 },
+ { name:"gizmo.mp4", type:"video/mp4", duration:5.56, size:383631 },
+ // A mp3 file with id3 tags.
+ { name:"id3tags.mp3", type:"audio/mpeg", duration:0.28, size:3530},
+ { name:"bogus.duh", type:"bogus/duh" }
+];
+
+// Files that contain resolution changes
+var gResolutionChangeTests = [
+ { name:"resolution-change.webm", type:"video/webm", duration:6.533 },
+];
+
+// Files we must reject as invalid.
+var gInvalidTests = [
+ { name:"invalid-m0c0.opus", type:"audio/ogg; codecs=opus"},
+ { name:"invalid-m0c3.opus", type:"audio/ogg; codecs=opus"},
+ { name:"invalid-m1c0.opus", type:"audio/ogg; codecs=opus"},
+ { name:"invalid-m1c9.opus", type:"audio/ogg; codecs=opus"},
+ { name:"invalid-m2c0.opus", type:"audio/ogg; codecs=opus"},
+ { name:"invalid-m2c1.opus", type:"audio/ogg; codecs=opus"},
+ { name:"invalid-cmap-short.opus", type:"audio/ogg; codecs=opus"},
+ { name:"invalid-cmap-s0c0.opus", type:"audio/ogg; codecs=opus"},
+ { name:"invalid-cmap-s0c2.opus", type:"audio/ogg; codecs=opus"},
+ { name:"invalid-cmap-s1c2.opus", type:"audio/ogg; codecs=opus"},
+ { name:"invalid-preskip.webm", type:"audio/webm; codecs=opus"},
+];
+
+var gInvalidPlayTests = [
+ { name:"invalid-excess_discard.webm", type:"audio/webm; codecs=opus"},
+ { name:"invalid-excess_neg_discard.webm", type:"audio/webm; codecs=opus"},
+ { name:"invalid-neg_discard.webm", type:"audio/webm; codecs=opus"},
+ { name:"invalid-discard_on_multi_blocks.webm", type:"audio/webm; codecs=opus"},
+];
+
+// Files to check different cases of ogg skeleton information.
+// sample-fisbone-skeleton4.ogv
+// - Skeleton v4, w/ Content-Type,Role,Name,Language,Title for both theora/vorbis
+// sample-fisbone-wrong-header.ogv
+// - Skeleton v4, wrong message field sequence for vorbis
+// multiple-bos-more-header-fields.ogg
+// - Skeleton v3, w/ Content-Type,Role,Name,Language,Title for both theora/vorbis
+// seek-short.ogv
+// - No skeleton, but theora
+// audio-gaps-short.ogg
+// - No skeleton, but vorbis
+var gMultitrackInfoOggPlayList = [
+ { name:"sample-fisbone-skeleton4.ogv", type:"video/ogg", duration:1.00 },
+ { name:"sample-fisbone-wrong-header.ogv", type:"video/ogg", duration:1.00 },
+ { name:"multiple-bos-more-header-fileds.ogg", type:"video/ogg", duration:0.431 },
+ { name:"seek-short.ogv", type:"video/ogg", duration:1.03 },
+ { name:"audio-gaps-short.ogg", type:"audio/ogg", duration:0.50 }
+];
+// Pre-parsed results of gMultitrackInfoOggPlayList.
+var gOggTrackInfoResults = {
+ "sample-fisbone-skeleton4.ogv" : {
+ "audio_id":" audio_1",
+ "audio_kind":"main",
+ "audio_language":" en-US",
+ "audio_label":" Audio track for test",
+ "video_id":" video_1",
+ "video_kind":"main",
+ "video_language":" fr",
+ "video_label":" Video track for test"
+ },
+ "sample-fisbone-wrong-header.ogv" : {
+ "audio_id":"1",
+ "audio_kind":"main",
+ "audio_language":"",
+ "audio_label":"",
+ "video_id":" video_1",
+ "video_kind":"main",
+ "video_language":" fr",
+ "video_label":" Video track for test"
+ },
+ "multiple-bos-more-header-fileds.ogg" : {
+ "audio_id":"1",
+ "audio_kind":"main",
+ "audio_language":"",
+ "audio_label":"",
+ "video_id":"2",
+ "video_kind":"main",
+ "video_language":"",
+ "video_label":""
+ },
+ "seek-short.ogv" : {
+ "video_id":"2",
+ "video_kind":"main",
+ "video_language":"",
+ "video_label":""
+ },
+ "audio-gaps-short.ogg" : {
+ "audio_id":"1",
+ "audio_kind":"main",
+ "audio_language":"",
+ "audio_label":""
+ }
+};
+
+// Converts a path/filename to a file:// URI which we can load from disk.
+// Optionally checks whether the file actually exists on disk at the location
+// we've specified.
+function fileUriToSrc(path, mustExist) {
+ // android mochitest doesn't support file://
+ if (manifestNavigator().appVersion.indexOf("Android") != -1 || SpecialPowers.Services.appinfo.name == "B2G")
+ return path;
+
+ const Ci = SpecialPowers.Ci;
+ const Cc = SpecialPowers.Cc;
+ const Cr = SpecialPowers.Cr;
+ var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
+ getService(Ci.nsIProperties);
+ var f = dirSvc.get("CurWorkD", Ci.nsILocalFile);
+ var split = path.split("/");
+ for(var i = 0; i < split.length; ++i) {
+ f.append(split[i]);
+ }
+ if (mustExist && !f.exists()) {
+ ok(false, "We expected '" + path + "' to exist, but it doesn't!");
+ }
+ return f.path;
+}
+
+// Returns true if two TimeRanges are equal, false otherwise
+function range_equals(r1, r2) {
+ if (r1.length != r2.length) {
+ return false;
+ }
+ for (var i = 0; i < r1.length; i++) {
+ if (r1.start(i) != r2.start(i) || r1.end(i) != r2.end(i)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// These are URIs to files that we use to check that we don't leak any state
+// or other information such that script can determine stuff about a user's
+// environment. Used by test_info_leak.
+var gInfoLeakTests = [
+ {
+ type: 'video/ogg',
+ src: fileUriToSrc("tests/dom/media/test/320x240.ogv", true),
+ },{
+ type: 'video/ogg',
+ src: fileUriToSrc("tests/dom/media/test/404.ogv", false),
+ }, {
+ type: 'audio/x-wav',
+ src: fileUriToSrc("tests/dom/media/test/r11025_s16_c1.wav", true),
+ }, {
+ type: 'audio/x-wav',
+ src: fileUriToSrc("tests/dom/media/test/404.wav", false),
+ }, {
+ type: 'audio/ogg',
+ src: fileUriToSrc("tests/dom/media/test/bug461281.ogg", true),
+ }, {
+ type: 'audio/ogg',
+ src: fileUriToSrc("tests/dom/media/test/404.ogg", false),
+ }, {
+ type: 'video/webm',
+ src: fileUriToSrc("tests/dom/media/test/seek.webm", true),
+ }, {
+ type: 'video/webm',
+ src: fileUriToSrc("tests/dom/media/test/404.webm", false),
+ }, {
+ type: 'video/ogg',
+ src: 'http://localhost/404.ogv',
+ }, {
+ type: 'audio/x-wav',
+ src: 'http://localhost/404.wav',
+ }, {
+ type: 'video/webm',
+ src: 'http://localhost/404.webm',
+ }, {
+ type: 'video/ogg',
+ src: 'http://example.com/tests/dom/media/test/test_info_leak.html'
+ }, {
+ type: 'audio/ogg',
+ src: 'http://example.com/tests/dom/media/test/test_info_leak.html'
+ }
+];
+
+// These are files that must fire an error during load or playback, and do not
+// cause a crash. Used by test_playback_errors, which expects one error event
+// and no ended event. Put files of the same type together in this list so if
+// something crashes we have some idea of which backend is responsible.
+var gErrorTests = [
+ { name:"bogus.wav", type:"audio/x-wav" },
+ { name:"bogus.ogv", type:"video/ogg" },
+ { name:"448636.ogv", type:"video/ogg" },
+ { name:"bug504843.ogv", type:"video/ogg" },
+ { name:"bug501279.ogg", type:"audio/ogg" },
+ { name:"bug580982.webm", type:"video/webm" },
+ { name:"bug603918.webm", type:"video/webm" },
+ { name:"bug604067.webm", type:"video/webm" },
+ { name:"bogus.duh", type:"bogus/duh" }
+];
+
+function IsWindowsVistaOrLater() {
+ var re = /Windows NT (\d+.\d)/;
+ var winver = manifestNavigator().userAgent.match(re);
+ return winver && winver.length == 2 && parseFloat(winver[1]) >= 6.0;
+}
+
+// Windows' H.264 decoder cannot handle H.264 streams with resolution
+// less than 48x48 pixels. We refuse to play and error on such streams.
+if (IsWindowsVistaOrLater() &&
+ manifestVideo().canPlayType('video/mp4; codecs="avc1.42E01E"')) {
+ gErrorTests = gErrorTests.concat({name: "red-46x48.mp4", type:"video/mp4"},
+ {name: "red-48x46.mp4", type:"video/mp4"});
+}
+
+// These are files that have nontrivial duration and are useful for seeking within.
+var gSeekTests = [
+ { name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
+ { name:"audio.wav", type:"audio/x-wav", duration:0.031247 },
+ { name:"seek.ogv", type:"video/ogg", duration:3.966 },
+ { name:"320x240.ogv", type:"video/ogg", duration:0.266 },
+ { name:"seek.webm", type:"video/webm", duration:3.966 },
+ { name:"sine.webm", type:"audio/webm", duration:4.001 },
+ { name:"bug516323.indexed.ogv", type:"video/ogg", duration:4.208333 },
+ { name:"split.webm", type:"video/webm", duration:1.967 },
+ { name:"detodos.opus", type:"audio/ogg; codecs=opus", duration:2.9135 },
+ { name:"gizmo.mp4", type:"video/mp4", duration:5.56 },
+ { name:"owl.mp3", type:"audio/mpeg", duration:3.343 },
+ { name:"bogus.duh", type:"bogus/duh", duration:123 },
+
+ // Bug 1242338: hit a numerical problem while seeking to the duration.
+ { name:"bug482461-theora.ogv", type:"video/ogg", duration:4.138 },
+];
+
+var gFastSeekTests = [
+ { name:"gizmo.mp4", type:"video/mp4", keyframes:[0, 1.0, 2.0, 3.0, 4.0, 5.0 ] },
+ // Note: Not all keyframes in the file are actually referenced in the Cues in this file.
+ { name:"seek.webm", type:"video/webm", keyframes:[0, 0.8, 1.6, 2.4, 3.2]},
+ // Note: the sync points are the points on both the audio and video streams
+ // before the keyframes. You can't just assume that the keyframes are the sync
+ // points, as the audio required for that sync point may be before the keyframe.
+ { name:"bug516323.indexed.ogv", type:"video/ogg", keyframes:[0, 0.46, 3.06] },
+];
+
+// These files are WebMs without cues. They're seekable within their buffered
+// ranges. If work renders WebMs fully seekable these files should be moved
+// into gSeekTests
+var gCuelessWebMTests = [
+ { name:"no-cues.webm", type:"video/webm", duration:3.967 },
+];
+
+// These are files that are non seekable, due to problems with the media,
+// for example broken or missing indexes.
+var gUnseekableTests = [
+ { name:"bogus.duh", type:"bogus/duh"}
+];
+
+var androidVersion = -1; // non-Android platforms
+if (manifestNavigator().userAgent.indexOf("Mobile") != -1 ||
+ manifestNavigator().userAgent.indexOf("Tablet") != -1) {
+ // See nsSystemInfo.cpp, the getProperty('version') returns different value
+ // on each platforms, so we need to distinguish the android and B2G platform.
+ var versionString = manifestNavigator().userAgent.indexOf("Android") != -1 ?
+ 'version' : 'sdk_version';
+ androidVersion = SpecialPowers.Cc['@mozilla.org/system-info;1']
+ .getService(SpecialPowers.Ci.nsIPropertyBag2)
+ .getProperty(versionString);
+}
+
+function getAndroidVersion() {
+ return androidVersion;
+}
+
+//Android supports fragmented MP4 playback from 4.3.
+//Fragmented MP4.
+if (getAndroidVersion() >= 18) {
+ gUnseekableTests = gUnseekableTests.concat([
+ { name:"street.mp4", type:"video/mp4" }
+ ]);
+}
+
+// These are files suitable for using with a "new Audio" constructor.
+var gAudioTests = [
+ { name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
+ { name:"sound.ogg", type:"audio/ogg" },
+ { name:"owl.mp3", type:"audio/mpeg", duration:3.343 },
+ { name:"small-shot.m4a", type:"audio/mp4", duration:0.29 },
+ { name:"bogus.duh", type:"bogus/duh", duration:123 }
+];
+
+// These files ensure our handling of 404 errors is consistent across the
+// various backends.
+var g404Tests = [
+ { name:"404.wav", type:"audio/x-wav" },
+ { name:"404.ogv", type:"video/ogg" },
+ { name:"404.oga", type:"audio/ogg" },
+ { name:"404.webm", type:"video/webm" },
+ { name:"bogus.duh", type:"bogus/duh" }
+];
+
+// These are files suitable for testing various decoder failures that are
+// expected to fire MEDIA_ERR_DECODE. Used by test_decode_error, which expects
+// an error and emptied event, and no loadedmetadata or ended event.
+var gDecodeErrorTests = [
+ // Valid files with unsupported codecs
+ { name:"r11025_msadpcm_c1.wav", type:"audio/x-wav" },
+ { name:"dirac.ogg", type:"video/ogg" },
+ // Invalid files
+ { name:"bogus.wav", type:"audio/x-wav" },
+ { name:"bogus.ogv", type:"video/ogg" },
+
+ { name:"bogus.duh", type:"bogus/duh" }
+];
+
+// These are files that are used for media fragments tests
+var gFragmentTests = [
+ { name:"big.wav", type:"audio/x-wav", duration:9.278982, size:102444 }
+];
+
+// Used by test_chaining.html. The |links| attributes is the number of links in
+// this file that we should be able to play.
+var gChainingTests = [
+ // Vorbis and Opus chained file. They have user comments |index=n| where `n`
+ // is the index of this segment in the file, 0 indexed.
+ { name:"chain.ogg", type:"audio/ogg", links: 4},
+ { name:"chain.opus", type:"audio/ogg; codec=opus", links: 4},
+ // Those files are chained files with a different number of channels in each
+ // part. This is not supported and should stop playing after the first part.
+ { name:"variable-channel.ogg", type:"audio/ogg", links: 1 },
+ { name:"variable-channel.opus", type:"audio/ogg; codec=opus", links: 1 },
+ // Those files are chained files with a different sample rate in each
+ // part. This is not supported and should stop playing after the first part.
+ { name:"variable-samplerate.ogg", type:"audio/ogg", links: 1 },
+ // Opus decoding in Firefox outputs 48 kHz PCM despite having a different
+ // original sample rate, so we can safely play Opus chained media that have
+ // different samplerate accross links.
+ { name:"variable-samplerate.opus", type:"audio/ogg; codec=opus", links: 2 },
+ // A chained video file. We don't support those, so only one link should be
+ // reported.
+ { name:"chained-video.ogv", type:"video/ogg", links: 1 },
+ // A file that consist in 4 links of audio, then another link that has video.
+ // We should stop right after the 4 audio links.
+ { name:"chained-audio-video.ogg", type:"video/ogg", links: 4 },
+ // An opus file that has two links, with a different preskip value for each
+ // link. We should be able to play both links.
+ { name:"variable-preskip.opus", type:"audio/ogg; codec=opus", links: 2 },
+ { name:"bogus.duh", type:"bogus/duh" }
+];
+
+// Videos with an aspect ratio. Used for testing that displaying frames
+// on a canvas works correctly in the case of non-standard aspect ratios.
+// See bug 874897 for an example.
+var gAspectRatioTests = [
+ { name:"VID_0001.ogg", type:"video/ogg", duration:19.966 }
+];
+
+// These are files with non-trivial tag sets.
+// Used by test_metadata.html.
+var gMetadataTests = [
+ // Ogg Vorbis files
+ { name:"short-video.ogv", tags: {
+ TITLE:"Lepidoptera",
+ ARTIST:"Epoq",
+ ALBUM:"Kahvi Collective",
+ DATE:"2002",
+ COMMENT:"http://www.kahvi.org",
+ }
+ },
+ { name:"bug516323.ogv", tags: {
+ GENRE:"Open Movie",
+ ENCODER:"Audacity",
+ TITLE:"Elephants Dream",
+ ARTIST:"Silvia Pfeiffer",
+ COMMENTS:"Audio Description"
+ }
+ },
+ { name:"bug516323.indexed.ogv", tags: {
+ GENRE:"Open Movie",
+ ENCODER:"Audacity",
+ TITLE:"Elephants Dream",
+ ARTIST:"Silvia Pfeiffer",
+ COMMENTS:"Audio Description"
+ }
+ },
+ { name:"detodos.opus", tags: {
+ title:"De todos. Para todos.",
+ artist:"Mozilla.org"
+ }
+ },
+ { name:"sound.ogg", tags: { } },
+ { name:"small-shot.ogg", tags: {
+ title:"Pew SFX"
+ }
+ },
+ { name:"badtags.ogg", tags: {
+ // We list only the valid tags here, and verify
+ // the invalid ones are filtered out.
+ title:"Invalid comments test file",
+ empty:"",
+ "":"empty",
+ "{- [(`!@\"#$%^&')] -}":"valid tag name, surprisingly"
+ // The file also includes the following invalid tags.
+ // "A description with no separator is a common problem.",
+ // "雨":"Likely, but an invalid key (non-ascii).",
+ // "not\nval\x1fid":"invalid tag name",
+ // "not~valid":"this isn't a valid name either",
+ // "not-utf-8":"invalid sequences: \xff\xfe\xfa\xfb\0eol"
+ }
+ },
+ { name:"wave_metadata.wav", tags: {
+ name:"Track Title",
+ artist:"Artist Name",
+ comments:"Comments",
+ }
+ },
+ { name:"wave_metadata_utf8.wav", tags: {
+ name:"歌曲名稱",
+ artist:"作曲者",
+ comments:"註解",
+ }
+ },
+ { name:"wave_metadata_unknown_tag.wav", tags: {
+ name:"Track Title",
+ comments:"Comments",
+ }
+ },
+ { name:"wave_metadata_bad_len.wav", tags: {
+ name:"Track Title",
+ artist:"Artist Name",
+ comments:"Comments",
+ }
+ },
+ { name:"wave_metadata_bad_no_null.wav", tags: {
+ name:"Track Title",
+ artist:"Artist Name",
+ comments:"Comments!!",
+ }
+ },
+ { name:"wave_metadata_bad_utf8.wav", tags: {
+ name:"歌曲名稱",
+ comments:"註解",
+ }
+ },
+ { name:"wavedata_u8.wav", tags: { }
+ },
+ { name:"flac-s24.flac", tags: {
+ ALBUM:"Seascapes",
+ TITLE:"(La Mer) - II. Jeux de vagues. Allegro",
+ COMPOSER:"Debussy, Claude",
+ TRACKNUMBER:"2/9",
+ DISCNUMBER:"1/1",
+ encoder:"Lavf57.41.100",
+ }
+ },
+];
+
+// Test files for Encrypted Media Extensions
+var gEMETests = [
+ {
+ name:"video-only with 2 keys",
+ tracks: [
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop-cenc-videoinit.mp4",
+ "bipbop-cenc-video1.m4s",
+ "bipbop-cenc-video2.m4s",
+ ]
+ }
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
+ "7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
+ },
+ sessionType:"temporary",
+ sessionCount:1,
+ duration:1.60,
+ },
+ {
+ name:"video-only with 2 keys, CORS",
+ tracks: [
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop-cenc-videoinit.mp4",
+ "bipbop-cenc-video1.m4s",
+ "bipbop-cenc-video2.m4s",
+ ]
+ }
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
+ "7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
+ },
+ sessionType:"temporary",
+ sessionCount:1,
+ crossOrigin:true,
+ duration:1.60,
+ },
+ {
+ name:"audio&video tracks, both with all keys",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[ "bipbop-cenc-audioinit.mp4",
+ "bipbop-cenc-audio1.m4s",
+ "bipbop-cenc-audio2.m4s",
+ "bipbop-cenc-audio3.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop-cenc-videoinit.mp4",
+ "bipbop-cenc-video1.m4s",
+ "bipbop-cenc-video2.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
+ "7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
+ },
+ sessionType:"temporary",
+ sessionCount:2,
+ duration:1.60,
+ },
+ {
+ name:"audio&video tracks, both with all keys, CORS",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[ "bipbop-cenc-audioinit.mp4",
+ "bipbop-cenc-audio1.m4s",
+ "bipbop-cenc-audio2.m4s",
+ "bipbop-cenc-audio3.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop-cenc-videoinit.mp4",
+ "bipbop-cenc-video1.m4s",
+ "bipbop-cenc-video2.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
+ "7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
+ },
+ sessionType:"temporary",
+ sessionCount:2,
+ crossOrigin:true,
+ duration:1.60,
+ },
+ {
+ name:"400x300 audio&video tracks, each with its key",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[ "bipbop_300_215kbps-cenc-audio-key1-init.mp4",
+ "bipbop_300_215kbps-cenc-audio-key1-1.m4s",
+ "bipbop_300_215kbps-cenc-audio-key1-2.m4s",
+ "bipbop_300_215kbps-cenc-audio-key1-3.m4s",
+ "bipbop_300_215kbps-cenc-audio-key1-4.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop_300_215kbps-cenc-video-key1-init.mp4",
+ "bipbop_300_215kbps-cenc-video-key1-1.m4s",
+ "bipbop_300_215kbps-cenc-video-key1-2.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
+ "7e571d047e571d047e571d047e571d21" : "7e5744447e5744447e5744447e574421",
+ },
+ sessionType:"temporary",
+ sessionCount:2,
+ duration:1.60,
+ },
+ {
+ name:"640x480@624kbps audio&video tracks, each with its key",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[ "bipbop_480_624kbps-cenc-audio-key1-init.mp4",
+ "bipbop_480_624kbps-cenc-audio-key1-1.m4s",
+ "bipbop_480_624kbps-cenc-audio-key1-2.m4s",
+ "bipbop_480_624kbps-cenc-audio-key1-3.m4s",
+ "bipbop_480_624kbps-cenc-audio-key1-4.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop_480_624kbps-cenc-video-key1-init.mp4",
+ "bipbop_480_624kbps-cenc-video-key1-1.m4s",
+ "bipbop_480_624kbps-cenc-video-key1-2.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
+ "7e571d047e571d047e571d047e571d21" : "7e5744447e5744447e5744447e574421",
+ },
+ sessionType:"temporary",
+ sessionCount:2,
+ duration:1.60,
+ },
+ {
+ name:"640x480@959kbps audio&video tracks, each with its key",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[ "bipbop_480_959kbps-cenc-audio-key1-init.mp4",
+ "bipbop_480_959kbps-cenc-audio-key1-1.m4s",
+ "bipbop_480_959kbps-cenc-audio-key1-2.m4s",
+ "bipbop_480_959kbps-cenc-audio-key1-3.m4s",
+ "bipbop_480_959kbps-cenc-audio-key1-4.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop_480_959kbps-cenc-video-key1-init.mp4",
+ "bipbop_480_959kbps-cenc-video-key1-1.m4s",
+ "bipbop_480_959kbps-cenc-video-key1-2.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
+ "7e571d047e571d047e571d047e571d21" : "7e5744447e5744447e5744447e574421",
+ },
+ sessionType:"temporary",
+ sessionCount:2,
+ duration:1.60,
+ },
+ {
+ name:"640x480 then 400x300, same key (1st) per track",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[ "bipbop_480_624kbps-cenc-audio-key1-init.mp4",
+ "bipbop_480_624kbps-cenc-audio-key1-1.m4s",
+ "bipbop_480_624kbps-cenc-audio-key1-2.m4s",
+ "bipbop_480_624kbps-cenc-audio-key1-3.m4s",
+ "bipbop_480_624kbps-cenc-audio-key1-4.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop_480_624kbps-cenc-video-key1-init.mp4",
+ "bipbop_480_624kbps-cenc-video-key1-1.m4s",
+ "bipbop_300_215kbps-cenc-video-key1-init.mp4",
+ "bipbop_300_215kbps-cenc-video-key1-2.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
+ "7e571d047e571d047e571d047e571d21" : "7e5744447e5744447e5744447e574421",
+ },
+ sessionType:"temporary",
+ sessionCount:3,
+ duration:1.60,
+ },
+ {
+ name:"640x480 then 400x300, same key (2nd) per track",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[ "bipbop_480_624kbps-cenc-audio-key2-init.mp4",
+ "bipbop_480_624kbps-cenc-audio-key2-1.m4s",
+ "bipbop_480_624kbps-cenc-audio-key2-2.m4s",
+ "bipbop_480_624kbps-cenc-audio-key2-3.m4s",
+ "bipbop_480_624kbps-cenc-audio-key2-4.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop_480_624kbps-cenc-video-key2-init.mp4",
+ "bipbop_480_624kbps-cenc-video-key2-1.m4s",
+ "bipbop_300_215kbps-cenc-video-key2-init.mp4",
+ "bipbop_300_215kbps-cenc-video-key2-2.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d12" : "7e5733337e5733337e5733337e573312",
+ "7e571d047e571d047e571d047e571d22" : "7e5744447e5744447e5744447e574422",
+ },
+ sessionType:"temporary",
+ sessionCount:3,
+ duration:1.60,
+ },
+ {
+ name:"640x480 with 1st keys then 400x300 with 2nd keys",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[ "bipbop_480_624kbps-cenc-audio-key1-init.mp4",
+ "bipbop_480_624kbps-cenc-audio-key1-1.m4s",
+ "bipbop_480_624kbps-cenc-audio-key1-2.m4s",
+ "bipbop_480_624kbps-cenc-audio-key1-3.m4s",
+ "bipbop_480_624kbps-cenc-audio-key1-4.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop_480_624kbps-cenc-video-key1-init.mp4",
+ "bipbop_480_624kbps-cenc-video-key1-1.m4s",
+ "bipbop_300_215kbps-cenc-video-key2-init.mp4",
+ "bipbop_300_215kbps-cenc-video-key2-2.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
+ "7e571d037e571d037e571d037e571d12" : "7e5733337e5733337e5733337e573312",
+ "7e571d047e571d047e571d047e571d21" : "7e5744447e5744447e5744447e574421",
+ },
+ sessionType:"temporary",
+ sessionCount:3,
+ duration:1.60,
+ },
+ {
+ name:"400x300 with 1st keys then 640x480 with 2nd keys",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[ "bipbop_300_215kbps-cenc-audio-key1-init.mp4",
+ "bipbop_300_215kbps-cenc-audio-key1-1.m4s",
+ "bipbop_300_215kbps-cenc-audio-key1-2.m4s",
+ "bipbop_300_215kbps-cenc-audio-key1-3.m4s",
+ "bipbop_300_215kbps-cenc-audio-key1-4.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop_300_215kbps-cenc-video-key1-init.mp4",
+ "bipbop_300_215kbps-cenc-video-key1-1.m4s",
+ "bipbop_480_624kbps-cenc-video-key2-init.mp4",
+ "bipbop_480_624kbps-cenc-video-key2-2.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
+ "7e571d037e571d037e571d037e571d12" : "7e5733337e5733337e5733337e573312",
+ "7e571d047e571d047e571d047e571d21" : "7e5744447e5744447e5744447e574421",
+ },
+ sessionType:"temporary",
+ sessionCount:3,
+ duration:1.60,
+ },
+ {
+ name:"640x480@959kbps with 1st keys then 640x480@624kbps with 2nd keys",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[ "bipbop_480_959kbps-cenc-audio-key1-init.mp4",
+ "bipbop_480_959kbps-cenc-audio-key1-1.m4s",
+ "bipbop_480_959kbps-cenc-audio-key1-2.m4s",
+ "bipbop_480_959kbps-cenc-audio-key1-3.m4s",
+ "bipbop_480_959kbps-cenc-audio-key1-4.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop_480_959kbps-cenc-video-key1-init.mp4",
+ "bipbop_480_959kbps-cenc-video-key1-1.m4s",
+ "bipbop_480_624kbps-cenc-video-key2-init.mp4",
+ "bipbop_480_624kbps-cenc-video-key2-2.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
+ "7e571d037e571d037e571d037e571d12" : "7e5733337e5733337e5733337e573312",
+ "7e571d047e571d047e571d047e571d21" : "7e5744447e5744447e5744447e574421",
+ },
+ sessionType:"temporary",
+ sessionCount:3,
+ duration:1.60,
+ },
+ {
+ name:"640x480@624kbps with 1st keys then 640x480@959kbps with 2nd keys",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[ "bipbop_480_624kbps-cenc-audio-key1-init.mp4",
+ "bipbop_480_624kbps-cenc-audio-key1-1.m4s",
+ "bipbop_480_624kbps-cenc-audio-key1-2.m4s",
+ "bipbop_480_624kbps-cenc-audio-key1-3.m4s",
+ "bipbop_480_624kbps-cenc-audio-key1-4.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop_480_624kbps-cenc-video-key1-init.mp4",
+ "bipbop_480_624kbps-cenc-video-key1-1.m4s",
+ "bipbop_480_959kbps-cenc-video-key2-init.mp4",
+ "bipbop_480_959kbps-cenc-video-key2-2.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
+ "7e571d037e571d037e571d037e571d12" : "7e5733337e5733337e5733337e573312",
+ "7e571d047e571d047e571d047e571d21" : "7e5744447e5744447e5744447e574421",
+ },
+ sessionType:"temporary",
+ sessionCount:3,
+ duration:1.60,
+ },
+ {
+ name:"400x300 with presentation size 533x300",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[ "bipbop_300wp_227kbps-cenc-audio-key1-init.mp4",
+ "bipbop_300wp_227kbps-cenc-audio-key1-1.m4s",
+ "bipbop_300wp_227kbps-cenc-audio-key1-2.m4s",
+ "bipbop_300wp_227kbps-cenc-audio-key1-3.m4s",
+ "bipbop_300wp_227kbps-cenc-audio-key1-4.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop_300wp_227kbps-cenc-video-key1-init.mp4",
+ "bipbop_300wp_227kbps-cenc-video-key1-1.m4s",
+ "bipbop_300wp_227kbps-cenc-video-key1-2.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
+ "7e571d047e571d047e571d047e571d21" : "7e5744447e5744447e5744447e574421",
+ },
+ sessionType:"temporary",
+ sessionCount:2,
+ duration:1.60,
+ },
+ {
+ name:"400x300 as-is then 400x300 presented as 533x300",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[
+ "bipbop_300_215kbps-cenc-audio-key1-init.mp4",
+ "bipbop_300_215kbps-cenc-audio-key1-1.m4s",
+ "bipbop_300_215kbps-cenc-audio-key1-2.m4s",
+ "bipbop_300_215kbps-cenc-audio-key1-3.m4s",
+ "bipbop_300_215kbps-cenc-audio-key1-4.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop_300_215kbps-cenc-video-key1-init.mp4",
+ "bipbop_300_215kbps-cenc-video-key1-1.m4s",
+ "bipbop_300wp_227kbps-cenc-video-key1-init.mp4",
+ "bipbop_300wp_227kbps-cenc-video-key1-2.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
+ "7e571d047e571d047e571d047e571d21" : "7e5744447e5744447e5744447e574421",
+ },
+ sessionType:"temporary",
+ sessionCount:3,
+ duration:1.60,
+ },
+ {
+ name:"400x225",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[ "bipbop_225w_175kbps-cenc-audio-key1-init.mp4",
+ "bipbop_225w_175kbps-cenc-audio-key1-1.m4s",
+ "bipbop_225w_175kbps-cenc-audio-key1-2.m4s",
+ "bipbop_225w_175kbps-cenc-audio-key1-3.m4s",
+ "bipbop_225w_175kbps-cenc-audio-key1-4.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop_225w_175kbps-cenc-video-key1-init.mp4",
+ "bipbop_225w_175kbps-cenc-video-key1-1.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
+ "7e571d047e571d047e571d047e571d21" : "7e5744447e5744447e5744447e574421",
+ },
+ sessionType:"temporary",
+ sessionCount:2,
+ duration:1.60,
+ },
+ {
+ name:"640x360",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[ "bipbop_360w_253kbps-cenc-audio-key1-init.mp4",
+ "bipbop_360w_253kbps-cenc-audio-key1-1.m4s",
+ "bipbop_360w_253kbps-cenc-audio-key1-2.m4s",
+ "bipbop_360w_253kbps-cenc-audio-key1-3.m4s",
+ "bipbop_360w_253kbps-cenc-audio-key1-4.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop_360w_253kbps-cenc-video-key1-init.mp4",
+ "bipbop_360w_253kbps-cenc-video-key1-1.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
+ "7e571d047e571d047e571d047e571d21" : "7e5744447e5744447e5744447e574421",
+ },
+ sessionType:"temporary",
+ sessionCount:2,
+ duration:1.60,
+ },
+ {
+ name:"400x225 then 640x360",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[ "bipbop_225w_175kbps-cenc-audio-key1-init.mp4",
+ "bipbop_225w_175kbps-cenc-audio-key1-1.m4s",
+ "bipbop_225w_175kbps-cenc-audio-key1-2.m4s",
+ "bipbop_225w_175kbps-cenc-audio-key1-3.m4s",
+ "bipbop_225w_175kbps-cenc-audio-key1-4.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop_225w_175kbps-cenc-video-key1-init.mp4",
+ "bipbop_225w_175kbps-cenc-video-key1-1.m4s",
+ "bipbop_360w_253kbps-cenc-video-key2-init.mp4",
+ "bipbop_360w_253kbps-cenc-video-key2-1.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
+ "7e571d047e571d047e571d047e571d21" : "7e5744447e5744447e5744447e574421",
+ "7e571d037e571d037e571d037e571d12" : "7e5733337e5733337e5733337e573312",
+ },
+ sessionType:"temporary",
+ sessionCount:3,
+ duration:1.60,
+ },
+ {
+ name:"640x360 then 640x480",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/mp4; codecs=\"mp4a.40.2\"",
+ fragments:[ "bipbop_360w_253kbps-cenc-audio-key1-init.mp4",
+ "bipbop_360w_253kbps-cenc-audio-key1-1.m4s",
+ "bipbop_360w_253kbps-cenc-audio-key1-2.m4s",
+ "bipbop_360w_253kbps-cenc-audio-key1-3.m4s",
+ "bipbop_360w_253kbps-cenc-audio-key1-4.m4s",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/mp4; codecs=\"avc1.64000d\"",
+ fragments:[ "bipbop_360w_253kbps-cenc-video-key1-init.mp4",
+ "bipbop_360w_253kbps-cenc-video-key1-1.m4s",
+ "bipbop_480_624kbps-cenc-video-key2-init.mp4",
+ "bipbop_480_624kbps-cenc-video-key2-2.m4s",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "7e571d037e571d037e571d037e571d11" : "7e5733337e5733337e5733337e573311",
+ "7e571d047e571d047e571d047e571d21" : "7e5744447e5744447e5744447e574421",
+ "7e571d037e571d037e571d037e571d12" : "7e5733337e5733337e5733337e573312",
+ },
+ sessionType:"temporary",
+ sessionCount:3,
+ duration:1.60,
+ },
+ {
+ name: "WebM vorbis audio & vp8 video clearkey",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/webm; codecs=\"vorbis\"",
+ fragments:[ "bipbop_360w_253kbps-clearkey-audio.webm",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/webm; codecs=\"vp8\"",
+ fragments:[ "bipbop_360w_253kbps-clearkey-video-vp8.webm",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "f1f3ee1790527e9de47217d43835f76a" : "97b9ddc459c8d5ff23c1f2754c95abe8",
+ "8b5df745ad84145b5617c33116e35a67" : "bddfd35dd9be033ee73bc18bc1885056",
+ },
+ sessionType:"temporary",
+ sessionCount:2,
+ duration:1.60,
+ },
+ {
+ name: "WebM vorbis audio & vp9 video clearkey",
+ tracks: [
+ {
+ name:"audio",
+ type:"audio/webm; codecs=\"vorbis\"",
+ fragments:[ "bipbop_360w_253kbps-clearkey-audio.webm",
+ ],
+ },
+ {
+ name:"video",
+ type:"video/webm; codecs=\"vp9\"",
+ fragments:[ "bipbop_360w_253kbps-clearkey-video-vp9.webm",
+ ],
+ },
+ ],
+ keys: {
+ // "keyid" : "key"
+ "f1f3ee1790527e9de47217d43835f76a" : "97b9ddc459c8d5ff23c1f2754c95abe8",
+ "eedf63a94fa7c398ee094f123a4ee709" : "973b679a746c82f3acdb856b30e9378e",
+ },
+ sessionType:"temporary",
+ sessionCount:2,
+ duration:1.60,
+ },
+];
+
+var gEMENonMSEFailTests = [
+ {
+ name:"short-cenc.mp4",
+ audioType:"audio/mp4; codecs=\"mp4a.40.2\"",
+ videoType:"video/mp4; codecs=\"avc1.64000d\"",
+ duration:0.47,
+ },
+];
+
+// These are files that are used for video decode suspend in
+// background tabs tests.
+var gDecodeSuspendTests = [
+ { name:"gizmo.mp4", type:"video/mp4", duration:5.56 },
+ { name:"gizmo-noaudio.mp4", type:"video/mp4", duration:5.56 },
+ { name:"gizmo.webm", type:'video/webm; codecs="vp9,opus"', duration:5.56 },
+ { name:"gizmo-noaudio.webm", type:'video/webm; codecs="vp9"', duration:5.56 }
+];
+
+function checkMetadata(msg, e, test) {
+ if (test.width) {
+ is(e.videoWidth, test.width, msg + " video width");
+ }
+ if (test.height) {
+ is(e.videoHeight, test.height, msg + " video height");
+ }
+ if (test.duration) {
+ ok(Math.abs(e.duration - test.duration) < 0.1,
+ msg + " duration (" + e.duration + ") should be around " + test.duration);
+ }
+ is(!!test.keys, SpecialPowers.do_lookupGetter(e, "isEncrypted").apply(e),
+ msg + " isEncrypted should be true if we have decryption keys");
+}
+
+// Returns the first test from candidates array which we can play with the
+// installed video backends.
+function getPlayableVideo(candidates) {
+ var resources = getPlayableVideos(candidates);
+ if (resources.length > 0)
+ return resources[0];
+ return null;
+}
+
+function getPlayableVideos(candidates) {
+ var v = manifestVideo();
+ return candidates.filter(function(x){return /^video/.test(x.type) && v.canPlayType(x.type);});
+}
+
+function getPlayableAudio(candidates) {
+ var v = manifestVideo();
+ var resources = candidates.filter(function(x){return /^audio/.test(x.type) && v.canPlayType(x.type);});
+ if (resources.length > 0)
+ return resources[0];
+ return null;
+}
+
+// Returns the type of element that should be created for the given mimetype.
+function getMajorMimeType(mimetype) {
+ if (/^video/.test(mimetype)) {
+ return "video";
+ } else {
+ return "audio";
+ }
+}
+
+// Force releasing decoder to avoid timeout in waiting for decoding resource.
+function removeNodeAndSource(n) {
+ n.remove();
+ // Clearing srcObject and/or src will actually set them to some default
+ // URI that will fail to load, so make sure we don't produce a spurious
+ // bailing error.
+ n.onerror = null;
+ // reset |srcObject| first since it takes precedence over |src|.
+ n.srcObject = null;
+ n.src = "";
+ while (n.firstChild) {
+ n.removeChild(n.firstChild);
+ }
+}
+
+function once(target, name, cb) {
+ var p = new Promise(function(resolve, reject) {
+ target.addEventListener(name, function onceEvent() {
+ target.removeEventListener(name, onceEvent);
+ resolve();
+ });
+ });
+ if (cb) {
+ p.then(cb);
+ }
+ return p;
+}
+
+function TimeStamp(token) {
+ function pad(x) {
+ return (x < 10) ? "0" + x : x;
+ }
+ var now = new Date();
+ var ms = now.getMilliseconds();
+ var time = "[" +
+ pad(now.getHours()) + ":" +
+ pad(now.getMinutes()) + ":" +
+ pad(now.getSeconds()) + "." +
+ ms +
+ "]" +
+ (ms < 10 ? " " : (ms < 100 ? " " : ""));
+ return token ? (time + " " + token) : time;
+}
+
+function Log(token, msg) {
+ info(TimeStamp(token) + " " + msg);
+}
+
+// Number of tests to run in parallel.
+var PARALLEL_TESTS = 2;
+
+// Prefs to set before running tests. Use this to improve coverage of
+// conditions that might not otherwise be encountered on the test data.
+var gTestPrefs = [
+ ['media.recorder.max_memory', 1024],
+];
+
+// When true, we'll loop forever on whatever test we run. Use this to debug
+// intermittent test failures.
+const DEBUG_TEST_LOOP_FOREVER = false;
+
+// Manages a run of media tests. Runs them in chunks in order to limit
+// the number of media elements/threads running in parallel. This limits peak
+// memory use, particularly on Linux x86 where thread stacks use 10MB of
+// virtual address space.
+// Usage:
+// 1. Create a new MediaTestManager object.
+// 2. Create a test startTest function. This takes a test object and a token,
+// and performs anything necessary to start the test. The test object is an
+// element in one of the g*Tests above. Your startTest function must call
+// MediaTestManager.start(token) if it starts a test. The test object is
+// guaranteed to be playable by our supported decoders; you don't need to
+// check canPlayType.
+// 3. When your tests finishes, call MediaTestManager.finished(), passing
+// the token back to the manager. The manager may either start the next run
+// or end the mochitest if all the tests are done.
+function MediaTestManager() {
+
+ // Return how many seconds elapsed since |begin|.
+ function elapsedTime(begin) {
+ var end = new Date();
+ return (end.getTime() - begin.getTime()) / 1000;
+ }
+ // Sets up a MediaTestManager to runs through the 'tests' array, which needs
+ // to be one of, or have the same fields as, the g*Test arrays of tests. Uses
+ // the user supplied 'startTest' function to initialize the test. This
+ // function must accept two arguments, the test entry from the 'tests' array,
+ // and a token. Call MediaTestManager.started(token) if you start the test,
+ // and MediaTestManager.finished(token) when the test finishes. You don't have
+ // to start every test, but if you call started() you *must* call finish()
+ // else you'll timeout.
+ this.runTests = function(tests, startTest) {
+ this.startTime = new Date();
+ SimpleTest.info("Started " + this.startTime + " (" + this.startTime.getTime()/1000 + "s)");
+ this.testNum = 0;
+ this.tests = tests;
+ this.startTest = startTest;
+ this.tokens = [];
+ this.isShutdown = false;
+ this.numTestsRunning = 0;
+ this.handlers = {};
+
+ // Always wait for explicit finish.
+ SimpleTest.waitForExplicitFinish();
+ SpecialPowers.pushPrefEnv({'set': gTestPrefs}, (function() {
+ this.nextTest();
+ }).bind(this));
+
+ SimpleTest.registerCleanupFunction(function() {
+ if (this.tokens.length > 0) {
+ info("Test timed out. Remaining tests=" + this.tokens);
+ }
+ for (var token of this.tokens) {
+ var handler = this.handlers[token];
+ if (handler && handler.ontimeout) {
+ handler.ontimeout();
+ }
+ }
+ }.bind(this));
+ }
+
+ // Registers that the test corresponding to 'token' has been started.
+ // Don't call more than once per token.
+ this.started = function(token, handler) {
+ this.tokens.push(token);
+ this.numTestsRunning++;
+ this.handlers[token] = handler;
+ is(this.numTestsRunning, this.tokens.length,
+ "[started " + token + " t=" + elapsedTime(this.startTime) + "] Length of array should match number of running tests");
+ }
+
+ // Registers that the test corresponding to 'token' has finished. Call when
+ // you've finished your test. If all tests are complete this will finish the
+ // run, otherwise it may start up the next run. It's ok to call multiple times
+ // per token.
+ this.finished = function(token) {
+ var i = this.tokens.indexOf(token);
+ if (i != -1) {
+ // Remove the element from the list of running tests.
+ this.tokens.splice(i, 1);
+ }
+
+ info("[finished " + token + "] remaining= " + this.tokens);
+ this.numTestsRunning--;
+ is(this.numTestsRunning, this.tokens.length,
+ "[finished " + token + " t=" + elapsedTime(this.startTime) + "] Length of array should match number of running tests");
+ if (this.tokens.length < PARALLEL_TESTS) {
+ this.nextTest();
+ }
+ }
+
+ // Starts the next batch of tests, or finishes if they're all done.
+ // Don't call this directly, call finished(token) when you're done.
+ this.nextTest = function() {
+ while (this.testNum < this.tests.length && this.tokens.length < PARALLEL_TESTS) {
+ var test = this.tests[this.testNum];
+ var token = (test.name ? (test.name + "-"): "") + this.testNum;
+ this.testNum++;
+
+ if (DEBUG_TEST_LOOP_FOREVER && this.testNum == this.tests.length) {
+ this.testNum = 0;
+ }
+
+ // Ensure we can play the resource type.
+ if (test.type && !document.createElement('video').canPlayType(test.type))
+ continue;
+
+ // Do the init. This should start the test.
+ this.startTest(test, token);
+ }
+
+ if (this.testNum == this.tests.length &&
+ !DEBUG_TEST_LOOP_FOREVER &&
+ this.tokens.length == 0 &&
+ !this.isShutdown)
+ {
+ this.isShutdown = true;
+ if (this.onFinished) {
+ this.onFinished();
+ }
+ var onCleanup = function() {
+ var end = new Date();
+ SimpleTest.info("Finished at " + end + " (" + (end.getTime() / 1000) + "s)");
+ SimpleTest.info("Running time: " + elapsedTime(this.startTime) + "s");
+ SimpleTest.finish();
+ }.bind(this);
+ mediaTestCleanup(onCleanup);
+ return;
+ }
+ }
+}
+
+// Ensures we've got no active video or audio elements in the document, and
+// forces a GC to release the address space reserved by the decoders' threads'
+// stacks.
+function mediaTestCleanup(callback) {
+ var V = document.getElementsByTagName("video");
+ for (i=0; i<V.length; i++) {
+ removeNodeAndSource(V[i]);
+ V[i] = null;
+ }
+ var A = document.getElementsByTagName("audio");
+ for (i=0; i<A.length; i++) {
+ removeNodeAndSource(A[i]);
+ A[i] = null;
+ }
+ SpecialPowers.exactGC(callback);
+}
+
+// B2G emulator and Android 2.3 are condidered slow platforms
+function isSlowPlatform() {
+ return SpecialPowers.Services.appinfo.name == "B2G" || getAndroidVersion() == 10;
+}
+
+// Could be undefined in a page opened by the parent test page
+// like file_access_controls.html.
+if ("SimpleTest" in window) {
+ SimpleTest.requestFlakyTimeout("untriaged");
+
+ // Register timeout function to dump debugging logs.
+ SimpleTest.registerTimeoutFunction(function() {
+ for (var v of document.getElementsByTagName("video")) {
+ v.mozDumpDebugInfo();
+ }
+ for (var a of document.getElementsByTagName("audio")) {
+ a.mozDumpDebugInfo();
+ }
+ });
+}
diff --git a/dom/media/test/mochitest.ini b/dom/media/test/mochitest.ini
new file mode 100644
index 000000000..ddabf78b6
--- /dev/null
+++ b/dom/media/test/mochitest.ini
@@ -0,0 +1,922 @@
+# Media tests should be backend independent, i.e., not conditioned on ogg,
+# wave etc. (The only exception is the can_play_type tests, which
+# necessarily depend on the backend(s) configured.) As far as possible, each
+# test should work with any resource type. This makes it easy to add new
+# backends and reduces the amount of test duplication.
+
+# For each supported backend, resources that can be played by that backend
+# should be added to the lists in manifest.js. Media tests that aren't
+# testing for a bug in handling a specific resource type should pick one of
+# the lists in manifest.js and run the test for each resource in the list
+# that is supported in the current build (the canPlayType API is useful for
+# this).
+
+# To test whether a valid resource can simply be played through correctly,
+# and optionally that its metadata is read correctly, just add it to
+# gPlayTests in manifest.js. To test whether an invalid resource correctly
+# throws an error (and does not cause a crash or hang), just add it to
+# gErrorTests in manifest.js.
+
+# To test for a specific bug in handling a specific resource type, make the
+# test first check canPlayType for the type, and if it's not supported, just
+# do ok(true, "Type not supported") and stop the test.
+
+[DEFAULT]
+subsuite = media
+skip-if = android_version == '18' # Run on real devices via autophone
+support-files =
+ 16bit_wave_extrametadata.wav
+ 16bit_wave_extrametadata.wav^headers^
+ 320x240.ogv
+ 320x240.ogv^headers^
+ 448636.ogv
+ 448636.ogv^headers^
+ A4.ogv
+ A4.ogv^headers^
+ VID_0001.ogg
+ VID_0001.ogg^headers^
+ allowed.sjs
+ audio-gaps.ogg
+ audio-gaps.ogg^headers^
+ audio-gaps-short.ogg
+ audio-gaps-short.ogg^headers^
+ audio-overhang.ogg
+ audio-overhang.ogg^headers^
+ audio.wav
+ audio.wav^headers^
+ background_video.js
+ badtags.ogg
+ badtags.ogg^headers^
+ basic.vtt
+ bad-signature.vtt
+ beta-phrasebook.ogg
+ beta-phrasebook.ogg^headers^
+ big.wav
+ big.wav^headers^
+ big-short.wav
+ big-short.wav^headers^
+ bipbop-cenc-audio1.m4s
+ bipbop-cenc-audio1.m4s^headers^
+ bipbop-cenc-audio2.m4s
+ bipbop-cenc-audio2.m4s^headers^
+ bipbop-cenc-audio3.m4s
+ bipbop-cenc-audio3.m4s^headers^
+ bipbop-cenc-audioinit.mp4
+ bipbop-cenc-audioinit.mp4^headers^
+ bipbop-cenc-video1.m4s
+ bipbop-cenc-video1.m4s^headers^
+ bipbop-cenc-video2.m4s
+ bipbop-cenc-video2.m4s^headers^
+ bipbop-cenc-videoinit.mp4
+ bipbop-cenc-videoinit.mp4^headers^
+ bipbop_225w_175kbps-cenc-audio-key1-1.m4s
+ bipbop_225w_175kbps-cenc-audio-key1-1.m4s^headers^
+ bipbop_225w_175kbps-cenc-audio-key1-2.m4s
+ bipbop_225w_175kbps-cenc-audio-key1-2.m4s^headers^
+ bipbop_225w_175kbps-cenc-audio-key1-3.m4s
+ bipbop_225w_175kbps-cenc-audio-key1-3.m4s^headers^
+ bipbop_225w_175kbps-cenc-audio-key1-4.m4s
+ bipbop_225w_175kbps-cenc-audio-key1-4.m4s^headers^
+ bipbop_225w_175kbps-cenc-audio-key1-init.mp4
+ bipbop_225w_175kbps-cenc-audio-key1-init.mp4^headers^
+ bipbop_225w_175kbps-cenc-audio-key2-1.m4s
+ bipbop_225w_175kbps-cenc-audio-key2-1.m4s^headers^
+ bipbop_225w_175kbps-cenc-audio-key2-2.m4s
+ bipbop_225w_175kbps-cenc-audio-key2-2.m4s^headers^
+ bipbop_225w_175kbps-cenc-audio-key2-3.m4s
+ bipbop_225w_175kbps-cenc-audio-key2-3.m4s^headers^
+ bipbop_225w_175kbps-cenc-audio-key2-4.m4s
+ bipbop_225w_175kbps-cenc-audio-key2-4.m4s^headers^
+ bipbop_225w_175kbps-cenc-audio-key2-init.mp4
+ bipbop_225w_175kbps-cenc-audio-key2-init.mp4^headers^
+ bipbop_225w_175kbps-cenc-video-key1-1.m4s
+ bipbop_225w_175kbps-cenc-video-key1-1.m4s^headers^
+ bipbop_225w_175kbps-cenc-video-key1-init.mp4
+ bipbop_225w_175kbps-cenc-video-key1-init.mp4^headers^
+ bipbop_225w_175kbps-cenc-video-key2-1.m4s
+ bipbop_225w_175kbps-cenc-video-key2-1.m4s^headers^
+ bipbop_225w_175kbps-cenc-video-key2-init.mp4
+ bipbop_225w_175kbps-cenc-video-key2-init.mp4^headers^
+ bipbop_300_215kbps-cenc-audio-key1-1.m4s
+ bipbop_300_215kbps-cenc-audio-key1-1.m4s^headers^
+ bipbop_300_215kbps-cenc-audio-key1-2.m4s
+ bipbop_300_215kbps-cenc-audio-key1-2.m4s^headers^
+ bipbop_300_215kbps-cenc-audio-key1-3.m4s
+ bipbop_300_215kbps-cenc-audio-key1-3.m4s^headers^
+ bipbop_300_215kbps-cenc-audio-key1-4.m4s
+ bipbop_300_215kbps-cenc-audio-key1-4.m4s^headers^
+ bipbop_300_215kbps-cenc-audio-key1-init.mp4
+ bipbop_300_215kbps-cenc-audio-key1-init.mp4^headers^
+ bipbop_300_215kbps-cenc-audio-key2-1.m4s
+ bipbop_300_215kbps-cenc-audio-key2-1.m4s^headers^
+ bipbop_300_215kbps-cenc-audio-key2-2.m4s
+ bipbop_300_215kbps-cenc-audio-key2-2.m4s^headers^
+ bipbop_300_215kbps-cenc-audio-key2-3.m4s
+ bipbop_300_215kbps-cenc-audio-key2-3.m4s^headers^
+ bipbop_300_215kbps-cenc-audio-key2-4.m4s
+ bipbop_300_215kbps-cenc-audio-key2-4.m4s^headers^
+ bipbop_300_215kbps-cenc-audio-key2-init.mp4
+ bipbop_300_215kbps-cenc-audio-key2-init.mp4^headers^
+ bipbop_300_215kbps-cenc-video-key1-1.m4s
+ bipbop_300_215kbps-cenc-video-key1-1.m4s^headers^
+ bipbop_300_215kbps-cenc-video-key1-2.m4s
+ bipbop_300_215kbps-cenc-video-key1-2.m4s^headers^
+ bipbop_300_215kbps-cenc-video-key1-init.mp4
+ bipbop_300_215kbps-cenc-video-key1-init.mp4^headers^
+ bipbop_300_215kbps-cenc-video-key2-1.m4s
+ bipbop_300_215kbps-cenc-video-key2-1.m4s^headers^
+ bipbop_300_215kbps-cenc-video-key2-2.m4s
+ bipbop_300_215kbps-cenc-video-key2-2.m4s^headers^
+ bipbop_300_215kbps-cenc-video-key2-init.mp4
+ bipbop_300_215kbps-cenc-video-key2-init.mp4^headers^
+ bipbop_300wp_227kbps-cenc-audio-key1-1.m4s
+ bipbop_300wp_227kbps-cenc-audio-key1-1.m4s^headers^
+ bipbop_300wp_227kbps-cenc-audio-key1-2.m4s
+ bipbop_300wp_227kbps-cenc-audio-key1-2.m4s^headers^
+ bipbop_300wp_227kbps-cenc-audio-key1-3.m4s
+ bipbop_300wp_227kbps-cenc-audio-key1-3.m4s^headers^
+ bipbop_300wp_227kbps-cenc-audio-key1-4.m4s
+ bipbop_300wp_227kbps-cenc-audio-key1-4.m4s^headers^
+ bipbop_300wp_227kbps-cenc-audio-key1-init.mp4
+ bipbop_300wp_227kbps-cenc-audio-key1-init.mp4^headers^
+ bipbop_300wp_227kbps-cenc-audio-key2-1.m4s
+ bipbop_300wp_227kbps-cenc-audio-key2-1.m4s^headers^
+ bipbop_300wp_227kbps-cenc-audio-key2-2.m4s
+ bipbop_300wp_227kbps-cenc-audio-key2-2.m4s^headers^
+ bipbop_300wp_227kbps-cenc-audio-key2-3.m4s
+ bipbop_300wp_227kbps-cenc-audio-key2-3.m4s^headers^
+ bipbop_300wp_227kbps-cenc-audio-key2-4.m4s
+ bipbop_300wp_227kbps-cenc-audio-key2-4.m4s^headers^
+ bipbop_300wp_227kbps-cenc-audio-key2-init.mp4
+ bipbop_300wp_227kbps-cenc-audio-key2-init.mp4^headers^
+ bipbop_300wp_227kbps-cenc-video-key1-1.m4s
+ bipbop_300wp_227kbps-cenc-video-key1-1.m4s^headers^
+ bipbop_300wp_227kbps-cenc-video-key1-2.m4s
+ bipbop_300wp_227kbps-cenc-video-key1-2.m4s^headers^
+ bipbop_300wp_227kbps-cenc-video-key1-init.mp4
+ bipbop_300wp_227kbps-cenc-video-key1-init.mp4^headers^
+ bipbop_300wp_227kbps-cenc-video-key2-1.m4s
+ bipbop_300wp_227kbps-cenc-video-key2-1.m4s^headers^
+ bipbop_300wp_227kbps-cenc-video-key2-2.m4s
+ bipbop_300wp_227kbps-cenc-video-key2-2.m4s^headers^
+ bipbop_300wp_227kbps-cenc-video-key2-init.mp4
+ bipbop_300wp_227kbps-cenc-video-key2-init.mp4^headers^
+ bipbop_360w_253kbps-cenc-audio-key1-1.m4s
+ bipbop_360w_253kbps-cenc-audio-key1-1.m4s^headers^
+ bipbop_360w_253kbps-cenc-audio-key1-2.m4s
+ bipbop_360w_253kbps-cenc-audio-key1-2.m4s^headers^
+ bipbop_360w_253kbps-cenc-audio-key1-3.m4s
+ bipbop_360w_253kbps-cenc-audio-key1-3.m4s^headers^
+ bipbop_360w_253kbps-cenc-audio-key1-4.m4s
+ bipbop_360w_253kbps-cenc-audio-key1-4.m4s^headers^
+ bipbop_360w_253kbps-cenc-audio-key1-init.mp4
+ bipbop_360w_253kbps-cenc-audio-key1-init.mp4^headers^
+ bipbop_360w_253kbps-cenc-audio-key2-1.m4s
+ bipbop_360w_253kbps-cenc-audio-key2-1.m4s^headers^
+ bipbop_360w_253kbps-cenc-audio-key2-2.m4s
+ bipbop_360w_253kbps-cenc-audio-key2-2.m4s^headers^
+ bipbop_360w_253kbps-cenc-audio-key2-3.m4s
+ bipbop_360w_253kbps-cenc-audio-key2-3.m4s^headers^
+ bipbop_360w_253kbps-cenc-audio-key2-4.m4s
+ bipbop_360w_253kbps-cenc-audio-key2-4.m4s^headers^
+ bipbop_360w_253kbps-cenc-audio-key2-init.mp4
+ bipbop_360w_253kbps-cenc-audio-key2-init.mp4^headers^
+ bipbop_360w_253kbps-cenc-video-key1-1.m4s
+ bipbop_360w_253kbps-cenc-video-key1-1.m4s^headers^
+ bipbop_360w_253kbps-cenc-video-key1-init.mp4
+ bipbop_360w_253kbps-cenc-video-key1-init.mp4^headers^
+ bipbop_360w_253kbps-cenc-video-key2-1.m4s
+ bipbop_360w_253kbps-cenc-video-key2-1.m4s^headers^
+ bipbop_360w_253kbps-cenc-video-key2-init.mp4
+ bipbop_360w_253kbps-cenc-video-key2-init.mp4^headers^
+ bipbop_360w_253kbps-clearkey-audio.webm
+ bipbop_360w_253kbps-clearkey-audio.webm^headers^
+ bipbop_360w_253kbps-clearkey-video-vp8.webm
+ bipbop_360w_253kbps-clearkey-video-vp8.webm^headers^
+ bipbop_360w_253kbps-clearkey-video-vp9.webm
+ bipbop_360w_253kbps-clearkey-video-vp9.webm^headers^
+ bipbop_480_624kbps-cenc-audio-key1-1.m4s
+ bipbop_480_624kbps-cenc-audio-key1-1.m4s^headers^
+ bipbop_480_624kbps-cenc-audio-key1-2.m4s
+ bipbop_480_624kbps-cenc-audio-key1-2.m4s^headers^
+ bipbop_480_624kbps-cenc-audio-key1-3.m4s
+ bipbop_480_624kbps-cenc-audio-key1-3.m4s^headers^
+ bipbop_480_624kbps-cenc-audio-key1-4.m4s
+ bipbop_480_624kbps-cenc-audio-key1-4.m4s^headers^
+ bipbop_480_624kbps-cenc-audio-key1-init.mp4
+ bipbop_480_624kbps-cenc-audio-key1-init.mp4^headers^
+ bipbop_480_624kbps-cenc-audio-key2-1.m4s
+ bipbop_480_624kbps-cenc-audio-key2-1.m4s^headers^
+ bipbop_480_624kbps-cenc-audio-key2-2.m4s
+ bipbop_480_624kbps-cenc-audio-key2-2.m4s^headers^
+ bipbop_480_624kbps-cenc-audio-key2-3.m4s
+ bipbop_480_624kbps-cenc-audio-key2-3.m4s^headers^
+ bipbop_480_624kbps-cenc-audio-key2-4.m4s
+ bipbop_480_624kbps-cenc-audio-key2-4.m4s^headers^
+ bipbop_480_624kbps-cenc-audio-key2-init.mp4
+ bipbop_480_624kbps-cenc-audio-key2-init.mp4^headers^
+ bipbop_480_624kbps-cenc-video-key1-1.m4s
+ bipbop_480_624kbps-cenc-video-key1-1.m4s^headers^
+ bipbop_480_624kbps-cenc-video-key1-2.m4s
+ bipbop_480_624kbps-cenc-video-key1-2.m4s^headers^
+ bipbop_480_624kbps-cenc-video-key1-init.mp4
+ bipbop_480_624kbps-cenc-video-key1-init.mp4^headers^
+ bipbop_480_624kbps-cenc-video-key2-1.m4s
+ bipbop_480_624kbps-cenc-video-key2-1.m4s^headers^
+ bipbop_480_624kbps-cenc-video-key2-2.m4s
+ bipbop_480_624kbps-cenc-video-key2-2.m4s^headers^
+ bipbop_480_624kbps-cenc-video-key2-init.mp4
+ bipbop_480_624kbps-cenc-video-key2-init.mp4^headers^
+ bipbop_480_959kbps-cenc-audio-key1-1.m4s
+ bipbop_480_959kbps-cenc-audio-key1-1.m4s^headers^
+ bipbop_480_959kbps-cenc-audio-key1-2.m4s
+ bipbop_480_959kbps-cenc-audio-key1-2.m4s^headers^
+ bipbop_480_959kbps-cenc-audio-key1-3.m4s
+ bipbop_480_959kbps-cenc-audio-key1-3.m4s^headers^
+ bipbop_480_959kbps-cenc-audio-key1-4.m4s
+ bipbop_480_959kbps-cenc-audio-key1-4.m4s^headers^
+ bipbop_480_959kbps-cenc-audio-key1-init.mp4
+ bipbop_480_959kbps-cenc-audio-key1-init.mp4^headers^
+ bipbop_480_959kbps-cenc-audio-key2-1.m4s
+ bipbop_480_959kbps-cenc-audio-key2-1.m4s^headers^
+ bipbop_480_959kbps-cenc-audio-key2-2.m4s
+ bipbop_480_959kbps-cenc-audio-key2-2.m4s^headers^
+ bipbop_480_959kbps-cenc-audio-key2-3.m4s
+ bipbop_480_959kbps-cenc-audio-key2-3.m4s^headers^
+ bipbop_480_959kbps-cenc-audio-key2-4.m4s
+ bipbop_480_959kbps-cenc-audio-key2-4.m4s^headers^
+ bipbop_480_959kbps-cenc-audio-key2-init.mp4
+ bipbop_480_959kbps-cenc-audio-key2-init.mp4^headers^
+ bipbop_480_959kbps-cenc-video-key1-1.m4s
+ bipbop_480_959kbps-cenc-video-key1-1.m4s^headers^
+ bipbop_480_959kbps-cenc-video-key1-2.m4s
+ bipbop_480_959kbps-cenc-video-key1-2.m4s^headers^
+ bipbop_480_959kbps-cenc-video-key1-init.mp4
+ bipbop_480_959kbps-cenc-video-key1-init.mp4^headers^
+ bipbop_480_959kbps-cenc-video-key2-1.m4s
+ bipbop_480_959kbps-cenc-video-key2-1.m4s^headers^
+ bipbop_480_959kbps-cenc-video-key2-2.m4s
+ bipbop_480_959kbps-cenc-video-key2-2.m4s^headers^
+ bipbop_480_959kbps-cenc-video-key2-init.mp4
+ bipbop_480_959kbps-cenc-video-key2-init.mp4^headers^
+ bipbop_480wp_663kbps-cenc-audio-key1-1.m4s
+ bipbop_480wp_663kbps-cenc-audio-key1-1.m4s^headers^
+ bipbop_480wp_663kbps-cenc-audio-key1-2.m4s
+ bipbop_480wp_663kbps-cenc-audio-key1-2.m4s^headers^
+ bipbop_480wp_663kbps-cenc-audio-key1-3.m4s
+ bipbop_480wp_663kbps-cenc-audio-key1-3.m4s^headers^
+ bipbop_480wp_663kbps-cenc-audio-key1-4.m4s
+ bipbop_480wp_663kbps-cenc-audio-key1-4.m4s^headers^
+ bipbop_480wp_663kbps-cenc-audio-key1-init.mp4
+ bipbop_480wp_663kbps-cenc-audio-key1-init.mp4^headers^
+ bipbop_480wp_663kbps-cenc-audio-key2-1.m4s
+ bipbop_480wp_663kbps-cenc-audio-key2-1.m4s^headers^
+ bipbop_480wp_663kbps-cenc-audio-key2-2.m4s
+ bipbop_480wp_663kbps-cenc-audio-key2-2.m4s^headers^
+ bipbop_480wp_663kbps-cenc-audio-key2-3.m4s
+ bipbop_480wp_663kbps-cenc-audio-key2-3.m4s^headers^
+ bipbop_480wp_663kbps-cenc-audio-key2-4.m4s
+ bipbop_480wp_663kbps-cenc-audio-key2-4.m4s^headers^
+ bipbop_480wp_663kbps-cenc-audio-key2-init.mp4
+ bipbop_480wp_663kbps-cenc-audio-key2-init.mp4^headers^
+ bipbop_480wp_663kbps-cenc-video-key1-1.m4s
+ bipbop_480wp_663kbps-cenc-video-key1-1.m4s^headers^
+ bipbop_480wp_663kbps-cenc-video-key1-2.m4s
+ bipbop_480wp_663kbps-cenc-video-key1-2.m4s^headers^
+ bipbop_480wp_663kbps-cenc-video-key1-init.mp4
+ bipbop_480wp_663kbps-cenc-video-key1-init.mp4^headers^
+ bipbop_480wp_663kbps-cenc-video-key2-1.m4s
+ bipbop_480wp_663kbps-cenc-video-key2-1.m4s^headers^
+ bipbop_480wp_663kbps-cenc-video-key2-2.m4s
+ bipbop_480wp_663kbps-cenc-video-key2-2.m4s^headers^
+ bipbop_480wp_663kbps-cenc-video-key2-init.mp4
+ bipbop_480wp_663kbps-cenc-video-key2-init.mp4^headers^
+ bipbop_480wp_1001kbps-cenc-audio-key1-1.m4s
+ bipbop_480wp_1001kbps-cenc-audio-key1-1.m4s^headers^
+ bipbop_480wp_1001kbps-cenc-audio-key1-2.m4s
+ bipbop_480wp_1001kbps-cenc-audio-key1-2.m4s^headers^
+ bipbop_480wp_1001kbps-cenc-audio-key1-3.m4s
+ bipbop_480wp_1001kbps-cenc-audio-key1-3.m4s^headers^
+ bipbop_480wp_1001kbps-cenc-audio-key1-4.m4s
+ bipbop_480wp_1001kbps-cenc-audio-key1-4.m4s^headers^
+ bipbop_480wp_1001kbps-cenc-audio-key1-init.mp4
+ bipbop_480wp_1001kbps-cenc-audio-key1-init.mp4^headers^
+ bipbop_480wp_1001kbps-cenc-audio-key2-1.m4s
+ bipbop_480wp_1001kbps-cenc-audio-key2-1.m4s^headers^
+ bipbop_480wp_1001kbps-cenc-audio-key2-2.m4s
+ bipbop_480wp_1001kbps-cenc-audio-key2-2.m4s^headers^
+ bipbop_480wp_1001kbps-cenc-audio-key2-3.m4s
+ bipbop_480wp_1001kbps-cenc-audio-key2-3.m4s^headers^
+ bipbop_480wp_1001kbps-cenc-audio-key2-4.m4s
+ bipbop_480wp_1001kbps-cenc-audio-key2-4.m4s^headers^
+ bipbop_480wp_1001kbps-cenc-audio-key2-init.mp4
+ bipbop_480wp_1001kbps-cenc-audio-key2-init.mp4^headers^
+ bipbop_480wp_1001kbps-cenc-video-key1-1.m4s
+ bipbop_480wp_1001kbps-cenc-video-key1-1.m4s^headers^
+ bipbop_480wp_1001kbps-cenc-video-key1-2.m4s
+ bipbop_480wp_1001kbps-cenc-video-key1-2.m4s^headers^
+ bipbop_480wp_1001kbps-cenc-video-key1-init.mp4
+ bipbop_480wp_1001kbps-cenc-video-key1-init.mp4^headers^
+ bipbop_480wp_1001kbps-cenc-video-key2-1.m4s
+ bipbop_480wp_1001kbps-cenc-video-key2-1.m4s^headers^
+ bipbop_480wp_1001kbps-cenc-video-key2-2.m4s
+ bipbop_480wp_1001kbps-cenc-video-key2-2.m4s^headers^
+ bipbop_480wp_1001kbps-cenc-video-key2-init.mp4
+ bipbop_480wp_1001kbps-cenc-video-key2-init.mp4^headers^
+ bipbop-lateaudio.mp4
+ bipbop-lateaudio.mp4^headers^
+ black100x100-aspect3to2.ogv
+ black100x100-aspect3to2.ogv^headers^
+ bogus.duh
+ bogus.ogv
+ bogus.ogv^headers^
+ bogus.wav
+ bogus.wav^headers^
+ bug461281.ogg
+ bug461281.ogg^headers^
+ bug482461-theora.ogv
+ bug482461-theora.ogv^headers^
+ bug482461.ogv
+ bug482461.ogv^headers^
+ bug495129.ogv
+ bug495129.ogv^headers^
+ bug495794.ogg
+ bug495794.ogg^headers^
+ bug498380.ogv
+ bug498380.ogv^headers^
+ bug498855-1.ogv
+ bug498855-1.ogv^headers^
+ bug498855-2.ogv
+ bug498855-2.ogv^headers^
+ bug498855-3.ogv
+ bug498855-3.ogv^headers^
+ bug499519.ogv
+ bug499519.ogv^headers^
+ bug500311.ogv
+ bug500311.ogv^headers^
+ bug501279.ogg
+ bug501279.ogg^headers^
+ bug504613.ogv
+ bug504613.ogv^headers^
+ bug504644.ogv
+ bug504644.ogv^headers^
+ bug504843.ogv
+ bug504843.ogv^headers^
+ bug506094.ogv
+ bug506094.ogv^headers^
+ bug516323.indexed.ogv
+ bug516323.indexed.ogv^headers^
+ bug516323.ogv
+ bug516323.ogv^headers^
+ bug520493.ogg
+ bug520493.ogg^headers^
+ bug520500.ogg
+ bug520500.ogg^headers^
+ bug520908.ogv
+ bug520908.ogv^headers^
+ bug523816.ogv
+ bug523816.ogv^headers^
+ bug533822.ogg
+ bug533822.ogg^headers^
+ bug556821.ogv
+ bug556821.ogv^headers^
+ bug557094.ogv
+ bug557094.ogv^headers^
+ bug580982.webm
+ bug580982.webm^headers^
+ bug603918.webm
+ bug603918.webm^headers^
+ bug604067.webm
+ bug604067.webm^headers^
+ bug883173.vtt
+ bug1066943.webm
+ bug1066943.webm^headers^
+ bug1301226.wav
+ bug1301226.wav^headers^
+ bug1301226-odd.wav
+ bug1301226-odd.wav^headers^
+ can_play_type_dash.js
+ can_play_type_ogg.js
+ can_play_type_wave.js
+ can_play_type_webm.js
+ cancellable_request.sjs
+ chain.ogg
+ chain.ogg^headers^
+ chain.ogv
+ chain.ogv^headers^
+ chain.opus
+ chain.opus^headers^
+ chained-audio-video.ogg
+ chained-audio-video.ogg^headers^
+ chained-video.ogv
+ chained-video.ogv^headers^
+ contentType.sjs
+ detodos.opus
+ detodos.opus^headers^
+ detodos.webm
+ detodos.webm^headers^
+ detodos-short.webm
+ detodos-short.webm^headers^
+ detodos-recorder-test.opus
+ detodos-recorder-test.opus^headers^
+ detodos-short.opus
+ detodos-short.opus^headers^
+ dirac.ogg
+ dirac.ogg^headers^
+ dynamic_redirect.sjs
+ dynamic_resource.sjs
+ eme.js
+ file_access_controls.html
+ flac-s24.flac
+ flac-s24.flac^headers^
+ flac-noheader-s16.flac
+ flac-noheader-s16.flac^headers^
+ fragment_noplay.js
+ fragment_play.js
+ gizmo.mp4
+ gizmo.mp4^headers^
+ gizmo-noaudio.mp4
+ gizmo-noaudio.mp4^headers^
+ gizmo-short.mp4
+ gizmo-short.mp4^headers^
+ gizmo.webm
+ gizmo.webm^headers^
+ gizmo-noaudio.webm
+ gizmo-noaudio.webm^headers^
+ huge-id3.mp3
+ huge-id3.mp3^headers^
+ id3tags.mp3
+ id3tags.mp3^headers^
+ invalid-cmap-s0c0.opus
+ invalid-cmap-s0c0.opus^headers^
+ invalid-cmap-s0c2.opus
+ invalid-cmap-s0c2.opus^headers^
+ invalid-cmap-s1c2.opus
+ invalid-cmap-s1c2.opus^headers^
+ invalid-cmap-short.opus
+ invalid-cmap-short.opus^headers^
+ invalid-discard_on_multi_blocks.webm
+ invalid-discard_on_multi_blocks.webm^headers^
+ invalid-excess_discard.webm
+ invalid-excess_discard.webm^headers^
+ invalid-excess_neg_discard.webm
+ invalid-excess_neg_discard.webm^headers^
+ invalid-m0c0.opus
+ invalid-m0c0.opus^headers^
+ invalid-m0c3.opus
+ invalid-m0c3.opus^headers^
+ invalid-m1c0.opus
+ invalid-m1c0.opus^headers^
+ invalid-m1c9.opus
+ invalid-m1c9.opus^headers^
+ invalid-m2c0.opus
+ invalid-m2c0.opus^headers^
+ invalid-m2c1.opus
+ invalid-m2c1.opus^headers^
+ invalid-neg_discard.webm
+ invalid-neg_discard.webm^headers^
+ invalid-preskip.webm
+ invalid-preskip.webm^headers^
+ long.vtt
+ manifest.js
+ multiple-bos.ogg
+ multiple-bos.ogg^headers^
+ multiple-bos-more-header-fileds.ogg
+ multiple-bos-more-header-fileds.ogg^headers^
+ no-cues.webm
+ no-cues.webm^headers^
+ notags.mp3
+ notags.mp3^headers^
+ owl-funnier-id3.mp3
+ owl-funnier-id3.mp3^headers^
+ owl-funny-id3.mp3
+ owl-funny-id3.mp3^headers^
+ owl.mp3
+ owl.mp3^headers^
+ owl-short.mp3
+ owl-short.mp3^headers^
+ parser.vtt
+ pixel_aspect_ratio.mp4
+ r11025_msadpcm_c1.wav
+ r11025_msadpcm_c1.wav^headers^
+ r11025_s16_c1.wav
+ r11025_s16_c1.wav^headers^
+ r11025_s16_c1_trailing.wav
+ r11025_s16_c1_trailing.wav^headers^
+ r11025_s16_c1-short.wav
+ r11025_s16_c1-short.wav^headers^
+ r11025_u8_c1.wav
+ r11025_u8_c1.wav^headers^
+ r11025_u8_c1_trunc.wav
+ r11025_u8_c1_trunc.wav^headers^
+ r16000_u8_c1_list.wav
+ r16000_u8_c1_list.wav^headers^
+ reactivate_helper.html
+ red-46x48.mp4
+ red-46x48.mp4^headers^
+ red-48x46.mp4
+ red-48x46.mp4^headers^
+ redirect.sjs
+ referer.sjs
+ region.vtt
+ resolution-change.webm
+ resolution-change.webm^headers^
+ sample.3gp
+ sample.3g2
+ sample-fisbone-skeleton4.ogv
+ sample-fisbone-skeleton4.ogv^headers^
+ sample-fisbone-wrong-header.ogv
+ sample-fisbone-wrong-header.ogv^headers^
+ seek.ogv
+ seek.ogv^headers^
+ seek-short.ogv
+ seek-short.ogv^headers^
+ seek.webm
+ seek.webm^headers^
+ seek-short.webm
+ seek-short.webm^headers^
+ seek.yuv
+ seek_support.js
+ seekLies.sjs
+ seek_with_sound.ogg^headers^
+ sequential.vtt
+ short-cenc.mp4
+ sine.webm
+ sine.webm^headers^
+ short.mp4
+ short.mp4^headers^
+ short-audio-fragmented-cenc-without-pssh.mp4
+ short-audio-fragmented-cenc-without-pssh.mp4^headers^
+ short-video.ogv
+ short-video.ogv^headers^
+ small-shot-mp3.mp4
+ small-shot-mp3.mp4^headers^
+ small-shot.m4a
+ small-shot.mp3
+ small-shot.mp3^headers^
+ small-shot.ogg
+ small-shot.ogg^headers^
+ small-shot.flac
+ sound.ogg
+ sound.ogg^headers^
+ spacestorm-1000Hz-100ms.ogg
+ spacestorm-1000Hz-100ms.ogg^headers^
+ split.webm
+ split.webm^headers^
+ street.mp4
+ street.mp4^headers^
+ test-1-mono.opus
+ test-1-mono.opus^headers^
+ test-2-stereo.opus
+ test-2-stereo.opus^headers^
+ test-3-LCR.opus
+ test-3-LCR.opus^headers^
+ test-4-quad.opus
+ test-4-quad.opus^headers^
+ test-5-5.0.opus
+ test-5-5.0.opus^headers^
+ test-6-5.1.opus
+ test-6-5.1.opus^headers^
+ test-7-6.1.opus
+ test-7-6.1.opus^headers^
+ test-8-7.1.opus
+ test-8-7.1.opus^headers^
+ variable-channel.ogg
+ variable-channel.ogg^headers^
+ variable-channel.opus
+ variable-channel.opus^headers^
+ variable-preskip.opus
+ variable-preskip.opus^headers^
+ variable-samplerate.ogg
+ variable-samplerate.ogg^headers^
+ variable-samplerate.opus
+ variable-samplerate.opus^headers^
+ vbr-head.mp3
+ vbr-head.mp3^headers^
+ vbr.mp3
+ vbr.mp3^headers^
+ video-overhang.ogg
+ video-overhang.ogg^headers^
+ vp9.webm
+ vp9.webm^headers^
+ vp9-short.webm
+ vp9-short.webm^headers^
+ vp9cake.webm
+ vp9cake.webm^headers^
+ vp9cake-short.webm
+ vp9cake-short.webm^headers^
+ vttPositionAlign.vtt
+ wave_metadata.wav
+ wave_metadata.wav^headers^
+ wave_metadata_bad_len.wav
+ wave_metadata_bad_len.wav^headers^
+ wave_metadata_bad_no_null.wav
+ wave_metadata_bad_no_null.wav^headers^
+ wave_metadata_bad_utf8.wav
+ wave_metadata_bad_utf8.wav^headers^
+ wave_metadata_unknown_tag.wav
+ wave_metadata_unknown_tag.wav^headers^
+ wave_metadata_utf8.wav
+ wave_metadata_utf8.wav^headers^
+ wavedata_alaw.wav
+ wavedata_alaw.wav^headers^
+ wavedata_s24.wav
+ wavedata_s24.wav^headers^
+ wavedata_s16.wav
+ wavedata_s16.wav^headers^
+ wavedata_u8.wav
+ wavedata_u8.wav^headers^
+ wavedata_ulaw.wav
+ wavedata_ulaw.wav^headers^
+ !/dom/canvas/test/captureStream_common.js
+ !/dom/html/test/reflect.js
+
+[test_access_control.html]
+[test_aspectratio_mp4.html]
+[test_audio1.html]
+[test_audio2.html]
+[test_audioDocumentTitle.html]
+skip-if = true # bug 475110 - disabled since we don't play Wave files standalone
+[test_autoplay.html]
+[test_autoplay_contentEditable.html]
+[test_buffered.html]
+[test_bug448534.html]
+[test_bug463162.xhtml]
+[test_bug465498.html]
+[test_bug495145.html]
+skip-if = (os == 'mac' && os_version == '10.6') # bug 1021174
+[test_bug495300.html]
+[test_bug654550.html]
+[test_bug686942.html]
+[test_bug726904.html]
+[test_bug874897.html]
+[test_bug879717.html]
+tags=capturestream
+[test_bug883173.html]
+[test_bug895091.html]
+tags=webvtt
+[test_bug895305.html]
+[test_bug919265.html]
+[test_bug957847.html]
+[test_bug1018933.html]
+[test_bug1113600.html]
+tags=capturestream
+[test_bug1242338.html]
+[test_bug1242594.html]
+[test_bug1248229.html]
+tags=capturestream
+[test_can_play_type.html]
+[test_can_play_type_mpeg.html]
+[test_can_play_type_no_ogg.html]
+[test_can_play_type_ogg.html]
+[test_chaining.html]
+[test_clone_media_element.html]
+[test_closing_connections.html]
+[test_constants.html]
+[test_controls.html]
+[test_cueless_webm_seek-1.html]
+[test_cueless_webm_seek-2.html]
+[test_cueless_webm_seek-3.html]
+[test_currentTime.html]
+[test_decode_error.html]
+[test_decoder_disable.html]
+[test_defaultMuted.html]
+[test_delay_load.html]
+[test_eme_session_callable_value.html]
+[test_eme_canvas_blocked.html]
+skip-if = toolkit == 'android' # bug 1149374
+[test_eme_detach_media_keys.html]
+skip-if = toolkit == 'android' # bug 1149374
+[test_eme_initDataTypes.html]
+skip-if = toolkit == 'android' # bug 1149374
+[test_eme_missing_pssh.html]
+skip-if = toolkit == 'android' # bug 1149374
+[test_eme_non_mse_fails.html]
+skip-if = toolkit == 'android' # bug 1149374
+[test_eme_request_notifications.html]
+skip-if = toolkit == 'android' # bug 1149374
+[test_eme_playback.html]
+skip-if = toolkit == 'android' # bug 1149374
+[test_eme_requestKeySystemAccess.html]
+skip-if = toolkit == 'android' # bug 1149374
+[test_eme_setMediaKeys_before_attach_MediaSource.html]
+skip-if = toolkit == 'android' # bug 1149374
+[test_eme_stream_capture_blocked_case1.html]
+tags=msg capturestream
+skip-if = toolkit == 'android' # bug 1149374
+[test_eme_stream_capture_blocked_case2.html]
+tags=msg capturestream
+skip-if = toolkit == 'android' # bug 1149374
+[test_eme_stream_capture_blocked_case3.html]
+tags=msg capturestream
+skip-if = toolkit == 'android' # bug 1149374
+[test_eme_waitingforkey.html]
+skip-if = toolkit == 'android' # bug 1149374
+[test_empty_resource.html]
+[test_error_in_video_document.html]
+[test_error_on_404.html]
+[test_fastSeek.html]
+[test_fastSeek-forwards.html]
+[test_gmp_playback.html]
+skip-if = (os != 'win' || os_version == '5.1') # Only gmp-clearkey on Windows Vista and later decodes
+[test_imagecapture.html]
+[test_info_leak.html]
+[test_invalid_reject.html]
+[test_invalid_reject_play.html]
+[test_invalid_seek.html]
+[test_load.html]
+[test_load_candidates.html]
+[test_load_same_resource.html]
+[test_load_source.html]
+[test_loop.html]
+[test_media_selection.html]
+[test_media_sniffer.html]
+[test_mediarecorder_avoid_recursion.html]
+skip-if = os == 'win' && !debug # bug 1228605
+tags=msg
+[test_mediarecorder_bitrate.html]
+tags=msg
+[test_mediarecorder_creation.html]
+tags=msg capturestream
+[test_mediarecorder_creation_fail.html]
+tags=msg
+[test_mediarecorder_getencodeddata.html]
+tags=msg
+[test_mediarecorder_principals.html]
+skip-if = (os == 'linux' && bits == 64) # See bug 1266345
+tags=msg
+[test_mediarecorder_record_4ch_audiocontext.html]
+tags=msg
+[test_mediarecorder_record_audiocontext.html]
+tags=msg
+[test_mediarecorder_record_audiocontext_mlk.html]
+tags=msg
+[test_mediarecorder_record_audionode.html]
+tags=msg
+[test_mediarecorder_record_canvas_captureStream.html]
+tags=msg
+[test_mediarecorder_record_changing_video_resolution.html]
+tags=msg
+[test_mediarecorder_record_gum_video_timeslice.html]
+tags=msg
+[test_mediarecorder_record_immediate_stop.html]
+tags=msg capturestream
+[test_mediarecorder_record_no_timeslice.html]
+tags=msg capturestream
+[test_mediarecorder_record_session.html]
+tags=msg capturestream
+[test_mediarecorder_record_startstopstart.html]
+tags=msg
+[test_mediarecorder_record_stopms.html]
+tags=msg
+[test_mediarecorder_record_timeslice.html]
+tags=msg capturestream
+[test_mediarecorder_reload_crash.html]
+tags=msg capturestream
+[test_mediarecorder_unsupported_src.html]
+tags=msg
+[test_mediarecorder_webm_support.html]
+skip-if = os == 'android' || arch == 'arm' || arch == 'arm64'
+tags=msg
+[test_mediarecorder_record_getdata_afterstart.html]
+tags=msg capturestream
+[test_mediatrack_consuming_mediaresource.html]
+[test_mediatrack_consuming_mediastream.html]
+tags=msg
+[test_mediatrack_events.html]
+[test_mediatrack_parsing_ogg.html]
+[test_mediatrack_replay_from_end.html]
+[test_metadata.html]
+[test_mixed_principals.html]
+[test_mozHasAudio.html]
+[test_multiple_mediastreamtracks.html]
+[test_networkState.html]
+[test_new_audio.html]
+[test_no_load_event.html]
+[test_paused.html]
+[test_paused_after_ended.html]
+[test_play_events.html]
+[test_play_events_2.html]
+[test_play_twice.html]
+# Seamonkey: Bug 598252
+skip-if = appname == "seamonkey"
+[test_playback.html]
+[test_playback_errors.html]
+[test_playback_rate.html]
+[test_playback_rate_playpause.html]
+[test_playback_reactivate.html]
+[test_played.html]
+[test_preload_actions.html]
+[test_preload_attribute.html]
+[test_preload_suspend.html]
+[test_preserve_playbackrate_after_ui_play.html]
+[test_progress.html]
+[test_reactivate.html]
+[test_readyState.html]
+[test_referer.html]
+[test_replay_metadata.html]
+[test_reset_events_async.html]
+[test_reset_src.html]
+[test_video_dimensions.html]
+[test_resolution_change.html]
+tags=capturestream
+[test_resume.html]
+skip-if = true # bug 1021673
+[test_seek_negative.html]
+[test_seek_nosrc.html]
+[test_seek_out_of_range.html]
+[test_seek-1.html]
+[test_seek-2.html]
+[test_seek-3.html]
+[test_seek-4.html]
+[test_seek-5.html]
+[test_seek-6.html]
+[test_seek-7.html]
+[test_seek-8.html]
+[test_seek-9.html]
+[test_seek-10.html]
+[test_seek-11.html]
+[test_seek-12.html]
+[test_seek-13.html]
+[test_seekable1.html]
+[test_seekLies.html]
+[test_seekToNextFrame.html]
+tags=seektonextframe
+[test_source.html]
+[test_source_media.html]
+[test_source_null.html]
+[test_source_write.html]
+[test_standalone.html]
+[test_streams_autoplay.html]
+tags=msg capturestream
+[test_streams_capture_origin.html]
+tags=msg capturestream
+[test_streams_element_capture.html]
+tags=msg capturestream
+[test_streams_element_capture_createObjectURL.html]
+tags=msg capturestream
+[test_streams_element_capture_playback.html]
+tags=msg capturestream
+[test_streams_element_capture_reset.html]
+tags=msg capturestream
+[test_streams_gc.html]
+tags=msg capturestream
+[test_streams_individual_pause.html]
+tags=msg
+[test_streams_srcObject.html]
+tags=msg capturestream
+[test_streams_tracks.html]
+tags=msg capturestream
+[test_texttrack.html]
+tags = webvtt
+[test_texttrackcue.html]
+tags = webvtt
+[test_texttrackcue_moz.html]
+tags = webvtt
+[test_texttrackevents_video.html]
+tags = webvtt
+[test_texttracklist.html]
+tags = webvtt
+[test_texttracklist_moz.html]
+tags = webvtt
+[test_texttrackregion.html]
+tags = webvtt
+[test_texttrack_moz.html]
+tags = webvtt
+[test_timeupdate_small_files.html]
+[test_trackelementevent.html]
+tags = webvtt
+[test_trackelementsrc.html]
+tags = webvtt
+[test_trackevent.html]
+tags = webvtt
+[test_unseekable.html]
+[test_video_to_canvas.html]
+[test_video_in_audio_element.html]
+[test_videoDocumentTitle.html]
+[test_VideoPlaybackQuality.html]
+[test_VideoPlaybackQuality_disabled.html]
+[test_volume.html]
+[test_vttparser.html]
+tags = webvtt
+[test_webvtt_empty_displaystate.html]
+tags = webvtt
+[test_webvtt_positionalign.html]
+tags = webvtt
+
+# The tests below contain backend-specific tests. Write backend independent
+# tests rather than adding to this list.
+[test_can_play_type_webm.html]
+[test_can_play_type_wave.html]
+[test_fragment_noplay.html]
+[test_fragment_play.html]
+
+[test_background_video_suspend.html]
+tags = suspend
+[test_background_video_suspend_ends.html]
+tags = suspend
+[test_background_video_no_suspend_short_vid.html]
+tags = suspend
+[test_background_video_no_suspend_disabled.html]
+tags = suspend
+[test_temporary_file_blob_video_plays.html]
diff --git a/dom/media/test/multiple-bos-more-header-fileds.ogg b/dom/media/test/multiple-bos-more-header-fileds.ogg
new file mode 100644
index 000000000..c9721cb98
--- /dev/null
+++ b/dom/media/test/multiple-bos-more-header-fileds.ogg
Binary files differ
diff --git a/dom/media/test/multiple-bos-more-header-fileds.ogg^headers^ b/dom/media/test/multiple-bos-more-header-fileds.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/multiple-bos-more-header-fileds.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/multiple-bos.ogg b/dom/media/test/multiple-bos.ogg
new file mode 100644
index 000000000..193200868
--- /dev/null
+++ b/dom/media/test/multiple-bos.ogg
Binary files differ
diff --git a/dom/media/test/multiple-bos.ogg^headers^ b/dom/media/test/multiple-bos.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/multiple-bos.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/no-cues.webm b/dom/media/test/no-cues.webm
new file mode 100644
index 000000000..8ed761099
--- /dev/null
+++ b/dom/media/test/no-cues.webm
Binary files differ
diff --git a/dom/media/test/no-cues.webm^headers^ b/dom/media/test/no-cues.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/no-cues.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/notags.mp3 b/dom/media/test/notags.mp3
new file mode 100644
index 000000000..7f298131a
--- /dev/null
+++ b/dom/media/test/notags.mp3
Binary files differ
diff --git a/dom/media/test/notags.mp3^headers^ b/dom/media/test/notags.mp3^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/notags.mp3^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/owl-funnier-id3.mp3 b/dom/media/test/owl-funnier-id3.mp3
new file mode 100644
index 000000000..05ec50753
--- /dev/null
+++ b/dom/media/test/owl-funnier-id3.mp3
Binary files differ
diff --git a/dom/media/test/owl-funnier-id3.mp3^headers^ b/dom/media/test/owl-funnier-id3.mp3^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/owl-funnier-id3.mp3^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/owl-funny-id3.mp3 b/dom/media/test/owl-funny-id3.mp3
new file mode 100644
index 000000000..6533755a3
--- /dev/null
+++ b/dom/media/test/owl-funny-id3.mp3
Binary files differ
diff --git a/dom/media/test/owl-funny-id3.mp3^headers^ b/dom/media/test/owl-funny-id3.mp3^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/owl-funny-id3.mp3^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/owl-short.mp3 b/dom/media/test/owl-short.mp3
new file mode 100644
index 000000000..9b31531f2
--- /dev/null
+++ b/dom/media/test/owl-short.mp3
Binary files differ
diff --git a/dom/media/test/owl-short.mp3^headers^ b/dom/media/test/owl-short.mp3^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/owl-short.mp3^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/owl.mp3 b/dom/media/test/owl.mp3
new file mode 100644
index 000000000..9fafa32f9
--- /dev/null
+++ b/dom/media/test/owl.mp3
Binary files differ
diff --git a/dom/media/test/owl.mp3^headers^ b/dom/media/test/owl.mp3^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/owl.mp3^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/parser.vtt b/dom/media/test/parser.vtt
new file mode 100644
index 000000000..2a56c65f8
--- /dev/null
+++ b/dom/media/test/parser.vtt
@@ -0,0 +1,6 @@
+WEBVTT
+
+00:00.500 --> 00:00.700
+Test
+00:00.500 --> 00:00.700
+Stuff
diff --git a/dom/media/test/pixel_aspect_ratio.mp4 b/dom/media/test/pixel_aspect_ratio.mp4
new file mode 100644
index 000000000..fce12cc03
--- /dev/null
+++ b/dom/media/test/pixel_aspect_ratio.mp4
Binary files differ
diff --git a/dom/media/test/r11025_msadpcm_c1.wav b/dom/media/test/r11025_msadpcm_c1.wav
new file mode 100644
index 000000000..2e883ba5e
--- /dev/null
+++ b/dom/media/test/r11025_msadpcm_c1.wav
Binary files differ
diff --git a/dom/media/test/r11025_msadpcm_c1.wav^headers^ b/dom/media/test/r11025_msadpcm_c1.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/r11025_msadpcm_c1.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/r11025_s16_c1-short.wav b/dom/media/test/r11025_s16_c1-short.wav
new file mode 100644
index 000000000..e08d5bbdc
--- /dev/null
+++ b/dom/media/test/r11025_s16_c1-short.wav
Binary files differ
diff --git a/dom/media/test/r11025_s16_c1-short.wav^headers^ b/dom/media/test/r11025_s16_c1-short.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/r11025_s16_c1-short.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/r11025_s16_c1.wav b/dom/media/test/r11025_s16_c1.wav
new file mode 100644
index 000000000..ab2e08bef
--- /dev/null
+++ b/dom/media/test/r11025_s16_c1.wav
Binary files differ
diff --git a/dom/media/test/r11025_s16_c1.wav^headers^ b/dom/media/test/r11025_s16_c1.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/r11025_s16_c1.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/r11025_s16_c1_trailing.wav b/dom/media/test/r11025_s16_c1_trailing.wav
new file mode 100644
index 000000000..af53beaf2
--- /dev/null
+++ b/dom/media/test/r11025_s16_c1_trailing.wav
Binary files differ
diff --git a/dom/media/test/r11025_s16_c1_trailing.wav^headers^ b/dom/media/test/r11025_s16_c1_trailing.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/r11025_s16_c1_trailing.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/r11025_u8_c1.wav b/dom/media/test/r11025_u8_c1.wav
new file mode 100644
index 000000000..97dc453b9
--- /dev/null
+++ b/dom/media/test/r11025_u8_c1.wav
Binary files differ
diff --git a/dom/media/test/r11025_u8_c1.wav^headers^ b/dom/media/test/r11025_u8_c1.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/r11025_u8_c1.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/r11025_u8_c1_trunc.wav b/dom/media/test/r11025_u8_c1_trunc.wav
new file mode 100644
index 000000000..4d2db3977
--- /dev/null
+++ b/dom/media/test/r11025_u8_c1_trunc.wav
Binary files differ
diff --git a/dom/media/test/r11025_u8_c1_trunc.wav^headers^ b/dom/media/test/r11025_u8_c1_trunc.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/r11025_u8_c1_trunc.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/r16000_u8_c1_list.wav b/dom/media/test/r16000_u8_c1_list.wav
new file mode 100644
index 000000000..afde32e9a
--- /dev/null
+++ b/dom/media/test/r16000_u8_c1_list.wav
Binary files differ
diff --git a/dom/media/test/r16000_u8_c1_list.wav^headers^ b/dom/media/test/r16000_u8_c1_list.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/r16000_u8_c1_list.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/reactivate_helper.html b/dom/media/test/reactivate_helper.html
new file mode 100644
index 000000000..af4c8b9ca
--- /dev/null
+++ b/dom/media/test/reactivate_helper.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<script>
+var loadsWaiting = 0;
+var elements = [];
+
+function checkAllLoaded() {
+ --loadsWaiting;
+ if (loadsWaiting == 0) {
+ parent.loadedAll(elements);
+ }
+}
+
+function loadedData(event) {
+ var e = event.target;
+ parent.ok(elements.indexOf(e) == -1, "Element already loaded: " + e._name);
+ parent.info("Loaded " + e._name);
+ elements.push(e);
+ // Reset "onerror" handler to avoid triggering another error in removeNodeAndSource().
+ e.onerror = null;
+ checkAllLoaded();
+
+}
+
+function error(event) {
+ var e = event.target;
+ parent.info("Error " + e._name);
+ // Don't wait for the element encounting errors.
+ checkAllLoaded();
+}
+
+for (var i = 0; i < parent.gSmallTests.length; ++i) {
+ var test = parent.gSmallTests[i];
+ var elemType = /^audio/.test(test.type) ? "audio" : "video";
+ // Associate these elements with the subframe's document
+ var e = document.createElement(elemType);
+ e.preload = "metadata";
+ if (e.canPlayType(test.type)) {
+ e.src = test.name;
+ e._name = test.name;
+ e.onloadeddata = loadedData;
+ e.onerror = error;
+ e.load();
+ ++loadsWaiting;
+ parent.info("Loading " + e._name);
+ }
+}
+
+if (loadsWaiting == 0) {
+ parent.todo(false, "Can't play anything");
+} else {
+ parent.SimpleTest.waitForExplicitFinish();
+}
+</script>
+</body>
+</html>
diff --git a/dom/media/test/red-46x48.mp4 b/dom/media/test/red-46x48.mp4
new file mode 100644
index 000000000..0760cc1c1
--- /dev/null
+++ b/dom/media/test/red-46x48.mp4
Binary files differ
diff --git a/dom/media/test/red-46x48.mp4^headers^ b/dom/media/test/red-46x48.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/red-46x48.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/red-48x46.mp4 b/dom/media/test/red-48x46.mp4
new file mode 100644
index 000000000..d83de4027
--- /dev/null
+++ b/dom/media/test/red-48x46.mp4
Binary files differ
diff --git a/dom/media/test/red-48x46.mp4^headers^ b/dom/media/test/red-48x46.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/red-48x46.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/redirect.sjs b/dom/media/test/redirect.sjs
new file mode 100644
index 000000000..1653e8efc
--- /dev/null
+++ b/dom/media/test/redirect.sjs
@@ -0,0 +1,26 @@
+function parseQuery(request, key) {
+ var params = request.queryString.split('&');
+ for (var j = 0; j < params.length; ++j) {
+ var p = params[j];
+ if (p == key)
+ return true;
+ if (p.indexOf(key + "=") == 0)
+ return p.substring(key.length + 1);
+ if (p.indexOf("=") < 0 && key == "")
+ return p;
+ }
+ return false;
+}
+
+// Return file content for the first request with a given key.
+// All subsequent requests return a redirect to a different-origin resource.
+function handleRequest(request, response)
+{
+ var domain = parseQuery(request, "domain");
+ var file = parseQuery(request, "file");
+ var allowed = parseQuery(request, "allowed");
+
+ response.setStatusLine(request.httpVersion, 303, "See Other");
+ response.setHeader("Location", "http://" + domain + "/tests/dom/media/test/" + (allowed ? "allowed.sjs?" : "") + file);
+ response.setHeader("Content-Type", "text/html");
+}
diff --git a/dom/media/test/referer.sjs b/dom/media/test/referer.sjs
new file mode 100644
index 000000000..1ddec5721
--- /dev/null
+++ b/dom/media/test/referer.sjs
@@ -0,0 +1,45 @@
+function parseQuery(request, key) {
+ var params = request.queryString.split('&');
+ for (var j = 0; j < params.length; ++j) {
+ var p = params[j];
+ if (p == key)
+ return true;
+ if (p.indexOf(key + "=") == 0)
+ return p.substring(key.length + 1);
+ if (p.indexOf("=") < 0 && key == "")
+ return p;
+ }
+ return false;
+}
+
+function handleRequest(request, response)
+{
+ var referer = request.hasHeader("Referer") ? request.getHeader("Referer")
+ : undefined;
+ if (referer == "http://mochi.test:8888/tests/dom/media/test/test_referer.html") {
+ var name = parseQuery(request, "name");
+ var type = parseQuery(request, "type");
+ var file = Components.classes["@mozilla.org/file/directory_service;1"].
+ getService(Components.interfaces.nsIProperties).
+ get("CurWorkD", Components.interfaces.nsILocalFile);
+ var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
+ createInstance(Components.interfaces.nsIFileInputStream);
+ var bis = Components.classes["@mozilla.org/binaryinputstream;1"].
+ createInstance(Components.interfaces.nsIBinaryInputStream);
+ var paths = "tests/dom/media/test/" + name;
+ var split = paths.split("/");
+ for(var i = 0; i < split.length; ++i) {
+ file.append(split[i]);
+ }
+ fis.init(file, -1, -1, false);
+ bis.setInputStream(fis);
+ var bytes = bis.readBytes(bis.available());
+ response.setHeader("Content-Length", ""+bytes.length, false);
+ response.setHeader("Content-Type", type, false);
+ response.write(bytes, bytes.length);
+ bis.close();
+ }
+ else {
+ response.setStatusLine(request.httpVersion, 404, "Not found");
+ }
+}
diff --git a/dom/media/test/region.vtt b/dom/media/test/region.vtt
new file mode 100644
index 000000000..883341fc6
--- /dev/null
+++ b/dom/media/test/region.vtt
@@ -0,0 +1,5 @@
+WEBVTT
+Region: id=fred width=62% lines=5 regionanchor=4%,78% viewportanchor=10%,90% scroll=up
+
+00:01.000 --> 00:02.000 region:fred
+Test here.
diff --git a/dom/media/test/resolution-change.webm b/dom/media/test/resolution-change.webm
new file mode 100644
index 000000000..29aad93b9
--- /dev/null
+++ b/dom/media/test/resolution-change.webm
Binary files differ
diff --git a/dom/media/test/resolution-change.webm^headers^ b/dom/media/test/resolution-change.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/resolution-change.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/sample-fisbone-skeleton4.ogv b/dom/media/test/sample-fisbone-skeleton4.ogv
new file mode 100644
index 000000000..8afe0be7a
--- /dev/null
+++ b/dom/media/test/sample-fisbone-skeleton4.ogv
Binary files differ
diff --git a/dom/media/test/sample-fisbone-skeleton4.ogv^headers^ b/dom/media/test/sample-fisbone-skeleton4.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/sample-fisbone-skeleton4.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/sample-fisbone-wrong-header.ogv b/dom/media/test/sample-fisbone-wrong-header.ogv
new file mode 100644
index 000000000..46c3933da
--- /dev/null
+++ b/dom/media/test/sample-fisbone-wrong-header.ogv
Binary files differ
diff --git a/dom/media/test/sample-fisbone-wrong-header.ogv^headers^ b/dom/media/test/sample-fisbone-wrong-header.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/sample-fisbone-wrong-header.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/sample.3g2 b/dom/media/test/sample.3g2
new file mode 100644
index 000000000..769cb01db
--- /dev/null
+++ b/dom/media/test/sample.3g2
Binary files differ
diff --git a/dom/media/test/sample.3gp b/dom/media/test/sample.3gp
new file mode 100644
index 000000000..4a3d8ea66
--- /dev/null
+++ b/dom/media/test/sample.3gp
Binary files differ
diff --git a/dom/media/test/seek-short.ogv b/dom/media/test/seek-short.ogv
new file mode 100644
index 000000000..a5ca6951d
--- /dev/null
+++ b/dom/media/test/seek-short.ogv
Binary files differ
diff --git a/dom/media/test/seek-short.ogv^headers^ b/dom/media/test/seek-short.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/seek-short.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/seek-short.webm b/dom/media/test/seek-short.webm
new file mode 100644
index 000000000..36abd1570
--- /dev/null
+++ b/dom/media/test/seek-short.webm
Binary files differ
diff --git a/dom/media/test/seek-short.webm^headers^ b/dom/media/test/seek-short.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/seek-short.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/seek.ogv b/dom/media/test/seek.ogv
new file mode 100644
index 000000000..ac7ece351
--- /dev/null
+++ b/dom/media/test/seek.ogv
Binary files differ
diff --git a/dom/media/test/seek.ogv^headers^ b/dom/media/test/seek.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/seek.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/seek.webm b/dom/media/test/seek.webm
new file mode 100644
index 000000000..72b029723
--- /dev/null
+++ b/dom/media/test/seek.webm
Binary files differ
diff --git a/dom/media/test/seek.webm^headers^ b/dom/media/test/seek.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/seek.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/seek.yuv b/dom/media/test/seek.yuv
new file mode 100644
index 000000000..69485e8e1
--- /dev/null
+++ b/dom/media/test/seek.yuv
Binary files differ
diff --git a/dom/media/test/seekLies.sjs b/dom/media/test/seekLies.sjs
new file mode 100644
index 000000000..d9c6fd051
--- /dev/null
+++ b/dom/media/test/seekLies.sjs
@@ -0,0 +1,23 @@
+function handleRequest(request, response)
+{
+ var file = Components.classes["@mozilla.org/file/directory_service;1"].
+ getService(Components.interfaces.nsIProperties).
+ get("CurWorkD", Components.interfaces.nsILocalFile);
+ var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
+ createInstance(Components.interfaces.nsIFileInputStream);
+ var bis = Components.classes["@mozilla.org/binaryinputstream;1"].
+ createInstance(Components.interfaces.nsIBinaryInputStream);
+ var paths = "tests/dom/media/test/seek.ogv";
+ var split = paths.split("/");
+ for(var i = 0; i < split.length; ++i) {
+ file.append(split[i]);
+ }
+ fis.init(file, -1, -1, false);
+ bis.setInputStream(fis);
+ var bytes = bis.readBytes(bis.available());
+ response.setHeader("Content-Length", ""+bytes.length, false);
+ response.setHeader("Content-Type", "video/ogg", false);
+ response.setHeader("Accept-Ranges", "bytes", false);
+ response.write(bytes, bytes.length);
+ bis.close();
+}
diff --git a/dom/media/test/seek_support.js b/dom/media/test/seek_support.js
new file mode 100644
index 000000000..b193fb60a
--- /dev/null
+++ b/dom/media/test/seek_support.js
@@ -0,0 +1,55 @@
+SimpleTest.requestLongerTimeout(3);
+var manager = new MediaTestManager;
+
+// https://bugzilla.mozilla.org/show_bug.cgi?id=634747
+if (navigator.platform.startsWith("Win")) {
+ SimpleTest.expectAssertions(0, 5);
+} else {
+ // This is "###!!! ASSERTION: Page read cursor should be inside range: 'mPageOffset <= endOffset'"
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=846769
+ SimpleTest.expectAssertions(0, 5);
+}
+
+function createTestArray() {
+ var tests = [];
+ var tmpVid = document.createElement("video");
+
+ for (var testNum=0; testNum<gSeekTests.length; testNum++) {
+ var test = gSeekTests[testNum];
+ if (!tmpVid.canPlayType(test.type)) {
+ continue;
+ }
+
+ var t = new Object;
+ t.name = test.name;
+ t.type = test.type;
+ t.duration = test.duration;
+ t.number = SEEK_TEST_NUMBER;
+ tests.push(t);
+ }
+ return tests;
+}
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ v.token = token += "-seek" + test.number + ".js";
+ manager.started(v.token);
+ v.src = test.name;
+ v.preload = "metadata";
+ document.body.appendChild(v);
+ var name = test.name + " seek test " + test.number;
+ var localIs = function(name) { return function(a, b, msg) {
+ is(a, b, name + ": " + msg);
+ }}(name);
+ var localOk = function(name) { return function(a, msg) {
+ ok(a, name + ": " + msg);
+ }}(name);
+ var localFinish = function(v, manager) { return function() {
+ v.onerror = null;
+ removeNodeAndSource(v);
+ dump("SEEK-TEST: Finished " + name + " token: " + v.token + "\n");
+ manager.finished(v.token);
+ }}(v, manager);
+ dump("SEEK-TEST: Started " + name + "\n");
+ window['test_seek' + test.number](v, test.duration/2, localIs, localOk, localFinish);
+}
diff --git a/dom/media/test/seek_with_sound.ogg b/dom/media/test/seek_with_sound.ogg
new file mode 100644
index 000000000..c86d9946b
--- /dev/null
+++ b/dom/media/test/seek_with_sound.ogg
Binary files differ
diff --git a/dom/media/test/seek_with_sound.ogg^headers^ b/dom/media/test/seek_with_sound.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/seek_with_sound.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/sequential.vtt b/dom/media/test/sequential.vtt
new file mode 100644
index 000000000..94e92e38a
--- /dev/null
+++ b/dom/media/test/sequential.vtt
@@ -0,0 +1,10 @@
+WEBVTT
+
+00:01.000 --> 00:02.000
+This
+
+00:03.000 --> 00:04.000
+Is
+
+00:05.000 --> 00:06.000
+A Test
diff --git a/dom/media/test/short-audio-fragmented-cenc-without-pssh.mp4 b/dom/media/test/short-audio-fragmented-cenc-without-pssh.mp4
new file mode 100644
index 000000000..bc5862399
--- /dev/null
+++ b/dom/media/test/short-audio-fragmented-cenc-without-pssh.mp4
Binary files differ
diff --git a/dom/media/test/short-audio-fragmented-cenc-without-pssh.mp4^headers^ b/dom/media/test/short-audio-fragmented-cenc-without-pssh.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/short-audio-fragmented-cenc-without-pssh.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/short-cenc.mp4 b/dom/media/test/short-cenc.mp4
new file mode 100644
index 000000000..aa44c3b9a
--- /dev/null
+++ b/dom/media/test/short-cenc.mp4
Binary files differ
diff --git a/dom/media/test/short-cenc.xml b/dom/media/test/short-cenc.xml
new file mode 100644
index 000000000..9658c3e32
--- /dev/null
+++ b/dom/media/test/short-cenc.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ This XML file describes the encryption applied to short-cenc.mp4. To generate
+ short-cenc, run the following command:
+
+ MP4Box -crypt short-cenc.xml -out short-cenc.mp4 short.mp4
+-->
+
+<GPACDRM type="CENC AES-CTR">
+
+ <DRMInfo type="pssh" version="1">
+ <!--
+ SystemID specified in
+ https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
+ -->
+ <BS ID128="1077efecc0b24d02ace33c1e52e2fb4b" />
+ <!-- Number of KeyIDs = 2 -->
+ <BS bits="32" value="2" />
+ <!-- KeyID -->
+ <BS ID128="0x7e571d017e571d017e571d017e571d01" />
+ <BS ID128="0x7e571d027e571d027e571d027e571d02" />
+ </DRMInfo>
+
+ <CrypTrack trackID="1" isEncrypted="1" IV_size="16" saiSavedBox="senc"
+ first_IV="0x00000000000000000000000000000000">
+ <key KID="0x7e571d017e571d017e571d017e571d01"
+ value="0x7e5711117e5711117e5711117e571111" />
+ </CrypTrack>
+
+ <CrypTrack trackID="2" isEncrypted="1" IV_size="16" saiSavedBox="senc"
+ first_IV="0x00000000000000000000000000000000">
+ <key KID="0x7e571d027e571d027e571d027e571d02"
+ value="0x7e5722227e5722227e5722227e572222" />
+ </CrypTrack>
+
+</GPACDRM>
diff --git a/dom/media/test/short-video.ogv b/dom/media/test/short-video.ogv
new file mode 100644
index 000000000..68dee3cf2
--- /dev/null
+++ b/dom/media/test/short-video.ogv
Binary files differ
diff --git a/dom/media/test/short-video.ogv^headers^ b/dom/media/test/short-video.ogv^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/short-video.ogv^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/short.mp4 b/dom/media/test/short.mp4
new file mode 100644
index 000000000..a674b7eb6
--- /dev/null
+++ b/dom/media/test/short.mp4
Binary files differ
diff --git a/dom/media/test/short.mp4^headers^ b/dom/media/test/short.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/short.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/sine.webm b/dom/media/test/sine.webm
new file mode 100644
index 000000000..3913ffa87
--- /dev/null
+++ b/dom/media/test/sine.webm
Binary files differ
diff --git a/dom/media/test/sine.webm^headers^ b/dom/media/test/sine.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/sine.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/small-shot-mp3.mp4 b/dom/media/test/small-shot-mp3.mp4
new file mode 100644
index 000000000..61fe0ac71
--- /dev/null
+++ b/dom/media/test/small-shot-mp3.mp4
Binary files differ
diff --git a/dom/media/test/small-shot-mp3.mp4^headers^ b/dom/media/test/small-shot-mp3.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/small-shot-mp3.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/small-shot.flac b/dom/media/test/small-shot.flac
new file mode 100644
index 000000000..0da7c9044
--- /dev/null
+++ b/dom/media/test/small-shot.flac
Binary files differ
diff --git a/dom/media/test/small-shot.m4a b/dom/media/test/small-shot.m4a
new file mode 100644
index 000000000..51a23c5b4
--- /dev/null
+++ b/dom/media/test/small-shot.m4a
Binary files differ
diff --git a/dom/media/test/small-shot.mp3 b/dom/media/test/small-shot.mp3
new file mode 100644
index 000000000..f9397a510
--- /dev/null
+++ b/dom/media/test/small-shot.mp3
Binary files differ
diff --git a/dom/media/test/small-shot.mp3^headers^ b/dom/media/test/small-shot.mp3^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/small-shot.mp3^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/small-shot.ogg b/dom/media/test/small-shot.ogg
new file mode 100644
index 000000000..1a41623f8
--- /dev/null
+++ b/dom/media/test/small-shot.ogg
Binary files differ
diff --git a/dom/media/test/small-shot.ogg^headers^ b/dom/media/test/small-shot.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/small-shot.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/sound.ogg b/dom/media/test/sound.ogg
new file mode 100644
index 000000000..edda4e912
--- /dev/null
+++ b/dom/media/test/sound.ogg
Binary files differ
diff --git a/dom/media/test/sound.ogg^headers^ b/dom/media/test/sound.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/sound.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/spacestorm-1000Hz-100ms.ogg b/dom/media/test/spacestorm-1000Hz-100ms.ogg
new file mode 100644
index 000000000..994041e1b
--- /dev/null
+++ b/dom/media/test/spacestorm-1000Hz-100ms.ogg
Binary files differ
diff --git a/dom/media/test/spacestorm-1000Hz-100ms.ogg^headers^ b/dom/media/test/spacestorm-1000Hz-100ms.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/spacestorm-1000Hz-100ms.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/split.webm b/dom/media/test/split.webm
new file mode 100644
index 000000000..9207017fb
--- /dev/null
+++ b/dom/media/test/split.webm
Binary files differ
diff --git a/dom/media/test/split.webm^headers^ b/dom/media/test/split.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/split.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/street.mp4 b/dom/media/test/street.mp4
new file mode 100644
index 000000000..837d23b38
--- /dev/null
+++ b/dom/media/test/street.mp4
Binary files differ
diff --git a/dom/media/test/street.mp4^headers^ b/dom/media/test/street.mp4^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/street.mp4^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/test-1-mono.opus b/dom/media/test/test-1-mono.opus
new file mode 100644
index 000000000..d5198e9ce
--- /dev/null
+++ b/dom/media/test/test-1-mono.opus
Binary files differ
diff --git a/dom/media/test/test-1-mono.opus^headers^ b/dom/media/test/test-1-mono.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/test-1-mono.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/test-2-stereo.opus b/dom/media/test/test-2-stereo.opus
new file mode 100644
index 000000000..7115cac24
--- /dev/null
+++ b/dom/media/test/test-2-stereo.opus
Binary files differ
diff --git a/dom/media/test/test-2-stereo.opus^headers^ b/dom/media/test/test-2-stereo.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/test-2-stereo.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/test-3-LCR.opus b/dom/media/test/test-3-LCR.opus
new file mode 100644
index 000000000..145536f3e
--- /dev/null
+++ b/dom/media/test/test-3-LCR.opus
Binary files differ
diff --git a/dom/media/test/test-3-LCR.opus^headers^ b/dom/media/test/test-3-LCR.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/test-3-LCR.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/test-4-quad.opus b/dom/media/test/test-4-quad.opus
new file mode 100644
index 000000000..731b867b2
--- /dev/null
+++ b/dom/media/test/test-4-quad.opus
Binary files differ
diff --git a/dom/media/test/test-4-quad.opus^headers^ b/dom/media/test/test-4-quad.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/test-4-quad.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/test-5-5.0.opus b/dom/media/test/test-5-5.0.opus
new file mode 100644
index 000000000..7eb2faa81
--- /dev/null
+++ b/dom/media/test/test-5-5.0.opus
Binary files differ
diff --git a/dom/media/test/test-5-5.0.opus^headers^ b/dom/media/test/test-5-5.0.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/test-5-5.0.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/test-6-5.1.opus b/dom/media/test/test-6-5.1.opus
new file mode 100644
index 000000000..526515eb7
--- /dev/null
+++ b/dom/media/test/test-6-5.1.opus
Binary files differ
diff --git a/dom/media/test/test-6-5.1.opus^headers^ b/dom/media/test/test-6-5.1.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/test-6-5.1.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/test-7-6.1.opus b/dom/media/test/test-7-6.1.opus
new file mode 100644
index 000000000..8b6a7ce32
--- /dev/null
+++ b/dom/media/test/test-7-6.1.opus
Binary files differ
diff --git a/dom/media/test/test-7-6.1.opus^headers^ b/dom/media/test/test-7-6.1.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/test-7-6.1.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/test-8-7.1.opus b/dom/media/test/test-8-7.1.opus
new file mode 100644
index 000000000..e56176a30
--- /dev/null
+++ b/dom/media/test/test-8-7.1.opus
Binary files differ
diff --git a/dom/media/test/test-8-7.1.opus^headers^ b/dom/media/test/test-8-7.1.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/test-8-7.1.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/test_VideoPlaybackQuality.html b/dom/media/test/test_VideoPlaybackQuality.html
new file mode 100644
index 000000000..be051c0a6
--- /dev/null
+++ b/dom/media/test/test_VideoPlaybackQuality.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test basic functionality of VideoPlaybackQuality</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function test() {
+ var video = document.createElement("video");
+ ok(video.getVideoPlaybackQuality, "getVideoPlaybackQuality should be exposed with pref set");
+
+ var vpq = video.getVideoPlaybackQuality();
+ ok(vpq, "getVideoPlaybackQuality should return an object");
+ ok(vpq.creationTime <= performance.now(), "creationTime should be in the past");
+ is(vpq.totalVideoFrames, 0, "totalVideoFrames should be 0");
+ is(vpq.droppedVideoFrames, 0, "droppedVideoFrames should be 0");
+ is(vpq.corruptedVideoFrames, 0, "corruptedVideoFrames should be 0");
+
+ var vpq2 = video.getVideoPlaybackQuality();
+ ok(vpq !== vpq2, "getVideoPlaybackQuality should return a new object");
+ ok(vpq.creationTime <= vpq2.creationTime, "VideoPlaybackQuality objects should have increasing creationTime");
+
+ var audio = document.createElement("audio");
+ ok(!audio.getVideoPlaybackQuality, "getVideoPlaybackQuality should not be available on Audio elements");
+
+ video.src = "seek.webm";
+ video.play();
+ video.addEventListener("ended", function () {
+ vpq = video.getVideoPlaybackQuality();
+ ok(vpq.creationTime <= performance.now(), "creationTime should be in the past");
+ ok(vpq.totalVideoFrames > 0, "totalVideoFrames should be > 0");
+ ok(vpq.droppedVideoFrames >= 0, "droppedVideoFrames should be >= 0");
+ ok(vpq.droppedVideoFrames <= vpq.totalVideoFrames, "droppedVideoFrames should be <= totalVideoFrames");
+ ok(vpq.corruptedVideoFrames >= 0, "corruptedVideoFrames should be >= 0");
+
+ SpecialPowers.pushPrefEnv({"set": [["media.video_stats.enabled", false]]}, function () {
+ vpq = video.getVideoPlaybackQuality();
+ is(vpq.creationTime, 0, "creationTime should be 0");
+ is(vpq.totalVideoFrames, 0, "totalVideoFrames should be 0");
+ is(vpq.droppedVideoFrames, 0, "droppedVideoFrames should be 0");
+ is(vpq.corruptedVideoFrames, 0, "corruptedVideoFrames should be 0");
+
+ SimpleTest.finish();
+ });
+ });
+}
+
+addLoadEvent(function() {
+ SpecialPowers.pushPrefEnv({"set":
+ [
+ ["media.mediasource.enabled", true],
+ ]
+ }, test);
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_VideoPlaybackQuality_disabled.html b/dom/media/test/test_VideoPlaybackQuality_disabled.html
new file mode 100644
index 000000000..756c3bedc
--- /dev/null
+++ b/dom/media/test/test_VideoPlaybackQuality_disabled.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test basic functionality of VideoPlaybackQuality</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function test() {
+ var video = document.createElement("video");
+ ok(!video.getVideoPlaybackQuality, "getVideoPlaybackQuality should be hidden behind a pref");
+ var accessThrows = false;
+ try {
+ video.getVideoPlaybackQuality();
+ } catch (e) {
+ accessThrows = true;
+ }
+ ok(accessThrows, "getVideoPlaybackQuality should be hidden behind a pref");
+ SimpleTest.finish();
+}
+
+addLoadEvent(function() {
+ SpecialPowers.pushPrefEnv({"set":
+ [
+ ["media.mediasource.enabled", false],
+ ]
+ }, test);
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_access_control.html b/dom/media/test/test_access_control.html
new file mode 100644
index 000000000..57bfeb97b
--- /dev/null
+++ b/dom/media/test/test_access_control.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=451958
+-->
+<head>
+ <title>Test for Bug 451958</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=451958">Mozilla Bug 451958</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 451958 **/
+
+function run() {
+ window.open("http://example.org:80/tests/dom/media/test/file_access_controls.html", "", "width=500,height=500");
+}
+
+function done() {
+ mediaTestCleanup();
+ SimpleTest.finish();
+}
+
+addLoadEvent(run);
+SimpleTest.waitForExplicitFinish();
+
+
+window.addEventListener("message", receiveMessage, false);
+
+function receiveMessage(event)
+{
+ if (event.origin !== "http://example.org") {
+ ok(false, "Received message from wrong domain");
+ return;
+ }
+
+ if (event.data.done == "true")
+ return done();
+
+ ok(event.data.result, event.data.message);
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_aspectratio_mp4.html b/dom/media/test/test_aspectratio_mp4.html
new file mode 100644
index 000000000..27ad9bb1f
--- /dev/null
+++ b/dom/media/test/test_aspectratio_mp4.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=975978
+-->
+
+<head>
+ <title>Media test: default video size</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=975978">Mozilla Bug 975978</a>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function IsWindows7OrLater() {
+ var re = /Windows NT (\d.\d)/;
+ var winver = navigator.userAgent.match(re);
+ return winver && winver.length == 2 && parseFloat(winver[1]) >= 6.1;
+}
+
+SimpleTest.waitForExplicitFinish();
+
+// MP4 video with display size is difference to decode frame size.
+// The display size is recorded in TrackHeaderBox 'tkhd' of this mp4 video.
+var resource =
+ { name:"pixel_aspect_ratio.mp4", type:"video/mp4", width:525, height:288 };
+
+var v = document.createElement("video");
+v.onloadedmetadata = function() {
+ is(v.videoWidth, resource.width, "Intrinsic width should match video width");
+ is(v.videoHeight, resource.height, "Intrinsic height should match video height");
+ SimpleTest.finish();
+}
+v.addEventListener("error", function(ev) {
+ if (v.readyState < v.HAVE_METADATA) {
+ info("Video element returns with readyState " + v.readyState + " error.code " + v.error.code);
+ todo(false, "This platform doesn't support to retrieve MP4 metadata.");
+ SimpleTest.finish();
+ }
+}, false);
+
+v.src = resource.name;
+v.preload = "auto";
+
+document.body.appendChild(v);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_audio1.html b/dom/media/test/test_audio1.html
new file mode 100644
index 000000000..8d9ca7b68
--- /dev/null
+++ b/dom/media/test/test_audio1.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: Audio Constructor Test 1</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ var a1 = new Audio();
+ if (!a1.canPlayType(test.type))
+ return;
+ manager.started(token);
+
+ is(a1.getAttribute("preload"), "auto", "preload:auto automatically set");
+ is(a1.src, "", "Src set?");
+ a1 = null;
+ manager.finished(token);
+}
+
+manager.runTests(gAudioTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_audio2.html b/dom/media/test/test_audio2.html
new file mode 100644
index 000000000..ae0126189
--- /dev/null
+++ b/dom/media/test/test_audio2.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: Audio Constructor Test 2</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var tmpAudio = new Audio();
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ if (!tmpAudio.canPlayType(test.type))
+ return;
+ manager.started(token);
+ var a1 = new Audio(test.name);
+ is(a1.getAttribute("preload"), "auto", "Preload automatically set to auto");
+ ok(a1.src.endsWith("/" + test.name), "src OK");
+ manager.finished(token);
+}
+
+manager.runTests(gAudioTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_audioDocumentTitle.html b/dom/media/test/test_audioDocumentTitle.html
new file mode 100644
index 000000000..d8d84a563
--- /dev/null
+++ b/dom/media/test/test_audioDocumentTitle.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=463830
+-->
+<head>
+ <title>Test for Bug 463830</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=463830">Mozilla Bug 463830</a>
+<p id="display"></p>
+<iframe id="i"></iframe>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 463830 **/
+
+var gTests = [
+ { file: "r11025_s16_c1.wav", title: "r11025_s16_c1.wav" }
+];
+
+var gTestNum = 0;
+
+addLoadEvent(runTest);
+
+var title;
+var i = document.getElementById("i");
+
+function runTest() {
+ if (gTestNum == gTests.length) {
+ SimpleTest.finish();
+ return;
+ }
+ if (gTestNum == 0) {
+ i.addEventListener("load", function() {
+ is(i.contentDocument.title, title, "Doc title incorrect");
+ setTimeout(runTest, 0);
+ }, false);
+ }
+
+ title = gTests[gTestNum].title;
+ i.src = gTests[gTestNum].file;
+ gTestNum++;
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_autoplay.html b/dom/media/test/test_autoplay.html
new file mode 100644
index 000000000..ea3191b4b
--- /dev/null
+++ b/dom/media/test/test_autoplay.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: autoplay attribute</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<video id='v1'"></video><audio id='a1'></audio>
+<video id='v2' autoplay></video><audio id='a2' autoplay></audio>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var v1 = document.getElementById('v1');
+var a1 = document.getElementById('a1');
+var v2 = document.getElementById('v2');
+var a2 = document.getElementById('a2');
+ok(!v1.autoplay, "v1.autoplay should be false by default");
+ok(!a1.autoplay, "v1.autoplay should be false by default");
+ok(v2.autoplay, "v2.autoplay should be true");
+ok(a2.autoplay, "v2.autoplay should be true");
+
+v1.autoplay = true;
+a1.autoplay = true;
+ok(v1.autoplay, "video.autoplay not true");
+ok(a1.autoplay, "audio.autoplay not true");
+is(v1.getAttribute("autoplay"), "", "video autoplay attribute not set");
+is(a1.getAttribute("autoplay"), "", "video autoplay attribute not set");
+
+mediaTestCleanup();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_autoplay_contentEditable.html b/dom/media/test/test_autoplay_contentEditable.html
new file mode 100644
index 000000000..e2375d18b
--- /dev/null
+++ b/dom/media/test/test_autoplay_contentEditable.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: play() method</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body contenteditable="true">
+<pre id="test">
+
+<script>
+
+var manager = new MediaTestManager;
+
+var tokens = {
+ 0: ["canplay"],
+ "canplay": ["canplay", "canplaythrough"],
+ "canplaythrough": ["canplay", "canplaythrough"]
+};
+
+var eventList = ["play", "canplay", "playing", "canplaythrough", "ended"];
+
+function gotPlayEvent(event) {
+ var v = event.target;
+ ok(tokens[v._state].indexOf(event.type) >= 0,
+ "Check expected event got " + uneval(event.type) +
+ " at " + uneval(v._state) + " for " + v._name);
+ v._state = event.type;
+ if (event.type == 'canplaythrough') {
+ // Remove all event listeners to avoid running tests after finishing test case.
+ eventList.forEach(function (e) {
+ v.removeEventListener(e, gotPlayEvent, false);
+ });
+ v.pause();
+ goToNext(v);
+ }
+}
+
+function goToNext(v) {
+ v.parentNode.removeChild(v);
+ manager.finished(v.token);
+}
+
+function initTest(test, token) {
+ var v = document.createElement('video');
+ v.preload = "metadata";
+ v.token = token;
+ manager.started(token);
+ v._state = 0;
+
+ eventList.forEach(function (e) {
+ v.addEventListener(e, gotPlayEvent, false);
+ });
+
+ v.src = test.name;
+ v._name = test.name;
+ v.autoplay = true;
+ document.body.appendChild(v); // Causes load.
+}
+
+manager.runTests(gSmallTests, initTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_background_video_no_suspend_disabled.html b/dom/media/test/test_background_video_no_suspend_disabled.html
new file mode 100644
index 000000000..81a253b6c
--- /dev/null
+++ b/dom/media/test/test_background_video_no_suspend_disabled.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test Background Video Doesn't Suspend When Feature Disabled</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="manifest.js"></script>
+<script src="background_video.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<script>
+"use strict";
+
+var manager = new MediaTestManager;
+
+startTest({
+ desc: "Test Background Video Doesn't Suspend When Feature Disabled.",
+ prefs: [
+ [ 'media.test.setVisible', true ],
+ [ 'media.suspend-bkgnd-video.enabled', false ],
+ [ 'media.suspend-bkgnd-video.delay-ms', 0 ]
+ ],
+ tests: gDecodeSuspendTests,
+ runTest: (test, token) => {
+ let v = appendVideoToDoc(test.name, token);
+ manager.started(token);
+
+ /* This test checks that suspend doesn't occur when the feature is disabled */
+ waitUntilPlaying(v)
+ .then(() => checkVideoDoesntSuspend(v))
+ .then(() => {
+ ok(true, 'Video ended before decode was suspended');
+ manager.finished(token); })
+ .catch((e) => {
+ ok(false, 'Test Failed: ' + e.toString());
+ manager.finished(token); });
+ }
+});
+</script> \ No newline at end of file
diff --git a/dom/media/test/test_background_video_no_suspend_short_vid.html b/dom/media/test/test_background_video_no_suspend_short_vid.html
new file mode 100644
index 000000000..980c1b2b3
--- /dev/null
+++ b/dom/media/test/test_background_video_no_suspend_short_vid.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test Background Video Doesn't Suspend When Timeout Is Longer Than Video</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="manifest.js"></script>
+<script src="background_video.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<script>
+"use strict";
+
+var manager = new MediaTestManager;
+
+startTest({
+ desc: "Test Background Video Doesn't Suspend When Timeout Is Longer Than Video.",
+ prefs: [
+ [ 'media.test.setVisible', true ],
+ [ 'media.suspend-bkgnd-video.enabled', true ],
+ // Gizmo.mp4 is about 5.6s
+ [ 'media.suspend-bkgnd-video.delay-ms', 10000 ]
+ ],
+ tests: gDecodeSuspendTests,
+ runTest: (test, token) => {
+ let v = appendVideoToDoc(test.name, token);
+ manager.started(token);
+
+ /* This test checks that suspend doesn't occur when the delay is longer
+ than the duration of the video that's playing */
+ waitUntilPlaying(v)
+ .then(() => checkVideoDoesntSuspend(v))
+ .then(() => {
+ ok(true, 'Video ended before decode was suspended');
+ manager.finished(token); })
+ .catch((e) => {
+ ok(false, 'Test Failed: ' + e.toString());
+ manager.finished(token); });
+ }
+});
+</script> \ No newline at end of file
diff --git a/dom/media/test/test_background_video_suspend.html b/dom/media/test/test_background_video_suspend.html
new file mode 100644
index 000000000..e872eacf8
--- /dev/null
+++ b/dom/media/test/test_background_video_suspend.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test Background Video Suspends</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="manifest.js"></script>
+<script src="background_video.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<script type="text/javascript">
+"use strict";
+
+var manager = new MediaTestManager;
+
+var MIN_DELAY = 100;
+
+function testDelay(v, start, min) {
+ let end = performance.now();
+ let delay = end - start;
+ ok(delay > min, `${v.token} suspended with a delay of ${delay} ms`);
+}
+
+startTest({
+ desc: 'Test Background Video Suspends',
+ prefs: [
+ [ "media.test.setVisible", true ],
+ [ "media.suspend-bkgnd-video.enabled", true ],
+ // User a short delay to ensure video decode suspend happens before end
+ // of video.
+ [ "media.suspend-bkgnd-video.delay-ms", MIN_DELAY ]
+ ],
+ tests: gDecodeSuspendTests,
+ runTest: (test, token) => {
+ let v = appendVideoToDoc(test.name, token);
+ manager.started(token);
+
+ let start;
+ waitUntilPlaying(v)
+ .then(() => { start = performance.now(); })
+ .then(() => testVideoSuspendsWhenHidden(v))
+ .then(() => {
+ testDelay(v, start, MIN_DELAY);
+ return testVideoResumesWhenShown(v);
+ })
+ .then(() => waitUntilEnded(v))
+ .then(() => {
+ removeNodeAndSource(v);
+ manager.finished(token);
+ });
+ }
+});
+</script>
diff --git a/dom/media/test/test_background_video_suspend_ends.html b/dom/media/test/test_background_video_suspend_ends.html
new file mode 100644
index 000000000..e1b72c07a
--- /dev/null
+++ b/dom/media/test/test_background_video_suspend_ends.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test Background Suspended Video Fires 'ended' Event</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="manifest.js"></script>
+<script src="background_video.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<script type="text/javascript">
+"use strict";
+
+var manager = new MediaTestManager;
+
+startTest({
+ desc: "Test Background Suspended Video Fires 'ended' Event",
+ prefs: [
+ [ "media.test.setVisible", true ],
+ [ "media.suspend-bkgnd-video.enabled", true ],
+ // User a short delay to ensure video decode suspend happens before end
+ // of video.
+ [ "media.suspend-bkgnd-video.delay-ms", 1000 ]
+ ],
+ tests: gDecodeSuspendTests,
+ runTest: (test, token) => {
+ let v = appendVideoToDoc(test.name, token);
+ manager.started(token);
+
+ // This test checks that 'ended' event is received for videos with
+ // suspended video decoding. This is important for looping video logic
+ // handling in HTMLMediaElement.
+ waitUntilPlaying(v)
+ .then(() => testVideoSuspendsWhenHidden(v))
+ .then(() => waitUntilEnded(v))
+ .then(() => {
+ ok(v.currentTime >= v.duration, 'current time approximates duration.');
+ manager.finished(token);
+ });
+ }
+});
+</script>
diff --git a/dom/media/test/test_buffered.html b/dom/media/test/test_buffered.html
new file mode 100644
index 000000000..407ae7404
--- /dev/null
+++ b/dom/media/test/test_buffered.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=462957
+-->
+<head>
+ <title>Test for Bug 462957</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=462957">Mozilla Bug 462957</a>
+
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+// Test for Bug 462957; HTMLMediaElement.buffered.
+
+var manager = new MediaTestManager;
+
+function testBuffered(e) {
+ var v = e.target;
+ v.removeEventListener('timeupdate', testBuffered);
+
+ // The whole media should be buffered...
+ var b = v.buffered;
+ is(b.length, 1, v._name + ": Should be buffered in one range");
+ is(b.start(0), 0, v._name + ": First range start should be media start");
+ ok(Math.abs(b.end(0) - v.duration) < 0.1, v._name + ": First range end should be media end");
+
+ // Ensure INDEX_SIZE_ERR is thrown when we access outside the range
+ var caught = false;
+ try {
+ b.start(-1);
+ } catch (e) {
+ caught = e.name == "IndexSizeError" && e.code == DOMException.INDEX_SIZE_ERR;
+ }
+ is(caught, true, v._name + ": Should throw INDEX_SIZE_ERR on under start bounds range");
+
+ caught = false;
+ try {
+ b.end(-1);
+ } catch (e) {
+ caught = e.name == "IndexSizeError" && e.code == DOMException.INDEX_SIZE_ERR;
+ }
+ is(caught, true, v._name + ": Should throw INDEX_SIZE_ERR on under end bounds range");
+
+ caught = false;
+ try {
+ b.start(b.length);
+ } catch (e) {
+ caught = e.name == "IndexSizeError" && e.code == DOMException.INDEX_SIZE_ERR;
+ }
+ is(caught, true, v._name + ": Should throw INDEX_SIZE_ERR on over start bounds range");
+
+ caught = false;
+ try {
+ b.end(b.length);
+ } catch (e) {
+ caught = e.name == "IndexSizeError" && e.code == DOMException.INDEX_SIZE_ERR;
+ }
+ is(caught, true, v._name + ": Should throw INDEX_SIZE_ERR on over end bounds range");
+
+ removeNodeAndSource(v);
+ manager.finished(v._token);
+}
+
+function fetch(url, fetched_callback) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", url, true);
+ xhr.responseType = "blob";
+
+ var loaded = function (event) {
+ if (xhr.status == 200 || xhr.status == 206) {
+ // Request fulfilled. Note sometimes we get 206... Presumably because either
+ // httpd.js or Necko cached the result.
+ fetched_callback(window.URL.createObjectURL(xhr.response));
+ } else {
+ ok(false, "Fetch failed headers=" + xhr.getAllResponseHeaders());
+ }
+ };
+
+ xhr.addEventListener("load", loaded, false);
+ xhr.send();
+}
+
+function startTest(test, token) {
+ // Fetch the media resource using XHR so we can be sure the entire
+ // resource is loaded before we test buffered ranges. This ensures
+ // we have deterministic behaviour.
+ var onfetched = function(uri) {
+ var v = document.createElement('video');
+ v.autoplay = true;
+ v._token = token;
+ v.src = uri;
+ v._name = test.name;
+ v._test = test;
+ v.addEventListener("timeupdate", testBuffered, false);
+ document.body.appendChild(v);
+ };
+
+ manager.started(token);
+ fetch(test.name, onfetched);
+}
+
+// Note: No need to set media test prefs, since we're using XHR to fetch
+// media data.
+SimpleTest.waitForExplicitFinish();
+manager.runTests(gSeekTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_bug1018933.html b/dom/media/test/test_bug1018933.html
new file mode 100644
index 000000000..3159588ae
--- /dev/null
+++ b/dom/media/test/test_bug1018933.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1018933
+-->
+<head>
+ <meta charset='utf-8'>
+ <title>Regression test for bug 1018933 - HTMLTrackElement should create only one TextTrack</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var video = document.createElement("video");
+video.src = "seek.webm";
+video.preload = "auto";
+
+var trackElement = document.createElement("track");
+trackElement.src = "basic.vtt";
+trackElement.kind = "subtitles";
+
+document.getElementById("content").appendChild(video);
+video.appendChild(trackElement);
+
+// Accessing the track now would have caused the bug as the track element
+// shouldn't have had time to bind to the tree yet.
+trackElement.track.mode = 'showing';
+
+video.addEventListener("loadedmetadata", function run_tests() {
+ // Re-que run_tests() at the end of the event loop until the track
+ // element has loaded its data.
+ if (trackElement.readyState == 1) {
+ setTimeout(run_tests, 0);
+ return;
+ }
+
+ is(video.textTracks.length, 1, "Video should have one TextTrack.");
+ SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_bug1113600.html b/dom/media/test/test_bug1113600.html
new file mode 100644
index 000000000..394994d0a
--- /dev/null
+++ b/dom/media/test/test_bug1113600.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test that a video element captured to a stream mid-playback can be played to the end</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+PARALLEL_TESTS = 1;
+SimpleTest.requestCompleteLog();
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ v.style = "background-color:#aca;";
+ v.width = 160;
+ v.height = 120;
+
+ manager.started(token);
+
+ v.src = test.name;
+
+ v.ontimeupdate = function() {
+ if (v.currentTime < test.duration / 4) {
+ // Allow some time to pass before starting the capture.
+ return;
+ }
+ v.ontimeupdate = null;
+ v.mozCaptureStreamUntilEnded();
+ info(test.name + " capture started at " + v.currentTime + ". Duration=" + test.duration);
+ };
+
+ v.onended = function() {
+ ok(true, test.name + " ended");
+ removeNodeAndSource(v);
+ manager.finished(token);
+ };
+
+ document.body.appendChild(v);
+ v.play();
+}
+
+manager.runTests(gSmallTests, startTest);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_bug1242338.html b/dom/media/test/test_bug1242338.html
new file mode 100644
index 000000000..c404d7b1d
--- /dev/null
+++ b/dom/media/test/test_bug1242338.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test Bug 1242338</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ var video = document.createElement('video');
+ video.preload = "metadata";
+ video.token = token;
+
+ var handler = {
+ "ontimeout": function() {
+ Log(token, "timed out");
+ }
+ };
+ manager.started(token, handler);
+
+ video.src = test.name;
+ video.name = test.name;
+
+ function finish() {
+ video.finished = true;
+ video.removeEventListener("loadedmetadata", onLoadedmetadata, false);
+ video.removeEventListener("ended", onEnded, false);
+ removeNodeAndSource(video);
+ manager.finished(video.token);
+ }
+
+ function onLoadedmetadata() {
+ // seek to the media's duration
+ var duration = video.duration;
+ console.log("onloadedmetadata(), duration = " + duration);
+ video.currentTime = duration;
+ }
+
+ function onEnded() {
+ ok(video.ended, test.name + " checking playback has ended");
+ ok(!video.finished, test.name + " shouldn't be finished");
+ ok(!video.seenEnded, test.name + " shouldn't be ended");
+ video.seenEnded = true;
+
+ ok(true, "Seeking to the duration triggers ended event");
+ finish();
+ }
+
+ video.addEventListener("loadedmetadata", onLoadedmetadata, false);
+ video.addEventListener("ended", onEnded, false);
+
+ document.body.appendChild(video);
+}
+
+manager.runTests(gSeekTests, startTest);
+
+</script>
+</pre>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/media/test/test_bug1242594.html b/dom/media/test/test_bug1242594.html
new file mode 100644
index 000000000..780de0005
--- /dev/null
+++ b/dom/media/test/test_bug1242594.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1242594
+-->
+<head>
+ <meta charset='utf-8'>
+ <title>Bug 1242594 - Unbind a video element with HTMLTrackElement
+ should not remove the TextTrack</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var video = document.createElement("video");
+video.src = "seek.webm";
+video.preload = "auto";
+
+var trackElement = document.createElement("track");
+trackElement.src = "basic.vtt";
+trackElement.kind = "subtitles";
+
+document.getElementById("content").appendChild(video);
+video.appendChild(trackElement);
+
+// Bug 1242599, access video.textTracks.length immediately after
+// the track element binds into the media element.
+is(video.textTracks.length, 1, "Video should have one TextTrack.");
+var parent = video.parentNode;
+parent.removeChild(video);
+is(video.textTracks.length, 1, "After unbind the video element, should have one TextTrack.");
+parent.appendChild(video);
+is(video.textTracks.length, 1, "After bind the video element, should have one TextTrack.");
+SimpleTest.finish();
+
+</script>
+</pre>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/media/test/test_bug1248229.html b/dom/media/test/test_bug1248229.html
new file mode 100644
index 000000000..4feb265a3
--- /dev/null
+++ b/dom/media/test/test_bug1248229.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test garbage collection of captured stream (bug 1248229)</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body onload="doTest()">
+<video id="v" src="black100x100-aspect3to2.ogv"></video>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+function doTest() {
+ window.oak = v.mozCaptureStreamUntilEnded();
+ v.mozCaptureStreamUntilEnded();
+ v.play();
+
+ v.onended = function() {
+ info("Got ended.");
+ v.onended = null;
+ SpecialPowers.exactGC(function() {
+ info("GC completed.");
+ v.play();
+ SimpleTest.finish();
+ });
+ }
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_bug448534.html b/dom/media/test/test_bug448534.html
new file mode 100644
index 000000000..d768ccced
--- /dev/null
+++ b/dom/media/test/test_bug448534.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=448534
+-->
+
+<head>
+ <title>Test for Bug 448534</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=448535">Mozilla Bug 448534</a>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function loaded(event) {
+ var v = event.target;
+ info(v.token + ": event=" + event.type);
+ if (v._finished)
+ return;
+ v.play();
+}
+
+function started(event) {
+ var v = event.target;
+ info(v.token + ": event=" + event.type);
+ // For a short file, it could reach the end before 'play' received. We will
+ // skip the test for 'paused' would be true when ended.
+ if (v._finished || v.ended)
+ return;
+ ok(!v.paused, v.token + ": Video should not be paused while playing");
+ v.parentNode.removeChild(v);
+ v._played = true;
+}
+
+function stopped(event) {
+ var v = event.target;
+ info(v.token + ": event=" + event.type);
+ if (v._finished)
+ return;
+ v._finished = true;
+ ok(v.paused, v.token + ": Video should be paused after removing from the Document");
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+}
+
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ v.preload = "metadata";
+ v.token = token;
+ manager.started(token);
+ v.src = test.name;
+ v._played = false;
+ v._finished = false;
+ v.addEventListener("loadedmetadata", loaded, false);
+ v.addEventListener("play", started, false);
+ v.addEventListener("pause", stopped, false);
+ document.body.appendChild(v);
+}
+
+manager.runTests(gSmallTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_bug463162.xhtml b/dom/media/test/test_bug463162.xhtml
new file mode 100644
index 000000000..3d1dde405
--- /dev/null
+++ b/dom/media/test/test_bug463162.xhtml
@@ -0,0 +1,78 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns:svg="http://www.w3.org/2000/svg">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=463162
+-->
+<head>
+ <title>Test for Bug 463162</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"/>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=463162">Mozilla Bug 463162</a>
+
+<script class="testbody" type="text/javascript">
+<![CDATA[
+
+var gExpectedResult = {
+ 'a1' : 'error',
+ 'a2' : 'loaded',
+ 'a3' : 'loaded',
+ 'a4' : 'error',
+};
+
+var gResultCount = 0;
+
+function onError(event, id) {
+ is('error', gExpectedResult[id], 'unexpected error loading ' + id);
+ gResultCount++;
+ dump('error('+id+') expected ' + gExpectedResult[id] + ' gResultCount=' + gResultCount + '\n');
+ if (gResultCount == 4)
+ SimpleTest.finish();
+}
+
+function onMetaData(id) {
+ is('loaded', gExpectedResult[id], 'unexpected loadedmetadata loading ' + id);
+ gResultCount++;
+ dump('onMetaData('+id+') expected ' + gExpectedResult[id] + ' gResultCount=' + gResultCount + '\n');
+ if (gResultCount == 4)
+ SimpleTest.finish();
+}
+
+]]>
+</script>
+
+<video id="a1" preload="metadata" onloadedmetadata="onMetaData('a1');"><sauce/><source type="bad" src="404" onerror="onError(event, 'a1');"/></video>
+<video id="a2" preload="metadata" onloadedmetadata="onMetaData('a2');"><source onerror="onError(event, 'a2');"/></video>
+<video id="a3" preload="metadata" onloadedmetadata="onMetaData('a3');"><html:source onerror="onError(event, 'a3');"/></video>
+<video id="a4" preload="metadata" onloadedmetadata="onMetaData('a4');"><svg:source/><source onerror="onError(event, 'a4');" type="bad" src="404"/></video>
+
+<script class="testbody" type="text/javascript">
+<![CDATA[
+
+function setSource(id, res) {
+ var v = document.getElementById(id);
+ v.firstChild.src = res.name;
+ v.firstChild.type = res.type;
+}
+
+var t = getPlayableVideo(gSmallTests);
+
+setSource('a1', t);
+setSource('a2', t);
+setSource('a3', t);
+setSource('a4', t);
+
+SimpleTest.waitForExplicitFinish();
+
+]]>
+</script>
+
+<pre id="test">
+
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_bug465498.html b/dom/media/test/test_bug465498.html
new file mode 100644
index 000000000..77bc68e71
--- /dev/null
+++ b/dom/media/test/test_bug465498.html
@@ -0,0 +1,83 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: Bug 465498 - Seeking after playback ended</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=465498">Mozilla Bug 465498</a>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function startTest(e) {
+ var v = e.target;
+ info(v._name + " loadedmetadata");
+ e.target.play();
+}
+
+function playbackEnded(e) {
+ var v = e.target;
+ info(v._name + " ended");
+ if (v._finished)
+ return;
+ ok(v.currentTime >= v.duration - 0.1 && v.currentTime <= v.duration + 0.1,
+ "Checking currentTime at end: " + v.currentTime + " for " + v._name);
+ ok(v.ended, "Checking playback has ended for " + v._name);
+ v.pause();
+ v.currentTime = 0;
+ ok(!v.ended, "Checking ended is no longer true for " + v._name);
+ v._seeked = true;
+}
+
+function seekEnded(e) {
+ var v = e.target;
+ info(v._name + " seeked");
+ if (v._finished)
+ return;
+ ok(v.currentTime == 0, "Checking currentTime after seek: " +
+ v.currentTime + " for " + v._name);
+ ok(!v.ended, "Checking ended is false for " + v._name);
+ v._finished = true;
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+}
+
+function seeking(e) {
+ var v = e.target;
+ info(v._name + " seeking");
+}
+
+function initTest(test, token) {
+ var type = getMajorMimeType(test.type);
+ var v = document.createElement(type);
+ if (!v.canPlayType(test.type))
+ return;
+ v.preload = "metadata";
+ v.token = token;
+ manager.started(token);
+ v._name = test.name;
+
+ var s = document.createElement("source");
+ s.type = test.type;
+ s.src = test.name;
+ v.appendChild(s);
+
+ v._seeked = false;
+ v._finished = false;
+ v.addEventListener("loadedmetadata", startTest, false);
+ v.addEventListener("ended", playbackEnded, false);
+ v.addEventListener("seeked", seekEnded, false);
+ v.addEventListener("seeking", seeking, false);
+ document.body.appendChild(v);
+}
+
+manager.runTests(gSmallTests, initTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_bug495145.html b/dom/media/test/test_bug495145.html
new file mode 100644
index 000000000..ea7007ce8
--- /dev/null
+++ b/dom/media/test/test_bug495145.html
@@ -0,0 +1,99 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=495145
+-->
+
+<head>
+ <title>Bug 495145 - pausing while ended shouldn't cause problems</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=495145">Mozilla Bug 495145</a>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+//longer timeout for slow platforms
+if (isSlowPlatform()) {
+ SimpleTest.requestLongerTimeout(1.5);
+}
+
+var manager = new MediaTestManager;
+
+function start(e) {
+ e.target.play();
+}
+
+function ended1(e) {
+ var v = e.target;
+ if (v._finished)
+ return;
+
+ ++v._endCount;
+ if (v._endCount == 2) {
+ ok(true, "Playing after pause while ended works for " + v._name);
+ v._finished = true;
+ v.removeEventListener("loadedmetadata", start, false);
+ v.removeEventListener("ended", ended1, false);
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+ return;
+ }
+
+ v.pause();
+ v.play();
+}
+
+function ended2(e) {
+ var v = e.target;
+ if (v._finished)
+ return;
+
+ v.pause();
+ v.currentTime = 0;
+}
+
+function seeked2(e) {
+ var v = e.target;
+ if (v._finished)
+ return;
+
+ ok(v.paused, "Paused after seek after pause while ended for " + v._name);
+ v._finished = true;
+ v.removeEventListener("loadedmetadata", start, false);
+ v.removeEventListener("ended", ended2, false);
+ v.removeEventListener("seeked", seeked2, false);
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+}
+
+function createVideo(test, x, token) {
+ var v = document.createElement('video');
+ v.preload = "metadata";
+ v.token = token;
+ manager.started(token);
+ v.src = test.name;
+ v._name = test.name + "#" + x;
+ v._endCount = 0;
+ v._finished = false;
+ v.addEventListener("loadedmetadata", start, false);
+ v.addEventListener("ended", x == 1 ? ended1 : ended2, false);
+ if (x == 2)
+ v.addEventListener("seeked", seeked2, false);
+ document.body.appendChild(v);
+}
+
+function startTest(test, token) {
+ createVideo(test, 1, token + "a");
+ createVideo(test, 2, token + "b");
+}
+
+manager.runTests(gSmallTests, startTest);
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_bug495300.html b/dom/media/test/test_bug495300.html
new file mode 100644
index 000000000..49a23c214
--- /dev/null
+++ b/dom/media/test/test_bug495300.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=495300
+-->
+
+<head>
+ <title>Bug 495300 - seeking to the end should behave as "ended"</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=495300">Mozilla Bug 495300</a>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function filename(uri) {
+ return uri.substr(uri.lastIndexOf("/")+1);
+}
+
+function mediaEnded(event) {
+ ok(true, "Got expected 'ended' event: " + filename(event.target.currentSrc));
+
+ if (event.target._expectedDuration)
+ ok(Math.abs(event.target.currentTime - event.target._expectedDuration) < 0.1,
+ "currentTime equals duration: " + filename(event.target.currentSrc));
+
+ event.target.removeEventListener("ended", mediaEnded, false);
+ manager.finished(event.target.token);
+ removeNodeAndSource(event.target);
+}
+
+function mediaLoadedmetadata(event) {
+ event.target.currentTime = event.target.duration;
+ event.target.removeEventListener("loadedmetadata", mediaLoadedmetadata, false);
+}
+
+function startTest(test, token) {
+ var elemType = /^audio/.test(test.type) ? "audio" : "video";
+ var v1 = document.createElement(elemType);
+ v1.preload = "auto";
+
+ v1.src = test.name;
+ if (test.duration) {
+ v1._expectedDuration = test.duration;
+ }
+ v1.addEventListener("loadedmetadata", mediaLoadedmetadata, false);
+ v1.addEventListener("ended", mediaEnded, false);
+ v1.load();
+
+ v1.token = token;
+ manager.started(token);
+}
+
+manager.runTests(gSeekTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_bug654550.html b/dom/media/test/test_bug654550.html
new file mode 100644
index 000000000..07922874d
--- /dev/null
+++ b/dom/media/test/test_bug654550.html
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=654550
+-->
+
+<head>
+ <title>Test for Bug 654550</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=654550">Mozilla Bug 654550</a>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+ /* Test for Bug 654550 */
+
+ // Parallel test must be disabled for media.video_stats.enabled is a global setting
+ // to prevent the setting from changing unexpectedly in the middle of the test.
+ PARALLEL_TESTS = 1;
+ SimpleTest.waitForExplicitFinish();
+ var manager = new MediaTestManager;
+
+ function checkStats(v, aShouldBeEnabled) {
+ if (aShouldBeEnabled) {
+ ok(v.mozParsedFrames != 0,
+ "At least one value should be different from 0 if stats are enabled");
+ } else {
+ ok(!v.mozParsedFrames,
+ "mozParsedFrames should be 0 if stats are disabled");
+ ok(!v.mozDecodedFrames,
+ "mozDecodedFrames should be 0 if stats are disabled");
+ ok(!v.mozPresentedFrames,
+ "mozPresentedFrames should be 0 if stats are disabled");
+ ok(!v.mozPaintedFrames,
+ "mozPaintedFrames should be 0 if stats are disabled");
+ }
+
+ }
+
+ function ontimeupdate_statsEnabled(event) {
+ var v = event.target;
+ v.removeEventListener('timeupdate', ontimeupdate_statsEnabled, false);
+ checkStats(v, true);
+ SpecialPowers.popPrefEnv(
+ function() {
+ v.addEventListener("timeupdate", ontimeupdate_statsDisabled);
+ });
+ }
+
+ function ontimeupdate_statsDisabled(event) {
+ var v = event.target;
+ v.removeEventListener('timeupdate', ontimeupdate_statsDisabled, false);
+ checkStats(v, false);
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+ }
+
+ function startTest(test, token) {
+ var v = document.createElement('video');
+ v.token = token;
+ v.src = test.name;
+ // playback may reach the end before pref is changed for the duration is short
+ // set 'loop' to true to keep playing so that we won't miss 'timeupdate' events
+ v.loop = true;
+ manager.started(token);
+ SpecialPowers.pushPrefEnv({"set": [["media.video_stats.enabled", true]]},
+ function() {
+ v.play();
+ v.addEventListener("timeupdate", ontimeupdate_statsEnabled);
+ });
+ }
+
+ SpecialPowers.pushPrefEnv({"set": [["media.video_stats.enabled", false]]},
+ function() {
+ manager.runTests(gVideoTests, startTest);
+ });
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_bug686942.html b/dom/media/test/test_bug686942.html
new file mode 100644
index 000000000..2f67dfa6e
--- /dev/null
+++ b/dom/media/test/test_bug686942.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=686942
+-->
+
+<head>
+ <title>Test for Bug 448534</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=686942">Mozilla Bug 686942</a>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+if (navigator.platform.startsWith("Win")) {
+ SimpleTest.expectAssertions(0, 2);
+}
+
+var manager = new MediaTestManager;
+
+function onloaded(event) {
+ var v = event.target;
+ v.removeEventListener("loadedmetadata", onloaded);
+ v.currentTime = v.duration;
+ return;
+}
+
+function checkNotPlaying(v) {
+ ok(v.currentTime == 0, "Should not be playing after seek to end and back to beginning");
+ v._finished = true;
+ manager.finished(v.token);
+ removeNodeAndSource(v);
+}
+
+function onseeked(event) {
+ var v = event.target;
+ v.removeEventListener("seeked", onseeked);
+ setTimeout(function() { checkNotPlaying(v); }, 500);
+}
+
+function onended(event) {
+ var v = event.target;
+ v.removeEventListener("ended", onended);
+ if (v._finished)
+ return;
+ v.addEventListener("seeked", onseeked, false);
+ v.currentTime = 0;
+}
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ v.preload = "auto";
+ v.token = token;
+ manager.started(token);
+ v.src = test.name;
+ v._played = false;
+ v._finished = false;
+ v.addEventListener("loadedmetadata", onloaded, false);
+ v.addEventListener("ended", onended, false);
+
+ document.body.appendChild(v);
+}
+
+manager.runTests(gSmallTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_bug726904.html b/dom/media/test/test_bug726904.html
new file mode 100644
index 000000000..7c319bbc7
--- /dev/null
+++ b/dom/media/test/test_bug726904.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=726904
+-->
+
+<head>
+ <title>Media test: default video size</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body onload="bodyLoaded();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=726904">Mozilla Bug 726904</a>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var v1 = document.createElement("video"),
+ v2 = document.createElement("video"),
+ poster = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQCAAAAACl1GkQAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAALJJREFUeNrtwQENAAAAwqD3T20ON6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHg0cq4AATRk8BYAAAAASUVORK5CYII",
+ resource = getPlayableVideo(gSmallTests);
+
+function bodyLoaded(){
+ // Note: For DASH, width and height would vary once the video started playing, so
+ // the values would not correlate with those in manifest.js. Since this test has
+ // no playing, this should not affect the result.
+ is(v1.videoWidth, resource.width, "Intrinsic width should match video width");
+ is(v1.videoHeight, resource.height, "Intrinsic height should match video height");
+ is(v2.clientWidth, 400, "clientWidth should be 400");
+ is(v2.clientHeight, 400, "clientHeight should be 400");
+ SimpleTest.finish();
+}
+
+if (resource) {
+ v1.poster = v2.poster = poster;
+
+ v1.src = v2.src = "http://mochi.test:8888/tests/dom/media/test/" + resource.name;
+
+ v1.preload = "auto";
+ v2.preload = "none";
+
+ v1.muted = v2.muted = true;
+
+ document.body.appendChild(v1);
+ document.body.appendChild(v2);
+} else {
+ todo(false, "No types supported");
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_bug874897.html b/dom/media/test/test_bug874897.html
new file mode 100644
index 000000000..f22bb89e4
--- /dev/null
+++ b/dom/media/test/test_bug874897.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=874897
+-->
+
+<head>
+ <title>Test for Bug 874897</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function loadeddata(e) {
+ var v = e.target;
+ ok(v.readyState >= v.HAVE_CURRENT_DATA,
+ "readyState must be >= HAVE_CURRENT_DATA for " + v._name);
+
+ var canvas = document.createElement("canvas");
+ canvas.width = 210;
+ canvas.height = 120;
+ document.body.appendChild(canvas);
+ var ctx = canvas.getContext("2d");
+ try {
+ ctx.drawImage(v, 0, 0, v.videoWidth, v.videoHeight, 0, 0, canvas.width, canvas.height);
+ ok(true, "Shouldn't throw exception while drawing to canvas from video for " + v._name);
+ } catch (ex) {
+ ok(false, "Shouldn't throw exception while drawing to canvas from video for " + v._name);
+ }
+
+ v._finished = true;
+ v.parentNode.removeChild(v);
+ manager.finished(v.token);
+}
+
+function startTest(test, token) {
+ var type = getMajorMimeType(test.type);
+ if (type != "video")
+ return;
+
+ var v = document.createElement('video');
+ v.token = token;
+ manager.started(token);
+ v.src = test.name;
+ v._name = test.name;
+ v._finished = false;
+ v.autoplay = true;
+ v.style.display = "none";
+ v.addEventListener("loadeddata", loadeddata, false);
+ document.body.appendChild(v);
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [["media.cache_size", 40000]]}, beginTest);
+function beginTest() {
+ manager.runTests(gAspectRatioTests, startTest);
+}
+
+</script>
+</pre>
+
+</body>
+</html>
diff --git a/dom/media/test/test_bug879717.html b/dom/media/test/test_bug879717.html
new file mode 100644
index 000000000..37c9a402a
--- /dev/null
+++ b/dom/media/test/test_bug879717.html
@@ -0,0 +1,134 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for bug 879717, check that a video element can be drawn into a canvas at various states of playback</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+//longer timeout for slow platforms
+if (isSlowPlatform()) {
+ SimpleTest.requestLongerTimeout(1.5);
+}
+
+var manager = new MediaTestManager;
+
+var canvas = document.createElement('canvas');
+document.body.appendChild(canvas);
+
+var checkDrawImage = function(eventName, videoElement) {
+ var exception = null;
+ var exceptionName = "nothing";
+ try {
+ var ctx = canvas.getContext('2d');
+ ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
+ } catch (e) {
+ exception = e;
+ exceptionName = e.name;
+ }
+ ok(exception === null,
+ "drawImage shouldn't throw an exception on " + eventName +
+ " of " + videoElement.testName + ", got " + exceptionName);
+};
+
+var checkDrawImageEventHandler = function(ev) {
+ checkDrawImage(ev.type, ev.target);
+};
+var startTest = function(media, token) {
+ manager.started(token);
+
+ // File playback
+ var v1 = document.createElement("video");
+ v1.autoplay = true;
+
+ // Captured file playback
+ var v2 = document.createElement("video");
+
+ // Stream playback
+ var v3 = document.createElement("video");
+ v3.autoplay = true;
+
+ v1.gotLoadeddata = false;
+ v2.gotLoadeddata = false;
+ v3.gotLoadeddata = false;
+
+ v1.testName = "v1 (" + media.name + ")";
+ v2.testName = "v2 (Captured " + media.name + ")";
+ v3.testName = "v3 (Stream of " + media.name + ")";
+
+ checkDrawImage("beforeplay", v1);
+ checkDrawImage("beforeplay", v2);
+ checkDrawImage("beforeplay", v3);
+
+ v1.onloadedmetadata = checkDrawImageEventHandler;
+ v2.onloadedmetadata = checkDrawImageEventHandler;
+ v3.onloadedmetadata = checkDrawImageEventHandler;
+
+ v1.onplay = checkDrawImageEventHandler;
+ v2.onplay = checkDrawImageEventHandler;
+ v3.onplay = checkDrawImageEventHandler;
+
+ function onplaying(ev) {
+ if (!ev.target.gotPlaying) {
+ ev.target.gotPlaying = true;
+ checkDrawImageEventHandler(ev);
+ }
+ }
+ v1.onplaying = onplaying;
+ v2.onplaying = onplaying;
+ v3.onplaying = onplaying;
+
+ var onloadeddata = function(ev) {
+ ev.target.gotLoadeddata = true;
+ checkDrawImageEventHandler(ev);
+ };
+
+ v1.onloadeddata = onloadeddata;
+ v2.onloadeddata = onloadeddata;
+ v3.onloadeddata = onloadeddata;
+
+ var checkFinished = function() {
+ if (!v1.testFinished || !v2.testFinished || !v3.testFinished) {
+ return;
+ }
+
+ ok(v1.gotLoadeddata, v1.testName + " should have gotten the 'loadeddata' event callback");
+ ok(v2.gotLoadeddata, v2.testName + " should have gotten the 'loadeddata' event callback");
+ ok(v3.gotLoadeddata, v3.testName + " should have gotten the 'loadeddata' event callback");
+
+ manager.finished(token);
+ };
+
+ var onended = function(ev) {
+ checkDrawImageEventHandler(ev);
+ removeNodeAndSource(ev.target);
+ ev.target.testFinished = true;
+ checkFinished();
+ };
+
+ v1.onended = onended;
+ v2.onended = onended;
+ v3.onended = onended;
+
+ document.body.appendChild(v1);
+ document.body.appendChild(v2);
+ document.body.appendChild(v3);
+
+ v1.src = media.name;
+ v2.src = media.name;
+ v2.preload = 'metadata';
+
+ v2.addEventListener('loadedmetadata', function () {
+ v3.srcObject = v2.mozCaptureStreamUntilEnded();
+ v2.play();
+ });
+}
+
+manager.runTests(getPlayableVideos(gSmallTests), startTest);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_bug883173.html b/dom/media/test/test_bug883173.html
new file mode 100644
index 000000000..4ccd9c0bd
--- /dev/null
+++ b/dom/media/test/test_bug883173.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=883173
+-->
+<head>
+ <meta charset='utf-8'>
+ <title>Test for Bug 883173 - TextTrackCue(List) Sorting</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var video = document.createElement("video");
+video.src = "seek.webm";
+video.preload = "metadata";
+
+var trackElement = document.createElement("track");
+trackElement.src = "bug883173.vtt";
+trackElement.kind = "subtitles";
+
+document.getElementById("content").appendChild(video);
+video.appendChild(trackElement);
+video.addEventListener("loadedmetadata",
+ function run_tests() {
+ // Re-queue run_tests() at the end of the event loop until the track
+ // element has loaded its data.
+ if (trackElement.readyState == 1) {
+ setTimeout(run_tests, 0);
+ return;
+ }
+ is(trackElement.readyState, 2, "Track::ReadyState should be set to LOADED.");
+
+ // Set mode to hidden so that the active cue lists are being updated.
+ trackElement.track.mode = "hidden";
+
+ var expected = [[1, 3], [1, 2], [2, 4], [2, 3], [3, 4]];
+ var cueList = trackElement.track.cues;
+ is(cueList.length, expected.length, "Cue list length should be 5.");
+
+ for (var i = 0; i < expected.length; i++) {
+ is(cueList[i].startTime, expected[i][0], "Cue's start time should be " + expected[i][0]);
+ is(cueList[i].endTime, expected[i][1], "Cue's end time should be " + expected[i][1]);
+ }
+
+ SimpleTest.finish();
+ }
+);
+</script>
+</pre>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/media/test/test_bug895091.html b/dom/media/test/test_bug895091.html
new file mode 100644
index 000000000..ae370ac59
--- /dev/null
+++ b/dom/media/test/test_bug895091.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=895091
+-->
+<head>
+ <meta charset='utf-8'>
+ <title>Test for Bug 895091 - Integrating vtt.js</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var video = document.createElement("video");
+video.src = "seek.webm";
+video.preload = "metadata";
+
+var trackElement = document.createElement("track");
+trackElement.src = "long.vtt";
+trackElement.kind = "subtitles";
+
+var trackElementTwo = document.createElement("track");
+trackElementTwo.src = "long.vtt";
+trackElementTwo.kind = "subtitles";
+
+document.getElementById("content").appendChild(video);
+video.appendChild(trackElement);
+video.appendChild(trackElementTwo);
+
+video.addEventListener("loadedmetadata", function run_tests() {
+ // Re-que run_tests() at the end of the event loop until the track
+ // element has loaded its data.
+ if (trackElement.readyState == 1 || trackElementTwo.readyState == 1) {
+ setTimeout(run_tests, 0);
+ return;
+ }
+
+ // Set mode to hidden so that the active cue lists are being updated.
+ trackElement.track.mode = "hidden";
+ trackElementTwo.track.mode = "hidden";
+
+ is(trackElement.readyState, 2, "Track::ReadyState should be set to LOADED.");
+ is(trackElementTwo.readyState, 2, "Track::ReadyState should be set to LOADED.");
+
+ is(trackElement.track.cues.length, 2000, "Cue list length should be 2000.");
+ is(trackElementTwo.track.cues.length, 2000, "Cue list length should be 2000.");
+
+ SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_bug895305.html b/dom/media/test/test_bug895305.html
new file mode 100644
index 000000000..2b1b55c3f
--- /dev/null
+++ b/dom/media/test/test_bug895305.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=895305
+https://bugzilla.mozilla.org/show_bug.cgi?id=905320
+-->
+<head>
+ <meta charset='utf-8'>
+ <title>Regression test for bug 895305 and 905320 - TextTrack* leaks</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var audio = document.createElement("audio");
+
+// Check leaking on TextTrackList objects.
+window.ttl = audio.textTracks;
+ttl.addEventListener("click", function(){}, false);
+
+// Check leaking on VTTCue objects.
+window.ttc = new VTTCue(3, 4, "Test.");
+ttc.addEventListener("click", function() {}, false);
+
+// Check leaking on TextTrack objects.
+audio.addTextTrack("subtitles", "label", "en-CA");
+ttl[0].addEventListener("click", function() {}, false);
+
+ok(true); // Need to have at least one assertion for Mochitest to be happy.
+SimpleTest.finish();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_bug919265.html b/dom/media/test/test_bug919265.html
new file mode 100644
index 000000000..3ebdd37eb
--- /dev/null
+++ b/dom/media/test/test_bug919265.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=919265
+-->
+<head>
+ <meta charset='utf-8'>
+ <title>Regression test for bug 919265 - Leak on VTTCue::GetCueAsHTML()</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+// We shouldn't leak upon shutdown.
+(new VTTCue(0, 0, "")).getCueAsHTML();
+
+// We need to assert something for Mochitest to be happy.
+ok(true);
+SimpleTest.finish();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_bug957847.html b/dom/media/test/test_bug957847.html
new file mode 100644
index 000000000..b0ab59531
--- /dev/null
+++ b/dom/media/test/test_bug957847.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=957847
+-->
+<head>
+ <meta charset='utf-8'>
+ <title>Regression test for bug 957847 - Crash on TextTrack::AddCue </title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var trackElement = document.createElement('track');
+trackElement.track.addCue(new VTTCue(0, 1, "A"));
+
+// We need to assert something for Mochitest to be happy.
+ok(true);
+SimpleTest.finish();
+</script>
+</pre>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/media/test/test_can_play_type.html b/dom/media/test/test_can_play_type.html
new file mode 100644
index 000000000..2deae49f1
--- /dev/null
+++ b/dom/media/test/test_can_play_type.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=469247
+-->
+<head>
+ <title>Test for Bug 469247</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=469247">Mozill
+a Bug 469247</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<video id="v"></video>
+
+<pre id="test">
+<script type="application/javascript">
+
+var v = document.getElementById('v');
+
+function check(type, expected) {
+ is(v.canPlayType(type), expected, type);
+}
+
+// Invalid types
+check("foo/bar", "");
+check("", "");
+check("!!!", "");
+
+mediaTestCleanup();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_can_play_type_mpeg.html b/dom/media/test/test_can_play_type_mpeg.html
new file mode 100644
index 000000000..89e5fabef
--- /dev/null
+++ b/dom/media/test/test_can_play_type_mpeg.html
@@ -0,0 +1,167 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=799315
+-->
+<head>
+ <title>Test for MP4 and MP3 support</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<video id="v"></video>
+
+<pre id="test">
+<script>
+
+function check_mp4(v, enabled) {
+ function check(type, expected) {
+ var ex = enabled ? expected : "";
+ is(v.canPlayType(type), ex, type + "='" + ex + "'");
+ }
+
+ check("video/mp4", "maybe");
+ check("video/x-m4v", "maybe");
+ check("audio/mp4", "maybe");
+ check("audio/x-m4a", "maybe");
+
+ // Not the MIME type that other browsers respond to, so we won't either.
+ check("audio/m4a", "");
+ check("video/m4v", "");
+
+ check("audio/aac", "maybe");
+ check("audio/aacp", "maybe");
+
+ // H.264 Constrained Baseline Profile Level 3.0, AAC-LC
+ check("video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\"", "probably");
+
+ // H.264 Constrained Baseline Profile Level 3.0, mp3
+ check("video/mp4; codecs=\"avc1.42E01E, mp3\"", "probably");
+
+ check("video/mp4; codecs=\"avc1.42001E, mp4a.40.2\"", "probably");
+ check("video/mp4; codecs=\"avc1.58A01E, mp4a.40.2\"", "probably");
+
+ // H.264 Main Profile Level 3.0, AAC-LC
+ check("video/mp4; codecs=\"avc1.4D401E, mp4a.40.2\"", "probably");
+ // H.264 Main Profile Level 3.1, AAC-LC
+ check("video/mp4; codecs=\"avc1.4D401F, mp4a.40.2\"", "probably");
+ // H.264 Main Profile Level 4.0, AAC-LC
+ check("video/mp4; codecs=\"avc1.4D4028, mp4a.40.2\"", "probably");
+ // H.264 High Profile Level 3.0, AAC-LC
+ check("video/mp4; codecs=\"avc1.64001E, mp4a.40.2\"", "probably");
+ // H.264 High Profile Level 3.1, AAC-LC
+ check("video/mp4; codecs=\"avc1.64001F, mp4a.40.2\"", "probably");
+
+ check("video/mp4; codecs=\"avc1.42E01E\"", "probably");
+ check("video/mp4; codecs=\"avc1.42001E\"", "probably");
+ check("video/mp4; codecs=\"avc1.58A01E\"", "probably");
+ check("video/mp4; codecs=\"avc1.4D401E\"", "probably");
+ check("video/mp4; codecs=\"avc1.64001F\"", "probably");
+
+ // AAC-LC
+ check("audio/mp4; codecs=\"mp4a.40.2\"", "probably");
+ check("audio/mp4; codecs=mp4a.40.2", "probably");
+ check("audio/x-m4a; codecs=\"mp4a.40.2\"", "probably");
+ check("audio/x-m4a; codecs=mp4a.40.2", "probably");
+
+ check("audio/mp4; codecs=\"mp4a.40.2,\"", ""); // Invalid codecs string
+
+ // HE-AAC v1
+ check("audio/mp4; codecs=\"mp4a.40.5\"", "probably");
+ check("audio/mp4; codecs=mp4a.40.5", "probably");
+ check("audio/x-m4a; codecs=\"mp4a.40.5\"", "probably");
+ check("audio/x-m4a; codecs=mp4a.40.5", "probably");
+ // HE-AAC v2
+ check("audio/mp4; codecs=\"mp4a.40.29\"", "probably");
+
+ // Opus
+ check("audio/mp4; codecs=\"opus\"", "probably");
+ check("audio/mp4; codecs=opus", "probably");
+
+ // Flac.
+ // Not available on Android yet.
+ var expectedResult = IsSupportedAndroid() ? "" : "probably";
+ check("audio/mp4; codecs=\"flac\"", expectedResult);
+ check("audio/mp4; codecs=flac", expectedResult);
+}
+
+function check_mp3(v, enabled) {
+ function check(type, expected) {
+ var ex = enabled ? expected : "";
+ is(v.canPlayType(type), ex, type + "='" + ex + "'");
+ }
+
+ check("audio/mpeg", "maybe");
+ check("audio/mp3", "maybe");
+
+ check("audio/mpeg; codecs=\"mp3\"", "probably");
+ check("audio/mpeg; codecs=mp3", "probably");
+
+ check("audio/mp3; codecs=\"mp3\"", "probably");
+ check("audio/mp3; codecs=mp3", "probably");
+}
+
+function IsWindowsVistaOrLater() {
+ var re = /Windows NT (\d+\.\d)/;
+ var winver = navigator.userAgent.match(re);
+ return winver && winver.length == 2 && parseFloat(winver[1]) >= 6.0;
+}
+
+function IsMacOSSnowLeopardOrLater() {
+ var re = /Mac OS X (\d+)\.(\d+)/;
+ var ver = navigator.userAgent.match(re);
+ if (!ver || ver.length != 3) {
+ return false;
+ }
+ var major = ver[1] | 0;
+ var minor = ver[2] | 0;
+ return major == 10 && minor >= 6;
+}
+
+function IsLinux() {
+ return navigator.userAgent.indexOf("Linux") != -1;
+}
+
+function getPref(name) {
+ var pref = false;
+ try {
+ pref = SpecialPowers.getBoolPref(name);
+ } catch(ex) { }
+ return pref;
+}
+
+function IsSupportedAndroid() {
+ return getAndroidVersion() >= 14;
+}
+
+function IsJellyBeanOrLater() {
+ return getAndroidVersion() >= 16;
+}
+
+var haveMp4 = (getPref("media.wmf.enabled") && IsWindowsVistaOrLater()) ||
+ IsMacOSSnowLeopardOrLater() ||
+ (IsSupportedAndroid() &&
+ (IsJellyBeanOrLater() || getPref("media.plugins.enabled"))) ||
+ (IsLinux() && getPref("media.ffmpeg.enabled"));
+
+check_mp4(document.getElementById('v'), haveMp4);
+
+var haveMp3 = getPref("media.directshow.enabled") ||
+ (getPref("media.wmf.enabled") && IsWindowsVistaOrLater()) ||
+ (IsLinux() && getPref("media.ffmpeg.enabled")) ||
+ (IsSupportedAndroid() &&
+ ((IsJellyBeanOrLater() && getPref("media.android-media-codec.enabled")) ||
+ getPref("media.plugins.enabled"))) ||
+ getPref("media.apple.mp3.enabled");
+check_mp3(document.getElementById('v'), haveMp3);
+
+mediaTestCleanup();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_can_play_type_no_ogg.html b/dom/media/test/test_can_play_type_no_ogg.html
new file mode 100644
index 000000000..03f336b8d
--- /dev/null
+++ b/dom/media/test/test_can_play_type_no_ogg.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=469247
+-->
+<head>
+ <title>Test for Bug 469247: Ogg backend disabled</title>
+ <script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=469247">Mozill
+a Bug 469247</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<video id="v"></video>
+
+<pre id="test">
+<script src="can_play_type_ogg.js"></script>
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+function finish() {
+ mediaTestCleanup();
+ SimpleTest.finish();
+}
+
+SpecialPowers.pushPrefEnv({"set": [["media.ogg.enabled", false]]},
+ function() {
+ check_ogg(document.getElementById('v'), false, finish);
+ }
+);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_can_play_type_ogg.html b/dom/media/test/test_can_play_type_ogg.html
new file mode 100644
index 000000000..9a3359322
--- /dev/null
+++ b/dom/media/test/test_can_play_type_ogg.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=469247
+-->
+<head>
+ <title>Test for Bug 469247: Ogg backend</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=469247">Mozill
+a Bug 469247</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<video id="v"></video>
+
+<pre id="test">
+<script src="can_play_type_ogg.js"></script>
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+function finish() {
+ mediaTestCleanup();
+ SimpleTest.finish();
+}
+
+check_ogg(document.getElementById('v'), true, finish);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_can_play_type_wave.html b/dom/media/test/test_can_play_type_wave.html
new file mode 100644
index 000000000..95b6fa429
--- /dev/null
+++ b/dom/media/test/test_can_play_type_wave.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=469247
+-->
+<head>
+ <title>Test for Bug 469247: WAVE backend</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=469247">Mozill
+a Bug 469247</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<video id="v"></video>
+
+<pre id="test">
+<script src="can_play_type_wave.js"></script>
+<script>
+check_wave(document.getElementById('v'), true);
+
+mediaTestCleanup();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_can_play_type_webm.html b/dom/media/test/test_can_play_type_webm.html
new file mode 100644
index 000000000..8763d4f04
--- /dev/null
+++ b/dom/media/test/test_can_play_type_webm.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=566245
+-->
+<head>
+ <title>Test for Bug 566245: WebM backend</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=566245">Mozill
+a Bug 566245</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+
+<video id="v"></video>
+
+<pre id="test">
+<script src="can_play_type_webm.js"></script>
+<script>
+check_webm(document.getElementById('v'), true);
+mediaTestCleanup();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_chaining.html b/dom/media/test/test_chaining.html
new file mode 100644
index 000000000..8e74393b7
--- /dev/null
+++ b/dom/media/test/test_chaining.html
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: chained ogg files.</title>
+ <meta charset='utf-8'>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function finish_test(element) {
+ removeNodeAndSource(element);
+ manager.finished(element.token);
+}
+
+function onended(e) {
+ var t = e.target;
+ is(t._metadataCount, t._links, "We should have received "+ t._links +
+ " metadataloaded event. " + t.src);
+
+ // If we encounter a file that has links with a different numbers of channel,
+ // we stop the decoding at the end of the first link. Hence, we report normal
+ // |seekable| and |buffered| values.
+ if (t._links != 1) {
+ is(t.seekable.length, 0, "No seekable ranges should be reported." + t.src);
+ is(t.buffered.length, 0, "No buffered region should be reported." + t.src);
+ }
+
+ is(t.played.length, 1, "The played region should be continuous." + t.src);
+
+ if (t._links != 1) {
+ var oldCurrentTime = t.currentTime;
+ t.currentTime = 0.0;
+ is(t.currentTime, oldCurrentTime,
+ "Seeking should be disabled when playing chained media." + t.src);
+ }
+
+ finish_test(t);
+}
+
+function onmetadataloaded(e) {
+ var t = e.target;
+ if (! t._metadataCount) {
+ t._metadataCount = 0;
+ }
+
+ if (t._metadataCount > 1 && t._links === 1) {
+ ok(false, "We should receive only one \"loadedmetadata\" event for a chained file we don't support.")
+ }
+
+ // We should be able to assert equality here, but somehow it fails (rarely but
+ // still) on try. Instead, we give it a little slack and assert that the index
+ // increases monotonically.
+ ok(t.mozGetMetadata().index >= t._metadataCount || t._links === 1,
+ "The metadata index value should increase." + t.src);
+
+ // The files have all a user comment name 'index' that increments at each link
+ // in the chained media.
+ t._metadataCount++;
+ if (!t.playing && !t.ended) {
+ t.play();
+ }
+}
+
+function startTest(test, token) {
+ var elemType = /^audio/.test(test.type) ? "audio" : "video";
+ var element = document.createElement(elemType);
+ document.body.appendChild(element);
+ manager.started(token);
+ element._links= test.links;
+ element.src = test.name;
+ element.token = token;
+ element.controls = true;
+ element.addEventListener("loadedmetadata", onmetadataloaded);
+ element.addEventListener("ended", onended);
+ element.preload = "metadata";
+}
+
+manager.runTests(gChainingTests, startTest);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_clone_media_element.html b/dom/media/test/test_clone_media_element.html
new file mode 100644
index 000000000..cfd8388da
--- /dev/null
+++ b/dom/media/test/test_clone_media_element.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test: cloned media element should continue to play to the end even after the source of the original element is cleared</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// tests must run in sequence otherwise concurrent running test will also
+// update media cache which will hide the fact media cache not updated
+// after changes in media cache streams.
+PARALLEL_TESTS = 1;
+
+function startTest(test, token) {
+ manager.started(token);
+ info("Trying to load " + token);
+ var v = document.createElement('video');
+ v.preload = "metadata";
+ v.token = token;
+ v.src = test.name;
+
+ v.onloadedmetadata = function(evt) {
+ info(evt.target.token + " metadata loaded.");
+ evt.target.onloadedmetadata = null;
+ var clone = evt.target.cloneNode(false);
+ clone.token = evt.target.token;
+ clone.play();
+
+ clone.onloadstart = function(evt) {
+ info("cloned " + evt.target.token + " start loading.");
+ evt.target.onloadstart = null;
+ removeNodeAndSource(v);
+ }
+
+ clone.onended = function(evt) {
+ ok(true, "cloned " + evt.target.token + " ended.");
+ evt.target.onended = null;
+ removeNodeAndSource(evt.target);
+ manager.finished(evt.target.token);
+ }
+ }
+}
+
+var manager = new MediaTestManager;
+manager.runTests(gSmallTests.concat(gPlayedTests), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_closing_connections.html b/dom/media/test/test_closing_connections.html
new file mode 100644
index 000000000..177f54da9
--- /dev/null
+++ b/dom/media/test/test_closing_connections.html
@@ -0,0 +1,58 @@
+hg diff<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=479863
+-->
+<head>
+ <title>Test for Bug 479863 --- loading many connections</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript" src="use_large_cache.js"></script>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=479863">Mozilla Bug 479863</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+
+<script type="application/javascript">
+window.onload = function() {
+ ok(true, "loaded metadata for all videos");
+ mediaTestCleanup();
+ SimpleTest.finish();
+}
+
+/* With normal per-domain connection limits and a naive implementation, we
+ won't ever be able to load all these videos because the first 15 (or whatever)
+ will each take up one HTTP connection (which will be suspended) and then
+ the others will be blocked by the per-domain HTTP connection limit. We
+ pass this test by closing the connection for non-buffered videos after
+ we've got the first frame.
+*/
+
+var resource = getPlayableVideo(gClosingConnectionsTest);
+
+SimpleTest.waitForExplicitFinish();
+function beginTest() {
+ if (resource != null) {
+ for (var i=0; i<20; ++i) {
+ var v = document.createElement("video");
+ v.src = resource.name;
+ v.preload = "metadata";
+ document.body.appendChild(v);
+ }
+ } else {
+ todo(false, "No types supported");
+ }
+}
+beginTest();
+</script>
+
+<pre id="test">
+<script type="application/javascript">
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_constants.html b/dom/media/test/test_constants.html
new file mode 100644
index 000000000..644088b82
--- /dev/null
+++ b/dom/media/test/test_constants.html
@@ -0,0 +1,228 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+ Adapted from:
+ http://simon.html5.org/test/html/dom/interfaces/htmlelement/htmlmediaelement/const-unsigned-short/001.htm
+-->
+<head>
+ <title>Media test: constants</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<video><source></video><audio><source></audio>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+is(HTMLElement.NETWORK_EMPTY, undefined);
+is(HTMLElement.NETWORK_IDLE, undefined);
+is(HTMLElement.NETWORK_LOADING, undefined);
+is(HTMLElement.NETWORK_NO_SOURCE, undefined);
+is(HTMLElement.HAVE_NOTHING, undefined);
+is(HTMLElement.HAVE_METADATA, undefined);
+is(HTMLElement.HAVE_CURRENT_DATA, undefined);
+is(HTMLElement.HAVE_FUTURE_DATA, undefined);
+is(HTMLElement.HAVE_ENOUGH_DATA, undefined);
+is(HTMLElement.MEDIA_ERR_ABORTED, undefined);
+is(HTMLElement.MEDIA_ERR_NETWORK, undefined);
+is(HTMLElement.MEDIA_ERR_DECODE, undefined);
+is(HTMLElement.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined);
+is(HTMLMediaElement.NETWORK_EMPTY, 0);
+is(HTMLMediaElement.NETWORK_IDLE, 1);
+is(HTMLMediaElement.NETWORK_LOADING, 2);
+is(HTMLMediaElement.NETWORK_NO_SOURCE, 3);
+is(HTMLMediaElement.HAVE_NOTHING, 0);
+is(HTMLMediaElement.HAVE_METADATA, 1);
+is(HTMLMediaElement.HAVE_CURRENT_DATA, 2);
+is(HTMLMediaElement.HAVE_FUTURE_DATA, 3);
+is(HTMLMediaElement.HAVE_ENOUGH_DATA, 4);
+is(HTMLMediaElement.MEDIA_ERR_ABORTED, undefined);
+is(HTMLMediaElement.MEDIA_ERR_NETWORK, undefined);
+is(HTMLMediaElement.MEDIA_ERR_DECODE, undefined);
+is(HTMLMediaElement.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined);
+is(HTMLVideoElement.NETWORK_EMPTY, 0);
+is(HTMLVideoElement.NETWORK_IDLE, 1);
+is(HTMLVideoElement.NETWORK_LOADING, 2);
+is(HTMLVideoElement.NETWORK_NO_SOURCE, 3);
+is(HTMLVideoElement.HAVE_NOTHING, 0);
+is(HTMLVideoElement.HAVE_METADATA, 1);
+is(HTMLVideoElement.HAVE_CURRENT_DATA, 2);
+is(HTMLVideoElement.HAVE_FUTURE_DATA, 3);
+is(HTMLVideoElement.HAVE_ENOUGH_DATA, 4);
+is(HTMLVideoElement.MEDIA_ERR_ABORTED, undefined);
+is(HTMLVideoElement.MEDIA_ERR_NETWORK, undefined);
+is(HTMLVideoElement.MEDIA_ERR_DECODE, undefined);
+is(HTMLVideoElement.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined);
+is(HTMLAudioElement.NETWORK_EMPTY, 0);
+is(HTMLAudioElement.NETWORK_IDLE, 1);
+is(HTMLAudioElement.NETWORK_LOADING, 2);
+is(HTMLAudioElement.NETWORK_NO_SOURCE, 3);
+is(HTMLAudioElement.HAVE_NOTHING, 0);
+is(HTMLAudioElement.HAVE_METADATA, 1);
+is(HTMLAudioElement.HAVE_CURRENT_DATA, 2);
+is(HTMLAudioElement.HAVE_FUTURE_DATA, 3);
+is(HTMLAudioElement.HAVE_ENOUGH_DATA, 4);
+is(HTMLAudioElement.MEDIA_ERR_ABORTED, undefined);
+is(HTMLAudioElement.MEDIA_ERR_NETWORK, undefined);
+is(HTMLAudioElement.MEDIA_ERR_DECODE, undefined);
+is(HTMLAudioElement.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined);
+is(HTMLSourceElement.NETWORK_EMPTY, undefined);
+is(HTMLSourceElement.NETWORK_IDLE, undefined);
+is(HTMLSourceElement.NETWORK_LOADING, undefined);
+is(HTMLSourceElement.NETWORK_NO_SOURCE, undefined);
+is(HTMLSourceElement.HAVE_NOTHING, undefined);
+is(HTMLSourceElement.HAVE_METADATA, undefined);
+is(HTMLSourceElement.HAVE_CURRENT_DATA, undefined);
+is(HTMLSourceElement.HAVE_FUTURE_DATA, undefined);
+is(HTMLSourceElement.HAVE_ENOUGH_DATA, undefined);
+is(HTMLSourceElement.MEDIA_ERR_ABORTED, undefined);
+is(HTMLSourceElement.MEDIA_ERR_NETWORK, undefined);
+is(HTMLSourceElement.MEDIA_ERR_DECODE, undefined);
+is(HTMLSourceElement.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined);
+is(MediaError.NETWORK_EMPTY, undefined);
+is(MediaError.NETWORK_IDLE, undefined);
+is(MediaError.NETWORK_LOADING, undefined);
+is(MediaError.NETWORK_NO_SOURCE, undefined);
+is(MediaError.HAVE_NOTHING, undefined);
+is(MediaError.HAVE_METADATA, undefined);
+is(MediaError.HAVE_CURRENT_DATA, undefined);
+is(MediaError.HAVE_FUTURE_DATA, undefined);
+is(MediaError.HAVE_ENOUGH_DATA, undefined);
+is(MediaError.MEDIA_ERR_ABORTED, 1);
+is(MediaError.MEDIA_ERR_NETWORK, 2);
+is(MediaError.MEDIA_ERR_DECODE, 3);
+is(MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED, 4);
+is(document.body.NETWORK_EMPTY, undefined);
+is(document.body.NETWORK_IDLE, undefined);
+is(document.body.NETWORK_LOADING, undefined);
+is(document.body.NETWORK_NO_SOURCE, undefined);
+is(document.body.HAVE_NOTHING, undefined);
+is(document.body.HAVE_METADATA, undefined);
+is(document.body.HAVE_CURRENT_DATA, undefined);
+is(document.body.HAVE_FUTURE_DATA, undefined);
+is(document.body.HAVE_ENOUGH_DATA, undefined);
+is(document.body.MEDIA_ERR_ABORTED, undefined);
+is(document.body.MEDIA_ERR_NETWORK, undefined);
+is(document.body.MEDIA_ERR_DECODE, undefined);
+is(document.body.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined);
+is(document.getElementsByTagName("video")[0].NETWORK_EMPTY, 0);
+is(document.getElementsByTagName("video")[0].NETWORK_IDLE, 1);
+is(document.getElementsByTagName("video")[0].NETWORK_LOADING, 2);
+is(document.getElementsByTagName("video")[0].NETWORK_NO_SOURCE, 3);
+is(document.getElementsByTagName("video")[0].HAVE_NOTHING, 0);
+is(document.getElementsByTagName("video")[0].HAVE_METADATA, 1);
+is(document.getElementsByTagName("video")[0].HAVE_CURRENT_DATA, 2);
+is(document.getElementsByTagName("video")[0].HAVE_FUTURE_DATA, 3);
+is(document.getElementsByTagName("video")[0].HAVE_ENOUGH_DATA, 4);
+is(document.getElementsByTagName("video")[0].MEDIA_ERR_ABORTED, undefined);
+is(document.getElementsByTagName("video")[0].MEDIA_ERR_NETWORK, undefined);
+is(document.getElementsByTagName("video")[0].MEDIA_ERR_DECODE, undefined);
+is(document.getElementsByTagName("video")[0].MEDIA_ERR_SRC_NOT_SUPPORTED, undefined);
+is(document.getElementsByTagName("audio")[0].NETWORK_EMPTY, 0);
+is(document.getElementsByTagName("audio")[0].NETWORK_IDLE, 1);
+is(document.getElementsByTagName("audio")[0].NETWORK_LOADING, 2);
+is(document.getElementsByTagName("audio")[0].NETWORK_NO_SOURCE, 3);
+is(document.getElementsByTagName("audio")[0].HAVE_NOTHING, 0);
+is(document.getElementsByTagName("audio")[0].HAVE_METADATA, 1);
+is(document.getElementsByTagName("audio")[0].HAVE_CURRENT_DATA, 2);
+is(document.getElementsByTagName("audio")[0].HAVE_FUTURE_DATA, 3);
+is(document.getElementsByTagName("audio")[0].HAVE_ENOUGH_DATA, 4);
+is(document.getElementsByTagName("audio")[0].MEDIA_ERR_ABORTED, undefined);
+is(document.getElementsByTagName("audio")[0].MEDIA_ERR_NETWORK, undefined);
+is(document.getElementsByTagName("audio")[0].MEDIA_ERR_DECODE, undefined);
+is(document.getElementsByTagName("audio")[0].MEDIA_ERR_SRC_NOT_SUPPORTED, undefined);
+is(document.getElementsByTagName("source")[0].NETWORK_EMPTY, undefined);
+is(document.getElementsByTagName("source")[0].NETWORK_IDLE, undefined);
+is(document.getElementsByTagName("source")[0].NETWORK_LOADING, undefined);
+is(document.getElementsByTagName("source")[0].NETWORK_NO_SOURCE, undefined);
+is(document.getElementsByTagName("source")[0].HAVE_NOTHING, undefined);
+is(document.getElementsByTagName("source")[0].HAVE_METADATA, undefined);
+is(document.getElementsByTagName("source")[0].HAVE_CURRENT_DATA, undefined);
+is(document.getElementsByTagName("source")[0].HAVE_FUTURE_DATA, undefined);
+is(document.getElementsByTagName("source")[0].HAVE_ENOUGH_DATA, undefined);
+is(document.getElementsByTagName("source")[0].MEDIA_ERR_ABORTED, undefined);
+is(document.getElementsByTagName("source")[0].MEDIA_ERR_NETWORK, undefined);
+is(document.getElementsByTagName("source")[0].MEDIA_ERR_DECODE, undefined);
+is(document.getElementsByTagName("source")[0].MEDIA_ERR_SRC_NOT_SUPPORTED, undefined);
+is(HTMLElement.prototype.NETWORK_EMPTY, undefined);
+is(HTMLElement.prototype.NETWORK_IDLE, undefined);
+is(HTMLElement.prototype.NETWORK_LOADING, undefined);
+is(HTMLElement.prototype.NETWORK_NO_SOURCE, undefined);
+is(HTMLElement.prototype.HAVE_NOTHING, undefined);
+is(HTMLElement.prototype.HAVE_METADATA, undefined);
+is(HTMLElement.prototype.HAVE_CURRENT_DATA, undefined);
+is(HTMLElement.prototype.HAVE_FUTURE_DATA, undefined);
+is(HTMLElement.prototype.HAVE_ENOUGH_DATA, undefined);
+is(HTMLElement.prototype.MEDIA_ERR_ABORTED, undefined);
+is(HTMLElement.prototype.MEDIA_ERR_NETWORK, undefined);
+is(HTMLElement.prototype.MEDIA_ERR_DECODE, undefined);
+is(HTMLElement.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined);
+is(HTMLMediaElement.prototype.NETWORK_EMPTY, 0, "HTMLMediaElement.prototype.NETWORK_EMPTY");
+is(HTMLMediaElement.prototype.NETWORK_IDLE, 1, "HTMLMediaElement.prototype.NETWORK_IDLE");
+is(HTMLMediaElement.prototype.NETWORK_LOADING, 2, "HTMLMediaElement.prototype.NETWORK_LOADING");
+is(HTMLMediaElement.prototype.NETWORK_NO_SOURCE, 3, "HTMLMediaElement.prototype.NETWORK_NO_SOURCE");
+is(HTMLMediaElement.prototype.HAVE_NOTHING, 0, "HTMLMediaElement.prototype.HAVE_NOTHING");
+is(HTMLMediaElement.prototype.HAVE_METADATA, 1, "HTMLMediaElement.prototype.HAVE_METADATA");
+is(HTMLMediaElement.prototype.HAVE_CURRENT_DATA, 2, "HTMLMediaElement.prototype.HAVE_CURRENT_DATA");
+is(HTMLMediaElement.prototype.HAVE_FUTURE_DATA, 3, "HTMLMediaElement.prototype.HAVE_FUTURE_DATA");
+is(HTMLMediaElement.prototype.HAVE_ENOUGH_DATA, 4, "HTMLMediaElement.prototype.HAVE_ENOUGH_DATA");
+is(HTMLMediaElement.prototype.MEDIA_ERR_ABORTED, undefined, "HTMLMediaElement.prototype.MEDIA_ERR_ABORTED");
+is(HTMLMediaElement.prototype.MEDIA_ERR_NETWORK, undefined, "HTMLMediaElement.prototype.MEDIA_ERR_NETWORK");
+is(HTMLMediaElement.prototype.MEDIA_ERR_DECODE, undefined, "HTMLMediaElement.prototype.MEDIA_ERR_DECODE");
+is(HTMLMediaElement.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined, "HTMLMediaElement.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED");
+is(HTMLVideoElement.prototype.NETWORK_EMPTY, 0);
+is(HTMLVideoElement.prototype.NETWORK_IDLE, 1);
+is(HTMLVideoElement.prototype.NETWORK_LOADING, 2);
+is(HTMLVideoElement.prototype.NETWORK_NO_SOURCE, 3);
+is(HTMLVideoElement.prototype.HAVE_NOTHING, 0);
+is(HTMLVideoElement.prototype.HAVE_METADATA, 1);
+is(HTMLVideoElement.prototype.HAVE_CURRENT_DATA, 2);
+is(HTMLVideoElement.prototype.HAVE_FUTURE_DATA, 3);
+is(HTMLVideoElement.prototype.HAVE_ENOUGH_DATA, 4);
+is(HTMLVideoElement.prototype.MEDIA_ERR_ABORTED, undefined);
+is(HTMLVideoElement.prototype.MEDIA_ERR_NETWORK, undefined);
+is(HTMLVideoElement.prototype.MEDIA_ERR_DECODE, undefined);
+is(HTMLVideoElement.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined);
+is(HTMLAudioElement.prototype.NETWORK_EMPTY, 0);
+is(HTMLAudioElement.prototype.NETWORK_IDLE, 1);
+is(HTMLAudioElement.prototype.NETWORK_LOADING, 2);
+is(HTMLAudioElement.prototype.NETWORK_NO_SOURCE, 3);
+is(HTMLAudioElement.prototype.HAVE_NOTHING, 0);
+is(HTMLAudioElement.prototype.HAVE_METADATA, 1);
+is(HTMLAudioElement.prototype.HAVE_CURRENT_DATA, 2);
+is(HTMLAudioElement.prototype.HAVE_FUTURE_DATA, 3);
+is(HTMLAudioElement.prototype.HAVE_ENOUGH_DATA, 4);
+is(HTMLAudioElement.prototype.MEDIA_ERR_ABORTED, undefined);
+is(HTMLAudioElement.prototype.MEDIA_ERR_NETWORK, undefined);
+is(HTMLAudioElement.prototype.MEDIA_ERR_DECODE, undefined);
+is(HTMLAudioElement.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined);
+is(HTMLSourceElement.prototype.NETWORK_EMPTY, undefined);
+is(HTMLSourceElement.prototype.NETWORK_IDLE, undefined);
+is(HTMLSourceElement.prototype.NETWORK_LOADING, undefined);
+is(HTMLSourceElement.prototype.NETWORK_NO_SOURCE, undefined);
+is(HTMLSourceElement.prototype.HAVE_NOTHING, undefined);
+is(HTMLSourceElement.prototype.HAVE_METADATA, undefined);
+is(HTMLSourceElement.prototype.HAVE_CURRENT_DATA, undefined);
+is(HTMLSourceElement.prototype.HAVE_FUTURE_DATA, undefined);
+is(HTMLSourceElement.prototype.HAVE_ENOUGH_DATA, undefined);
+is(HTMLSourceElement.prototype.MEDIA_ERR_ABORTED, undefined);
+is(HTMLSourceElement.prototype.MEDIA_ERR_NETWORK, undefined);
+is(HTMLSourceElement.prototype.MEDIA_ERR_DECODE, undefined);
+is(HTMLSourceElement.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined);
+is(MediaError.prototype.NETWORK_EMPTY, undefined);
+is(MediaError.prototype.NETWORK_IDLE, undefined);
+is(MediaError.prototype.NETWORK_LOADING, undefined);
+is(MediaError.prototype.NETWORK_NO_SOURCE, undefined);
+is(MediaError.prototype.HAVE_NOTHING, undefined);
+is(MediaError.prototype.HAVE_METADATA, undefined);
+is(MediaError.prototype.HAVE_CURRENT_DATA, undefined);
+is(MediaError.prototype.HAVE_FUTURE_DATA, undefined);
+is(MediaError.prototype.HAVE_ENOUGH_DATA, undefined);
+is(MediaError.prototype.MEDIA_ERR_ABORTED, 1);
+is(MediaError.prototype.MEDIA_ERR_NETWORK, 2);
+is(MediaError.prototype.MEDIA_ERR_DECODE, 3);
+is(MediaError.prototype.MEDIA_ERR_SRC_NOT_SUPPORTED, 4);
+ok(document.getElementsByTagName("video")[0].buffered instanceof TimeRanges, "video.buffered must be TimeRanges object");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_controls.html b/dom/media/test/test_controls.html
new file mode 100644
index 000000000..1c80cc7d8
--- /dev/null
+++ b/dom/media/test/test_controls.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: controls</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<video id='v1'></video><audio id='a1'></audio>
+<video id='v2' controls></video><audio id='a2' controls></audio>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var v1 = document.getElementById('v1');
+var a1 = document.getElementById('a1');
+var v2 = document.getElementById('v2');
+var a2 = document.getElementById('a2');
+ok(!v1.controls, "v1.controls should be false by default");
+ok(!a1.controls, "v1.controls should be false by default");
+ok(v2.controls, "v2.controls should be true");
+ok(a2.controls, "v2.controls should be true");
+v2.controls=false;
+a2.controls=false;
+ok(!v2.controls, "v2.controls should be false");
+ok(!a2.controls, "a2.controls should be false");
+v2.controls=true;
+a2.controls=true;
+ok(v2.controls, "v2.controls should be true");
+ok(a2.controls, "a2.controls should be true");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_cueless_webm_seek-1.html b/dom/media/test/test_cueless_webm_seek-1.html
new file mode 100644
index 000000000..8e501a61e
--- /dev/null
+++ b/dom/media/test/test_cueless_webm_seek-1.html
@@ -0,0 +1,136 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=657791
+-->
+<head>
+ <title>Test for Bug 657791</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=657791">Mozilla Bug 657791</a>
+
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+// Subset of seek tests for cueless WebMs. When random seeking (rather than just
+// in buffered ranges) is implemented for WebM, these tests can be removed and
+// the cueless WebM(s) references can be moved to the general test_seek test
+// array.
+// Test array is defined in manifest.js
+
+var manager = new MediaTestManager;
+
+// Exercise functionality as in test_seek-1
+function testWebM1(e) {
+ var v = e.target;
+ v.removeEventListener('loadeddata', testWebM1);
+
+ var startPassed = false;
+ var endPassed = false;
+ var seekFlagStart = false;
+ var seekFlagEnd = false;
+ var readonly = true;
+ var completed = false;
+
+ ok(v.buffered.length >= 1, "Should have a buffered range");
+ var halfBuffered = v.buffered.end(0) / 2;
+
+ function startTest() {
+ is(v.seekable.start(0), v.buffered.start(0), "Seekable start should be buffered start");
+ is(v.seekable.end(0), v.buffered.end(0), "Seekable end should be buffered end");
+ ok(!completed, "Should not be completed yet");
+ ok(!v.seeking, "seeking should default to false");
+ try {
+ v.seeking = true;
+ readonly = v.seeking === false;
+ }
+ catch(e) {
+ readonly = "threw exception: " + e;
+ }
+ is(readonly, true, "seeking should be readonly");
+
+ v.currentTime = halfBuffered;
+ seekFlagStart = v.seeking;
+ }
+
+ function seekStarted() {
+ ok(!completed, "should not be completed yet");
+ startPassed = true;
+ }
+
+ function seekEnded() {
+ ok(!completed, "should not be completed yet");
+ ok(Math.abs(v.currentTime - halfBuffered) < 0.1,
+ "Video currentTime should be around " + halfBuffered + ": " + v.currentTime + " (seeked)");
+ endPassed = true;
+ seekFlagEnd = v.seeking;
+ v.play();
+ }
+
+ function playbackEnded() {
+ ok(!completed, "should not be completed yet");
+
+ completed = true;
+ ok(startPassed, "seeking event");
+ ok(endPassed, "seeked event");
+ ok(seekFlagStart, "seeking flag on start should be true");
+ ok(!seekFlagEnd, "seeking flag on end should be false");
+ removeNodeAndSource(v);
+ manager.finished(v._token);
+ }
+
+ once(v, "ended", playbackEnded);
+ once(v, "seeking", seekStarted);
+ once(v, "seeked", seekEnded);
+
+ startTest();
+}
+
+// Fetch the media resource using XHR so we can be sure the entire
+// resource is loaded before we test buffered ranges. This ensures
+// we have deterministic behaviour.
+function fetch(url, fetched_callback) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", url, true);
+ xhr.responseType = "blob";
+
+ var loaded = function (event) {
+ if (xhr.status == 200 || xhr.status == 206) {
+ // Request fulfilled. Note sometimes we get 206... Presumably because either
+ // httpd.js or Necko cached the result.
+ fetched_callback(window.URL.createObjectURL(xhr.response));
+ } else {
+ ok(false, "Fetch failed headers=" + xhr.getAllResponseHeaders());
+ }
+ };
+
+ xhr.addEventListener("load", loaded, false);
+ xhr.send();
+}
+
+function startTest(test, token) {
+ var onfetched = function(uri) {
+ var v = document.createElement('video');
+ v._token = token;
+ v.src = uri;
+ v.addEventListener("loadeddata", testWebM1, false);
+ document.body.appendChild(v);
+ }
+ manager.started(token);
+ fetch(test.name, onfetched);
+}
+
+SimpleTest.waitForExplicitFinish();
+manager.runTests(gCuelessWebMTests, startTest);
+
+</script>
+</pre>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/media/test/test_cueless_webm_seek-2.html b/dom/media/test/test_cueless_webm_seek-2.html
new file mode 100644
index 000000000..baf14c8a5
--- /dev/null
+++ b/dom/media/test/test_cueless_webm_seek-2.html
@@ -0,0 +1,126 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=657791
+-->
+<head>
+ <title>Test for Bug 657791</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=657791">Mozilla Bug 657791</a>
+
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+// Subset of seek tests for cueless WebMs. When random seeking (rather than just
+// in buffered ranges) is implemented for WebM, these tests can be removed and
+// the cueless WebM(s) references can be moved to the general test_seek test
+// array.
+// Test array is defined in manifest.js
+
+var manager = new MediaTestManager;
+
+// Exercise functionality as in test_seek-2
+function testWebM2(e) {
+ var v = e.target;
+ v.removeEventListener('loadeddata', testWebM2);
+
+ var startPassed = false;
+ var endPassed = false;
+ var completed = false;
+
+ ok(v.buffered.length >= 1, "Should have a buffered range");
+ var halfBuffered = v.buffered.end(0) / 2;
+
+ function startTest() {
+ if (completed)
+ return;
+
+ is(v.seekable.start(0), v.buffered.start(0), "Seekable start should be buffered start");
+ is(v.seekable.end(0), v.buffered.end(0), "Seekable end should be buffered end");
+ v.currentTime=halfBuffered;
+ v.play();
+ }
+
+ function seekStarted() {
+ if (completed)
+ return;
+
+ startPassed = true;
+ }
+
+ function seekEnded() {
+ if (completed)
+ return;
+
+ endPassed = true;
+ }
+
+ function playbackEnded() {
+ if (completed)
+ return;
+
+ completed = true;
+ ok(startPassed, "send seeking event");
+ ok(endPassed, "send seeked event");
+ ok(v.ended, "Checking playback has ended");
+ ok(Math.abs(v.currentTime - v.duration) <= 0.1, "Checking currentTime at end: " + v.currentTime);
+ removeNodeAndSource(v);
+ manager.finished(v._token);
+ }
+
+ v.addEventListener("ended", playbackEnded, false);
+ v.addEventListener("seeking", seekStarted, false);
+ v.addEventListener("seeked", seekEnded, false);
+
+ startTest();
+}
+
+// Fetch the media resource using XHR so we can be sure the entire
+// resource is loaded before we test buffered ranges. This ensures
+// we have deterministic behaviour.
+function fetch(url, fetched_callback) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", url, true);
+ xhr.responseType = "blob";
+
+ var loaded = function (event) {
+ if (xhr.status == 200 || xhr.status == 206) {
+ // Request fulfilled. Note sometimes we get 206... Presumably because either
+ // httpd.js or Necko cached the result.
+ fetched_callback(window.URL.createObjectURL(xhr.response));
+ } else {
+ ok(false, "Fetch failed headers=" + xhr.getAllResponseHeaders());
+ }
+ };
+
+ xhr.addEventListener("load", loaded, false);
+ xhr.send();
+}
+
+function startTest(test, token) {
+ var onfetched = function(uri) {
+ var v = document.createElement('video');
+ v._token = token;
+ v.src = uri;
+ v.addEventListener("loadeddata", testWebM2, false);
+ document.body.appendChild(v);
+ }
+ manager.started(token);
+ fetch(test.name, onfetched);
+}
+
+SimpleTest.waitForExplicitFinish();
+manager.runTests(gCuelessWebMTests, startTest);
+
+</script>
+</pre>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/media/test/test_cueless_webm_seek-3.html b/dom/media/test/test_cueless_webm_seek-3.html
new file mode 100644
index 000000000..9058bdf05
--- /dev/null
+++ b/dom/media/test/test_cueless_webm_seek-3.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=657791
+-->
+<head>
+ <title>Test for Bug 657791</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=657791">Mozilla Bug 657791</a>
+
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+// Subset of seek tests for cueless WebMs. When random seeking (rather than just
+// in buffered ranges) is implemented for WebM, these tests can be removed and
+// the cueless WebM(s) references can be moved to the general test_seek test
+// array.
+// Test array is defined in manifest.js
+
+var manager = new MediaTestManager;
+
+// Exercise functionality as in test_seek-3
+function testWebM3(e) {
+ var v = e.target;
+ v.removeEventListener('loadeddata', testWebM3);
+
+ var startPassed = false;
+ var completed = false;
+ var gotTimeupdate = false;
+
+ ok(v.buffered.length >= 1, "Should have a buffered range");
+ var halfBuffered = v.buffered.end(0) / 2;
+
+ function startTest() {
+ if (completed)
+ return;
+
+ is(v.seekable.start(0), v.buffered.start(0), "Seekable start should be buffered start");
+ is(v.seekable.end(0), v.buffered.end(0), "Seekable end should be buffered end");
+ v.currentTime=halfBuffered;
+ }
+
+ function timeupdate() {
+ gotTimeupdate = true;
+ v.removeEventListener("timeupdate", timeupdate, false);
+ }
+
+ function seekStarted() {
+ if (completed)
+ return;
+
+ v.addEventListener("timeupdate", timeupdate, false);
+ startPassed = true;
+ }
+
+ function seekEnded() {
+ if (completed)
+ return;
+
+ var t = v.currentTime;
+ ok(Math.abs(t - halfBuffered) <= 0.1, "Video currentTime should be around " + halfBuffered + ": " + t);
+ ok(gotTimeupdate, "Should have got timeupdate between seeking and seekended");
+ completed = true;
+ removeNodeAndSource(v);
+ manager.finished(v._token);
+ }
+
+ v.addEventListener("seeking", seekStarted, false);
+ v.addEventListener("seeked", seekEnded, false);
+
+ startTest()
+}
+
+// Fetch the media resource using XHR so we can be sure the entire
+// resource is loaded before we test buffered ranges. This ensures
+// we have deterministic behaviour.
+function fetch(url, fetched_callback) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", url, true);
+ xhr.responseType = "blob";
+
+ var loaded = function (event) {
+ if (xhr.status == 200 || xhr.status == 206) {
+ // Request fulfilled. Note sometimes we get 206... Presumably because either
+ // httpd.js or Necko cached the result.
+ fetched_callback(window.URL.createObjectURL(xhr.response));
+ } else {
+ ok(false, "Fetch failed headers=" + xhr.getAllResponseHeaders());
+ }
+ };
+
+ xhr.addEventListener("load", loaded, false);
+ xhr.send();
+}
+
+function startTest(test, token) {
+ var onfetched = function(uri) {
+ var v = document.createElement('video');
+ v._token = token;
+ v.src = uri;
+ v.addEventListener("loadeddata", testWebM3, false);
+ document.body.appendChild(v);
+ }
+ manager.started(token);
+ fetch(test.name, onfetched);
+}
+
+SimpleTest.waitForExplicitFinish();
+manager.runTests(gCuelessWebMTests, startTest);
+
+</script>
+</pre>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/media/test/test_currentTime.html b/dom/media/test/test_currentTime.html
new file mode 100644
index 000000000..67b3a4b26
--- /dev/null
+++ b/dom/media/test/test_currentTime.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: currentTime</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<video id='v1'></video><audio id='a1'></audio>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var v1 = document.getElementById('v1');
+var a1 = document.getElementById('a1');
+is(v1.currentTime, 0.0);
+is(a1.currentTime, 0.0);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_decode_error.html b/dom/media/test/test_decode_error.html
new file mode 100644
index 000000000..e940fcd18
--- /dev/null
+++ b/dom/media/test/test_decode_error.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: unknown/invalid formats raise decode error</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ var ok = function (condition, name) {
+ SimpleTest.ok(condition, test.name + ": " + name);
+ }
+ var is = function (a, b, name) {
+ SimpleTest.is(a, b, test.name + ": " + name);
+ }
+
+ var v = document.createElement("video");
+ manager.started(token);
+ v.addEventListener("error", function (event) {
+ var el = event.currentTarget;
+ is(event.type, "error", "Expected event of type 'error'");
+ ok(el.error, "Element 'error' attr expected to have a value");
+ ok(el.error instanceof MediaError, "Element 'error' attr expected to be MediaError");
+ if (v.readyState == v.HAVE_NOTHING) {
+ is(el.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED, "Expected media not supported error");
+ } else {
+ is(el.error.code, MediaError.MEDIA_ERR_DECODE, "Expected a decode error");
+ }
+ ok(typeof el.error.message === 'string' || el.error.essage instanceof String, "Element 'message' attr expected to be a string");
+ ok(el.error.message.length > 0, "Element 'message' attr has content");
+ el._sawError = true;
+ manager.finished(token);
+ }, false);
+
+ v.addEventListener("loadeddata", function () {
+ ok(false, "Unexpected loadeddata event");
+ manager.finished(token);
+ }, false);
+
+ v.autoplay = true;
+ v.addEventListener("ended", function () {
+ ok(false, "Unexpected ended event");
+ manager.finished(token);
+ }, false);
+
+ v.src = test.name; // implicitly starts a load.
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({
+ "set": [
+ ["media.cache_size", 40000],
+ ]
+}, beginTest);
+function beginTest() {
+ manager.runTests(gDecodeErrorTests, startTest);
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_decoder_disable.html b/dom/media/test/test_decoder_disable.html
new file mode 100644
index 000000000..218d527f2
--- /dev/null
+++ b/dom/media/test/test_decoder_disable.html
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=448600
+-->
+<head>
+ <title>Test for Bug 448600</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=448600">Mozilla Bug 448600</a>
+<p id="display"></p>
+
+
+<pre id="test">
+<script type="application/javascript">
+
+function filename(uri) {
+ return uri.substr(uri.lastIndexOf("/")+1);
+}
+
+function e(id) {
+ return document.getElementById(id);
+}
+
+var gLoadError = new Object();
+
+gLoadError['video1'] = 0;
+gLoadError['video2'] = 0;
+gLoadError['video3'] = 0;
+
+var gErrorCount = 0;
+
+SimpleTest.waitForExplicitFinish();
+
+function finishTest() {
+ is(e('video1').currentSrc,
+ "",
+ 'video1 currentSrc should be empty when there\'s no playable typed source children');
+ is(filename(e('video2').currentSrc),
+ filename(e('video2').src),
+ 'video2 currentSrc should match src');
+ is(filename(e('video3').currentSrc),
+ filename(e('video3').src),
+ 'video3 currentSrc should match src');
+
+ is(gLoadError['video1'], 2, "Expect one error per invalid source child on video1");
+ is(gLoadError['video2'], 1, "Expect one error on video2");
+ is(gLoadError['video3'], 1, "Expect one error on video3");
+
+ SimpleTest.finish();
+}
+
+function videoError(event, id) {
+ gLoadError[id]++;
+ gErrorCount++;
+ if (gErrorCount >= 4) {
+ finishTest();
+ }
+}
+
+</script>
+<!-- We make the resource URIs unique to ensure that they are (re)loaded with the new disable-decoder prefs. -->
+<div id="content">
+</div>
+<script>
+function makeVideos() {
+ document.getElementById('content').innerHTML = '<video id="video1" preload="metadata"><source type="video/ogg" src="320x240.ogv?decoder_disabled=1" onerror="videoError(event, \'video1\');"/><source type="audio/wave" src="r11025_u8_c1.wav?decoder_disabled=1" id=\'s2\' onerror="videoError(event, \'video1\');"/></video><video id="video2" preload="metadata" src="320x240.ogv?decoder_disabled=2" onerror="videoError(event, \'video2\');"></video><video id="video3" preload="metadata" src="r11025_u8_c1.wav?decoder_disabled=2" onerror="videoError(event, \'video3\');"></video>';
+}
+
+SpecialPowers.pushPrefEnv({"set": [["media.ogg.enabled", false], ["media.wave.enabled", false]]}, makeVideos);
+</script>
+
+</pre>
+
+</body>
+</html>
diff --git a/dom/media/test/test_defaultMuted.html b/dom/media/test/test_defaultMuted.html
new file mode 100644
index 000000000..de6d642e5
--- /dev/null
+++ b/dom/media/test/test_defaultMuted.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: defaultMuted</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="../../../dom/html/test/reflect.js"></script>
+</head>
+<body>
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=706731">Mozilla Bug 706731</a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <video id='v1'></video><audio id='a1'></audio>
+ <video id='v2' muted></video><audio id='a2' muted></audio>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+ reflectBoolean({
+ element: document.createElement("video"),
+ attribute: { content: "muted", idl: "defaultMuted" },
+ });
+
+ reflectBoolean({
+ element: document.createElement("audio"),
+ attribute: { content: "muted", idl: "defaultMuted" },
+ });
+
+ var v1 = document.getElementById('v1');
+ var a1 = document.getElementById('a1');
+ var v2 = document.getElementById('v2');
+ var a2 = document.getElementById('a2');
+
+ // Check that muted state correspond to the default value.
+ is(v1.muted, false, "v1.muted should be false by default");
+ is(a1.muted, false, "a1.muted should be false by default");
+ is(v2.muted, true, "v2.muted should be true by default");
+ is(a2.muted, true, "a2.muted should be true by default");
+
+ // Changing defaultMuted value should not change current muted state.
+ v1.defaultMuted = true;
+ a1.defaultMuted = true;
+ v2.defaultMuted = false;
+ a2.defaultMuted = false;
+
+ is(v1.muted, false, "v1.muted should not have changed");
+ is(a1.muted, false, "a1.muted should not have changed");
+ is(v2.muted, true, "v2.muted should not have changed");
+ is(a2.muted, true, "a2.muted should not have changed");
+
+ mediaTestCleanup();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_delay_load.html b/dom/media/test/test_delay_load.html
new file mode 100644
index 000000000..419f0d636
--- /dev/null
+++ b/dom/media/test/test_delay_load.html
@@ -0,0 +1,108 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=479711
+-->
+<head>
+ <title>Test for Bug 479711</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+ <script>
+
+ var gRegisteredElements = [];
+ var testWindows = [];
+
+ function register(v) {
+ gRegisteredElements.push(v);
+ }
+
+ function loaded() {
+ info("onload fired!");
+
+ for (var i = 0; i < gRegisteredElements.length; ++i) {
+ var v = gRegisteredElements[i];
+ ok(v.readyState >= v.HAVE_CURRENT_DATA,
+ v._name + ":" + v.id + " is not ready before onload fired (" + v.readyState + ")");
+ }
+
+ for (i=0; i<testWindows.length; ++i) {
+ testWindows[i].close();
+ }
+
+ mediaTestCleanup();
+
+ SimpleTest.finish();
+ }
+
+ addLoadEvent(loaded);
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=479711">Mozilla Bug 479711</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 479711 **/
+
+function createVideo(name, type, id) {
+ var v = document.createElement("video");
+ v.preload = "metadata";
+ // Make sure each video is a unique resource
+ v.src = name + "?" + id;
+ v._name = name;
+ v.id = id;
+ register(v);
+ return v;
+}
+
+var test = getPlayableVideo(gSmallTests);
+
+// Straightforward add, causing a load.
+var v = createVideo(test.name, test.type, "1");
+document.body.appendChild(v);
+
+// Load, add, then remove.
+v = createVideo(test.name, test.type, "1");
+v.load();
+document.body.appendChild(v);
+v.remove();
+
+// Load and add.
+v = createVideo(test.name, test.type, "2");
+v.load();
+document.body.appendChild(v);
+
+// Load outside of doc.
+v = createVideo(test.name, test.type, "3");
+v.load();
+
+// Open a new window for the following test. We open it here instead of in
+// the event handler to ensure that our document load event doesn't fire while
+// window.open is spinning the event loop.
+var w = window.open("", "testWindow", "width=400,height=400");
+testWindows.push(w);
+
+v = createVideo(test.name, test.type, "4");
+v.onloadstart = function(e) {
+ // Using a new window to do this is a bit annoying, but if we use an iframe here,
+ // delaying of the iframe's load event might interfere with the firing of our load event
+ // in some confusing way. So it's simpler just to use another window.
+ w.document.body.appendChild(v);
+};
+v.load(); // load started while in this document, this doc's load will block until
+ // the video's finished loading (in the other document).
+
+if (gRegisteredElements.length > 0) {
+ SimpleTest.waitForExplicitFinish();
+} else {
+ todo(false, "No types supported");
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_eme_canvas_blocked.html b/dom/media/test/test_eme_canvas_blocked.html
new file mode 100644
index 000000000..e84b6db40
--- /dev/null
+++ b/dom/media/test/test_eme_canvas_blocked.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test Encrypted Media Extensions</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="eme.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function startTest(test, token)
+{
+ manager.started(token);
+
+ var sessions = [];
+
+ var v = SetupEME(test, token);
+ v.preload = "auto"; // Required due to "canplay" not firing for MSE unless we do this.
+
+ v.addEventListener("loadeddata", function(ev) {
+ var video = ev.target;
+ var canvas = document.createElement("canvas");
+ canvas.width = video.videoWidth;
+ canvas.height = video.videoHeight;
+ document.body.appendChild(canvas);
+ var ctx = canvas.getContext("2d");
+ var threwError = false;
+ try {
+ ctx.drawImage(video, 0, 0);
+ } catch (ex) {
+ threwError = true;
+ }
+ ok(threwError, TimeStamp(token) + " - Should throw an error when trying to draw EME video to canvas.");
+ manager.finished(token);
+ });
+
+ LoadTestWithManagedLoadToken(test, v, manager, token,
+ { onlyLoadFirstFragments:2, noEndOfStream:false });
+}
+
+function beginTest() {
+ manager.runTests(gEMETests, startTest);
+}
+
+if (!IsMacOSSnowLeopardOrEarlier()) {
+ SimpleTest.waitForExplicitFinish();
+ SetupEMEPref(beginTest);
+} else {
+ todo(false, "Test disabled on this platform.");
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_eme_detach_media_keys.html b/dom/media/test/test_eme_detach_media_keys.html
new file mode 100644
index 000000000..6d3dc8467
--- /dev/null
+++ b/dom/media/test/test_eme_detach_media_keys.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test Encrypted Media Extensions</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="eme.js"></script>
+</head>
+<body>
+<pre id="test">
+<video id="v" controls></video>
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function createAndSet() {
+ return new Promise(function(resolve, reject) {
+ var m;
+ navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, gCencMediaKeySystemConfig)
+ .then(function (access) {
+ return access.createMediaKeys();
+ })
+ .then(function (mediaKeys) {
+ m = mediaKeys;
+ return document.getElementById("v").setMediaKeys(mediaKeys);
+ })
+ .then(function() {
+ resolve(m);
+ });
+ }
+)}
+
+var m1,m2;
+
+// Test that if we create and set two MediaKeys on one video element,
+// that if the first MediaKeys we set on the media elemnt is still usable
+// after the second MediaKeys has been set on the media element.
+SetupEMEPref(() => {
+ createAndSet().then((m) => {
+ m1 = m; // Stash MediaKeys.
+ return createAndSet();
+ })
+ .then((m) => {
+ m2 = m;
+ is(document.getElementById("v").mediaKeys, m2, "Should have set MediaKeys on media element");
+ ok(document.getElementById("v").mediaKeys != m1, "First MediaKeys should no longer be set on media element");
+ var s = m1.createSession("temporary");
+ return s.generateRequest("webm", StringToArrayBuffer(atob('YAYeAX5Hfod+V9ANHtANHg==')));
+ })
+ .then(() => {
+ ok(true, "Was able to generateRequest using second CDM");
+ SimpleTest.finish();
+ }, () => {
+ ok(false, "Was *NOT* able to generateRequest using second CDM");
+ SimpleTest.finish();
+ });
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_eme_initDataTypes.html b/dom/media/test/test_eme_initDataTypes.html
new file mode 100644
index 000000000..4821c3cb8
--- /dev/null
+++ b/dom/media/test/test_eme_initDataTypes.html
@@ -0,0 +1,133 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test Encrypted Media Extensions</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="eme.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var tests = [
+ {
+ name: "One keyId",
+ initDataType: 'keyids',
+ initData: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A"]}',
+ expectedRequest: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A"],"type":"temporary"}',
+ sessionType: 'temporary',
+ expectPass: true,
+ },
+ {
+ name: "Two keyIds",
+ initDataType: 'keyids',
+ initData: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A", "0DdtU9od-Bh5L3xbv0Xf_A"]}',
+ expectedRequest: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A","0DdtU9od-Bh5L3xbv0Xf_A"],"type":"temporary"}',
+ sessionType: 'temporary',
+ expectPass: true,
+ },
+ {
+ name: "Two keyIds, temporary session",
+ initDataType: 'keyids',
+ initData: '{"type":"temporary", "kids":["LwVHf8JLtPrv2GUXFW2v_A", "0DdtU9od-Bh5L3xbv0Xf_A"]}',
+ expectedRequest: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A","0DdtU9od-Bh5L3xbv0Xf_A"],"type":"temporary"}',
+ sessionType: 'temporary',
+ expectPass: true,
+ },
+ {
+ name: "Two keyIds, persistent session, type before kids",
+ initDataType: 'keyids',
+ initData: '{"type":"persistent-license", "kids":["LwVHf8JLtPrv2GUXFW2v_A", "0DdtU9od-Bh5L3xbv0Xf_A"]}',
+ expectedRequest: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A","0DdtU9od-Bh5L3xbv0Xf_A"],"type":"persistent-license"}',
+ sessionType: 'persistent-license',
+ expectPass: false,
+ },
+ {
+ name: "Invalid keyId",
+ initDataType: 'keyids',
+ initData: '{"kids":["0"]}',
+ sessionType: 'temporary',
+ expectPass: false,
+ },
+ {
+ name: "Empty keyId",
+ initDataType: 'keyids',
+ initData: '{"kids":[""]}',
+ sessionType: 'temporary',
+ expectPass: false,
+ },
+ {
+ name: "Invalid initData",
+ initDataType: 'keyids',
+ initData: 'invalid initData',
+ sessionType: 'temporary',
+ expectPass: false,
+ },
+ {
+ name: "'webm' initDataType",
+ initDataType: 'webm',
+ initData: 'YAYeAX5Hfod+V9ANHtANHg==',
+ expectedRequest: '{"kids":["YAYeAX5Hfod-V9ANHtANHg"],"type":"temporary"}',
+ sessionType: 'temporary',
+ expectPass: true,
+ },
+ {
+ name: "'webm' initDataType with non 16 byte keyid",
+ initDataType: 'webm',
+ initData: 'YAYeAX5Hfod',
+ expectedRequest: '{\"kids\":[\"YAYeAX5Hfoc\"],\"type\":\"temporary\"}',
+ sessionType: 'temporary',
+ expectPass: true,
+ },
+];
+
+function PrepareInitData(initDataType, initData)
+{
+ if (initDataType == "keyids") {
+ return new TextEncoder().encode(initData);
+ } else if (initDataType == "webm") {
+ return StringToArrayBuffer(atob(initData));
+ }
+}
+
+function Test(test) {
+ return new Promise(function(resolve, reject) {
+ var configs = [{
+ initDataTypes: [test.initDataType],
+ videoCapabilities: [{contentType: 'video/mp4' }],
+ }];
+ navigator.requestMediaKeySystemAccess('org.w3.clearkey', configs)
+ .then((access) => access.createMediaKeys())
+ .then((mediaKeys) => {
+ var session = mediaKeys.createSession(test.sessionType);
+ session.addEventListener("message", function(event) {
+ is(event.messageType, "license-request", "'" + test.name + "' MediaKeyMessage type should be license-request.");
+ var text = new TextDecoder().decode(event.message);
+ is(text, test.expectedRequest, "'" + test.name + "' got expected response.");
+ is(text == test.expectedRequest, test.expectPass,
+ "'" + test.name + "' expected to " + (test.expectPass ? "pass" : "fail"));
+ resolve();
+ });
+ var initData = PrepareInitData(test.initDataType, test.initData);
+ return session.generateRequest(test.initDataType, initData);
+ }
+ ).catch((x) => {
+ ok(!test.expectPass, "'" + test.name + "' expected to fail.");
+ resolve();
+ });
+ });
+}
+
+function beginTest() {
+ Promise.all(tests.map(Test)).then(function() { SimpleTest.finish(); });
+}
+
+SimpleTest.waitForExplicitFinish();
+SetupEMEPref(beginTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_eme_missing_pssh.html b/dom/media/test/test_eme_missing_pssh.html
new file mode 100644
index 000000000..196ced402
--- /dev/null
+++ b/dom/media/test/test_eme_missing_pssh.html
@@ -0,0 +1,92 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Test Encrypted Media Extensions</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="eme.js"></script>
+ </head>
+ <body>
+ <audio controls id="audio"></audio>
+ <pre id="test">
+ <script class="testbody" type="text/javascript">
+
+ // Tests that a fragmented MP4 file without a PSSH, but with valid encrypted
+ // tracks with valid TENC boxes, is able to load with EME.
+ // We setup MSE before starting up EME, so that we exercise the "waiting for
+ // cdm" step in the MediaDecoderStateMachine.
+
+ SimpleTest.waitForExplicitFinish();
+
+ var pssh = [
+ 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x73, 0x73, 0x68, // BMFF box header (76 bytes, 'pssh')
+ 0x01, 0x00, 0x00, 0x00, // Full box header (version = 1, flags = 0)
+ 0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, // SystemID
+ 0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b,
+ 0x00, 0x00, 0x00, 0x01, // KID_count (1)
+ 0x2f, 0xef, 0x8a, 0xd8, 0x12, 0xdf, 0x42, 0x97,
+ 0x83, 0xe9, 0xbf, 0x6e, 0x5e, 0x49, 0x3e, 0x53,
+ 0x00, 0x00, 0x00, 0x00 // Size of Data (0)
+ ];
+
+ var audio = document.getElementById("audio");
+
+ function LoadEME() {
+ var options = [{
+ initDataType: 'cenc',
+ audioType: 'audio/mp4; codecs="mp4a.40.2"',
+ }];
+ navigator.requestMediaKeySystemAccess("org.w3.clearkey", options)
+ .then((keySystemAccess) => {
+ return keySystemAccess.createMediaKeys();
+ }, bail("Failed to request key system access."))
+
+ .then((mediaKeys) => {
+ audio.setMediaKeys(mediaKeys);
+ var session = mediaKeys.createSession();
+ once(session, "message", (message) => {
+ is(message.messageType, 'license-request', "Expected a license-request");
+ var license = new TextEncoder().encode(JSON.stringify({
+ 'keys': [{
+ 'kty':'oct',
+ 'kid':'L--K2BLfQpeD6b9uXkk-Uw',
+ 'k':HexToBase64('7f412f0575f44f718259beef56ec7771')
+ }],
+ 'type': 'temporary'
+ }));
+ session.update(license);
+ });
+ session.generateRequest('cenc', new Uint8Array(pssh));
+ });
+ }
+
+ function DownloadMedia(url, type, mediaSource) {
+ return new Promise(function(resolve, reject) {
+ var sourceBuffer = mediaSource.addSourceBuffer(type);
+ fetchWithXHR(url, (response) => {
+ once(sourceBuffer, "updateend", resolve);
+ sourceBuffer.appendBuffer(new Uint8Array(response));
+ });
+ });
+ }
+
+ function LoadMSE() {
+ var ms = new MediaSource();
+ audio.src = URL.createObjectURL(ms);
+
+ once(ms, "sourceopen", ()=>{
+ DownloadMedia('short-audio-fragmented-cenc-without-pssh.mp4', 'audio/mp4; codecs="mp4a.40.2"', ms)
+ .then(() => { ms.endOfStream(); LoadEME();});
+ });
+
+ audio.addEventListener("loadeddata", SimpleTest.finish);
+ }
+
+ SetupEMEPref(LoadMSE);
+
+ </script>
+ </pre>
+ </body>
+</html>
diff --git a/dom/media/test/test_eme_non_mse_fails.html b/dom/media/test/test_eme_non_mse_fails.html
new file mode 100644
index 000000000..ede3edc5f
--- /dev/null
+++ b/dom/media/test/test_eme_non_mse_fails.html
@@ -0,0 +1,103 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 1131392 - Test that EME does not work for non-MSE media</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="eme.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function DoSetMediaKeys(v, test)
+{
+ var options = [{
+ initDataTypes: ["cenc"],
+ audioCapabilities: [{contentType: test.audioType}],
+ videoCapabilities: [{contentType: test.videoType}],
+ }];
+
+ return navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, options)
+
+ .then(function(keySystemAccess) {
+ return keySystemAccess.createMediaKeys();
+ })
+
+ .catch(function() {
+ ok(false, token + " was not expecting failure (yet)");
+ })
+
+ .then(function(mediaKeys) {
+ return v.setMediaKeys(mediaKeys);
+ });
+}
+
+function TestSetMediaKeys(test, token)
+{
+ manager.started(token);
+
+ var v = document.createElement("video");
+
+ v.addEventListener("encrypted", function() {
+ ok(false, token + " should not fire encrypted event");
+ });
+
+ var loadedMetadata = false;
+ v.addEventListener("loadedmetadata", function() {
+ loadedMetadata = true;
+ });
+
+ v.addEventListener("error", function() {
+ ok(true, token + " expected error event");
+ ok(loadedMetadata, token + " expected loadedmetadata to have fired");
+ manager.finished(token);
+ });
+
+ v.src = test.name;
+}
+
+function TestSetSrc(test, token)
+{
+ manager.started(token);
+
+ var v = document.createElement("video");
+ v.addEventListener("error", function(err) {
+ ok(true, token + " got error setting src on video element, as expected");
+ manager.finished(token);
+ });
+
+ DoSetMediaKeys(v, test)
+
+ .then(function() {
+ v.src = test.name;
+ })
+
+ .catch(function() {
+ ok(false, token + " got error setting media keys");
+ });
+}
+
+function startTest(test, token)
+{
+ TestSetMediaKeys(test, token + "_setMediaKeys");
+ TestSetSrc(test, token + "_setSrc");
+}
+
+function beginTest() {
+ manager.runTests(gEMENonMSEFailTests, startTest);
+}
+
+if (!IsMacOSSnowLeopardOrEarlier()) {
+ SimpleTest.waitForExplicitFinish();
+ SetupEMEPref(beginTest);
+} else {
+ todo(false, "Test disabled on this platform.");
+}
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/media/test/test_eme_playback.html b/dom/media/test/test_eme_playback.html
new file mode 100644
index 000000000..a568402cd
--- /dev/null
+++ b/dom/media/test/test_eme_playback.html
@@ -0,0 +1,188 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test Encrypted Media Extensions</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="http://test1.mochi.test:8888/tests/dom/media/test/eme.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function ArrayBuffersEqual(a, b) {
+ if (a.byteLength != b.byteLength) {
+ return false;
+ }
+ var ua = new Uint8Array(a);
+ var ub = new Uint8Array(b);
+ for (var i = 0; i < ua.length; i++) {
+ if (ua[i] != ub[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+function KeysChangeFunc(session, keys, token) {
+ session.keyIdsReceived = [];
+ for (var keyid in keys) {
+ Log(token, "Set " + keyid + " to false in session[" + session.sessionId + "].keyIdsReceived");
+ session.keyIdsReceived[keyid] = false;
+ }
+ return function(ev) {
+ var session = ev.target;
+ session.gotKeysChanged = true;
+
+ var keyList = [];
+ var valueList = [];
+ var map = session.keyStatuses;
+
+ // Test that accessing keys not known to the CDM has expected behaviour.
+ var absentKey = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
+ 0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]);
+ is(map.has(absentKey), false, "Shouldn't have a key that's not in the media");
+ is(map.get(absentKey), undefined, "Unknown keys should undefined status");
+
+ // Verify known keys have expected status.
+ for (var [key, val] of map.entries()) {
+ is(key.constructor, ArrayBuffer, "keyId should be ArrayBuffer");
+ ok(map.has(key), "MediaKeyStatusMap.has() should work.");
+ is(map.get(key), val, "MediaKeyStatusMap.get() should work.");
+ keyList.push(key);
+ valueList.push(val);
+ is(val, "usable", token + ": key status should be usable");
+ var kid = Base64ToHex(window.btoa(ArrayBufferToString(key)));
+ ok(kid in session.keyIdsReceived, TimeStamp(token) + " session[" + session.sessionId + "].keyIdsReceived contained " + kid + " as expected.");
+ session.keyIdsReceived[kid] = true;
+ }
+
+ var index = 0;
+ for (var keyId of map.keys()) {
+ ok(ArrayBuffersEqual(keyId, keyList[index]), "MediaKeyStatusMap.keys() should correspond to entries");
+ index++;
+ }
+ index = 0;
+ for (var val of map.values()) {
+ is(val, valueList[index], "MediaKeyStatusMap.values() should correspond to entries");
+ index++;
+ }
+ }
+}
+
+function startTest(test, token)
+{
+ manager.started(token);
+
+ var sessions = [];
+
+ var v = SetupEME(test, token,
+ {
+ onsessioncreated: function(session) {
+ sessions.push(session);
+ session.addEventListener("keystatuseschange", KeysChangeFunc(session, test.keys, token), false);
+
+ session.numKeystatuseschangeEvents = 0;
+ session.numOnkeystatuseschangeEvents = 0;
+
+ session.addEventListener("keystatuseschange", function() {
+ session.numKeystatuseschangeEvents += 1;
+ });
+ session.onkeystatuseschange = function() {
+ session.numOnkeystatuseschangeEvents += 1;
+ };
+
+ session.numMessageEvents = 0;
+ session.numOnMessageEvents = 0;
+ session.addEventListener("message", function() {
+ session.numMessageEvents += 1;
+ });
+ session.onmessage = function() {
+ session.numOnMessageEvents += 1;
+ };
+ }
+ }
+ );
+
+ document.body.appendChild(v);
+
+ var gotEncrypted = 0;
+
+ v.addEventListener("encrypted", function(ev) {
+ gotEncrypted += 1;
+ });
+
+ v.addEventListener("loadedmetadata", function() {
+ ok(SpecialPowers.do_lookupGetter(v, "isEncrypted").apply(v),
+ TimeStamp(token) + " isEncrypted should be true");
+ is(v.isEncrypted, undefined, "isEncrypted should not be accessible from content");
+ });
+
+ v.addEventListener("ended", function(ev) {
+ ok(true, TimeStamp(token) + " got ended event");
+
+ is(gotEncrypted, test.sessionCount,
+ TimeStamp(token) + " encrypted events expected: " + test.sessionCount
+ + ", actual: " + gotEncrypted);
+
+ ok(Math.abs(test.duration - v.duration) < 0.1,
+ TimeStamp(token) + " Duration of video should be corrrect");
+ ok(Math.abs(test.duration - v.currentTime) < 0.1,
+ TimeStamp(token) + " Current time should be same as duration");
+
+ // Verify all sessions had all keys went sent to the CDM usable, and thus
+ // that we received keystatuseschange event(s).
+ is(sessions.length, test.sessionCount, TimeStamp(token) + " should have "
+ + test.sessionCount
+ + " session" + (test.sessionCount === 1 ? "" : "s"));
+ var keyIdsReceived = [];
+ for (var keyid in test.keys) { keyIdsReceived[keyid] = false; }
+ for (var i = 0; i < sessions.length; i++) {
+ var session = sessions[i];
+ ok(session.gotKeysChanged,
+ TimeStamp(token) + " session[" + session.sessionId
+ + "] should have received at least one keychange event");
+ for (var kid in session.keyIdsReceived) {
+ Log(token, "session[" + session.sessionId + "] key " + kid + " = " + (session.keyIdsReceived[kid] ? "true" : "false"));
+ if (session.keyIdsReceived[kid]) { keyIdsReceived[kid] = true; }
+ }
+ ok(session.numKeystatuseschangeEvents > 0, TimeStamp(token) + " should get key status changes");
+ is(session.numKeystatuseschangeEvents, session.numOnkeystatuseschangeEvents,
+ TimeStamp(token) + " should have as many keystatuseschange event listener calls as event handler calls.");
+
+ ok(session.numMessageEvents > 0, TimeStamp(token) + " should get message events");
+ is(session.numMessageEvents, session.numOnMessageEvents,
+ TimeStamp(token) + " should have as many message event listener calls as event handler calls.");
+ }
+ for (var kid in keyIdsReceived) {
+ ok(keyIdsReceived[kid], TimeStamp(token) + " key with id " + kid + " was usable as expected");
+ }
+
+ v.closeSessions().then(() => manager.finished(token));
+ });
+
+ LoadTest(test, v, token)
+ .then(function() {
+ v.play();
+ }).catch(function() {
+ ok(false, token + " failed to load");
+ manager.finished(token);
+ });
+}
+
+function beginTest() {
+ manager.runTests(gEMETests, startTest);
+}
+
+if (!IsMacOSSnowLeopardOrEarlier()) {
+ SimpleTest.waitForExplicitFinish();
+ SetupEMEPref(beginTest);
+} else {
+ todo(false, "Test disabled on this platform.");
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_eme_requestKeySystemAccess.html b/dom/media/test/test_eme_requestKeySystemAccess.html
new file mode 100644
index 000000000..21ee91a68
--- /dev/null
+++ b/dom/media/test/test_eme_requestKeySystemAccess.html
@@ -0,0 +1,484 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test Encrypted Media Extensions</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="eme.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+const SUPPORTED_LABEL = "pass label";
+
+function ValidateConfig(name, expected, observed) {
+ info("ValidateConfig " + name);
+ info("expected cfg=" + JSON.stringify(expected));
+ info("observed cfg=" + JSON.stringify(observed));
+
+ is(observed.label, expected.label, name + " label should match");
+ if (expected.initDataTypes) {
+ ok(expected.initDataTypes.every((element, index, array) => observed.initDataTypes.includes(element)), name + " initDataTypes should match.");
+ }
+
+ if (expected.audioCapabilities) {
+ ok(expected.audioCapabilities.length == 1, "Test function can only handle one capability.");
+ ok(observed.audioCapabilities.length == 1, "Test function can only handle one capability.");
+ is(observed.audioCapabilities[0].contentType, expected.audioCapabilities[0].contentType, name + " audioCapabilities should match.");
+ }
+ if (typeof expected.videoCapabilities !== 'undefined') {
+ info("expected.videoCapabilities=" + expected.videoCapabilities);
+ dump("expected.videoCapabilities=" + expected.videoCapabilities + "\n");
+ ok(expected.videoCapabilities.length == 1, "Test function can only handle one capability.");
+ ok(observed.videoCapabilities.length == 1, "Test function can only handle one capability.");
+ is(observed.videoCapabilities[0].contentType, expected.videoCapabilities[0].contentType, name + " videoCapabilities should match.");
+ }
+ if (expected.sessionTypes) {
+ is(expected.sessionTypes.length, observed.sessionTypes.length, "Should have expected number of sessionTypes");
+ for (var i = 0; i < expected.sessionTypes.length; i++) {
+ is(expected[i], observed[i], "Session type " + i + " should match");
+ }
+ }
+}
+
+function Test(test) {
+ var name = "'" + test.name + "'";
+ return new Promise(function(resolve, reject) {
+ var p;
+ if (test.options) {
+ var keySystem = (test.keySystem !== undefined) ? test.keySystem : CLEARKEY_KEYSYSTEM;
+ p = navigator.requestMediaKeySystemAccess(keySystem, test.options);
+ } else {
+ p = navigator.requestMediaKeySystemAccess(keySystem);
+ }
+ p.then(
+ function(keySystemAccess) {
+ ok(test.shouldPass, name + " passed and was expected to " + (test.shouldPass ? "pass" : "fail"));
+ is(keySystemAccess.keySystem, CLEARKEY_KEYSYSTEM, "CDM keySystem should be in MediaKeySystemAccess.keySystem");
+ ValidateConfig(name, test.expectedConfig, keySystemAccess.getConfiguration());
+ resolve();
+ },
+ function(ex) {
+ if (test.shouldPass) {
+ info(name + " failed: " + ex);
+ }
+ ok(!test.shouldPass, name + " failed and was expected to " + (test.shouldPass ? "pass" : "fail"));
+ resolve();
+ });
+ });
+}
+
+var tests = [
+ {
+ name: 'Empty keySystem string',
+ keySystem: '',
+ options: [
+ {
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4'}],
+ }
+ ],
+ shouldPass: false,
+ },
+ {
+ name: 'Empty options specified',
+ options: [ ],
+ shouldPass: false,
+ },
+ {
+ name: 'Undefined options',
+ shouldPass: false,
+ },
+ {
+ name: 'Basic MP4 cenc',
+ options: [
+ {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['cenc'],
+ audioCapabilities: [{contentType: 'audio/mp4'}],
+ videoCapabilities: [{contentType: 'video/mp4'}],
+ }
+ ],
+ expectedConfig: {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['cenc'],
+ audioCapabilities: [{contentType: 'audio/mp4'}],
+ videoCapabilities: [{contentType: 'video/mp4'}],
+ },
+ shouldPass: true,
+ },
+ {
+ name: 'Invalid keysystem failure',
+ keySystem: 'bogusKeySystem',
+ options: [
+ {
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4'}],
+ }
+ ],
+ shouldPass: false,
+ },
+ {
+ name: 'Invalid initDataType',
+ options: [
+ {
+ initDataTypes: ['bogus'],
+ audioCapabilities: [{contentType: 'audio/mp4'}],
+ }
+ ],
+ shouldPass: false,
+ },
+ {
+ name: 'Valid initDataType after invalid',
+ options: [
+ {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['bogus', 'invalid', 'cenc'],
+ audioCapabilities: [{contentType: 'audio/mp4'}],
+ }
+ ],
+ expectedConfig: {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['cenc'],
+ audioCapabilities: [{contentType: 'audio/mp4'}],
+ },
+ shouldPass: true,
+ },
+ {
+ name: 'Invalid videoType',
+ options: [
+ {
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/bogus'}],
+ }
+ ],
+ shouldPass: false,
+ },
+ {
+ name: 'Invalid distinctiveIdentifier fails',
+ options: [
+ {
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4'}],
+ distinctiveIdentifier: 'bogus',
+ persistentState: 'bogus',
+ }
+ ],
+ shouldPass: false,
+ },
+ {
+ name: 'distinctiveIdentifier is prohibited for ClearKey',
+ options: [
+ {
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4'}],
+ distinctiveIdentifier: 'required',
+ }
+ ],
+ shouldPass: false,
+ },
+ {
+ name: 'Invalid persistentState fails',
+ options: [
+ {
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4'}],
+ persistentState: 'bogus',
+ }
+ ],
+ shouldPass: false,
+ },
+ {
+ name: 'Invalid robustness unsupported',
+ options: [
+ {
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4', robustness: 'very much so'}],
+ }
+ ],
+ shouldPass: false,
+ },
+ {
+ name: 'Unexpected config entry should be ignored',
+ options: [
+ {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4'}],
+ unexpectedEntry: 'this should be ignored',
+ }
+ ],
+ expectedConfig: {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4'}],
+ },
+ shouldPass: true,
+ },
+ {
+ name: 'Invalid option followed by valid',
+ options: [
+ {
+ label: "this config should not be supported",
+ initDataTypes: ['bogus'],
+ },
+ {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4'}],
+ }
+ ],
+ expectedConfig: {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4'}],
+ },
+ shouldPass: true,
+ },
+ {
+ name: 'Persistent-license should not be supported by ClearKey',
+ options: [
+ {
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4'}],
+ sessionTypes: ['persistent-license'],
+ persistentState: 'optional',
+ }
+ ],
+ shouldPass: false,
+ },
+ {
+ name: 'Persistent-usage-record should not be supported by ClearKey',
+ options: [
+ {
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4'}],
+ sessionTypes: ['persistent-usage-record'],
+ persistentState: 'optional',
+ }
+ ],
+ shouldPass: false,
+ },
+ {
+ name: 'MP4 audio container',
+ options: [
+ {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['cenc'],
+ audioCapabilities: [{contentType: 'audio/mp4'}],
+ }
+ ],
+ expectedConfig: {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['cenc'],
+ audioCapabilities: [{contentType: 'audio/mp4'}],
+ },
+ shouldPass: true,
+ },
+ {
+ name: 'MP4 audio container with AAC-LC',
+ options: [
+ {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['cenc'],
+ audioCapabilities: [{contentType: 'audio/mp4; codecs="mp4a.40.2"'}],
+ }
+ ],
+ expectedConfig: {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['cenc'],
+ audioCapabilities: [{contentType: 'audio/mp4; codecs="mp4a.40.2"'}],
+ },
+ shouldPass: true,
+ },
+ {
+ name: 'MP4 audio container with invalid codecs',
+ options: [
+ {
+ initDataTypes: ['cenc'],
+ audioCapabilities: [{contentType: 'audio/mp4; codecs="bogus"'}],
+ }
+ ],
+ shouldPass: false,
+ },
+ {
+ name: 'MP4 audio container with mp3 is unsupported',
+ options: [
+ {
+ initDataTypes: ['cenc'],
+ audioCapabilities: [{contentType: 'audio/mp4; codecs="mp3"'}],
+ }
+ ],
+ shouldPass: false,
+ },
+ {
+ name: 'MP4 video container type with an mp3 codec is unsupported',
+ options: [
+ {
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4; codecs="mp3"'}],
+ }
+ ],
+ shouldPass: false,
+ },
+ {
+ name: 'MP4 audio container type with a video codec is unsupported',
+ options: [
+ {
+ initDataTypes: ['cenc'],
+ audioCapabilities: [{contentType: 'audio/mp4; codecs="avc1.42E01E"'}],
+ }
+ ],
+ shouldPass: false,
+ },
+ {
+ name: 'MP4 video container with constrained baseline h.264',
+ options: [
+ {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4; codecs="avc1.42E01E"'}],
+ }
+ ],
+ expectedConfig: {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4; codecs="avc1.42E01E"'}],
+ },
+ shouldPass: true,
+ },
+ {
+ name: 'MP4 video container with invalid codecs',
+ options: [
+ {
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4; codecs="bogus"'}],
+ }
+ ],
+ shouldPass: false,
+ },
+ {
+ name: 'MP4 video container with both audio and video codec type in videoType',
+ options: [
+ {
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4; codecs="avc1.42E01E,mp4a.40.2"'}],
+ }
+ ],
+ shouldPass: false,
+ },
+ {
+ name: 'MP4 audio and video type both specified',
+ options: [
+ {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4; codecs="avc1.42E01E"'}],
+ audioCapabilities: [{contentType: 'audio/mp4; codecs="mp4a.40.2"'}],
+ }
+ ],
+ expectedConfig: {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['cenc'],
+ videoCapabilities: [{contentType: 'video/mp4; codecs="avc1.42E01E"'}],
+ audioCapabilities: [{contentType: 'audio/mp4; codecs="mp4a.40.2"'}],
+ },
+ shouldPass: true,
+ },
+ {
+ name: 'Basic WebM video',
+ options: [
+ {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['webm'],
+ videoCapabilities: [{contentType: 'video/webm'}],
+ }
+ ],
+ expectedConfig: {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['webm'],
+ videoCapabilities: [{contentType: 'video/webm'}],
+ },
+ shouldPass: true,
+ },
+ {
+ name: 'Basic WebM audio',
+ options: [
+ {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['webm'],
+ audioCapabilities: [{contentType: 'audio/webm'}],
+ }
+ ],
+ expectedConfig: {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['webm'],
+ audioCapabilities: [{contentType: 'audio/webm'}],
+ },
+ shouldPass: true,
+ },
+ {
+ name: 'Webm with Vorbis audio and VP8 video.',
+ options: [
+ {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['webm'],
+ videoCapabilities: [{contentType: 'video/webm;codecs="vp8"'}],
+ audioCapabilities: [{contentType: 'audio/webm;codecs="vorbis"'}],
+ }
+ ],
+ expectedConfig: {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['webm'],
+ videoCapabilities: [{contentType: 'video/webm;codecs="vp8"'}],
+ audioCapabilities: [{contentType: 'audio/webm;codecs="vorbis"'}],
+ },
+ shouldPass: true,
+ },
+ {
+ name: 'Webm with Vorbis audio and VP9 video.',
+ options: [
+ {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['webm'],
+ videoCapabilities: [{contentType: 'video/webm;codecs="vp9"'}],
+ audioCapabilities: [{contentType: 'audio/webm;codecs="vorbis"'}],
+ }
+ ],
+ expectedConfig: {
+ label: SUPPORTED_LABEL,
+ initDataTypes: ['webm'],
+ videoCapabilities: [{contentType: 'video/webm;codecs="vp9"'}],
+ audioCapabilities: [{contentType: 'audio/webm;codecs="vorbis"'}],
+ },
+ shouldPass: true,
+ },
+ {
+ name: 'Webm with bogus video.',
+ options: [
+ {
+ initDataTypes: ['webm'],
+ videoCapabilities: [{contentType: 'video/webm;codecs="bogus"'}],
+ }
+ ],
+ shouldPass: false,
+ },
+];
+
+function beginTest() {
+ Promise.all(tests.map(Test)).then(function() { SimpleTest.finish(); });
+}
+
+if (!IsMacOSSnowLeopardOrEarlier()) {
+ SimpleTest.waitForExplicitFinish();
+ SetupEMEPref(beginTest);
+} else {
+ todo(false, "Test disabled on this platform.");
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_eme_request_notifications.html b/dom/media/test/test_eme_request_notifications.html
new file mode 100644
index 000000000..c2fab5b15
--- /dev/null
+++ b/dom/media/test/test_eme_request_notifications.html
@@ -0,0 +1,88 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test Encrypted Media Extensions</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="eme.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function SetPrefs(prefs) {
+ return new Promise(function(resolve, reject) {
+ SpecialPowers.pushPrefEnv({"set": prefs}, function() { resolve(); });
+ });
+}
+
+function observe() {
+ return new Promise(function(resolve, reject) {
+ var observer = function(subject, topic, data) {
+ SpecialPowers.Services.obs.removeObserver(observer, "mediakeys-request");
+ resolve(JSON.parse(data).status);
+ };
+ SpecialPowers.Services.obs.addObserver(observer, "mediakeys-request", false);
+ });
+}
+
+function Test(test) {
+ var p = test.prefs ? SetPrefs(test.prefs) : Promise.resolve();
+ observedStatus = "nothing";
+ var name = "'" + test.keySystem + "'";
+
+ var res = observe().then((status) => {
+ is(status, test.expectedStatus, name + " expected status");
+ });
+
+ p.then(() => navigator.requestMediaKeySystemAccess(test.keySystem, gCencMediaKeySystemConfig))
+ .then((keySystemAccess) => keySystemAccess.createMediaKeys());
+
+ return res;
+}
+
+const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1;
+
+var tests = [
+ {
+ keySystem: CLEARKEY_KEYSYSTEM,
+ expectedStatus: 'cdm-created',
+ prefs: [["media.eme.enabled", false]]
+ },
+ {
+ keySystem: "com.widevine.alpha",
+ expectedStatus: 'api-disabled',
+ prefs: [["media.eme.enabled", false]]
+ },
+ {
+ keySystem: "com.widevine.alpha",
+ expectedStatus: (isWinXP ? 'cdm-not-supported' : 'cdm-disabled'),
+ prefs: [["media.eme.enabled", true], ["media.gmp-widevinecdm.enabled", false]]
+ },
+ {
+ keySystem: "com.widevine.alpha",
+ expectedStatus: (isWinXP ? 'cdm-not-supported' : 'cdm-not-installed'),
+ prefs: [["media.eme.enabled", true], , ["media.gmp-widevinecdm.enabled", true]]
+ },
+ {
+ keySystem: CLEARKEY_KEYSYSTEM,
+ expectedStatus: 'cdm-created',
+ prefs: [["media.eme.enabled", true]]
+ }
+];
+
+SetupEMEPref(function() {
+ tests.reduce(function(p,c,i,array) {
+ return p.then(function() { return Test(c); });
+ }, Promise.resolve()).then(SimpleTest.finish);
+});
+
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_eme_session_callable_value.html b/dom/media/test/test_eme_session_callable_value.html
new file mode 100644
index 000000000..5c5f51e30
--- /dev/null
+++ b/dom/media/test/test_eme_session_callable_value.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test Encrypted Media Extensions</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="eme.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function Test() {
+ navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, gCencMediaKeySystemConfig)
+ .then(access => access.createMediaKeys())
+ .then(mediaKeys => {
+ var initData = (new TextEncoder()).encode( 'this is an invalid license, and that is ok');
+ var s = mediaKeys.createSession("temporary");
+ s.generateRequest("cenc", initData); // ignore result.
+ // "update()" call should fail, because MediaKeySession is "not callable"
+ // yet, since CDM won't have had a chance to set the sessionId on MediaKeySession.
+ return s.update(initData);
+ })
+ .then(()=>{ok(false, "An exception should be thrown; MediaKeySession should be not callable."); SimpleTest.finish();},
+ ()=>{ok(true, "We expect this to fail; MediaKeySession should be not callable."); SimpleTest.finish();});
+}
+
+SimpleTest.waitForExplicitFinish();
+SetupEMEPref(Test);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_eme_setMediaKeys_before_attach_MediaSource.html b/dom/media/test/test_eme_setMediaKeys_before_attach_MediaSource.html
new file mode 100644
index 000000000..72bc77124
--- /dev/null
+++ b/dom/media/test/test_eme_setMediaKeys_before_attach_MediaSource.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test Encrypted Media Extensions</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="eme.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function beginTest() {
+ var video = document.createElement("video");
+
+ navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, gCencMediaKeySystemConfig)
+ .then(function(keySystemAccess) {
+ return keySystemAccess.createMediaKeys();
+ })
+ .then(mediaKeys => {
+ return video.setMediaKeys(mediaKeys);
+ })
+ .then(() => {
+ var ms = new MediaSource();
+ ms.addEventListener("sourceopen", ()=>{ok(true, "MediaSource should open"); SimpleTest.finish();});
+ video.addEventListener("error", ()=>{ok(false, "Shouldn't error."); SimpleTest.finish();});
+ video.src = URL.createObjectURL(ms);
+ });
+}
+
+if (!IsMacOSSnowLeopardOrEarlier()) {
+ SimpleTest.waitForExplicitFinish();
+ SetupEMEPref(beginTest);
+} else {
+ todo(false, "Test disabled on this platform.");
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_eme_stream_capture_blocked_case1.html b/dom/media/test/test_eme_stream_capture_blocked_case1.html
new file mode 100644
index 000000000..61e8d673f
--- /dev/null
+++ b/dom/media/test/test_eme_stream_capture_blocked_case1.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test Encrypted Media Extensions</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="eme.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function startTest(test, token)
+{
+ // Three cases:
+ // 1. setting MediaKeys on an element captured by MediaElementSource should fail, and
+ // 2. creating a MediaElementSource on a media element with a MediaKeys should fail, and
+ // 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
+
+ // Case 1. setting MediaKeys on an element captured by MediaElementSource should fail.
+ var case1token = token + "_case1";
+ var setKeysFailed = function() {
+ ok(true, TimeStamp(case1token) + " setMediaKeys failed as expected.");
+ manager.finished(case1token);
+ };
+ var v1 = SetupEME(test, case1token, { onSetKeysFail: setKeysFailed });
+ var context = new AudioContext();
+ var node = context.createMediaElementSource(v1);
+ v1.addEventListener("loadeddata", function(ev) {
+ ok(false, TimeStamp(case1token) + " should never reach loadeddata, as setMediaKeys should fail");
+ });
+ manager.started(case1token);
+ LoadTestWithManagedLoadToken(test, v1, manager, case1token,
+ { onlyLoadFirstFragments:2, noEndOfStream:false });
+}
+
+function beginTest() {
+ manager.runTests(gEMETests, startTest);
+}
+
+if (!IsMacOSSnowLeopardOrEarlier()) {
+ SimpleTest.waitForExplicitFinish();
+ SetupEMEPref(beginTest);
+} else {
+ todo(false, "Test disabled on this platform.");
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_eme_stream_capture_blocked_case2.html b/dom/media/test/test_eme_stream_capture_blocked_case2.html
new file mode 100644
index 000000000..48c8bf3e4
--- /dev/null
+++ b/dom/media/test/test_eme_stream_capture_blocked_case2.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test Encrypted Media Extensions</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="eme.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function startTest(test, token)
+{
+ // Three cases:
+ // 1. setting MediaKeys on an element captured by MediaElementSource should fail, and
+ // 2. creating a MediaElementSource on a media element with a MediaKeys should fail, and
+ // 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
+
+ // Case 2. creating a MediaElementSource on a media element with a MediaKeys should fail.
+ var case2token = token + "_case2";
+ var v2 = SetupEME(test, case2token);
+ v2.addEventListener("loadeddata", function(ev) {
+ ok(true, case2token + " should reach loadeddata");
+ var threw = false;
+ try {
+ var context = new AudioContext();
+ var node = context.createMediaElementSource(v2);
+ } catch (e) {
+ threw = true;
+ }
+ ok(threw, "Should throw an error creating a MediaElementSource on an EME video.");
+ manager.finished(case2token);
+ });
+ manager.started(case2token);
+ LoadTestWithManagedLoadToken(test, v2, manager, case2token,
+ { onlyLoadFirstFragments:2, noEndOfStream:false });
+}
+
+function beginTest() {
+ manager.runTests(gEMETests, startTest);
+}
+
+if (!IsMacOSSnowLeopardOrEarlier()) {
+ SimpleTest.waitForExplicitFinish();
+ SetupEMEPref(beginTest);
+} else {
+ todo(false, "Test disabled on this platform.");
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_eme_stream_capture_blocked_case3.html b/dom/media/test/test_eme_stream_capture_blocked_case3.html
new file mode 100644
index 000000000..1af4e0aad
--- /dev/null
+++ b/dom/media/test/test_eme_stream_capture_blocked_case3.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test Encrypted Media Extensions</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="eme.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function startTest(test, token)
+{
+ // Three cases:
+ // 1. setting MediaKeys on an element captured by MediaElementSource should fail, and
+ // 2. creating a MediaElementSource on a media element with a MediaKeys should fail, and
+ // 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
+
+ // Case 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail.
+ var case3token = token + "_case3";
+ var v3 = SetupEME(test, case3token);
+ v3.addEventListener("loadeddata", function(ev) {
+ ok(true, TimeStamp(case3token) + " should reach loadeddata");
+ var threw = false;
+ try {
+ var stream = v3.mozCaptureStreamUntilEnded();
+ } catch (e) {
+ threw = true;
+ }
+ ok(threw, TimeStamp(case3token) + " Should throw an error calling mozCaptureStreamUntilEnded an EME video.");
+ manager.finished(case3token);
+ });
+ manager.started(case3token);
+ LoadTestWithManagedLoadToken(test, v3, manager, case3token,
+ { onlyLoadFirstFragments:2, noEndOfStream:false });
+}
+
+function beginTest() {
+ manager.runTests(gEMETests, startTest);
+}
+
+if (!IsMacOSSnowLeopardOrEarlier()) {
+ SimpleTest.waitForExplicitFinish();
+ SetupEMEPref(beginTest);
+} else {
+ todo(false, "Test disabled on this platform.");
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_eme_waitingforkey.html b/dom/media/test/test_eme_waitingforkey.html
new file mode 100644
index 000000000..ce808342b
--- /dev/null
+++ b/dom/media/test/test_eme_waitingforkey.html
@@ -0,0 +1,117 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test Encrypted Media Extensions</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="http://test1.mochi.test:8888/tests/dom/media/test/eme.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function startTest(test, token)
+{
+ // Test if the appropriate preconditions are met such that we can start
+ // prcoessing delayed sessions.
+ function TestIfDoneDelaying()
+ {
+ var got = "Got:";
+ if (loaded) { got += " loaded,"; }
+ got += " " + gotEncrypted + "/" + test.sessionCount + " sessions,";
+ got += " " + gotWaitingForKey + " waiting for key events"
+ if (loaded && gotEncrypted == test.sessionCount && gotWaitingForKey > 0) {
+ Log(token, got + " -> Update sessions with keys");
+ params.ProcessSessions();
+ } else {
+ Log(token, got + " -> Wait for more...");
+ }
+ }
+
+ manager.started(token);
+
+ var updatedSessionsCount = 0;
+ var loaded = false;
+
+ var params = {
+ // params will be populated with a ProcessSessions() callback, that can be
+ // called to process delayed sessions.
+ delaySessions: true,
+ // Function to be called once we start processing and updating sessions.
+ // This should only be called once the preconditions in TestIfDoneDealying
+ // are met.
+ onsessionupdated: function(session) {
+ updatedSessionsCount += 1;
+ if (updatedSessionsCount == test.sessionCount) {
+ info(TimeStamp(token) + " Updated all sessions, loading complete -> Play");
+ v.play();
+ } else {
+ info(TimeStamp(token) + " Updated " + updatedSessionsCount + "/" + test.sessionCount + " sessions so far");
+ }
+ },
+ };
+ var v = SetupEME(test, token, params);
+
+ document.body.appendChild(v);
+
+ var gotEncrypted = 0;
+ var gotWaitingForKey = 0;
+ var gotOnwaitingforkey = 0;
+
+ v.addEventListener("encrypted", function() {
+ gotEncrypted += 1;
+ TestIfDoneDelaying();
+ });
+
+ v.addEventListener("waitingforkey", function() {
+ gotWaitingForKey += 1;
+ TestIfDoneDelaying()
+ });
+
+ v.onwaitingforkey = function() {
+ gotOnwaitingforkey += 1;
+ };
+
+ v.addEventListener("loadedmetadata", function() {
+ ok(SpecialPowers.do_lookupGetter(v, "isEncrypted").apply(v),
+ TimeStamp(token) + " isEncrypted should be true");
+ is(v.isEncrypted, undefined, "isEncrypted should not be accessible from content");
+ });
+
+ v.addEventListener("ended", function() {
+ ok(true, TimeStamp(token) + " got ended event");
+ // We expect only one waitingForKey as we delay until all sessions are ready.
+ // I.e. one waitingForKey should be fired, after which, we process all sessions,
+ // so it should not be possible to be blocked by a key after that point.
+ ok(gotWaitingForKey == 1, "Expected number 1 wait, got: " + gotWaitingForKey);
+ ok(gotOnwaitingforkey == gotWaitingForKey, "Should have as many event listener calls as event handler calls, got: " + gotOnwaitingforkey);
+
+ v.closeSessions().then(() => manager.finished(token));
+ });
+
+ LoadTest(test, v, token)
+ .then(function() {
+ loaded = true;
+ TestIfDoneDelaying();
+ }).catch(function() {
+ ok(false, token + " failed to load");
+ manager.finished(token);
+ });
+}
+
+function beginTest() {
+ manager.runTests(gEMETests, startTest);
+}
+
+if (!IsMacOSSnowLeopardOrEarlier()) {
+ SimpleTest.waitForExplicitFinish();
+ SetupEMEPref(beginTest);
+} else {
+ todo(false, "Test disabled on this platform.");
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_empty_resource.html b/dom/media/test/test_empty_resource.html
new file mode 100644
index 000000000..da3f54cee
--- /dev/null
+++ b/dom/media/test/test_empty_resource.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1094549
+-->
+<head>
+ <title>Test for Bug 1094549</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1094549">Mozilla Bug 1094549</a>
+
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+// Shorter timeout for this test should finish soon.
+SimpleTest.requestLongerTimeout(0.3);
+
+function finish(v) {
+ isnot(v.error, null, "should've got an error event");
+ SimpleTest.finish();
+}
+
+function onload() {
+ info("iframe loaded");
+ var v = document.body.getElementsByTagName("iframe")[0]
+ .contentDocument.body.getElementsByTagName("video")[0];
+
+ // Got 'error' as expected, finish the test.
+ if (v.error) {
+ finish(v);
+ return;
+ }
+
+ // Otherwise, wait for it.
+ v.onerror = function() {
+ finish(v);
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+var f = document.createElement("iframe");
+// Assign a resource file with zero length and expect the error event from
+// the video element since decoding metadata will fail.
+f.src = "data:video/webm,";
+f.addEventListener("load", onload, false);
+document.body.appendChild(f);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_error_in_video_document.html b/dom/media/test/test_error_in_video_document.html
new file mode 100644
index 000000000..f0404c4d8
--- /dev/null
+++ b/dom/media/test/test_error_in_video_document.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=604067
+-->
+<head>
+ <title>Test for Bug 604067</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=604067">Mozilla Bug 604067</a>
+
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 604067 **/
+
+function documentVideo() {
+ return document.body.getElementsByTagName("iframe")[0]
+ .contentDocument.body.getElementsByTagName("video")[0];
+}
+
+function check() {
+ var v = documentVideo();
+
+ // Debug info for Bug 608634
+ ok(true, "iframe src=" + document.body.getElementsByTagName("iframe")[0].src);
+ is(v.readyState, v.HAVE_NOTHING, "Ready state");
+
+ isnot(v.error, null, "Error object");
+ is(v.networkState, v.NETWORK_NO_SOURCE, "Network state");
+ is(v.error.code, MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED, "Expected media not supported error");
+ SimpleTest.finish();
+}
+
+// Find an error test that we'd think we should be able to play (if it
+// wasn't already known to fail).
+var t = getPlayableVideo(gErrorTests);
+if (!t) {
+ todo(false, "No types supported");
+} else {
+ SimpleTest.waitForExplicitFinish();
+
+ var f = document.createElement("iframe");
+ f.src = t.name;
+ f.addEventListener("load", function() {
+ if (documentVideo().error) {
+ info("Error occured by the time we got |load| - checking directly.");
+ check();
+ } else {
+ //TODO: Fix this todo in Bug 1295923.
+ todo(false, "Error hasn't occurred yet - adding |error| event listener. This shouldn't happen, see bug 608634.");
+ documentVideo().addEventListener("error", check);
+ }
+ }, false);
+ document.body.appendChild(f);
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_error_on_404.html b/dom/media/test/test_error_on_404.html
new file mode 100644
index 000000000..e49f03e22
--- /dev/null
+++ b/dom/media/test/test_error_on_404.html
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=476731
+-->
+<head>
+ <title>Test for Bug 476731</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=476731">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+/** Test for Bug 476731 **/
+
+var videos = [];
+
+function FinishedLoads() {
+ if (videos.length == 0)
+ return false;
+ for (var i=0; i<videos.length; ++i) {
+ if (videos[i]._loadedData) {
+ // A video loadeddata, it should have 404'd. Signal the end of the test
+ // so the error will be reported.
+ return true;
+ }
+ if (!videos[i]._loadError) {
+ return false;
+ }
+ }
+ return true;
+}
+
+function loadError(evt) {
+ var v = evt.target;
+ is(v._loadError, false, "Shouldn't receive multiple error events for " + v.src);
+ v._loadError = true;
+ is(v._loadStart, true, "Receive loadstart for " + v.src);
+ is(v._loadedData, false, "Shouldn't receive loadeddata for " + v.src);
+ if (FinishedLoads(videos))
+ SimpleTest.finish();
+}
+
+function loadedData(evt) {
+ evt.target._loadedData = true;
+}
+
+function loadStart(evt) {
+ evt.target._loadStart = true;
+}
+
+// Create all video objects.
+for (var i=0; i<g404Tests.length; ++i) {
+ var v = document.createElement("video");
+ v.preload = "metadata";
+ var test = g404Tests[i];
+ if (!v.canPlayType(test.type)) {
+ continue;
+ }
+ v.src = test.name;
+ v._loadedData = false;
+ v._loadStart = false;
+ v._loadError = false;
+ v.addEventListener("error", loadError, false);
+ v.addEventListener("loadstart", loadStart, false);
+ v.addEventListener("loadeddata", loadedData, false);
+ document.body.appendChild(v); // Will start load.
+ videos.push(v);
+}
+
+if (videos.length == 0) {
+ todo(false, "No types supported");
+} else {
+ SimpleTest.waitForExplicitFinish();
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_fastSeek-forwards.html b/dom/media/test/test_fastSeek-forwards.html
new file mode 100644
index 000000000..7c16e5151
--- /dev/null
+++ b/dom/media/test/test_fastSeek-forwards.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1022913
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1022913</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1022913">Mozilla Bug 1022913</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+ <script type="application/javascript">
+
+ // Test that if we're doing a fastSeek() forwards that we don't end up
+ // seeking backwards. This can happen if the keyframe before the seek
+ // target is before the current playback position. We'd prefer to seek to
+ // the keyframe after the seek target in this case, but we don't implement
+ // this yet (bug 1026330).
+ var manager = new MediaTestManager;
+
+ var onSecondSeekComplete = function(event) {
+ var v = event.target;
+ v.removeEventListener("seeked", onSecondSeekComplete);
+ ok(v.currentTime >= v.firstSeekTarget, v.name + " seek never go backwards. time=" + v.currentTime + " firstSeekTarget=" + v.firstSeekTarget + " secondSeekTarget=" + v.secondSeekTarget);
+ manager.finished(v.token);
+ removeNodeAndSource(v);
+ };
+
+ var onFirstSeekComplete = function(event) {
+ var v = event.target;
+ v.removeEventListener("seeked", onFirstSeekComplete);
+ // Seek to 75% of the way between the start and the first keyframe
+ // using fastSeek. We then test that the currentTime doesn't drop back
+ // to the previous keyframe, currentTime should go forwards.
+ v.addEventListener("seeked", onSecondSeekComplete);
+ v.secondSeekTarget = v.keyframes[1] * 0.75;
+ v.fastSeek(v.secondSeekTarget);
+ }
+
+ var onLoadedMetadata = function(event) {
+ // Seek to the mid-point between the start and the first keyframe.
+ var v = event.target;
+ v.removeEventListener("loadedmetadata", onLoadedMetadata);
+ v.addEventListener("seeked", onFirstSeekComplete);
+ v.firstSeekTarget = v.keyframes[1] * 0.5;
+ v.currentTime = v.firstSeekTarget;
+ }
+
+ function startTest(test, token) {
+ manager.started(token);
+ v = document.createElement("video");
+ v.src = test.name;
+ v.name = test.name;
+ v.preload = "metadata";
+ v.token = token;
+ v.target = 0;
+ v.keyframes = test.keyframes;
+ v.keyframeIndex = 0;
+ ok(v.keyframes.length >= 2, v.name + " - video should have at least two sync points");
+ v.addEventListener("loadedmetadata", onLoadedMetadata);
+ document.body.appendChild(v);
+ }
+
+ manager.runTests(gFastSeekTests, startTest);
+
+ </script>
+</body>
+</html>
diff --git a/dom/media/test/test_fastSeek.html b/dom/media/test/test_fastSeek.html
new file mode 100644
index 000000000..c14fa531b
--- /dev/null
+++ b/dom/media/test/test_fastSeek.html
@@ -0,0 +1,88 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=778077
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 778077</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=778077">Mozilla Bug 778077</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+ <script type="application/javascript">
+
+ /** Test for Bug 778077 - HTMLMediaElement.fastSeek() **/
+ // Iterate through a list of keyframe timestamps, and seek to
+ // halfway between the keyframe and the keyframe after it.
+ var manager = new MediaTestManager;
+
+ function doSeek(v) {
+ // fastSeek to half way between this keyframe and the next, or if this is the last
+ // keyframe seek to halfway between this keyframe and the end of media.
+ var nextKeyFrame = (v.keyframeIndex + 1) < v.keyframes.length ? v.keyframes[v.keyframeIndex + 1] : v.duration;
+ v.target = (v.keyframes[v.keyframeIndex] + nextKeyFrame) / 2;
+ v.fastSeek(v.target);
+ ok(Math.abs(v.currentTime - v.target) < 0.01,
+ v.name + " seekTo=" + v.target + " currentTime (" + v.currentTime + ") should be close to seek target initially");
+ }
+
+ function onloadedmetadata(event) {
+ var v = event.target;
+ doSeek(v);
+ }
+
+ function onseeked(event) {
+ var v = event.target;
+ var keyframe = v.keyframes[v.keyframeIndex];
+
+ // Check that the current time ended up roughly after the keyframe.
+ // We must be a bit fuzzy here, as the decoder backend may actually
+ // seek to the audio sample prior to the keyframe.
+ ok(v.currentTime >= keyframe - 0.05,
+ v.name + " seekTo=" + v.target + " currentTime (" + v.currentTime +
+ ") should be end up roughly after keyframe (" + keyframe + ") after fastSeek");
+
+ ok(v.currentTime <= v.target,
+ v.name + " seekTo=" + v.target + " currentTime (" + v.currentTime +
+ ") should be end up less than target after fastSeek");
+
+ v.keyframeIndex++
+ if (v.keyframeIndex == v.keyframes.length) {
+ v.src = "";
+ v.parentNode.removeChild(v);
+ manager.finished(v.token);
+ } else {
+ doSeek(v);
+ }
+ }
+
+ function startTest(test, token) {
+ manager.started(token);
+ v = document.createElement("video");
+ v.src = test.name;
+ v.name = test.name;
+ v.preload = "metadata";
+ v.token = token;
+ v.target = 0;
+ v.keyframes = test.keyframes;
+ v.keyframeIndex = 0;
+ ok(v.keyframes.length > 0, v.name + " - video should have at least one sync point");
+ v.addEventListener("loadedmetadata", onloadedmetadata);
+ v.addEventListener("seeked", onseeked);
+ document.body.appendChild(v);
+ }
+
+ manager.runTests(gFastSeekTests, startTest);
+
+ </script>
+</body>
+</html>
diff --git a/dom/media/test/test_fragment_noplay.html b/dom/media/test/test_fragment_noplay.html
new file mode 100644
index 000000000..802ec08c9
--- /dev/null
+++ b/dom/media/test/test_fragment_noplay.html
@@ -0,0 +1,135 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: fragment tests</title>
+ <script type="text/javascript" src="/MochiKit/packed.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="fragment_noplay.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+//longer timeout for slow platforms
+if (isSlowPlatform()) {
+ SimpleTest.requestLongerTimeout(1.5);
+}
+
+var manager = new MediaTestManager;
+
+// Fragment parameters to try
+var gFragmentParams = [
+ // W3C Media fragment tests
+ // http://www.w3.org/2008/WebVideo/Fragments/TC/ua-test-cases
+ { fragment: "#t=banana", start: null, end: null }, // TC0027-UA
+ { fragment: "#t=3,banana", start: null, end: null }, // TC0028-UA
+ { fragment: "#t=banana,7", start: null, end: null }, // TC0029-UA
+ { fragment: "#t='3'", start: null, end: null }, // TC0030-UA
+ { fragment: "#t=3-7", start: null, end: null }, // TC0031-UA
+ { fragment: "#t=3:7", start: null, end: null }, // TC0032-UA
+ { fragment: "#t=3,7,9", start: null, end: null }, // TC0033-UA
+ { fragment: "#t%3D3", start: null, end: null }, // TC0034-UA
+ { fragment: "#%74=3", start: 3, end: null }, // TC0035-UA
+ { fragment: "#t=%33", start: 3, end: null }, // TC0036-UA
+ { fragment: "#t=3%2C7", start: 3, end: 7 }, // TC0037-UA
+ { fragment: "#t=%6Ept:3", start: 3, end: null }, // TC0038-UA
+ { fragment: "#t=npt%3A3", start: 3, end: null }, // TC0039-UA
+ { fragment: "#t=-1,3", start: null, end: null }, // TC0044-UA
+ { fragment: "#t=3&", start: 3, end: null }, // TC0051-UA
+ { fragment: "#u=12&t=3", start: 3, end: null }, // TC0052-UA
+ { fragment: "#t=foo:7&t=npt:3", start: 3, end: null }, // TC0053-UA
+ { fragment: "#&&=&=tom&jerry=&t=3&t=meow:0#", start: 3, end: null }, // TC0054-UA
+ { fragment: "#t=7&t=3", start: 3, end: null }, // TC0055-UA
+ { fragment: "#T=3,7", start: null, end: null }, // TC0058-UA
+ { fragment: "#t=", start: null, end: null }, // TC0061-UA
+ { fragment: "#t=.", start: null, end: null }, // TC0062-UA
+ { fragment: "#t=.0", start: null, end: null }, // TC0063-UA
+ { fragment: "#t=0s", start: null, end: null }, // TC0064-UA
+ { fragment: "#t=,0s", start: null, end: null }, // TC0065-UA
+ { fragment: "#t=0s,0s", start: null, end: null }, // TC0066-UA
+ { fragment: "#t=00:00:00s", start: null, end: null }, // TC0067-UA
+ { fragment: "#t=s", start: null, end: null }, // TC0068-UA
+ { fragment: "#t=npt:", start: null, end: null }, // TC0069-UA
+ { fragment: "#t=1e-1:", start: null, end: null }, // TC0070-UA
+ { fragment: "#t=00:00:01.1e-1", start: null, end: null }, // TC0071-UA
+ { fragment: "#t=3.", start: 3, end: null }, // TC0072-UA
+ { fragment: "#t=0:0:0", start: null, end: null }, // TC0073-UA
+ { fragment: "#t=0:00:60", start: null, end: null }, // TC0074-UA
+ { fragment: "#t=0:01:60", start: null, end: null }, // TC0075-UA
+ { fragment: "#t=0:60:00", start: null, end: null }, // TC0076-UA
+ { fragment: "#t=0:000:000", start: null, end: null }, // TC0077-UA
+ { fragment: "#t=00:00:03,00:00:07", start: 3, end: 7 }, // TC0078-UA
+ { fragment: "#t=3,00:00:07", start: 3, end: 7 }, // TC0079-UA
+ { fragment: "#t=00:00.", start: null, end: null }, // TC0080-UA
+ { fragment: "#t=0:00:00.", start: null, end: null }, // TC0081-UA
+ { fragment: "#t=0:00:10e-1", start: null, end: null }, // TC0082-UA
+ { fragment: "#t=0:00:60.000", start: null, end: null }, // TC0083-UA
+ { fragment: "#t=0:60:00.000", start: null, end: null }, // TC0084-UA
+ { fragment: "#t=3,7&t=foo", start: 3, end: 7 }, // TC0085-UA
+ { fragment: "#foo&t=3,7", start: 3, end: 7 }, // TC0086-UA
+ { fragment: "#t=3,7&foo", start: 3, end: 7 }, // TC0087-UA
+ { fragment: "#t=3,7&&", start: 3, end: 7 }, // TC0088-UA
+ { fragment: "#&t=3,7", start: 3, end: 7 }, // TC0089-UA
+ { fragment: "#&&t=3,7", start: 3, end: 7 }, // TC0090-UA
+ { fragment: "#&t=3,7&", start: 3, end: 7 }, // TC0091-UA
+ { fragment: "#t%3d10", start: null, end: null }, // TC0092-UA
+ { fragment: "#t=10%26", start: null, end: null }, // TC0093-UA
+ { fragment: "#&t=3,7,", start: null, end: null } // TC0094-UA
+];
+
+function createTestArray() {
+ var tests = [];
+ var tmpVid = document.createElement("video");
+
+ for (var testNum=0; testNum<gFragmentTests.length; testNum++) {
+ var test = gFragmentTests[testNum];
+ if (!tmpVid.canPlayType(test.type)) {
+ continue;
+ }
+
+ for (var fragNum=0; fragNum<gFragmentParams.length; fragNum++) {
+ var p = gFragmentParams[fragNum];
+ var t = new Object;
+ t.name = test.name + p.fragment;
+ t.type = test.type;
+ t.duration = test.duration;
+ t.start = p.start;
+ t.end = p.end;
+ tests.push(t);
+ }
+ }
+ return tests;
+}
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ manager.started(token);
+ v.preload = "metadata";
+ v.src = test.name;
+ v.token = token;
+ v.controls = true;
+ document.body.appendChild(v);
+ var name = test.name + " fragment test";
+ var localIs = function(name) { return function(a, b, msg) {
+ is(a, b, name + ": " + msg);
+ }}(name);
+ var localOk = function(name) { return function(a, msg) {
+ ok(a, name + ": " + msg);
+ }}(name);
+ var localFinish = function(v, manager) { return function() {
+ if (v.parentNode) {
+ v.parentNode.removeChild(v);
+ }
+ manager.finished(v.token);
+ }}(v, manager);
+ window['test_fragment_noplay'](v, test.start, test.end, localIs, localOk, localFinish);
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_fragment_play.html b/dom/media/test/test_fragment_play.html
new file mode 100644
index 000000000..cd6e9d141
--- /dev/null
+++ b/dom/media/test/test_fragment_play.html
@@ -0,0 +1,92 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seek tests</title>
+ <script type="text/javascript" src="/MochiKit/packed.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="fragment_play.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+PARALLEL_TESTS = 1;
+var manager = new MediaTestManager;
+
+// Fragment parameters to try. These tests
+// try playing the video. Tests for other fragment
+// formats are in test_fragment_noplay.html.
+var gFragmentParams = [
+ { fragment: "", start: null, end: null },
+ { fragment: "#t=,", start: null, end: null },
+ { fragment: "#t=3,3", start: null, end: null },
+ { fragment: "#t=7,3", start: null, end: null },
+ { fragment: "#t=7,15", start: 7, end: null },
+ { fragment: "#t=15,20", start: 9.287982, end: null },
+ { fragment: "#t=5", start: 5, end: null },
+ { fragment: "#t=5.5", start: 5.5, end: null },
+ { fragment: "#t=5,", start: null, end: null },
+ { fragment: "#t=,5", start: 0, end: 5, todo: "See bugs 682141 and 720248" },
+ { fragment: "#t=2.5,5.5", start: 2.5, end: 5.5, todo: "See bugs 682141 and 720248" },
+ { fragment: "#t=1,2.5", start: 1, end: 2.5, todo: "See bugs 682141 and 720248" },
+ { fragment: "#t=,15", start: 0, end: null }
+];
+
+function createTestArray() {
+ var tests = [];
+ var tmpVid = document.createElement("video");
+
+ for (var testNum=0; testNum<gFragmentTests.length; testNum++) {
+ var test = gFragmentTests[testNum];
+ if (!tmpVid.canPlayType(test.type)) {
+ continue;
+ }
+
+ for (var fragNum=0; fragNum<gFragmentParams.length; fragNum++) {
+ var p = gFragmentParams[fragNum];
+ var t = new Object;
+ t.name = test.name + p.fragment;
+ t.type = test.type;
+ t.duration = test.duration;
+ t.start = p.start;
+ t.end = p.end;
+ t.todo = p.todo;
+ tests.push(t);
+ }
+ }
+ return tests;
+}
+
+function startTest(test, token) {
+ if (test.todo) {
+ todo(false, test.todo);
+ return;
+ }
+ var v = document.createElement('video');
+ manager.started(token);
+ v.preload = "metadata";
+ v.src = test.name;
+ v.token = token;
+ v.controls = true;
+ document.body.appendChild(v);
+ var name = test.name + " fragment test";
+ var localIs = function(name) { return function(a, b, msg) {
+ is(a, b, name + ": " + msg);
+ }}(name);
+ var localOk = function(name) { return function(a, msg) {
+ ok(a, name + ": " + msg);
+ }}(name);
+ var localFinish = function(v, manager) { return function() {
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+ }}(v, manager);
+ window['test_fragment_play'](v, test.start, test.end, localIs, localOk, localFinish);
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_gmp_playback.html b/dom/media/test/test_gmp_playback.html
new file mode 100644
index 000000000..b65a4203c
--- /dev/null
+++ b/dom/media/test/test_gmp_playback.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test playback of media files that should play OK</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function startTest() {
+ var v = document.createElement("video");
+ ok(v.canPlayType('video/mp4; codecs="avc1.64000d,mp4a.40.2"') != "",
+ "Should be able to play MP4/H.264/AAC via <video> using GMP");
+ v.src = "short.mp4";
+ v.addEventListener("ended", function(event) {
+ ok(true, "Reached end");
+ SimpleTest.finish();
+ });
+ document.body.appendChild(v);
+ v.play();
+}
+
+var testPrefs = [
+ ['media.gmp.decoder.aac', 1], // gmp-clearkey
+ ['media.gmp.decoder.h264', 1], // gmp-clearkey
+ ['media.gmp.decoder.enabled', true]
+];
+
+SpecialPowers.pushPrefEnv({'set': testPrefs}, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_imagecapture.html b/dom/media/test/test_imagecapture.html
new file mode 100644
index 000000000..f6da9e231
--- /dev/null
+++ b/dom/media/test/test_imagecapture.html
@@ -0,0 +1,156 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1041393
+-->
+<head>
+ <meta charset="utf-8">
+ <title>ImageCapture tests</title>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1041393">ImageCapture tests</a>
+<script type="application/javascript">
+
+var repeat = 100;
+var count;
+
+// Check if the callback returns even no JS reference on it.
+function gcTest(track) {
+ return new Promise(function(resolve, reject) {
+ count = 0;
+ var i;
+ var imageCapture;
+ for(i = 0; i < repeat; i++) {
+ imageCapture = new ImageCapture(track);
+ imageCapture.onphoto = function(blob) {
+ count++;
+ if (count == repeat) {
+ ok(true, "pass gc testing");
+ resolve(track);
+ }
+ };
+ imageCapture.onerror = function(error) {
+ ok(false, "takePhoto failure in gc testing");
+ reject();
+ };
+
+ imageCapture.takePhoto();
+ }
+ info("Call gc ");
+ SpecialPowers.gc();
+ });
+}
+
+// Continue calling takePhoto() in rapid succession.
+function rapidTest(track) {
+ return new Promise(function(resolve, reject) {
+ var imageCapture = new ImageCapture(track);
+ imageCapture.onphoto = function(blob) {
+ count++;
+ if (count == repeat) {
+ ok(true, "pass raipd takePhoto() testing");
+ resolve(track);
+ }
+ };
+ imageCapture.onerror = function(error) {
+ ok(false, "takePhoto() failure in rapid testing");
+ reject();
+ };
+
+ count = 0;
+ var i;
+ for(i = 0; i < repeat; i++) {
+ imageCapture.takePhoto();
+ }
+ });
+}
+
+// Check if the blob is decodable.
+function blobTest(track) {
+ return new Promise(function(resolve, reject) {
+ var imageCapture = new ImageCapture(track);
+ imageCapture.onphoto = function(blob) {
+ var img = new Image();
+ img.onerror = function() {
+ ok(false, "fail to decode blob");
+ reject();
+ }
+ img.onload = function() {
+ ok(true, "decode blob success");
+ resolve(track);
+ }
+ img.src = URL.createObjectURL(blob.data);
+ };
+ imageCapture.onerror = function(error) {
+ ok(false, "fail to capture image");
+ };
+
+ imageCapture.takePhoto();
+ });
+}
+
+// It should return an error event after disabling video track.
+function trackTest(track) {
+ return new Promise(function(resolve, reject) {
+ var imageCapture = new ImageCapture(track);
+ imageCapture.onphoto = function(blob) {
+ ok(false, "expect error when video track is disable");
+ reject();
+ };
+ imageCapture.onerror = function(error) {
+ ok(error.imageCaptureError.code == error.imageCaptureError.PHOTO_ERROR, "error code is PHOTO_ERROR")
+ track.enabled = true;
+ resolve(track);
+ };
+
+ track.enabled = false;
+ imageCapture.takePhoto()
+ });
+}
+
+function init() {
+ return new Promise(function(resolve, reject) {
+ // use fake camera, MediaStreamGraph will be the backend of ImageCapture.
+ var constraints = {video: true, fake: true}
+
+ window.navigator.mozGetUserMedia(
+ constraints,
+ function(stream) {
+ var track = stream.getVideoTracks()[0];
+ resolve(track);
+ },
+ function(err) {
+ reject(err);
+ }
+ );
+ });
+}
+
+function start() {
+ init().then(function(track) {
+ info("ImageCapture track disable test.");
+ return trackTest(track);
+ }).then(function(track) {
+ info("ImageCapture blob test.");
+ return blobTest(track);
+ }).then(function(track) {
+ info("ImageCapture rapid takePhoto() test.");
+ return rapidTest(track);
+ }).then(function(track) {
+ info("ImageCapture multiple instances test.");
+ return gcTest(track);
+ }).then(SimpleTest.finish);
+}
+
+SimpleTest.requestCompleteLog();
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv({"set": [["dom.imagecapture.enabled", true],
+ ["media.navigator.permission.disabled", true]
+ ]}, start);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_info_leak.html b/dom/media/test/test_info_leak.html
new file mode 100644
index 000000000..e3ff057cf
--- /dev/null
+++ b/dom/media/test/test_info_leak.html
@@ -0,0 +1,169 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=478957
+-->
+<head>
+ <title>Test for Bug 478957</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=478957">Mozilla Bug 478957</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+
+<div id="log" style="font-size: small;"></div>
+
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 478957 **/
+
+// Tests whether we leak events and state change info when loading stuff from local files from a webserver.
+
+var manager = new MediaTestManager;
+
+var gEventTypes = [ 'loadstart', 'progress', 'suspend', 'abort', 'error', 'emptied', 'stalled', 'play', 'pause', 'loadedmetadata', 'loadeddata', 'waiting', 'playing', 'canplay', 'canplaythrough', 'seeking', 'seeked', 'timeupdate', 'ended', 'ratechange', 'durationchange', 'volumechange' ];
+
+var gExpectedEvents = ['ratechange', 'loadstart', 'error'];
+
+function createTestArray() {
+ var tests = [];
+ var tmpVid = document.createElement("video");
+
+ for (var testNum=0; testNum<gInfoLeakTests.length; testNum++) {
+ var test = gInfoLeakTests[testNum];
+ if (!tmpVid.canPlayType(test.type)) {
+ continue;
+ }
+
+ var t = new Object;
+ t.name = test.src;
+ t.type = test.type;
+
+ tests.push(t);
+ }
+ return tests;
+}
+
+function log(msg) {
+ info(msg);
+ var l = document.getElementById('log');
+ l.innerHTML += msg + "<br>";
+}
+
+function finish(v) {
+ log("finish: " + v.name);
+ clearInterval(v.checkStateInterval);
+
+ for (var i=0; i<gEventTypes.length; i++) {
+ v.removeEventListener(gEventTypes[i], listener, false);
+ }
+ removeNodeAndSource(v);
+
+ manager.finished(v.token);
+ v = null;
+}
+
+function listener(evt) {
+ var v = evt.target;
+ log(filename(v.name) + ': got ' + evt.type);
+
+ // On slow machines like B2G emulator, progress timer could time out before
+ // receiving any HTTP notification. We will ignore the 'stalled' event to
+ // pass the tests.
+ if (evt.type == 'stalled') {
+ return;
+ }
+
+ ok(v.eventNum < gExpectedEvents.length, filename(v.name) + " Too many events received");
+ var expected = (v.eventNum < gExpectedEvents.length) ? gExpectedEvents[v.eventNum] : "NoEvent";
+ is(evt.type, expected, filename(v.name) + " Events received in wrong order");
+ v.eventNum++;
+ if (v.eventNum == gExpectedEvents.length) {
+ // In one second, move onto the next test. This give a chance for any
+ // other events to come in. Note: we don't expect any events to come
+ // in, unless we've leaked some info, and 1 second should be enough time
+ // for the leak to show up.
+ setTimeout(function() {finish(v);}, 1000);
+ }
+}
+
+function createMedia(type, src, token) {
+ var tag = getMajorMimeType(type);
+ var v = document.createElement(tag);
+ for (var i=0; i<gEventTypes.length; i++) {
+ v.addEventListener(gEventTypes[i], listener, false);
+ }
+ v.preload = "metadata";
+ v.src = src;
+ v.name = src;
+ document.body.appendChild(v);
+ v.eventNum = 0;
+ v.token = token;
+ setTimeout(
+ function() {
+ v.checkStateInterval = setInterval(function(){checkState(v);},1);
+ }, 0);
+}
+
+// Define our own ok() and is() functions. The mochitest ones take ages constructing the log
+// of all the passes, so only report failures.
+function test_ok(b, msg) {
+ if (!b) {
+ log("FAILED test_ok: " + msg);
+ ok(b, msg);
+ }
+}
+
+function test_is(a, b, msg) {
+ if (a != b) {
+ log("FAILED test_is: " + msg);
+ is(a,b,msg);
+ }
+}
+
+function filename(uri) {
+ return uri.substr(uri.lastIndexOf("/")+1);
+}
+
+function checkState(v) {
+ test_ok(v.networkState <= HTMLMediaElement.NETWORK_LOADING ||
+ v.networkState == HTMLMediaElement.NETWORK_NO_SOURCE,
+ "NetworkState of " + v.networkState + " was leaked.");
+ test_ok(v.readyState == HTMLMediaElement.HAVE_NOTHING,
+ "Ready state of " + v.readyState + " was leaked");
+ test_is(v.seeking, false, "Seeking leaked");
+ test_is(v.currentTime, 0, "Leaked currentTime");
+ test_ok(isNaN(v.duration), "Leaked duration");
+ test_is(v.paused, true, "Paused leaked");
+ test_is(v.ended, false, "Ended leaked");
+ test_is(v.autoplay, false, "Autoplay leaked");
+ test_is(v.controls, false, "Controls leaked");
+ test_is(v.muted, false, "muted leaked");
+ test_ok(v.error==null || v.error.code==MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED,
+ "Error code should not exist or be SRC_NOT_SUPPORTED. v.error=" +
+ (v.error ? v.error.code : "null"));
+ test_ok(filename(v.currentSrc) == filename(v.name) ||
+ v.networkState == HTMLMediaElement.NETWORK_NO_SOURCE,
+ "currentSrc should match candidate uri, if we've got a valid source");
+}
+
+
+function startTest(test, token) {
+ manager.started(token);
+ log("Testing: " + test.type + " @ " + test.name);
+ createMedia(test.type, test.name, token);
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+
+</body>
+</html>
diff --git a/dom/media/test/test_invalid_reject.html b/dom/media/test/test_invalid_reject.html
new file mode 100644
index 000000000..ac9b102de
--- /dev/null
+++ b/dom/media/test/test_invalid_reject.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="UTF-8" />
+ <title>Test rejection of invalid files</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ manager.started(token);
+
+ // Set up event handlers. Seeing any of these is a failure.
+ function badEvent(type) { return function(e) {
+ ok(false, test.name + " should not fire '" + type + "' event");
+ }};
+ var events = [
+ 'loadeddata', 'load',
+ 'canplay', 'canplaythrough',
+ 'playing'
+ ];
+ events.forEach( function(e) {
+ v.addEventListener(e, badEvent(e));
+ });
+
+ // Seeing a decoder error is a success.
+ v.addEventListener("error", function onerror(e) {
+ if (v.readyState == v.HAVE_NOTHING) {
+ is(v.error.code, v.error.MEDIA_ERR_SRC_NOT_SUPPORTED,
+ "decoder should reject " + test.name);
+ } else {
+ is(v.error.code, v.error.MEDIA_ERR_DECODE,
+ "decoder should reject " + test.name);
+ }
+ v.removeEventListener('error', onerror, false);
+ manager.finished(token);
+ });
+
+ // Now try to load and play the file, which should result in the
+ // error event handler above being called, terminating the test.
+ document.body.appendChild(v);
+ v.src = test.name;
+ v.play();
+}
+
+manager.runTests(gInvalidTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_invalid_reject_play.html b/dom/media/test/test_invalid_reject_play.html
new file mode 100644
index 000000000..5d9252d53
--- /dev/null
+++ b/dom/media/test/test_invalid_reject_play.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="UTF-8" />
+ <title>Test rejection of invalid files during playback</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ manager.started(token);
+
+ // Seeing a decoder error is a success.
+ v.addEventListener("error", function onerror(e) {
+ is(v.error.code, v.error.MEDIA_ERR_DECODE,
+ "decoder should reject " + test.name);
+ v.removeEventListener("error", onerror, false);
+ manager.finished(token);
+ });
+
+ v.addEventListener("ended", function onended(e) {
+ ok(false, "decoder should have rejected file before playback ended");
+ v.removeEventListener("ended", onended, false);
+ manager.finished(token);
+ });
+
+ document.body.appendChild(v);
+ v.src = test.name;
+ v.play();
+}
+
+manager.runTests(gInvalidPlayTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_invalid_seek.html b/dom/media/test/test_invalid_seek.html
new file mode 100644
index 000000000..481e15107
--- /dev/null
+++ b/dom/media/test/test_invalid_seek.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: invalide seek test</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<video id='v'></video>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+// http://www.whatwg.org/specs/web-apps/current-work/#dom-media-seek
+// If the media element's readyState is HAVE_NOTHING, then the user agent
+// must raise an InvalidStateError exception.
+var v = document.getElementById('v');
+var passed = false;
+
+ok(v.readyState == HTMLMediaElement.HAVE_NOTHING,
+ "Invalid ready state in media element");
+
+try {
+ v.seek(1);
+}
+catch(e) {
+ passed = true;
+}
+
+ok(passed, "Video did not raise error during invalid seek");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_load.html b/dom/media/test/test_load.html
new file mode 100644
index 000000000..f300ea57b
--- /dev/null
+++ b/dom/media/test/test_load.html
@@ -0,0 +1,226 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=479859
+-->
+<head>
+ <title>Test for Bug 479859</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=479859">Mozilla Bug 479859</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="text/javascript">
+
+function log(msg) {
+ //document.getElementById('log').innerHTML += "<p>" + msg + "</p>";
+}
+
+// We don't track: progress, canplay, canplaythrough and stalled events,
+// as these can be delivered out of order, and/or multiple times.
+var gEventTypes = [ 'loadstart', 'abort', 'error', 'emptied', 'play',
+ 'pause', 'loadedmetadata', 'loadeddata', 'waiting', 'playing', 'seeking',
+ 'seeked', 'timeupdate', 'ended', 'ratechange', 'durationchange', 'volumechange' ];
+
+var gEventNum = 0;
+var gTestNum = 0;
+var gTestFileNum = 0;
+var gExpectedEvents = null;
+var gTest = null;
+var gTestName = "?";
+
+function listener(evt) {
+ log('event ' + evt.type);
+ ok(gEventNum < gExpectedEvents.length, gTestName+" - corrent number of events received");
+ var expected = (gEventNum < gExpectedEvents.length) ? gExpectedEvents[gEventNum] : "NoEvent";
+ is(evt.type, expected, gTestName+" - events received in order");
+ gEventNum++;
+ if (gEventNum == gExpectedEvents.length) {
+ setTimeout(nextTest, 0);
+ }
+}
+
+function source_error(evt) {
+ log('event source_error');
+ ok(evt.type == "error", "Should only get error events here");
+ ok(gEventNum < gExpectedEvents.length, gTestName+" - corrent number of events received");
+ var expected = (gEventNum < gExpectedEvents.length) ? gExpectedEvents[gEventNum] : "NoEvent";
+ is("source_error", expected, gTestName+" - events received in order");
+ gEventNum++;
+ if (gEventNum == gExpectedEvents.length) {
+ setTimeout(nextTest, 0);
+ }
+}
+
+var gMedia = null;
+
+function createMedia(tag) {
+ gMedia = document.createElement(tag);
+ gMedia.preload = "metadata";
+ for (var i=0; i<gEventTypes.length; i++) {
+ gMedia.addEventListener(gEventTypes[i], listener, false);
+ }
+}
+
+function addSource(src, type) {
+ var s = document.createElement("source");
+ s.addEventListener("error", source_error, false);
+ s.src = src;
+ s.type = type;
+ gMedia.appendChild(s);
+ return s;
+}
+
+function prependSource(src, type) {
+ var s = document.createElement("source");
+ s.addEventListener("error", source_error, false);
+ s.src = src;
+ s.type = type;
+ gMedia.insertBefore(s, gMedia.firstChild);
+ return s;
+}
+
+var gTests = [
+ {
+ // Test 0: adding video to doc, then setting src should load implicitly.
+ create:
+ function(src, type) {
+ document.body.appendChild(gMedia);
+ gMedia.src = src;
+ },
+ expectedEvents: ['ratechange', 'loadstart', 'durationchange', 'loadedmetadata', 'loadeddata']
+ }, {
+ // Test 1: adding video to doc, then adding source.
+ create:
+ function(src, type) {
+ document.body.appendChild(gMedia);
+ addSource(src, type);
+ },
+ expectedEvents: ['loadstart', 'durationchange', 'loadedmetadata', 'loadeddata']
+ },{
+ // Test 2: video with multiple source, the first of which are bad, we should load the last,
+ // and receive error events for failed loads on the source children.
+ create:
+ function(src, type) {
+ document.body.appendChild(gMedia);
+ addSource("404a", type);
+ addSource("404b", type);
+ addSource(src, type);
+ },
+ expectedEvents: ['loadstart', 'source_error', 'source_error', 'durationchange', 'loadedmetadata', 'loadeddata']
+ }, {
+ // Test 3: video with bad src, good <source>, ensure that <source> aren't used.
+ create:
+ function(src, type) {
+ gMedia.src = "404a";
+ addSource(src, type);
+ document.body.appendChild(gMedia);
+ },
+ expectedEvents: ['ratechange', 'loadstart', 'error']
+ }, {
+ // Test 4: video with only bad source, loading, then adding a good source
+ // - should resume load.
+ create:
+ function(src, type) {
+ addSource("404a", type);
+ var s2 = addSource("404b", type);
+ s2.addEventListener("error",
+ function(e) {
+ // Should awaken waiting load, causing successful load.
+ addSource(src, type);
+ },
+ false);
+ document.body.appendChild(gMedia);
+ },
+ expectedEvents: ['loadstart', 'source_error', 'source_error', 'durationchange', 'loadedmetadata', 'loadeddata']
+ }, {
+ // Test 5: video with only 1 bad source, let it fail to load, then prepend
+ // a good <source> to the video, it shouldn't be selected, because the
+ // "pointer" should be after the last child - the bad source.
+ prepended: false,
+ create:
+ function(src, type) {
+ var prepended = false;
+ addSource("404a", type);
+ var s2 = addSource("404b", type);
+ s2.addEventListener("error",
+ function(e) {
+ // Should awaken waiting load, causing successful load.
+ if (!prepended) {
+ prependSource(src, type);
+ prepended = true;
+ }
+ },
+ false);
+ document.body.appendChild(gMedia);
+ },
+ expectedEvents: ['loadstart', 'source_error', 'source_error']
+ }, {
+ // Test 6: (Bug 1165203) preload="none" then followed by an explicit
+ // call to load() should load metadata
+ create:
+ function(src, type) {
+ gMedia.preload = "none";
+ gMedia.src = src;
+ document.body.appendChild(gMedia);
+ addSource(src, type);
+ gMedia.load();
+ },
+ expectedEvents: ['emptied', 'ratechange', 'loadstart', 'durationchange', 'loadedmetadata', 'loadeddata']
+ }
+];
+
+function nextTest() {
+ if (gMedia) {
+ for (var i=0; i<gEventTypes.length; i++) {
+ gMedia.removeEventListener(gEventTypes[i], listener, false);
+ }
+ removeNodeAndSource(gMedia);
+ gMedia = null;
+ }
+ gEventNum = 0;
+
+ if (gTestNum == gTests.length) {
+ gTestNum = 0;
+ ++gTestFileNum;
+ if (gTestFileNum == gSmallTests.length) {
+ SimpleTest.finish();
+ return;
+ }
+ }
+
+ var src = gSmallTests[gTestFileNum].name;
+ var type = gSmallTests[gTestFileNum].type;
+
+ var t = gTests[gTestNum];
+ gTestNum++;
+
+ createMedia(type.match(/^audio\//) ? "audio" : "video");
+ if (!gMedia.canPlayType(type)) {
+ // Unsupported type, skip to next test
+ nextTest();
+ return;
+ }
+
+ gTestName = "Test " + src + " " + (gTestNum - 1);
+ log("Starting " + gTestName);
+ gExpectedEvents = t.expectedEvents;
+
+ t.create(src, type);
+}
+
+addLoadEvent(nextTest);
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+
+<div id="log" style="font-size: small"></div>
+</body>
+</html>
diff --git a/dom/media/test/test_load_candidates.html b/dom/media/test/test_load_candidates.html
new file mode 100644
index 000000000..621f1e85b
--- /dev/null
+++ b/dom/media/test/test_load_candidates.html
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=465458
+-->
+<head>
+ <title>Test for Bug 465458</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=465458">Mozilla Bug 465458</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 465458 **/
+
+var manager = new MediaTestManager;
+
+function finish(evt) {
+ var v = evt.target;
+ is(v._error, 2, "Should have received 2 error events before loaded");
+ v._finished = true;
+ // remove error event handler, because this would otherwise
+ // cause a failure on Windows 7, see bug 1024535
+ v.onerror = null;
+ v.parentNode.removeChild(v);
+ manager.finished(v.token);
+}
+
+function errorHandler(evt) {
+ evt.target.parentNode._error++;
+}
+
+var extension = {
+ "audio/wav" : "wav",
+ "audio/x-wav": "wav",
+ "video/ogg" : "ogv",
+ "audio/ogg" : "oga",
+ "video/webm" : "webm"
+};
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ v.preload = "auto";
+ v.onerror = function(){ok(false,"Error events on source children should not bubble");}
+ v.token = token;
+ manager.started(token);
+ v._error = 0;
+ v._finished = false;
+ v._name = test.name;
+
+ var s1 = document.createElement("source");
+ s1.type = test.type;
+ s1.src = "404." + extension[test.type];
+ s1.addEventListener("error", errorHandler, false);
+ v.appendChild(s1);
+
+ var s2 = document.createElement("source");
+ s2.type = test.type;
+ s2.src = "test_load_candidates.html"; // definitely an invalid media file, regardless of its actual mime type...
+ s2.addEventListener("error", errorHandler, false);
+ v.appendChild(s2);
+
+ var s3 = document.createElement("source");
+ s3.type = test.type;
+ s3.src = test.name;
+ v.appendChild(s3);
+
+ v.addEventListener("loadeddata", finish, false);
+ document.body.appendChild(v);
+}
+
+manager.runTests(gSmallTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_load_same_resource.html b/dom/media/test/test_load_same_resource.html
new file mode 100644
index 000000000..b87abda32
--- /dev/null
+++ b/dom/media/test/test_load_same_resource.html
@@ -0,0 +1,100 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test loading of the same resource in multiple elements</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.requestCompleteLog();
+var manager = new MediaTestManager;
+
+function cloneLoaded(event) {
+ ok(true, "Clone loaded OK");
+ var e = event.target;
+
+ if (e._expectedDuration) {
+ ok(Math.abs(e.duration - e._expectedDuration) < 0.1,
+ "Clone " + e.currentSrc + " duration: " + e.duration + " expected: " + e._expectedDuration);
+ }
+
+ e.removeEventListener("loadeddata", cloneLoaded, false);
+ removeNodeAndSource(e);
+ manager.finished(e.token);
+}
+
+function tryClone(event) {
+ var e = event.target;
+ var clone = e.cloneNode(false);
+ clone.token = e.token;
+
+ // Log events for debugging.
+ var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
+ "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
+ "waiting", "pause"];
+ function logEvent(evt) {
+ var e = evt.target;
+ info(e.token + ": got " + evt.type);
+ }
+ events.forEach(function(e) {
+ clone.addEventListener(e, logEvent, false);
+ });
+
+
+ if (e._expectedDuration) {
+ ok(Math.abs(e.duration - e._expectedDuration) < 0.1,
+ e.currentSrc + " duration: " + e.duration + " expected: " + e._expectedDuration);
+ clone._expectedDuration = e._expectedDuration;
+ }
+
+ clone.addEventListener("loadeddata", cloneLoaded, false);
+ clone.onloadstart = function(evt) {
+ info("cloned " + evt.target.token + " start loading.");
+ evt.target.onloadstart = null;
+ // Since there is only one H264 decoder instance, we have to delete the
+ // decoder of the original element for the cloned element to load. However,
+ // we can't delete the decoder too early otherwise cloning decoder will
+ // fail to kick in. We wait for 'loadstart' event of the cloned element to
+ // know when the decoder is already cloned and we can delete the decoder of
+ // the original element.
+ removeNodeAndSource(e);
+ }
+
+ e.removeEventListener("loadeddata", tryClone, false);
+}
+
+// This test checks that loading the same URI twice in different elements at the same time
+// uses the same resource without doing another network fetch. One of the gCloneTests
+// uses dynamic_resource.sjs to return one resource on the first fetch and a different resource
+// on the second fetch. These resources have different lengths, so if the cloned element
+// does a network fetch it will get a resource with the wrong length and we get a test
+// failure.
+
+function initTest(test, token) {
+ var elemType = /^audio/.test(test.type) ? "audio" : "video";
+ var e = document.createElement(elemType);
+ e.preload = "auto";
+ if (e.canPlayType(test.type)) {
+ e.src = test.name;
+ if (test.duration) {
+ e._expectedDuration = test.duration;
+ }
+ ok(true, "Trying to load " + test.name);
+ e.addEventListener("loadeddata", tryClone, false);
+ e.load();
+ e.token = token;
+ manager.started(token);
+ }
+}
+
+manager.runTests(gCloneTests, initTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_load_source.html b/dom/media/test/test_load_source.html
new file mode 100644
index 000000000..49db96b93
--- /dev/null
+++ b/dom/media/test/test_load_source.html
@@ -0,0 +1,76 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=534571
+-->
+<head>
+ <title>Test for Bug 534571</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=534571">Mozilla Bug 534571</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 534571 **/
+
+// Test that when we load a video from a source child and then change the
+// source's src attribute and load again, that the subsequent loads work.
+
+var v = null;
+var s = null;
+
+function finish(event) {
+ ok(true, "Should have played both videos");
+ SimpleTest.finish();
+}
+
+var first = null;
+var second = null;
+
+function ended(event) {
+ s.type = second.type;
+ s.src = second.name;
+ v.removeEventListener("ended", ended, false);
+ v.addEventListener("ended", finish, false);
+ v.load();
+}
+
+// Find 2 videos we can play.
+v = document.createElement('video');
+for (var i=0; i<gPlayTests.length; i++) {
+ if (!v.canPlayType(gPlayTests[i].type))
+ continue;
+ if (!first) {
+ first = gPlayTests[i];
+ } else if (!second) {
+ second = gPlayTests[i];
+ break;
+ }
+}
+
+if (first && second) {
+ s = document.createElement('source');
+ s.type = first.type;
+ s.src = first.name;
+ v.appendChild(s);
+ v.autoplay = true;
+ v.addEventListener("ended", ended, false);
+ document.body.appendChild(v);
+ SimpleTest.waitForExplicitFinish();
+} else {
+ todo(false, "Need at least two media of supported types for this test!");
+}
+
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_loop.html b/dom/media/test/test_loop.html
new file mode 100644
index 000000000..d657ac696
--- /dev/null
+++ b/dom/media/test/test_loop.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test looping support</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+//longer timeout for slow platforms
+if (isSlowPlatform()) {
+ SimpleTest.requestLongerTimeout(2);
+}
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ manager.started(token);
+ var v = document.createElement('video');
+ v.token = token;
+ v.src = test.name;
+ v.name = test.name;
+ v.playCount = 0;
+ v.seekingCount = 0;
+ v.seekedCount = 0;
+ v.loop = true;
+
+ v.addEventListener("play", function (e) {
+ e.target.playCount += 1;
+ ok(e.target.playCount == 1, "Should get exactly one play event.");
+ }, false);
+
+ v.addEventListener("seeking", function (e) {
+ e.target.seekingCount += 1;
+ }, false);
+
+ v.addEventListener("seeked", function (e) {
+ e.target.seekedCount += 1;
+ if (e.target.seekedCount == 2) {
+ ok(e.target.seekingCount == 2, "Expect matched pairs of seeking/seeked events.");
+ e.target.loop = false;
+ }
+ }, false);
+
+ v.addEventListener("ended", function (e) {
+ ok(!e.target.loop, "Shouldn't get ended event while looping.");
+ removeNodeAndSource(e.target);
+ manager.finished(e.target.token);
+ }, false);
+
+ document.body.appendChild(v);
+ v.play();
+}
+
+manager.runTests(gSmallTests, startTest);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_media_selection.html b/dom/media/test/test_media_selection.html
new file mode 100644
index 000000000..51234f121
--- /dev/null
+++ b/dom/media/test/test_media_selection.html
@@ -0,0 +1,146 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: media selection</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="application/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+//longer timeout for sometimes B2G emulator runs very slowly
+if (SpecialPowers.Services.appinfo.name == "B2G") {
+ SimpleTest.requestLongerTimeout(3);
+}
+
+var manager = new MediaTestManager;
+
+function maketest(attach_media, name, type, check_metadata) {
+ return function (token) {
+ var e = document.createElement('video');
+ e.preload = "metadata";
+ token = name + "-" + token;
+ manager.started(token);
+ var errorRun = false;
+ if (check_metadata) {
+ e.addEventListener('loadedmetadata', function () {
+ ok(e.readyState >= HTMLMediaElement.HAVE_METADATA,
+ 'test ' + token + ' readyState ' + e.readyState + ' expected >= ' + HTMLMediaElement.HAVE_METADATA);
+ is(e.currentSrc.substring(e.currentSrc.length - name.length), name, 'test ' + token);
+ // The load can go idle due to cache size limits
+ ok(e.networkState >= HTMLMediaElement.NETWORK_IDLE,
+ 'test ' + token + ' networkState = ' + e.networkState + ' expected >= ' + HTMLMediaElement.NETWORK_IDLE);
+ check_metadata(e);
+ removeNodeAndSource(e);
+ manager.finished(token);
+ }, false);
+ } else {
+ e.addEventListener('error', function onerror(event) {
+ is(errorRun, false, "error handler should run once only!");
+ errorRun = true;
+ is(e.readyState, HTMLMediaElement.HAVE_NOTHING,
+ 'test ' + token + ' readyState should be HAVE_NOTHING when load fails.');
+ e.removeEventListener('error', onerror, true);
+ removeNodeAndSource(e);
+ manager.finished(token);
+ }, true);
+ }
+ attach_media(e, name, type);
+ }
+}
+
+function set_src(element, name, type) {
+ element.src = name;
+ document.body.appendChild(element);
+}
+
+function add_source(element, name, type) {
+ do_add_source(element, name, type);
+ document.body.appendChild(element);
+}
+
+function do_add_source(element, name, type) {
+ var source = document.createElement('source');
+ if (type) {
+ source.type = type;
+ }
+ source.src = name;
+ element.appendChild(source);
+}
+
+function add_sources_last(element, name, type) {
+ do_add_source(element, name, 'unsupported/type');
+ do_add_source(element, name, type);
+ document.body.appendChild(element);
+}
+
+function add_sources_first(element, name, type) {
+ do_add_source(element, name, type);
+ do_add_source(element, name, 'unsupported/type');
+ document.body.appendChild(element);
+}
+
+function late_add_sources_last(element, name, type) {
+ document.body.appendChild(element);
+ do_add_source(element, name, 'unsupported/type');
+ do_add_source(element, name, type);
+}
+
+function late_add_sources_first(element, name, type) {
+ document.body.appendChild(element);
+ do_add_source(element, name, type);
+ do_add_source(element, name, 'unsupported/type');
+}
+
+var nextTest = 0;
+var subtests = [
+ maketest(add_source, 'unknown.raw', 'bogus/type', null)
+];
+
+var tmpVid = document.createElement('video');
+
+for (var i = 0; i < gSmallTests.length; ++i) {
+ var test = gSmallTests[i];
+ var src = test.name;
+ var type = test.type;
+
+ if (!tmpVid.canPlayType(type))
+ continue;
+
+ // The following nested function hack is to ensure that 'test' is correctly
+ // captured in the closure and we don't end up getting the value 'test'
+ // had in the last iteration of the loop. I blame Brendan.
+ var check = function(test) { return function (e) {
+ checkMetadata(test.name, e, test);
+ }}(test);
+
+ var otherType = type.match(/^video\//) ? "audio/x-wav" : "video/ogg";
+ subtests.push(maketest(set_src, src, null, check),
+ maketest(add_source, src, null, check),
+ maketest(add_source, src, type, check),
+ maketest(add_sources_last, src, null, check),
+ maketest(add_sources_first, src, type, check),
+
+ // type hint matches a decoder, actual type matches different decoder
+ maketest(add_source, src, otherType, check),
+ maketest(add_source, 'unknown.raw', type, null),
+
+ // should not start loading, type excludes it from media candiate list
+ maketest(add_source, src, 'bogus/type', null),
+
+ // element doesn't notice source children attached later, needs bug 462455 fixed
+ maketest(late_add_sources_last, src, type, check),
+ maketest(late_add_sources_first, src, type, check));
+}
+
+function startTest(test, token) {
+ test(token);
+}
+
+manager.runTests(subtests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_media_sniffer.html b/dom/media/test/test_media_sniffer.html
new file mode 100644
index 000000000..a4988e710
--- /dev/null
+++ b/dom/media/test/test_media_sniffer.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: sniffing</title>
+ <meta charset='utf-8'>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function finish_test(element) {
+ element.removeEventListener("error", onerror, false);
+ removeNodeAndSource(element);
+ manager.finished(element.token);
+}
+
+function onmetadataloaded(e) {
+ var t = e.target;
+ ++t.srcIndex;
+ ok(true, "The media loads when loaded via " + t.src);
+ if (t.srcIndex < t.srcList.length) {
+ t.src = t.srcList[t.srcIndex];
+ } else {
+ finish_test(t);
+ }
+}
+
+function onerror(e) {
+ var t = e.target;
+ t.removeEventListener('error', onerror);
+ ok(false, "The media could not be loaded." + t.src + "\n");
+ finish_test(t);
+}
+
+function startTest(test, token) {
+ var elemType = /^audio/.test(test.type) ? "audio" : "video";
+ var element = document.createElement(elemType);
+ // This .sjs file serve the media file without Content-Type header, or with a
+ // specific Content-Type header.
+ var baseSrc = 'contentType.sjs?file=' + test.name;
+ element.srcList = [
+ baseSrc + "&nomime",
+ baseSrc + "&type=application/octet-stream",
+ baseSrc + "&type=audio/wav",
+ baseSrc + "&type=text/html",
+ baseSrc + "&type=absolute_nonsense"
+ ];
+ element.srcIndex = 0;
+ element.src = element.srcList[element.srcIndex];
+ element.token = token;
+ element.controls = true;
+ element.preload = "metadata";
+ document.body.appendChild(element);
+ manager.started(token);
+ element.addEventListener("loadedmetadata", onmetadataloaded);
+ element.addEventListener("error", onerror);
+}
+
+manager.runTests(gSnifferTests, startTest);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_avoid_recursion.html b/dom/media/test/test_mediarecorder_avoid_recursion.html
new file mode 100644
index 000000000..fd4500512
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_avoid_recursion.html
@@ -0,0 +1,51 @@
+<html>
+<head>
+ <title>MediaRecorder infinite recursion with requestData() calls in "dataavailable" event</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=897776">Mozill
+a Bug 897776</a>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+function startTest() {
+ navigator.mozGetUserMedia({audio: true, fake: true}, function(stream) {
+ var mediaRecorder = new MediaRecorder(stream);
+ var count = 0;
+ mediaRecorder.start();
+ info("mediaRecorder start");
+ mediaRecorder.ondataavailable = function (e) {
+ ++count;
+ info("got ondataavailable data size = " + e.data.size);
+ // no more requestData() to prevent busy main thread from starving
+ // the encoding thread
+ if (count == 30) {
+ info("stream.stop");
+ stream.stop();
+ } else if (count < 30 && mediaRecorder.state == 'recording') {
+ info("requestData again");
+ mediaRecorder.requestData();
+ }
+ }
+ mediaRecorder.requestData();
+ info("mediaRecorder requestData");
+ mediaRecorder.onstop = function () {
+ ok(true, "requestData within ondataavailable successfully avoided infinite recursion");
+ SimpleTest.finish();
+ }
+ }, function(err) {
+ ok(false, 'Unexpected error fired with: ' + err);
+ SimpleTest.finish();
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+startTest();
+
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/media/test/test_mediarecorder_bitrate.html b/dom/media/test/test_mediarecorder_bitrate.html
new file mode 100644
index 000000000..21e6f5b90
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_bitrate.html
@@ -0,0 +1,128 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaRecorder Bitrate</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+var results = [];
+
+/**
+ * Starts a test on every media recorder file included to check that
+ * the bitrate control works
+ */
+function startTest(test, token) {
+ manager.started(token);
+ runTest(test, token, 1000000);
+ runTest(test, token, 100000);
+}
+
+function runTest(test, token, bitrate) {
+ var element = document.createElement('video');
+ var expectedMimeType = test.type.substring(0, test.type.indexOf(';'));
+
+ element.token = token;
+
+ element.src = test.name;
+ element.preload = "metadata";
+ element.onloadedmetadata = function () {
+ info("loadedmetadata");
+ const stream = element.mozCaptureStreamUntilEnded();
+ element.onloadedmetadata = null;
+ element.play();
+
+ const mediaRecorder = new MediaRecorder(stream, {videoBitsPerSecond: bitrate});
+ mediaRecorder.start();
+ is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
+ is(mediaRecorder.stream, stream,
+ 'Media recorder stream = element stream at the start of recording');
+
+ var onStopFired = false;
+ var onDataAvailableFired = false;
+ var encoded_size = 0;
+
+ mediaRecorder.onerror = function () {
+ ok(false, 'Unexpected onerror callback fired');
+ };
+
+ mediaRecorder.onwarning = function () {
+ ok(false, 'Unexpected onwarning callback fired');
+ };
+
+ // This handler verifies that only a single onstop event handler is fired.
+ mediaRecorder.onstop = function () {
+ if (onStopFired) {
+ ok(false, 'onstop unexpectedly fired more than once');
+ } else {
+ onStopFired = true;
+
+ // ondataavailable should always fire before onstop
+ if (onDataAvailableFired) {
+ ok(true, 'onstop fired after ondataavailable');
+ info("test " + test.name + " encoded@" + bitrate + "=" + encoded_size);
+ if (results[test.name]) {
+ var big, small, temp;
+ big = {};
+ big.bitrate = bitrate;
+ big.size = encoded_size;
+ small = results[test.name];
+ // Don't assume the order that these will finish in
+ if (results[test.name].bitrate > bitrate) {
+ temp = big;
+ big = small;
+ small = temp;
+ }
+ // Ensure there is a big enough difference in the encoded
+ // sizes
+ ok(small.size*1.25 < big.size,
+ test.name + ' encoded@' + big.bitrate + '=' + big.size +
+ ' > encoded@' + small.bitrate + '=' + small.size);
+ manager.finished(token);
+ } else {
+ results[test.name] = {};
+ results[test.name].bitrate = bitrate;
+ results[test.name].size = encoded_size;
+ }
+ } else {
+ ok(false, 'onstop fired without an ondataavailable event first');
+ }
+ }
+ };
+
+ // This handler verifies that only a single ondataavailable event handler
+ // is fired with the blob generated having greater than zero size
+ // and a correct mime type.
+ mediaRecorder.ondataavailable = function (evt) {
+ if (onDataAvailableFired) {
+ ok(false, 'ondataavailable unexpectedly fired more than once');
+ } else {
+ onDataAvailableFired = true;
+
+ ok(evt instanceof BlobEvent,
+ 'Events fired from ondataavailable should be BlobEvent');
+ is(evt.type, 'dataavailable',
+ 'Event type should dataavailable');
+ ok(evt.data.size > 0,
+ 'Blob data received should be greater than zero');
+ encoded_size = evt.data.size;
+
+ // onstop should not have fired before ondataavailable
+ if (onStopFired) {
+ ok(false, 'ondataavailable unexpectedly fired later than onstop');
+ manager.finished(token);
+ }
+ }
+ };
+ };
+}
+
+manager.runTests(gMediaRecorderVideoTests, startTest);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_creation.html b/dom/media/test/test_mediarecorder_creation.html
new file mode 100644
index 000000000..4ce2b6560
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_creation.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaRecorder Creation</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+/**
+ * Starts a test on every media recorder file included to check that
+ * a media recorder object created with a stream derived from a media
+ * element with that file produces the correct starting attribute values.
+ */
+function startTest(test, token) {
+ var element = document.createElement('audio');
+
+ element.token = token;
+ manager.started(token);
+
+ element.src = test.name;
+ element.test = test;
+ element.stream = element.mozCaptureStreamUntilEnded();
+
+ var mediaRecorder = new MediaRecorder(element.stream);
+
+ is(mediaRecorder.stream, element.stream,
+ 'Stream should be provided stream on creation');
+ is(mediaRecorder.mimeType, '',
+ 'mimeType should be an empty string on creation');
+ is(mediaRecorder.state, 'inactive',
+ 'state should be inactive on creation');
+
+ manager.finished(token);
+}
+
+manager.runTests(gMediaRecorderTests, startTest);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_creation_fail.html b/dom/media/test/test_mediarecorder_creation_fail.html
new file mode 100644
index 000000000..903bf1cc7
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_creation_fail.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaRecorder Record with media.ogg.enabled = false</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function startTest() {
+ // the expect sequence should be
+ // 1. onerror
+ // 2. ondataavailable
+ // 3. onstop
+ var callbackStep = 0;
+ var stream = new AudioContext().createMediaStreamDestination().stream;
+ var mediaRecorder = new MediaRecorder(stream);
+
+ mediaRecorder.onerror = function (e) {
+ is(callbackStep, 0, 'should fired onstop callback');
+ is(e.name, 'GenericError', 'error name should be GenericError');
+ is(mediaRecorder.mimeType, '', 'mimetype should be empty');
+ is(mediaRecorder.state, 'recording', 'state is recording');
+ info('onerror callback fired');
+ callbackStep = 1;
+ };
+
+ mediaRecorder.onwarning = function () {
+ ok(false, 'Unexpected onwarning callback fired');
+ };
+
+ mediaRecorder.onstop = function () {
+ info('onstop callback fired');
+ is(mediaRecorder.state, 'inactive', 'state should be inactive');
+ is(callbackStep, 2, 'should fired onstop callback');
+ SimpleTest.finish();
+ };
+
+ // This handler fires every 250ms to generate a blob.
+ mediaRecorder.ondataavailable = function (evt) {
+ info('ondataavailable callback fired');
+ is(callbackStep, 1, 'should fired ondataavailable callback');
+ is(evt.data.size, 0, 'data size should be zero');
+ ok(evt instanceof BlobEvent,
+ 'Events fired from ondataavailable should be BlobEvent');
+ is(evt.data.type, '', 'encoder start fail, blob miemType should be empty');
+ callbackStep = 2;
+ };
+
+ // Start recording
+ mediaRecorder.start(250);
+ is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
+ is(mediaRecorder.stream, stream,
+ 'Media recorder stream = element stream at the start of recording');
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [["media.ogg.enabled", false]]}, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_getencodeddata.html b/dom/media/test/test_mediarecorder_getencodeddata.html
new file mode 100644
index 000000000..426552ce7
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_getencodeddata.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 957452 Test GetEncodedData problem on asan build</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+SpecialPowers.pushPrefEnv({"set": [["media.ogg.enabled", false]]},
+ function () {
+ var ac = new window.AudioContext();
+ var dest = ac.createMediaStreamDestination();
+ var stream = dest.stream;
+ var onErrorFired = false;
+ var expectedMimeType = '';
+ var ondataavailableFired = false;
+ setTimeout(function() {
+ var mediaRecorder = new MediaRecorder(stream);
+ mediaRecorder.onstop = function(e) {
+ is(e.target.state, 'inactive',
+ 'Media recorder is inactive after being stopped');
+ ok(onErrorFired, 'onStop after onError');
+ ok(ondataavailableFired, 'ondataavailableFired');
+
+ //Apparently, as soon as the document is unloading, mediaRecorder.ondataavailable
+ //fires again, so set it to null to avoid failures
+ mediaRecorder.ondataavailable = null;
+ SimpleTest.finish();
+ }
+ mediaRecorder.ondataavailable = function(evt) {
+ ondataavailableFired = true;
+ ok(evt instanceof BlobEvent,
+ 'Events fired from ondataavailable should be BlobEvent');
+ is(evt.type, 'dataavailable',
+ 'Event type should dataavailable');
+ is(evt.data.size, 0,
+ 'Blob data size received is equal to zero');
+ is(evt.data.type, expectedMimeType,
+ 'Blob data received should have type = ' + expectedMimeType);
+ is(evt.target.mimeType, expectedMimeType,
+ 'Mime type in ondataavailable = ' + expectedMimeType);
+ }
+ mediaRecorder.onerror = function(evt) {
+ ok(evt instanceof RecordErrorEvent,
+ 'Events fired from onerror should be RecordErrorEvent');
+ is(evt.type, 'error',
+ 'Event type should onerror');
+ is(evt.name, 'GenericError',
+ 'Event name is GenericError');
+ onErrorFired = true;
+ }
+ mediaRecorder.start(0);
+ is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
+ is(mediaRecorder.stream, stream,
+ 'Media recorder stream = element stream at the start of recording');
+ mediaRecorder.requestData();
+ }, 100);
+ }
+);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_principals.html b/dom/media/test/test_mediarecorder_principals.html
new file mode 100644
index 000000000..d60f70f54
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_principals.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=489415
+-->
+<head>
+ <title>Test for MediaRecorder Reaction to Principal Change</title>
+ <script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<div>
+ <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1018299">Test for MediaRecorder Principal Handling</a>
+</div>
+
+<video id="v1" preload="auto"></video>
+<video id="v2" preload="auto"></video>
+
+<pre id="test">
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var pushPrefs = (...p) => new Promise(r => SpecialPowers.pushPrefEnv({set: p}, r));
+var throwOutside = e => setTimeout(() => { throw e; });
+
+// Generate a random key. The first load with that key will return
+// data, the second and subsequent loads with that key will return a redirect
+// to a different origin ('localhost:8888' will be redirected to 'example.org',
+// and 'example.org' will be redirected to 'localhost:8888'). We rely on the
+// fact that Ogg will do a seek to the end of the resource, triggering a new
+// load with the same key which will return a same-origin resource.
+// Loading data from two different origins should be detected by the media
+// cache and result in a null principal so that the MediaRecorder usages below
+// fail.
+let key = Math.floor(Math.random()*100000000);
+let interval;
+
+function testPrincipals(resource) {
+ if (!resource) {
+ todo(false, "No types supported");
+ return;
+ }
+ // Reduce cache size and cache-ahead to make HTMLMediaElement do partial requests.
+ return pushPrefs(['media.cache_readahead_limit', 2],
+ ['media.cache_size', 192])
+ .then(() => {
+ // First test: Load file from same-origin first, then get redirected to
+ // another origin before attempting to record stream.
+ let video = document.getElementById("v1");
+ video.src =
+ "http://mochi.test:8888/tests/dom/media/test/dynamic_redirect.sjs?key=v1_" +
+ key + "&res=" + resource.name;
+ video.load();
+ // To limit readahead, avoid racing with playback and "catching up" mode.
+ return new Promise(resolve => video.oncanplaythrough = resolve).then(() => {
+ video.play();
+ interval = setInterval(() => info("video.currentTime = "+ video.currentTime), 1000);
+
+ let msg = "mediaRecorder.start() must throw SecurityError";
+ return new Promise(resolve => video.onplaying = resolve)
+ .then(() => waitUntil(() => video.currentTime > resource.duration / 2))
+ // Test failure of the next step only, so "catch-bypass" any errors above.
+ .then(() => Promise.resolve()
+ .then(() => new MediaRecorder(video.mozCaptureStreamUntilEnded()).start())
+ .then(() => ok(false, msg), e => is(e.name, "SecurityError", msg)), 0)
+ .then(() => clearInterval(interval));
+ });
+ })
+ .then(() => {
+ // Second test: Load file from same-origin first, but record ASAP, before
+ // getting redirected to another origin.
+ let video = document.getElementById("v2");
+ video.src =
+ "http://mochi.test:8888/tests/dom/media/test/dynamic_redirect.sjs?key=v2_" +
+ key + "&res=" + resource.name;
+ video.load();
+ let rec, hasStopped, hasEnded = new Promise(r => video.onended = r);
+ let data = [];
+
+ let msgNoThrow = "mediaRecorder.start() should not throw here";
+ let msgSecErr = "mediaRecorder.onerror must fire SecurityError";
+ let msgOnStop = "mediaRecorder.onstop must also have fired";
+ return new Promise(resolve => video.onloadedmetadata = resolve).then(() => {
+ rec = new MediaRecorder(video.mozCaptureStreamUntilEnded());
+ rec.ondataavailable = e => data.push(e.data);
+ rec.start();
+ hasStopped = new Promise(resolve => rec.onstop = resolve);
+ video.play();
+ })
+ .then(() => ok(true, msgNoThrow), e => is(e.name, null, msgNoThrow))
+ .then(() => Promise.race([
+ new Promise((_, reject) => rec.onerror = e => reject(new DOMException("", e.name))),
+ hasEnded
+ ]))
+ .then(() => ok(false, msgSecErr), e => is(e.name, "SecurityError", msgSecErr))
+ .then(() => Promise.race([hasStopped, hasEnded.then(() => Promise.reject())]))
+ .then(() => ok(true, msgOnStop), e => ok(false, msgOnStop))
+ .then(() => clearInterval(interval));
+ });
+}
+
+testPrincipals(getPlayableVideo(gSeekTests))
+.catch(e => throwOutside(e))
+.then(() => SimpleTest.finish())
+.catch(e => throwOutside(e));
+
+var stop = stream => stream.getTracks().forEach(track => track.stop());
+var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
+var waitUntil = f => new Promise(resolve => {
+ var ival = setInterval(() => f() && resolve(clearInterval(ival)), 100);
+});
+
+</script>
+</pre>
+
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_record_4ch_audiocontext.html b/dom/media/test/test_mediarecorder_record_4ch_audiocontext.html
new file mode 100644
index 000000000..2ea3d867d
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_record_4ch_audiocontext.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaRecorder Record AudioContext with four channels</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+
+<script class="testbody" type="text/javascript">
+
+function startTest() {
+ var context = new AudioContext();
+ var buffer = context.createBuffer(4, 80920, context.sampleRate);
+ for (var i = 0; i < 80920; ++i) {
+ for(var j = 0; j < 4; ++j) {
+ buffer.getChannelData(j)[i] = Math.sin(1000 * 2 * Math.PI * i / context.sampleRate);
+ }
+ }
+
+ var source = context.createBufferSource();
+ source.buffer = buffer;
+ source.loop = true;
+ var dest = context.createMediaStreamDestination();
+ var stopTriggered = false;
+ var onstopTriggered = false;
+ dest.channelCount = 4;
+ var expectedMimeType = 'audio/ogg';
+ var totalBlobSize = 0;
+ source.channelCountMode = 'explicit';
+ source.connect(dest);
+ var elem = document.createElement('audio');
+ elem.srcObject = dest.stream;
+ mMediaStream = dest.stream;
+ source.start(0);
+ elem.play();
+ mMediaRecorder = new MediaRecorder(dest.stream);
+ mMediaRecorder.onwarning = function() {
+ ok(false, 'onwarning unexpectedly fired');
+ };
+
+ mMediaRecorder.onerror = function() {
+ ok(false, 'onerror unexpectedly fired');
+ };
+
+ mMediaRecorder.onstop = function() {
+ ok(true, 'onstop fired successfully');
+ is(mMediaRecorder.state, 'inactive', 'check recording status is inactive');
+ onstopTriggered = true;
+ SimpleTest.finish();
+ };
+ mMediaRecorder.ondataavailable = function (e) {
+ if (mMediaRecorder.state == 'recording') {
+ ok(e.data.size > 0, 'check blob has data');
+ }
+ totalBlobSize += e.data.size;
+ ok(totalBlobSize > 0, 'check the totalBlobSize');
+ is(mMediaRecorder.mimeType, expectedMimeType, 'blob should has mimetype, return ' + mMediaRecorder.mimeType);
+ if (!stopTriggered) {
+ mMediaRecorder.stop();
+ stopTriggered = true;
+ } else if (onstopTriggered) {
+ ok(false, 'ondataavailable should come before onstop event');
+ }
+ };
+ try {
+ mMediaRecorder.start(1000);
+ is('recording', mMediaRecorder.state, "check record state recording");
+ } catch (e) {
+ ok(false, 'Can t record audio context');
+ }
+}
+
+startTest();
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_record_audiocontext.html b/dom/media/test/test_mediarecorder_record_audiocontext.html
new file mode 100644
index 000000000..2697ad8d0
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_record_audiocontext.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaRecorder Record AudioContext</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+
+<script class="testbody" type="text/javascript">
+
+function startTest() {
+ var context = new AudioContext();
+ var hasonstop = false;
+ var buffer = context.createBuffer(1, 80920, context.sampleRate);
+ for (var i = 0; i < 80920; ++i) {
+ buffer.getChannelData(0)[i] = Math.sin(1000 * 2 * Math.PI * i / context.sampleRate);
+ }
+
+ var source = context.createBufferSource();
+ source.buffer = buffer;
+ source.loop = true;
+
+ var dest = context.createMediaStreamDestination();
+ source.connect(dest);
+ var elem = document.createElement('audio');
+ elem.srcObject = dest.stream;
+ mMediaStream = dest.stream;
+ source.start(0);
+ elem.play();
+ mMediaRecorder = new MediaRecorder(dest.stream);
+ mMediaRecorder.onwarning = function() {
+ ok(false, 'onwarning unexpectedly fired');
+ };
+
+ mMediaRecorder.onerror = function() {
+ ok(false, 'onerror unexpectedly fired');
+ };
+
+ mMediaRecorder.onstop = function() {
+ ok(true, 'onstop fired successfully');
+ is(mMediaRecorder.state, 'inactive', 'check recording status is inactive');
+ SimpleTest.finish();
+ };
+ mMediaRecorder.ondataavailable = function (e) {
+ if (mMediaRecorder.state == 'recording') {
+ is('audio/ogg', mMediaRecorder.mimeType, "check the record mimetype return " + mMediaRecorder.mimeType);
+ ok(e.data.size > 0, 'check blob has data');
+ mMediaRecorder.stop();
+ }
+ };
+ try {
+ mMediaRecorder.start(1000);
+ is('recording', mMediaRecorder.state, "check record state recording");
+ } catch (e) {
+ ok(false, 'Can t record audio context');
+ }
+}
+
+startTest();
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_record_audiocontext_mlk.html b/dom/media/test/test_mediarecorder_record_audiocontext_mlk.html
new file mode 100644
index 000000000..4dc645285
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_record_audiocontext_mlk.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>capture for possible memory leak when record AudioContext</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=973765">Mozill
+a Bug 973765</a>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+ // This test case want to capture the memory leak if exit the browser after running those script.
+ var ac = new window.AudioContext();
+ var destStream = ac.createMediaStreamDestination().stream;
+ var recorder = new MediaRecorder(destStream);
+ recorder.start(1000);
+ is(recorder.state, 'recording', 'Media recorder should be recording');
+ is(recorder.stream, destStream,
+ 'Media recorder stream = element stream at the start of recording');
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_record_audionode.html b/dom/media/test/test_mediarecorder_record_audionode.html
new file mode 100644
index 000000000..ec38609e7
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_record_audionode.html
@@ -0,0 +1,126 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaRecorder Record AudioContext Node</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=968109">Mozilla Bug 968109</a>
+
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function setUpSource(contextType, nodeType) {
+ // Use contextType to choose offline or real-time context.
+ var context = contextType === 'offline'?
+ new OfflineAudioContext(2 , 80920, 44100) : new AudioContext();
+ var buffer = context.createBuffer(2, 80920, context.sampleRate);
+ for (var i = 0; i < 80920; ++i) {
+ buffer.getChannelData(0)[i] = Math.sin(1000 * 2 * Math.PI * i / context.sampleRate);
+ buffer.getChannelData(1)[i] = Math.sin(1000 * 2 * Math.PI * i / context.sampleRate);
+ }
+
+ var source = context.createBufferSource();
+ source.buffer = buffer;
+ source.loop = true;
+
+ source.start(0);
+
+ // nodeType decides which node in graph should be the source of recording.
+ var node;
+ if (nodeType === 'source') {
+ node = source;
+ } else if (nodeType === 'splitter') {
+ var splitter = context.createChannelSplitter();
+ source.connect(splitter);
+ node = splitter;
+ } else if (nodeType == 'destination') {
+ source.connect(context.destination);
+ node = context.destination;
+ }
+ // Explicitly start offline context.
+ if (contextType === 'offline') {
+ context.startRendering();
+ }
+
+ return node;
+}
+
+function testRecord(source, done) {
+ ok(source, 'source node should be ok');
+ var recorder;
+ var didThrow = false;
+ try {
+ recorder = new MediaRecorder(source);
+ } catch (e) {
+ didThrow = true;
+ }
+ ok(!didThrow, 'MediaRecorder(AudioNode) should be visible after pref turned on');
+
+ recorder.onwarning = function() {
+ ok(false, 'should not fire onwarning');
+ };
+
+ recorder.onerror = function() {
+ ok(false, 'should not fire onerror');
+ };
+
+ recorder.onstop = function() {
+ is(recorder.state, 'inactive', 'state should become "inactive" after calling stop()');
+ done();
+ };
+
+ recorder.ondataavailable = function (e) {
+ if (recorder.state == 'recording') {
+ is('audio/ogg', recorder.mimeType, 'mimetype should be audio/ogg, not ' + recorder.mimeType);
+ ok(e.data && e.data.size > 0, 'should get data and its length should be > 0');
+ recorder.stop();
+ }
+ };
+
+ try {
+ recorder.start(1000);
+ is('recording', recorder.state, 'state should become "recording" after calling start()');
+ } catch (e) {
+ didThrow = true;
+ }
+ ok(!didThrow, 'start() should succeed');
+}
+
+addLoadEvent(function() {
+ var src = setUpSource();
+ var recorder;
+ var didThrow = false;
+ try {
+ recorder = new MediaRecorder(src);
+ } catch (e) {
+ didThrow = true;
+ }
+ ok(didThrow, 'MediaRecorder(AudioNode) should be hidden behind a pref');
+
+ SpecialPowers.pushPrefEnv({"set": [[ 'media.recorder.audio_node.enabled', true ]]},
+ function () {
+ // Test with various context and source node types.
+ var done1 = new Promise(function (resolve, reject) {
+ testRecord(setUpSource('', 'source'), resolve);
+ });
+ var done2 = new Promise(function (resolve, reject) {
+ testRecord(setUpSource('', 'splitter'), resolve);
+ });
+ var done3 = new Promise(function (resolve, reject) {
+ testRecord(setUpSource('offline', 'destination'), resolve);
+ });
+ // Finish test after all is done.
+ Promise.all([done1, done2, done3]).then(
+ function () { SimpleTest.finish(); }
+ );
+ });
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_record_canvas_captureStream.html b/dom/media/test/test_mediarecorder_record_canvas_captureStream.html
new file mode 100644
index 000000000..7f440fba9
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_record_canvas_captureStream.html
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaRecorder Recording canvas stream</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/dom/canvas/test/captureStream_common.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<div id="content">
+</div>
+<script class="testbody" type="text/javascript">
+
+function startTest() {
+ var canvas = document.createElement("canvas");
+ canvas.width = canvas.height = 100;
+ document.getElementById("content").appendChild(canvas);
+
+ var helper = new CaptureStreamTestHelper2D(100, 100);
+ helper.drawColor(canvas, helper.red);
+
+ var stream = canvas.captureStream(0);
+
+ var blob;
+
+ mediaRecorder = new MediaRecorder(stream);
+ is(mediaRecorder.stream, stream,
+ "Media recorder stream = canvas stream at the start of recording");
+
+ mediaRecorder.onwarning = () => ok(false, "warning unexpectedly fired");
+
+ mediaRecorder.onerror = () => ok(false, "Recording failed");
+
+ mediaRecorder.ondataavailable = ev => {
+ is(blob, undefined, "Should only get one dataavailable event");
+ blob = ev.data;
+ };
+
+ mediaRecorder.onstart = () => {
+ info("Got 'start' event");
+ // We just want one frame encoded, to see that the recorder produces something readable.
+ mediaRecorder.stop();
+ };
+
+ mediaRecorder.onstop = () => {
+ info("Got 'stop' event");
+ ok(blob, "Should have gotten a data blob");
+
+ var video = document.createElement("video");
+ video.id = "recorded-video";
+ video.src = URL.createObjectURL(blob);
+ video.play();
+ video.onerror = err => {
+ ok(false, "Should be able to play the recording. Got error. code=" + video.error.code);
+ SimpleTest.finish();
+ };
+ document.getElementById("content").appendChild(video);
+ helper.waitForPixelColor(video, helper.red, 128, "Should become red")
+ .then(SimpleTest.finish);
+ };
+
+ mediaRecorder.start();
+ is(mediaRecorder.state, "recording", "Media recorder should be recording");
+}
+
+SimpleTest.waitForExplicitFinish();
+startTest();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_record_changing_video_resolution.html b/dom/media/test/test_mediarecorder_record_changing_video_resolution.html
new file mode 100644
index 000000000..96329ff2c
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_record_changing_video_resolution.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaRecorder Recording canvas stream that dynamically changes resolution</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<div id="content">
+</div>
+<script class="testbody" type="text/javascript">
+
+function startTest() {
+ var content = document.getElementById("content");
+
+ var canvas = document.createElement("canvas");
+ canvas.width = canvas.height = 100;
+
+ var ctx = canvas.getContext("2d");
+ ctx.fillStyle = "red";
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ var stream = canvas.captureStream(0);
+
+ var numErrorRaised = 0;
+ var numDataAvailabledRaised = 0;
+
+ mediaRecorder = new MediaRecorder(stream);
+ is(mediaRecorder.stream, stream,
+ "Media recorder stream = canvas stream at the start of recording");
+
+ mediaRecorder.onwarning = () => ok(false, "onwarning unexpectedly fired");
+
+ mediaRecorder.onerror = err => {
+ info("Got 'error' event, " + err.name + " (" + err.message + ")");
+ ++numErrorRaised;
+ };
+
+ mediaRecorder.ondataavailable = ev => {
+ info("Got 'dataavailable' event");
+ ++numDataAvailabledRaised;
+ };
+
+ mediaRecorder.onstart = () => {
+ canvas.width = canvas.height = canvas.width * 1.1;
+ ctx.fillStyle = "blue";
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ stream.requestFrame();
+ };
+
+ mediaRecorder.onstop = () => {
+ info("Got 'stop' event");
+ is(numErrorRaised, 1, "Should have gotten 1 error event");
+ is(numDataAvailabledRaised, 1, "Should have gotten 1 dataavailable event");
+ SimpleTest.finish();
+ };
+
+ mediaRecorder.start();
+ is(mediaRecorder.state, "recording", "Media recorder should be recording");
+}
+
+SimpleTest.waitForExplicitFinish();
+startTest();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_record_getdata_afterstart.html b/dom/media/test/test_mediarecorder_record_getdata_afterstart.html
new file mode 100644
index 000000000..04e4ec7c8
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_record_getdata_afterstart.html
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Bug 951008 Test MediaRecorder Record has start event</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+
+ var element = document.createElement('audio');
+ var hasonstart = false;
+ var hasondataavailable = false;
+ var mMediaRecorder;
+
+ element.token = token;
+ manager.started(token);
+ element.src = test.name;
+ element.test = test;
+ element.stream = element.mozCaptureStream();
+
+ mMediaRecorder = new MediaRecorder(element.stream);
+ mMediaRecorder.onwarning = function() {
+ ok(false, 'onwarning unexpectedly fired');
+ };
+
+ mMediaRecorder.onerror = function() {
+ ok(false, 'onerror unexpectedly fired');
+ };
+
+ mMediaRecorder.onstart = function() {
+ info('onstart fired successfully');
+ hasonstart = true;
+ // On audio only case, we produce audio/ogg as mimeType.
+ is('audio/ogg', mMediaRecorder.mimeType, "check the record mimetype return " + mMediaRecorder.mimeType);
+ mMediaRecorder.requestData();
+ };
+
+ mMediaRecorder.onstop = function() {
+ info('onstop fired successfully');
+ ok (hasondataavailable, "should have ondataavailable before onstop");
+ is(mMediaRecorder.state, 'inactive', 'check recording status is inactive');
+ SimpleTest.finish();
+ };
+
+ mMediaRecorder.ondataavailable = function (e) {
+ info('ondataavailable fired successfully');
+ if (mMediaRecorder.state == 'recording') {
+ hasondataavailable = true;
+ ok(hasonstart, "should has onstart event first");
+ ok(e.data.size > 0, 'check blob has data');
+ mMediaRecorder.stop();
+ }
+ };
+
+ // Start recording once metadata are parsed.
+ element.onloadedmetadata = function() {
+ element.oncanplaythrough = null;
+ mMediaRecorder.start(0);
+ is(mMediaRecorder.state, 'recording', 'Media recorder should be recording');
+ is(mMediaRecorder.stream, element.stream,
+ 'Media recorder stream = element stream at the start of recording');
+ };
+
+ element.play();
+}
+
+manager.runTests(gMediaRecorderTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_record_gum_video_timeslice.html b/dom/media/test/test_mediarecorder_record_gum_video_timeslice.html
new file mode 100644
index 000000000..efdd98303
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_record_gum_video_timeslice.html
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaRecorder Record gUM video with Timeslice</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<div id="content" style="display: none">
+</div>
+<script class="testbody" type="text/javascript">
+
+function startTest() {
+ navigator.mozGetUserMedia({audio: true, video: true, fake: true}, function(stream) {
+ var dataAvailableCount = 0;
+ var onDataAvailableFirst = false;
+
+ mediaRecorder = new MediaRecorder(stream);
+ is(mediaRecorder.stream, stream,
+ 'Media recorder stream = element stream at the start of recording');
+ mediaRecorder.onwarning = function() {
+ ok(false, 'onwarning unexpectedly fired');
+ };
+
+ mediaRecorder.onerror = function() {
+ ok(false, 'onerror unexpectedly fired');
+ };
+
+ mediaRecorder.onstop = function() {
+ ok(false, 'Unexpected onstop callback fired');
+ };
+
+ mediaRecorder.ondataavailable = function (evt) {
+ info('ondataavailable fired');
+ dataAvailableCount++;
+
+ ok(evt instanceof BlobEvent,
+ 'Events fired from ondataavailable should be BlobEvent');
+ is(evt.type, 'dataavailable',
+ 'Event type should dataavailable');
+ ok(evt.data.size >= 0,
+ 'Blob data size ' + evt.data.size + ' received is greater than or equal to zero');
+ is(mediaRecorder.mimeType, evt.data.type,
+ 'Mime type in MediaRecorder and ondataavailable : '
+ + mediaRecorder.mimeType + ' == ' + evt.data.type);
+
+ // We'll stop recording upon the 1st blob being received
+ if (dataAvailableCount === 1) {
+ mediaRecorder.onstop = function (evt) {
+ info('onstop fired');
+
+ if (!onDataAvailableFirst) {
+ ok(false, 'onstop unexpectedly fired before ondataavailable');
+ }
+
+ ok(true, 'onstop fired successfully');
+ is(mediaRecorder.state, 'inactive',
+ 'check recording status is inactive');
+ SimpleTest.finish();
+ };
+
+ mediaRecorder.stop();
+ is(mediaRecorder.state, 'inactive',
+ 'Media recorder is inactive after being stopped');
+
+ } else if (dataAvailableCount === 2) {
+ // Ensure we've received at least two ondataavailable events before
+ // onstop
+ onDataAvailableFirst = true;
+ }
+ };
+
+ mediaRecorder.start(250);
+ is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
+ }, function(err) {
+ ok(false, 'Unexpected error fired with: ' + err);
+ SimpleTest.finish();
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+startTest();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_record_immediate_stop.html b/dom/media/test/test_mediarecorder_record_immediate_stop.html
new file mode 100644
index 000000000..fd0f64c8a
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_record_immediate_stop.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaRecorder Immediate Stop</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+/**
+ * Stops the media recorder immediately after starting the recorder. This test
+ * verifies whether the media recorder can handle this scenario nicely. The
+ * return blob size should be greater than zero, but its duration would be zero
+ * length when play.
+ */
+function startTest(test, token) {
+ var element = document.createElement('audio');
+ var expectedMimeType = test.type.substring(0, test.type.indexOf(';'));
+
+ element.token = token;
+ manager.started(token);
+
+ element.src = test.name;
+ element.test = test;
+ element.stream = element.mozCaptureStreamUntilEnded();
+
+ var mediaRecorder = new MediaRecorder(element.stream);
+ var onStopFired = false;
+ var onDataAvailableFired = false;
+
+ mediaRecorder.onerror = function () {
+ ok(false, 'Unexpected onerror callback fired');
+ };
+
+ mediaRecorder.onwarning = function () {
+ ok(false, 'Unexpected onwarning callback fired');
+ };
+
+ // This handler verifies that only a single onstop event handler is fired.
+ mediaRecorder.onstop = function () {
+ if (onStopFired) {
+ ok(false, 'onstop unexpectedly fired more than once');
+ } else {
+ onStopFired = true;
+
+ // ondataavailable should always fire before onstop
+ if (onDataAvailableFired) {
+ manager.finished(token);
+ } else {
+ ok(false, 'onstop fired without an ondataavailable event first');
+ }
+ }
+ };
+
+ // This handler verifies that only a single ondataavailable event handler
+ // is fired with the blob generated having greater than zero size
+ // and a correct mime type.
+ mediaRecorder.ondataavailable = function (evt) {
+ if (onDataAvailableFired) {
+ ok(false, 'ondataavailable unexpectedly fired more than once');
+ } else {
+ onDataAvailableFired = true;
+
+ ok(evt instanceof BlobEvent,
+ 'Events fired from ondataavailable should be BlobEvent');
+ is(evt.type, 'dataavailable',
+ 'Event type should dataavailable');
+
+ // The initialization of encoder can be cancelled.
+ // On some platforms, the stop method may run after media stream track
+ // available, so the blob can contain the header data.
+ if (evt.data.size > 0) {
+ is(evt.data.type, expectedMimeType,
+ 'Blob data received and should have mime type');
+ is(mediaRecorder.mimeType, expectedMimeType,
+ 'Media Recorder mime type in ondataavailable = ' + expectedMimeType);
+ } else if (evt.data.size === 0) {
+ is(mediaRecorder.mimeType, '',
+ 'Blob data mime type is empty');
+ is(mediaRecorder.mimeType, '',
+ 'Media Recorder mime type in ondataavailable is empty');
+ } else {
+ ok(false, 'Blob size can not be negative');
+ }
+
+ // onstop should not have fired before ondataavailable
+ if (onStopFired) {
+ ok(false, 'ondataavailable unexpectedly fired later than onstop');
+ manager.finished(token);
+ }
+ }
+ };
+
+ // This handler completes a start and stop of recording and verifies
+ // respective media recorder state.
+ element.onloadedmetadata = function () {
+ element.onloadedmetadata = null;
+ element.play();
+ mediaRecorder.start();
+ is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
+ is(mediaRecorder.stream, element.stream,
+ 'Media recorder stream = element stream at the start of recording');
+
+ mediaRecorder.stop();
+ is(mediaRecorder.state, 'inactive',
+ 'Media recorder is inactive after being stopped');
+ is(mediaRecorder.stream, element.stream,
+ 'Media recorder stream = element stream post recording');
+ };
+
+ element.preload = "metadata";
+}
+
+manager.runTests(gMediaRecorderTests, startTest);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_record_no_timeslice.html b/dom/media/test/test_mediarecorder_record_no_timeslice.html
new file mode 100644
index 000000000..a408160a5
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_record_no_timeslice.html
@@ -0,0 +1,105 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaRecorder Record No Timeslice</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+/**
+ * Starts a test on every media recorder file included to check that a
+ * stream derived from the file can be recorded with no time slice provided.
+ */
+function startTest(test, token) {
+ var element = document.createElement('audio');
+ var expectedMimeType = test.type.substring(0, test.type.indexOf(';'));
+
+ element.token = token;
+ manager.started(token);
+
+ element.src = test.name;
+ element.test = test;
+ element.stream = element.mozCaptureStreamUntilEnded();
+
+ var mediaRecorder = new MediaRecorder(element.stream);
+ var onStopFired = false;
+ var onDataAvailableFired = false;
+
+ mediaRecorder.onerror = function () {
+ ok(false, 'Unexpected onerror callback fired');
+ };
+
+ mediaRecorder.onwarning = function () {
+ ok(false, 'Unexpected onwarning callback fired');
+ };
+
+ // This handler verifies that only a single onstop event handler is fired.
+ mediaRecorder.onstop = function () {
+ if (onStopFired) {
+ ok(false, 'onstop unexpectedly fired more than once');
+ } else {
+ onStopFired = true;
+
+ // ondataavailable should always fire before onstop
+ if (onDataAvailableFired) {
+ ok(true, 'onstop fired after ondataavailable');
+ manager.finished(token);
+ } else {
+ ok(false, 'onstop fired without an ondataavailable event first');
+ }
+ }
+ };
+
+ // This handler verifies that only a single ondataavailable event handler
+ // is fired with the blob generated having greater than zero size
+ // and a correct mime type.
+ mediaRecorder.ondataavailable = function (evt) {
+ if (onDataAvailableFired) {
+ ok(false, 'ondataavailable unexpectedly fired more than once');
+ } else {
+ onDataAvailableFired = true;
+
+ ok(evt instanceof BlobEvent,
+ 'Events fired from ondataavailable should be BlobEvent');
+ is(evt.type, 'dataavailable',
+ 'Event type should dataavailable');
+ ok(evt.data.size > 0,
+ 'Blob data received should be greater than zero');
+ is(evt.data.type, expectedMimeType,
+ 'Blob data received should have type = ' + expectedMimeType);
+
+ is(mediaRecorder.mimeType, expectedMimeType,
+ 'Mime type in ondataavailable = ' + expectedMimeType);
+
+ // onstop should not have fired before ondataavailable
+ if (onStopFired) {
+ ok(false, 'ondataavailable unexpectedly fired later than onstop');
+ manager.finished(token);
+ }
+ }
+ };
+
+ element.preload = "metadata";
+
+ element.onloadedmetadata = function () {
+ element.onloadedmetadata = null;
+ mediaRecorder.start();
+ is(mediaRecorder.state, 'recording',
+ 'Media recorder should be recording');
+ is(mediaRecorder.stream, element.stream,
+ 'Media recorder stream = element stream at the start of recording');
+
+ element.play();
+ }
+}
+
+manager.runTests(gMediaRecorderTests, startTest);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_record_session.html b/dom/media/test/test_mediarecorder_record_session.html
new file mode 100644
index 000000000..3c179ced0
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_record_session.html
@@ -0,0 +1,75 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=909670
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Media Recoder recording session</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ var element = document.createElement('audio');
+
+ element.token = token;
+ manager.started(token);
+
+ element.src = test.name;
+ element.test = test;
+ element.stream = element.mozCaptureStream();
+
+ var mStopCount = 0;
+ // Start and stop recording session three times continuously.
+ var mExpectStopCount = 3;
+ var mediaRecorder = new MediaRecorder(element.stream);
+
+ // Stop callback.
+ // Suppose to receive mExpectStopCount
+ mediaRecorder.onstop = function stopCallback() {
+ mStopCount++;
+
+ info("MediaRecorder.onstop callback: (" + mStopCount + ")");
+
+ if (mExpectStopCount === mStopCount)
+ {
+ manager.finished(token);
+ }
+ }
+
+ // data avaliable.
+ mediaRecorder.ondataavailable = function(evt) {}
+
+ mediaRecorder.onerror = function(err) {
+ ok(false, 'Unexpected error fired with:' + err);
+ }
+
+ mediaRecorder.onwarning = function() {
+ ok(false, 'Unexpected warning fired');
+ }
+
+ element.preload = "metadata";
+
+ element.onloadedmetadata = function () {
+ element.onloadedmetadata = null;
+ element.play();
+ for (var i = 0; i < mExpectStopCount; i++) {
+ mediaRecorder.start(1000);
+ mediaRecorder.stop();
+ }
+ }
+
+}
+
+manager.runTests(gMediaRecorderTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_record_startstopstart.html b/dom/media/test/test_mediarecorder_record_startstopstart.html
new file mode 100644
index 000000000..1d90a782b
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_record_startstopstart.html
@@ -0,0 +1,77 @@
+ <!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaRecorder crash on sequence start stop start method</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<div id="content" style="display: none">
+</div>
+<script class="testbody" type="text/javascript">
+
+function startTest() {
+ var ac = new window.AudioContext();
+ var dest = ac.createMediaStreamDestination();
+ var recorder = new MediaRecorder(dest.stream);
+ var stopCount = 0;
+ var dataavailable = 0;
+ // mobile device may produce another format, but not landed.
+ // In audio only case, we should produce opus type.
+ var expectedMimeType = 'audio/ogg';
+ recorder.onstop = function (e) {
+ info('onstop fired');
+ is(recorder.stream, dest.stream,
+ 'Media recorder stream = element stream post recording');
+ stopCount++;
+ if (stopCount == 2) {
+ if (dataavailable >= 2) {
+ SimpleTest.finish();
+ } else {
+ ok(false, 'Should have at least two dataavailable events');
+ }
+ }
+ }
+ recorder.ondataavailable = function (evt) {
+ info('ondataavailable fired');
+ ok(evt instanceof BlobEvent,
+ 'Events fired from ondataavailable should be BlobEvent');
+ is(evt.type, 'dataavailable',
+ 'Event type should dataavailable');
+ // If script runs slower, it may generate header data in blob from encoder
+ if (evt.data.size > 0) {
+ info('blob size = ' + evt.data.size);
+ is(evt.data.type, expectedMimeType,
+ 'Blob data received should have type = ' + expectedMimeType);
+ }
+ dataavailable++;
+ }
+ recorder.onerror = function (e) {
+ ok(false, 'it should execute normally without exception');
+ }
+ recorder.onwarning = function() {
+ ok(false, 'onwarning unexpectedly fired');
+ };
+
+ recorder.start(2000);
+ is(recorder.state, 'recording', 'Media recorder should be recording');
+ recorder.stop();
+ is(recorder.state, 'inactive', 'check recording status is inactive');
+ recorder.start(10000); // This bug would crash on this line without this fix.
+ is(recorder.state, 'recording', 'check recording status is recording');
+ // Simulate delay stop, only delay stop no no stop can trigger crash.
+ setTimeout(function() {
+ recorder.stop();
+ is(recorder.state, 'inactive','check recording status is recording');
+ }, 1000);
+}
+
+SimpleTest.requestFlakyTimeout("untriaged");
+startTest();
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/media/test/test_mediarecorder_record_stopms.html b/dom/media/test/test_mediarecorder_record_stopms.html
new file mode 100644
index 000000000..0dad5ba61
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_record_stopms.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaRecorder Record Stopped Stream</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<div id="content" style="display: none">
+ <audio id="testAudio"></audio>
+</div>
+<script class="testbody" type="text/javascript">
+
+function startTest() {
+ navigator.mozGetUserMedia({audio: true, fake: true}, function(stream) {
+ var testAudio = document.getElementById('testAudio');
+
+ testAudio.onended = function() {
+ var mediaRecorder = new MediaRecorder(stream);
+ try {
+ mediaRecorder.start();
+ ok(false, 'Recording a stopped stream failed to throw an exception');
+ } catch (e) {
+ is(e.name, 'InvalidStateError',
+ 'Recording a stopped stream threw an InvalidStateError');
+ } finally {
+ SimpleTest.finish();
+ }
+ };
+
+ testAudio.mozSrcObject = stream;
+ testAudio.play();
+ stream.stop();
+ }, function(err) {
+ ok(false, 'Unexpected error fired with: ' + err);
+ SimpleTest.finish();
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+startTest();
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/media/test/test_mediarecorder_record_timeslice.html b/dom/media/test/test_mediarecorder_record_timeslice.html
new file mode 100644
index 000000000..f1e4e9927
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_record_timeslice.html
@@ -0,0 +1,104 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaRecorder Record Timeslice</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+/**
+ * Starts a test on every media recorder file included to check that a stream
+ * derived from the file can be recorded with a timeslice provided
+ */
+function startTest(test, token) {
+ var element = document.createElement('audio');
+ var expectedMimeType = test.type.substring(0, test.type.indexOf(';'));
+
+ element.token = token;
+ manager.started(token);
+
+ element.src = test.name;
+ element.test = test;
+ element.preload = "auto";
+
+ // Set up MediaRecorder once loadedmetadata fires and tracks are available.
+ element.onloadedmetadata = function() {
+ element.onloadedmetadata = null;
+
+ const stream = element.mozCaptureStream();
+ const mediaRecorder = new MediaRecorder(stream);
+
+ mediaRecorder.onerror = function () {
+ ok(false, 'Unexpected onerror callback fired');
+ };
+
+ mediaRecorder.onwarning = function () {
+ ok(false, 'Unexpected onwarning callback fired');
+ };
+
+ mediaRecorder.onstop = function () {
+ ok(false, 'Unexpected onstop callback fired');
+ };
+
+ var dataAvailableCount = 0;
+ var onDataAvailableFirst = false;
+
+ // This handler fires every 250ms to generate a blob.
+ mediaRecorder.ondataavailable = function (evt) {
+ info('ondataavailable fired');
+ dataAvailableCount++;
+
+ ok(evt instanceof BlobEvent,
+ 'Events fired from ondataavailable should be BlobEvent');
+ is(evt.type, 'dataavailable',
+ 'Event type should dataavailable');
+ ok(evt.data.size >= 0,
+ 'Blob data size received is greater than or equal to zero');
+
+ is(evt.data.type, expectedMimeType,
+ 'Blob data received should have type = ' + expectedMimeType);
+ is(mediaRecorder.mimeType, expectedMimeType,
+ 'Mime type in ondataavailable = ' + mediaRecorder.mimeType);
+
+ // We'll stop recording upon the 1st blob being received
+ if (dataAvailableCount === 1) {
+ mediaRecorder.onstop = function (evt) {
+ info('onstop fired');
+
+ if (!onDataAvailableFirst) {
+ ok(false, 'onstop unexpectedly fired before ondataavailable');
+ }
+ element.pause();
+ manager.finished(token);
+ };
+
+ mediaRecorder.stop();
+ is(mediaRecorder.state, 'inactive',
+ 'Media recorder is inactive after being stopped');
+ is(mediaRecorder.stream, stream,
+ 'Media recorder stream = element stream post recording');
+
+ } else if (dataAvailableCount === 2) {
+ // Ensure we've received at least two ondataavailable events before onstop
+ onDataAvailableFirst = true;
+ }
+ };
+
+ mediaRecorder.start(1);
+ element.play();
+ is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
+ is(mediaRecorder.stream, stream,
+ 'Media recorder stream = element stream at the start of recording');
+ };
+}
+
+manager.runTests(gMediaRecorderTests, startTest);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_reload_crash.html b/dom/media/test/test_mediarecorder_reload_crash.html
new file mode 100644
index 000000000..f292ed7df
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_reload_crash.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test that reloading media recorder object</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=894348">Mozill
+a Bug 894348</a>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+ for (i = 0; i< 5; i++) {
+ try { o0 = document.createElement('audio') } catch(e) { }
+ try { o0.src = "sound.ogg" } catch(e) { }
+ try { (document.body || document.documentElement).appendChild(o0) } catch(e) { }
+ try { o1 = o0.mozCaptureStreamUntilEnded(); } catch(e) { }
+ try { o2 = new MediaRecorder(o1) } catch(e) { }
+ try { o2.start(0) } catch(e) { }
+ SpecialPowers.gc();
+ }
+ ok(true, "pass the crash test");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_state_transition.html b/dom/media/test/test_mediarecorder_state_transition.html
new file mode 100644
index 000000000..7b224c5fc
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_state_transition.html
@@ -0,0 +1,171 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaRecorder State Transition</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+// List of operation tests for media recorder objects to verify if running
+// these operations should result in an exception or not
+var operationTests = [
+ {
+ operations: ['stop'],
+ isValid: false
+ },
+ {
+ operations: ['requestData'],
+ isValid: false
+ },
+ {
+ operations: ['pause'],
+ isValid: false
+ },
+ {
+ operations: ['resume'],
+ isValid: false
+ },
+ {
+ operations: ['start'],
+ isValid: true
+ },
+ {
+ operations: ['start'],
+ isValid: true,
+ timeSlice: 200
+ },
+ {
+ operations: ['start', 'pause'],
+ isValid: true
+ },
+ {
+ operations: ['start', 'pause'],
+ isValid: true,
+ timeSlice: 200
+ },
+ {
+ operations: ['start', 'start'],
+ isValid: false
+ },
+ {
+ operations: ['start', 'resume'],
+ isValid: false
+ },
+ {
+ operations: ['start', 'stop'],
+ isValid: true
+ },
+ {
+ operations: ['start', 'stop'],
+ isValid: true,
+ timeSlice: 200
+ },
+ {
+ operations: ['start', 'requestData'],
+ isValid: true
+ },
+ {
+ operations: ['start', 'requestData'],
+ isValid: true,
+ timeSlice: 200
+ },
+ {
+ operations: ['start', 'pause', 'stop'],
+ isValid: true
+ },
+ {
+ operations: ['start', 'pause', 'start'],
+ isValid: false
+ },
+ {
+ operations: ['start', 'pause', 'pause'],
+ isValid: false
+ },
+ {
+ operations: ['start', 'pause', 'requestData'],
+ isValid: false
+ },
+ {
+ operations: ['start', 'pause', 'resume'],
+ isValid: true
+ },
+ {
+ operations: ['start', 'pause', 'resume'],
+ isValid: true,
+ timeSlice: 200
+ }
+];
+
+/**
+ * Runs through each available state transition test by running all
+ * available operations on a media recorder object. Then, we report
+ * back if the test was expected through an exception or not.
+ *
+ * @param {MediaStream} testStream the media stream used for media recorder
+ * operation tests
+ */
+function runStateTransitionTests(testStream) {
+ for (operationTest of operationTests) {
+ var mediaRecorder = new MediaRecorder(testStream);
+ var operationsString = operationTest.operations.toString();
+
+ try {
+ for (operation of operationTest.operations) {
+ if (operationTest.timeSlice && operation === 'start') {
+ operationsString += ' with timeslice ' + operationTest.timeSlice;
+ mediaRecorder[operation](operationTest.timeSlice);
+ } else {
+ mediaRecorder[operation]();
+ }
+ }
+
+ if (operationTest.isValid) {
+ ok(true, 'Successful transitions for ' + operationsString);
+ } else {
+ ok(false, 'Failed transitions for ' + operationsString);
+ }
+ } catch (err) {
+ if (!operationTest.isValid && err.name === 'InvalidStateError') {
+ ok(true, 'InvalidStateError fired for ' + operationsString);
+ } else {
+ ok(false, 'No InvalidStateError for ' + operationsString);
+ }
+ }
+ }
+}
+
+/**
+ * Starts a test on every media recorder file included to check that various
+ * state transition flows that can happen in the media recorder object throw
+ * exceptions when they are expected to and vice versa.
+ */
+function startTest(test, token) {
+ var element = document.createElement('audio');
+ var expectedMimeType = test.type.substring(0, test.type.indexOf(';'));
+
+ element.token = token;
+ manager.started(token);
+
+ element.src = test.name;
+ element.test = test;
+ element.stream = element.mozCaptureStream();
+
+ element.oncanplaythrough = function () {
+ element.oncanplaythrough = null;
+ runStateTransitionTests(element.stream);
+ manager.finished(token);
+ };
+
+ element.play();
+}
+
+manager.runTests(gMediaRecorderTests, startTest);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediarecorder_unsupported_src.html b/dom/media/test/test_mediarecorder_unsupported_src.html
new file mode 100644
index 000000000..cbbc82e7d
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_unsupported_src.html
@@ -0,0 +1,99 @@
+<html>
+<head>
+ <title>Bug 957439 - Media Recording - Assertion fail at Pause if unsupported input stream.</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=957439">Mozilla Bug 957439</a>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+
+function startTest() {
+ // also do general checks on mimetype support for audio-only
+ ok(MediaRecorder.isTypeSupported("audio/ogg"), 'Should support audio/ogg');
+ ok(MediaRecorder.isTypeSupported('audio/ogg; codecs="opus"'), 'Should support audio/ogg+opus');
+ ok(!MediaRecorder.isTypeSupported('audio/ogg; codecs="foobar"'), 'Should not support audio/ogg + unknown_codec');
+ ok(!MediaRecorder.isTypeSupported("video/webm"), 'Should not support video/webm');
+ ok(!MediaRecorder.isTypeSupported("video/mp4"), 'Should not support video/mp4');
+
+ navigator.mozGetUserMedia({audio: false, video: true, fake: true},
+ function(stream) {
+
+ // Expected callback sequence should be:
+ // 1. onerror (from start)
+ // 2. onerror (from pause)
+ // 3. ondataavailable
+ // 4. onstop
+ var callbackStep = 0;
+ var mediaRecorder = new MediaRecorder(stream);
+
+ is(mediaRecorder.stream, stream, 'Stream should be provided on creation');
+
+ mediaRecorder.onerror = function (e) {
+ callbackStep++;
+ if (callbackStep == 1) {
+ try {
+ mediaRecorder.pause();
+ } catch(e) {
+ ok(false, 'Should not get exception in pause call.');
+ }
+ }
+ ok(callbackStep < 3, 'onerror callback fired as expected.');
+ is(e.name, 'GenericError', 'Error name should be GenericError.');
+ is(mediaRecorder.mimeType, '', 'mimetype should be empty');
+ is(mediaRecorder.state, 'recording', 'state is recording');
+ info('onerror callback fired');
+ }
+
+ mediaRecorder.onwarning = function () {
+ ok(false, 'Unexpected onwarning callback fired.');
+ };
+
+ mediaRecorder.ondataavailable = function (evt) {
+ callbackStep++;
+ info('ondataavailable callback fired');
+ is(callbackStep, 3, 'should fired ondataavailable callback');
+ is(evt.data.size, 0, 'data size should be zero');
+ ok(evt instanceof BlobEvent,
+ 'Events fired from ondataavailable should be BlobEvent');
+ is(evt.data.type, '', 'encoder start fail, blob miemType should be empty');
+ };
+
+ mediaRecorder.onstop = function() {
+ callbackStep++;
+ info('onstop callback fired');
+ is(mediaRecorder.state, 'inactive', 'state should be inactive');
+ is(callbackStep, 4, 'should fired onstop callback');
+ SimpleTest.finish();
+ };
+
+ try {
+ mediaRecorder.start();
+ } catch(e) {
+ ok(false, 'Should not get exception in start call.');
+ }
+ },
+ function(err) {
+ ok(false, 'Unexpected error fired with: ' + err);
+ SimpleTest.finish();
+ }
+ );
+}
+
+SimpleTest.waitForExplicitFinish();
+
+// In order to generate an "unsupported stream", pref off video encoding to
+// make the platform support audio encoding only.
+SpecialPowers.pushPrefEnv(
+ {
+ "set": [
+ ["media.encoder.webm.enabled", false],
+ ]
+ }, startTest);
+
+</script>
+</head>
+</html>
diff --git a/dom/media/test/test_mediarecorder_webm_support.html b/dom/media/test/test_mediarecorder_webm_support.html
new file mode 100644
index 000000000..b17bd0bfd
--- /dev/null
+++ b/dom/media/test/test_mediarecorder_webm_support.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media Recording - test WebM MIME support</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+ok(MediaRecorder.isTypeSupported('video/webm'), 'Should support video/webm');
+ok(!MediaRecorder.isTypeSupported('video/webm; codecs="vp8, vorbis"'), 'Should not support video/webm + vp8/vorbis');
+ok(!MediaRecorder.isTypeSupported('video/webm; codecs="vp9, vorbis"'), 'Should not support video/webm + vp9/vorbis');
+ok(MediaRecorder.isTypeSupported('video/webm; codecs="vp8, opus"'), 'Should support video/webm + vp8/opus');
+ok(!MediaRecorder.isTypeSupported('video/webm; codecs="vp9, opus"'), 'Should not support video/webm + vp9/opus');
+</script>
+</head>
+</html>
diff --git a/dom/media/test/test_mediatrack_consuming_mediaresource.html b/dom/media/test/test_mediatrack_consuming_mediaresource.html
new file mode 100644
index 000000000..c8ce3a8b4
--- /dev/null
+++ b/dom/media/test/test_mediatrack_consuming_mediaresource.html
@@ -0,0 +1,181 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test track interfaces when consuming media resources</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ var elemType = getMajorMimeType(test.type);
+ var element = document.createElement(elemType);
+
+ var audioOnchange = 0;
+ var audioOnaddtrack = 0;
+ var audioOnremovetrack = 0;
+ var videoOnchange = 0;
+ var videoOnaddtrack = 0;
+ var videoOnremovetrack = 0;
+ var isPlaying = false;
+
+ isnot(element.audioTracks, undefined,
+ 'HTMLMediaElement::AudioTracks() property should be available.');
+ isnot(element.videoTracks, undefined,
+ 'HTMLMediaElement::VideoTracks() property should be available.');
+
+ element.audioTracks.onaddtrack = function(e) {
+ audioOnaddtrack++;
+ }
+
+ element.audioTracks.onremovetrack = function(e) {
+ audioOnremovetrack++;
+ }
+
+ element.audioTracks.onchange = function(e) {
+ audioOnchange++;
+ }
+
+ element.videoTracks.onaddtrack = function(e) {
+ videoOnaddtrack++;
+ }
+
+ element.videoTracks.onremovetrack = function(e) {
+ videoOnremovetrack++;
+ }
+
+ element.videoTracks.onchange = function(e) {
+ videoOnchange++;
+ }
+
+ function checkTrackRemoved() {
+ if (isPlaying) {
+ if (test.hasAudio) {
+ is(audioOnremovetrack, 1, 'Calls of onremovetrack on audioTracks should be 1.');
+ is(element.audioTracks.length, 0, 'The length of audioTracks should be 0.');
+ }
+ if (test.hasVideo) {
+ is(videoOnremovetrack, 1, 'Calls of onremovetrack on videoTracks should be 1.');
+ is(element.videoTracks.length, 0, 'The length of videoTracks should be 0.');
+ }
+ }
+ }
+
+ function onended() {
+ ok(true, 'Event ended is expected to be fired on element.');
+ checkTrackRemoved();
+ element.onended = null;
+ element.onplaying = null;
+ element.onpause = null;
+ manager.finished(element.token);
+ }
+
+ function checkTrackAdded() {
+ isPlaying = true;
+ if (test.hasAudio) {
+ is(audioOnaddtrack, 1, 'Calls of onaddtrack on audioTracks should be 1.');
+ is(element.audioTracks.length, 1, 'The length of audioTracks should be 1.');
+ ok(element.audioTracks[0].enabled, 'Audio track should be enabled as default.');
+ }
+ if (test.hasVideo) {
+ is(videoOnaddtrack, 1, 'Calls of onaddtrack on videoTracks should be 1.');
+ is(element.videoTracks.length, 1, 'The length of videoTracks should be 1.');
+ is(element.videoTracks.selectedIndex, 0,
+ 'The first video track is set selected as default.');
+ }
+ }
+
+ function setTrackEnabled(enabled) {
+ if (test.hasAudio) {
+ element.audioTracks[0].enabled = enabled;
+ }
+ if (test.hasVideo) {
+ element.videoTracks[0].selected = enabled;
+ }
+ }
+
+ function checkTrackChanged(calls, enabled) {
+ if (test.hasAudio) {
+ is(audioOnchange, calls, 'Calls of onchange on audioTracks should be '+calls);
+ is(element.audioTracks[0].enabled, enabled,
+ 'Enabled value of the audio track should be ' +enabled);
+ }
+ if (test.hasVideo) {
+ is(videoOnchange, calls, 'Calls of onchange on videoTracks should be '+calls);
+ is(element.videoTracks[0].selected, enabled,
+ 'Selected value of the video track should be ' +enabled);
+ var index = enabled ? 0 : -1;
+ is(element.videoTracks.selectedIndex, index,
+ 'SelectedIndex of video tracks should be ' +index);
+ }
+ }
+
+ function onpause() {
+ element.onpause = null;
+ if (element.ended) {
+ return;
+ }
+ if (steps == 1) {
+ setTrackEnabled(false);
+ element.onplaying = onplaying;
+ element.play();
+ steps++;
+ } else if (steps == 2) {
+ setTrackEnabled(true);
+ element.onplaying = onplaying;
+ element.play();
+ steps++;
+ }
+ }
+
+ function onplaying() {
+ element.onplaying = null;
+ if (element.ended) {
+ return;
+ }
+ if (steps == 1) {
+ element.onpause = onpause;
+ element.pause();
+ checkTrackAdded();
+ } else if (steps == 2) {
+ element.onpause = onpause;
+ element.pause();
+ checkTrackChanged(1, false);
+ } else if (steps == 3) {
+ checkTrackChanged(2, true);
+ }
+ }
+
+ var steps = 0;
+
+ element.token = token;
+ manager.started(token);
+
+ element.src = test.name;
+ element.test = test;
+ element.onplaying = onplaying;
+ element.onended = onended;
+ element.play();
+ steps++;
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv(
+ {
+ "set": [
+ ["media.track.enabled", true]
+ ]
+ },
+ function() {
+ manager.runTests(gTrackTests, startTest);
+ });
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediatrack_consuming_mediastream.html b/dom/media/test/test_mediatrack_consuming_mediastream.html
new file mode 100644
index 000000000..a0961d0ff
--- /dev/null
+++ b/dom/media/test/test_mediatrack_consuming_mediastream.html
@@ -0,0 +1,155 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test track interfaces when consuming a MediaStream from gUM</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+function startTest() {
+ navigator.mozGetUserMedia({audio:true, video:true, fake:true},
+ function(stream) {
+ var element = document.createElement("video");
+
+ var audioOnchange = 0;
+ var audioOnaddtrack = 0;
+ var audioOnremovetrack = 0;
+ var videoOnchange = 0;
+ var videoOnaddtrack = 0;
+ var videoOnremovetrack = 0;
+ var isPlaying = false;
+
+ element.audioTracks.onaddtrack = function(e) {
+ audioOnaddtrack++;
+ }
+
+ element.audioTracks.onremovetrack = function(e) {
+ audioOnremovetrack++;
+ }
+
+ element.audioTracks.onchange = function(e) {
+ audioOnchange++;
+ }
+
+ element.videoTracks.onaddtrack = function(e) {
+ videoOnaddtrack++;
+ }
+
+ element.videoTracks.onremovetrack = function(e) {
+ videoOnremovetrack++;
+ }
+
+ element.videoTracks.onchange = function(e) {
+ videoOnchange++;
+ }
+
+ function checkTrackRemoved() {
+ if (isPlaying) {
+ is(element.audioTracks.length, 0, 'The length of audioTracks should be 0.');
+ is(element.videoTracks.length, 0, 'The length of videoTracks should be 0.');
+ }
+ }
+
+ function onended() {
+ ok(true, 'Event ended is expected to be fired on element.');
+ checkTrackRemoved();
+ element.onended = null;
+ element.onplaying = null;
+ element.onpause = null;
+ SimpleTest.finish();
+ }
+
+ function checkTrackAdded() {
+ isPlaying = true;
+ is(audioOnaddtrack, 1, 'Calls of onaddtrack on audioTracks should be 1.');
+ is(element.audioTracks.length, 1, 'The length of audioTracks should be 1.');
+ ok(element.audioTracks[0].enabled, 'Audio track should be enabled as default.');
+ is(videoOnaddtrack, 1, 'Calls of onaddtrack on videoTracks should be 1.');
+ is(element.videoTracks.length, 1, 'The length of videoTracks should be 1.');
+ is(element.videoTracks.selectedIndex, 0,
+ 'The first video track is set selected as default.');
+ }
+
+ function setTrackEnabled(enabled) {
+ element.audioTracks[0].enabled = enabled;
+ element.videoTracks[0].selected = enabled;
+ }
+
+ function checkTrackChanged(calls, enabled) {
+ is(audioOnchange, calls, 'Calls of onchange on audioTracks should be '+calls);
+ is(element.audioTracks[0].enabled, enabled,
+ 'Enabled value of the audio track should be ' +enabled);
+ is(videoOnchange, calls, 'Calls of onchange on videoTracks should be '+calls);
+ is(element.videoTracks[0].selected, enabled,
+ 'Selected value of the video track should be ' +enabled);
+ var index = enabled ? 0 : -1;
+ is(element.videoTracks.selectedIndex, index,
+ 'SelectedIndex of video tracks should be ' +index);
+ }
+
+ function onpause() {
+ element.onpause = null;
+ if (element.ended) {
+ return;
+ }
+ if (steps == 1) {
+ setTrackEnabled(false);
+ element.onplaying = onplaying;
+ element.play();
+ steps++;
+ } else if (steps == 2) {
+ setTrackEnabled(true);
+ element.onplaying = onplaying;
+ element.play();
+ steps++;
+ }
+ }
+
+ function onplaying() {
+ element.onplaying = null;
+ if (element.ended) {
+ return;
+ }
+ if (steps == 1) {
+ element.onpause = onpause;
+ element.pause();
+ checkTrackAdded();
+ } else if (steps == 2) {
+ element.onpause = onpause;
+ element.pause();
+ checkTrackChanged(1, false);
+ } else if (steps == 3) {
+ checkTrackChanged(2, true);
+ stream.stop();
+ }
+ }
+
+ var steps = 0;
+ element.srcObject = stream;
+ element.onplaying = onplaying;
+ element.onended = onended;
+ element.play();
+ steps++;
+ },
+ function(err) {
+ ok(false, 'Unexpected error fired with: ' + err);
+ SimpleTest.finish();
+ }
+ );
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv(
+ {
+ "set": [
+ ["media.track.enabled", true]
+ ]
+ }, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediatrack_events.html b/dom/media/test/test_mediatrack_events.html
new file mode 100644
index 000000000..2f9686598
--- /dev/null
+++ b/dom/media/test/test_mediatrack_events.html
@@ -0,0 +1,133 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test events of media track interfaces</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+function startTest() {
+ navigator.mozGetUserMedia({audio:true, video:true, fake:true},
+ function(stream) {
+ var element = document.createElement("video");
+
+ isnot(element.audioTracks, undefined,
+ 'HTMLMediaElement::AudioTracks() property should be available.');
+ isnot(element.videoTracks, undefined,
+ 'HTMLMediaElement::VideoTracks() property should be available.');
+
+ function verifyEvent(e, type) {
+ is(e.type, type, "Event type should be " + type);
+ ok(e.isTrusted, "Event should be trusted.");
+ ok(!e.bubbles, "Event shouldn't bubble.");
+ ok(!e.cancelable, "Event shouldn't be cancelable.");
+ }
+
+ element.audioTracks.onaddtrack = function(e) {
+ ok(e instanceof TrackEvent, "Event fired from onaddtrack should be a TrackEvent");
+ ok(true, 'onaddtrack is expected to be called from audioTracks.');
+ verifyEvent(e, "addtrack");
+ }
+
+ element.audioTracks.onremovetrack = function(e) {
+ ok(e instanceof TrackEvent, "Event fired from onremovetrack should be a TrackEvent");
+ ok(true, 'onremovetrack is expected to be called from audioTracks.');
+ verifyEvent(e, "removetrack");
+ }
+
+ element.audioTracks.onchange = function(e) {
+ ok(e instanceof window.Event, "Event fired from onchange should be a simple event.");
+ ok(true, 'onchange is expected to be called from audioTracks.');
+ verifyEvent(e, "change");
+ }
+
+ element.videoTracks.onaddtrack = function(e) {
+ ok(e instanceof TrackEvent, "Event fired from onaddtrack should be a TrackEvent");
+ ok(true, 'onaddtrack is expected to be called from videoTracks.');
+ verifyEvent(e, "addtrack");
+ }
+
+ element.videoTracks.onremovetrack = function(e) {
+ ok(e instanceof TrackEvent, "Event fired from onremovetrack should be a TrackEvent");
+ ok(true, 'onremovetrack is expected to be called from videoTracks.');
+ verifyEvent(e, "removetrack");
+ }
+
+ element.videoTracks.onchange = function(e) {
+ ok(e instanceof window.Event, "Event fired from onchange should be a simple event.");
+ ok(true, 'onchange is expected to be called from videoTracks.');
+ verifyEvent(e, "change");
+ }
+
+ function onended() {
+ ok(true, 'Event ended is expected to be fired on element.');
+ element.onended = null;
+ element.onplaying = null;
+ element.onpause = null;
+ //This helps to prevent these events from firing after SimpleTest.finish()
+ //on B2G ICS Emulator, but not sure they have been run at all, then
+ element.audioTracks.onremovetrack = null;
+ element.audioTracks.onaddtrack = null;
+ element.audioTracks.onchange = null;
+ element.videoTracks.onremovetrack = null;
+ element.videoTracks.onaddtrack = null;
+ element.videoTracks.onchange = null;
+ SimpleTest.finish();
+ }
+
+ function onpause() {
+ element.onpause = null;
+ if (element.ended) {
+ return;
+ }
+ if (steps == 1) {
+ element.audioTracks[0].enabled = false;
+ element.videoTracks[0].selected = false;
+ element.onplaying = onplaying;
+ element.play();
+ steps++;
+ }
+ }
+
+ function onplaying() {
+ element.onplaying = null;
+ if (element.ended) {
+ return;
+ }
+ if (steps == 1) {
+ element.onpause = onpause;
+ element.pause();
+ } else if (steps == 2) {
+ stream.stop();
+ }
+ }
+
+ var steps = 0;
+ element.mozSrcObject = stream;
+ element.onplaying = onplaying;
+ element.onended = onended;
+ element.play();
+ steps++;
+ },
+ function(err) {
+ ok(false, 'Unexpected error fired with: ' + err);
+ SimpleTest.finish();
+ }
+ );
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv(
+ {
+ "set": [
+ ["media.track.enabled", true]
+ ]
+ }, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediatrack_parsing_ogg.html b/dom/media/test/test_mediatrack_parsing_ogg.html
new file mode 100644
index 000000000..e98636c2d
--- /dev/null
+++ b/dom/media/test/test_mediatrack_parsing_ogg.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test events of media track interfaces</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function localCheckMetadata(msg, e) {
+ ok(msg in gOggTrackInfoResults, "File: " + msg + " is in pre-parsed gOggTrackInfoResults list");
+ var r = gOggTrackInfoResults[msg];
+
+ var hasExpectedAudio = r && r.hasOwnProperty("audio_id");
+ var hasExpectedVideo = r && r.hasOwnProperty("video_id");
+
+ var hasParsedAudio = e.audioTracks.length >= 1;
+ var hasParsedVideo = e.videoTracks.length >= 1;
+
+ ok(!(hasExpectedAudio ^ hasParsedAudio), "Check availability of expected/parsed audio");
+ ok(!(hasExpectedVideo ^ hasParsedVideo), "Check availability of expected/parsed video");
+ if (hasParsedAudio) {
+ is(e.audioTracks.length, 1, "The length of audio track should be 1");
+ is(e.audioTracks[0].id, r.audio_id, "File: " + msg + ", Audio track id");
+ is(e.audioTracks[0].kind, r.audio_kind, "File: " + msg + ", Audio track kind");
+ is(e.audioTracks[0].language, r.audio_language, "File: " + msg + ", Audio track language");
+ is(e.audioTracks[0].label, r.audio_label, "File: " + msg + ", Audio track label");
+ }
+ if (hasParsedVideo) {
+ is(e.videoTracks.length, 1, "The length of video track should be 1");
+ is(e.videoTracks[0].id, r.video_id, "File: " + msg + ", Video track id");
+ is(e.videoTracks[0].kind, r.video_kind, "File: " + msg + ", Video track kind");
+ is(e.videoTracks[0].language, r.video_language, "File: " + msg + ", Video track language");
+ is(e.videoTracks[0].label, r.video_label, "File: " + msg + ", Video track label");
+ }
+}
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ v.preload = "metadata";
+ v.token = token;
+ manager.started(token);
+
+ v.src = test.name;
+ v.name = test.name;
+
+ v.onloadedmetadata = function(evt) {
+ localCheckMetadata(evt.target.name, evt.target);
+ evt.target.finished = true;
+ evt.target.onloadedmetadata = null;
+ removeNodeAndSource(evt.target);
+ manager.finished(evt.target.token);
+ };
+
+ document.body.appendChild(v);
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [["media.track.enabled", true]]},
+ function() {
+ manager.runTests(gMultitrackInfoOggPlayList, startTest);
+ }
+);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mediatrack_replay_from_end.html b/dom/media/test/test_mediatrack_replay_from_end.html
new file mode 100644
index 000000000..584849a59
--- /dev/null
+++ b/dom/media/test/test_mediatrack_replay_from_end.html
@@ -0,0 +1,146 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test media tracks if replay after playback has ended</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ // Scenario to test:
+ // 1. Audio tracks and video tracks should be added to the track list when
+ // playing, and all tracks should be removed from the list after we seek
+ // to the end.
+ // 2. All tracks should be added back to the list if we replay from the end,
+ // and all tracks should be removed from the list after we seek to the end.
+ // 3. After seek to the middle from end of playback, all tracks should be
+ // added back to the list if we play from here, and all tracks should be
+ // removed from the list after we seek to the end.
+
+ var elemType = getMajorMimeType(test.type);
+ var element = document.createElement(elemType);
+
+ var audioOnchange = 0;
+ var audioOnaddtrack = 0;
+ var audioOnremovetrack = 0;
+ var videoOnchange = 0;
+ var videoOnaddtrack = 0;
+ var videoOnremovetrack = 0;
+ var isPlaying = false;
+ var steps = 0;
+
+ element.audioTracks.onaddtrack = function(e) {
+ audioOnaddtrack++;
+ }
+
+ element.audioTracks.onremovetrack = function(e) {
+ audioOnremovetrack++;
+ }
+
+ element.videoTracks.onaddtrack = function(e) {
+ videoOnaddtrack++;
+ }
+
+ element.videoTracks.onremovetrack = function(e) {
+ videoOnremovetrack++;
+ }
+
+ function testTrackEventCalls(expectedCalls) {
+ if (test.hasAudio) {
+ is(audioOnaddtrack, expectedCalls,
+ 'Calls of onaddtrack on audioTracks should be '+expectedCalls+' times.');
+ is(audioOnremovetrack, expectedCalls,
+ 'Calls of onremovetrack on audioTracks should be '+expectedCalls+' times.');
+ }
+ if (test.hasVideo) {
+ is(videoOnaddtrack, expectedCalls,
+ 'Calls of onaddtrack on videoTracks should be '+expectedCalls+' times.');
+ is(videoOnremovetrack, expectedCalls,
+ 'Calls of onremovetrack on videoTracks should be '+expectedCalls+' times.');
+ }
+ }
+
+ function finishTesting() {
+ element.onpause = null;
+ element.onseeked = null;
+ element.onplaying = null;
+ element.onended = null;
+ manager.finished(element.token);
+ }
+
+ function onended() {
+ if (isPlaying) {
+ switch(steps) {
+ case 1:
+ testTrackEventCalls(1);
+ element.onplaying = onplaying;
+ element.play();
+ steps++;
+ break;
+ case 2:
+ testTrackEventCalls(2);
+ element.currentTime = element.duration * 0.5;
+ element.onplaying = onplaying;
+ element.play();
+ steps++;
+ break;
+ case 3:
+ testTrackEventCalls(3);
+ finishTesting();
+ break;
+ }
+ } else {
+ ok(true, 'Finish the test anyway if ended is fired before other events.');
+ finishTesting();
+ }
+ }
+
+ function seekToEnd() {
+ element.onpause = null;
+ element.currentTime = element.duration * 1.1;
+ }
+
+ function onseeked() {
+ element.onseeked = null;
+ element.onpause = seekToEnd;
+ element.pause();
+ }
+
+ function onplaying() {
+ isPlaying = true;
+ element.onplaying = null;
+ element.onseeked = onseeked;
+ }
+
+ element.token = token;
+ manager.started(token);
+
+ element.src = test.name;
+ element.test = test;
+ element.onplaying = onplaying;
+ element.onended = onended;
+ element.play();
+ steps++;
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv(
+ {
+ "set": [
+ ["media.track.enabled", true]
+ ]
+ },
+ function() {
+ manager.runTests(gTrackTests, startTest);
+ });
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_metadata.html b/dom/media/test/test_metadata.html
new file mode 100644
index 000000000..29b2f30ff
--- /dev/null
+++ b/dom/media/test/test_metadata.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test returning metadata from media files with mozGetMetadata()</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<div id="output"></div>
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ var a = document.createElement('audio');
+ a.preload = "metadata";
+ a.token = token;
+ manager.started(token);
+
+ a.src = test.name;
+ a.name = test.name;
+
+ // Tags should not be available immediately.
+ var exception_fired = false;
+ try {
+ var m = a.mozGetMetadata();
+ } catch (e) {
+ is(e.name, 'InvalidStateError',
+ "early mozGetMetadata() should throw InvalidStateError");
+ exception_fired = true;
+ }
+ ok(exception_fired,
+ "mozGetMetadata() should throw an exception before HAVE_METADATA");
+
+ // Wait until metadata has loaded.
+ a.addEventListener('loadedmetadata', function() {
+ // read decoded tags
+ tags = a.mozGetMetadata();
+ ok(tags, "mozGetMetadata() should return a truthy value");
+ // Dump them out.
+ var d = document.getElementById('output');
+ var html = '<table>\n';
+ html += '<caption><p>Called getMozMetadata()'
+ html += ' on '+test.name+'</p></caption>\n';
+ html += '<tr><th>tag</th>';
+ html += '<th>decoded value</th><th>expected value</th></tr>\n';
+ for (tag in tags) {
+ html += '<tr><td>'+tag+'</td>';
+ html += '<td>'+tags[tag]+'</td>';
+ html += '<td>'+test.tags[tag]+'</td>';
+ html += '</tr>\n';
+ }
+ if (!Object.keys(tags).length) {
+ html += '<tr><td colspan=3 align=center><em>no tags</em></td></tr>\n';
+ }
+ html += '</table>\n';
+ var div = document.createElement('div');
+ div.innerHTML = html;
+ d.appendChild(div);
+ // Verify decoded tag values.
+ for (tag in tags) {
+ is(tags[tag], test.tags[tag], "Tag '"+tag+"' should match");
+ }
+ // Verify expected tag values
+ for (tag in test.tags) {
+ is(tags[tag], test.tags[tag], "Tag '"+tag+"' should match");
+ }
+ removeNodeAndSource(a);
+ manager.finished(token);
+ }, false);
+}
+
+manager.runTests(gMetadataTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_mixed_principals.html b/dom/media/test/test_mixed_principals.html
new file mode 100644
index 000000000..d3f7ec257
--- /dev/null
+++ b/dom/media/test/test_mixed_principals.html
@@ -0,0 +1,94 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=489415
+-->
+<head>
+ <title>Test for Bug 489415</title>
+ <script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=489415">Mozilla Bug 489415</a>
+<p id="display"></p>
+
+<video id="v1" preload="metadata" onended="onendedcb('v1')"></video>
+<video id="v2" preload="metadata" onended="onendedcb('v2')"></video>
+
+<pre id="test">
+<script type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var pushPrefs = (...p) => new Promise(r => SpecialPowers.pushPrefEnv({set: p}, r));
+
+var v1 = document.getElementById("v1");
+var v2 = document.getElementById("v2");
+var count = 0;
+
+function onendedcb(id) {
+ var c = document.createElement("canvas");
+ var ctx = c.getContext("2d");
+ var v = document.getElementById(id);
+ ctx.drawImage(v, 0, 0);
+ try {
+ c.toDataURL();
+ ok(false, "Failed to throw exception in toDataURL for " + id);
+ } catch (ex) {
+ ok(true, "Threw exception in toDataURL for " + id);
+ }
+ if (++count == 2) {
+ SimpleTest.finish();
+ }
+}
+
+function testMixedPrincipals(resource) {
+ // In some OS(XP) can not play mp4. Add this checking for the test failure.
+ if (!resource || !v1.canPlayType(resource.type)) {
+ todo(false, "No types supported");
+ SimpleTest.finish();
+ return;
+ }
+ // Make sure the media cache size(50MB) is large enough that the data could
+ // be download in MediaCache completely.
+ return pushPrefs(['media.cache_size', 50*1024])
+ .then(() => {
+
+ // Generate a random key. The first load with that key will return
+ // data, the second and subsequent loads with that key will return a redirect
+ // to a different origin ('localhost:8888' will be redirected to 'example.org',
+ // and 'example.org' will be redirected to 'localhost:8888'). We rely on the
+ // fact that Ogg will do a seek to the end of the resource, triggering a new
+ // load with the same key which will return a same-origin resource.
+ // Loading data from two different origins should be detected by the media
+ // cache and result in a null principal so that the canvas usage above fails.
+ var key = Math.floor(Math.random()*100000000);
+
+ // In v1, try loading from same-origin first and then getting redirected to
+ // another origin.
+ v1.src =
+ "http://mochi.test:8888/tests/dom/media/test/dynamic_redirect.sjs?key=v1_" +
+ key + "&res=" + resource.name;
+ v1.onloadeddata = function () {
+ // To limit readahead, avoid racing with playback and "catching up" mode.
+ v1.play();
+ }
+
+ // In v2, try loading cross-origin first and then getting redirected to
+ // our origin.
+ v2.src = "http://example.org/tests/dom/media/test/dynamic_redirect.sjs?key=v2_" + key + "&res=" + resource.name;
+ v2.onloadeddata = function () {
+ // To limit readahead, avoid racing with playback and "catching up" mode.
+ v2.play();
+ }
+ });
+}
+
+testMixedPrincipals({ name:"pixel_aspect_ratio.mp4", type:"video/mp4", duration:28});
+
+</script>
+</pre>
+
+</body>
+</html>
diff --git a/dom/media/test/test_mozHasAudio.html b/dom/media/test/test_mozHasAudio.html
new file mode 100644
index 000000000..22da492bb
--- /dev/null
+++ b/dom/media/test/test_mozHasAudio.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test playback of media files that should play OK</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function onloadedmetadata(e) {
+ var t = e.target;
+ is(t.mozHasAudio, t.hasAudio, "The element reports the wrong audio property." + t.token);
+ manager.finished(t.token);
+}
+
+function startTest(test, token) {
+ var elemType = /^audio/.test(test.type) ? "audio" : "video";
+ var element = document.createElement(elemType);
+ element.preload = "auto";
+
+ element.token = token;
+ manager.started(token);
+
+ element.src = test.name;
+ element.name = test.name;
+ element.hasAudio = elemType == "video" ? test.hasAudio : undefined;
+ element.addEventListener("loadedmetadata", onloadedmetadata, false);
+
+ element.load();
+}
+
+manager.runTests(gTrackTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_multiple_mediastreamtracks.html b/dom/media/test/test_multiple_mediastreamtracks.html
new file mode 100644
index 000000000..afc172733
--- /dev/null
+++ b/dom/media/test/test_multiple_mediastreamtracks.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test the ability of MediaStream with multiple MediaStreamTracks</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+function startTest() {
+ navigator.mediaDevices.getUserMedia({audio:true, video:true, fake:true})
+ .then(function(orgStream) {
+ var a = orgStream.getAudioTracks()[0];
+ var v = orgStream.getVideoTracks()[0];
+ var stream = new MediaStream([a, a, a, a, v, v, v].map(track => track.clone()));
+ var element = document.createElement("video");
+
+ element.onloadedmetadata = function() {
+ is(stream.getAudioTracks().length, 4, 'Length of audio tracks should be 4.');
+ is(stream.getVideoTracks().length, 3, 'Length of vudio tracks should be 3.');
+ SimpleTest.finish();
+ };
+
+ element.srcObject = stream;
+ element.play();
+ })
+ .catch(function(reason) {
+ ok(false, "unexpected error = " + reason.message);
+ SimpleTest.finish();
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv(
+ {
+ "set": [
+ ["media.track.enabled", true]
+ ]
+ }, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_networkState.html b/dom/media/test/test_networkState.html
new file mode 100644
index 000000000..1e645a1d3
--- /dev/null
+++ b/dom/media/test/test_networkState.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: networkState</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body onunload="mediaTestCleanup();">
+<video id='v1'></video><audio id='a1'></audio>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+"use strict";
+var v1 = document.getElementById('v1');
+var a1 = document.getElementById('a1');
+var passed = "truthy";
+
+try {
+ v1.networkState = 0;
+} catch (e) {
+ passed = !passed;
+}
+try {
+ a1.networkState = 0;
+} catch (e) {
+ passed = !passed;
+}
+ok(passed === true,
+ "Setting networkState throws in strict mode (readonly attribute)");
+</script>
+
+<script class="testbody" type="text/javascript">
+var v1 = document.getElementById('v1');
+var a1 = document.getElementById('a1');
+var passed = false;
+
+var oldv1ns = v1.networkState, olda1ns = a1.networkState;
+try {
+ v1.networkState = 0;
+ a1.networkState = 0;
+ passed = v1.networkState === oldv1ns && a1.networkState === olda1ns;
+} catch (e) { }
+ok(passed, "Should not be able to modify networkState (readonly attribute)");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_new_audio.html b/dom/media/test/test_new_audio.html
new file mode 100644
index 000000000..61c284f8d
--- /dev/null
+++ b/dom/media/test/test_new_audio.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=528566
+-->
+<head>
+ <title>Test for Bug 528566</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=528566">Mozilla Bug 528566</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 528566 **/
+
+var manager = new MediaTestManager;
+
+var player = new Audio();
+
+function startTest(test, token) {
+ if (!player.canPlayType(test.type)) {
+ return;
+ }
+ manager.started(token);
+ var a = new Audio(test.name);
+ a.autoplay = true;
+ document.body.appendChild(a);
+ a.addEventListener("ended",
+ function(e){
+ ok(true, "[" + a.src + "]We should get to the end. Oh look we did.");
+ a.remove();
+ manager.finished(token);
+ },
+ false);
+}
+
+manager.runTests(gAudioTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_no_load_event.html b/dom/media/test/test_no_load_event.html
new file mode 100644
index 000000000..1e6e82524
--- /dev/null
+++ b/dom/media/test/test_no_load_event.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=715469
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 715469</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body onload="start();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=715469">Mozilla Bug 715469</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+
+<script type="application/javascript">
+
+/** Test for Bug 715469 **/
+
+var gotLoadEvent = false;
+
+function start() {
+ var resource = getPlayableVideo(gSmallTests);
+ if (resource == null) {
+ todo(false, "No types supported");
+ } else {
+ SimpleTest.waitForExplicitFinish();
+ var v = document.createElement("video");
+ v.src = resource.name;
+
+ v.addEventListener("load", function() {
+ gotLoadEvent = true;
+ }, false);
+
+ v.addEventListener("ended", finished, false);
+ document.body.appendChild(v);
+ v.play();
+ }
+}
+
+function finished() {
+ is(gotLoadEvent, false, "Should not receive a load on the video element");
+ SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_paused.html b/dom/media/test/test_paused.html
new file mode 100644
index 000000000..332622c3d
--- /dev/null
+++ b/dom/media/test/test_paused.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: paused</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<video id='v1'></video><audio id='a1'></audio>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var v1 = document.getElementById('v1');
+var a1 = document.getElementById('a1');
+ok(v1.paused, "v1.paused must initially be true");
+ok(a1.paused, "a1.paused must initially be true");
+mediaTestCleanup();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_paused_after_ended.html b/dom/media/test/test_paused_after_ended.html
new file mode 100644
index 000000000..22e2a3a54
--- /dev/null
+++ b/dom/media/test/test_paused_after_ended.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: paused</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function ended(evt) {
+ var v = evt.target;
+ v.removeEventListener("ended", ended);
+ is(v.gotPause, true, "We should have received a \"pause\" event.")
+ is(v.paused, true, v._name + " must be paused after end");
+ manager.finished(v.token);
+ removeNodeAndSource(v);
+}
+
+function pause(evt) {
+ var v = evt.target;
+ v.removeEventListener("pause", pause);
+ v.gotPause = true;
+}
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ document.body.appendChild(v);
+ v.token = token;
+ manager.started(v.token);
+ v.src = test.name;
+ v._name = test.name;
+ v._finished = false;
+ v.load();
+ is(v.paused, true, v._name + " must be paused at start");
+
+ v.play();
+ is(v.paused, false, v._name + " must not be paused after play");
+
+ v.addEventListener("pause", pause, false);
+ v.addEventListener("ended", ended, false);
+}
+
+manager.runTests(gPausedAfterEndedTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_play_events.html b/dom/media/test/test_play_events.html
new file mode 100644
index 000000000..69bd2edce
--- /dev/null
+++ b/dom/media/test/test_play_events.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: play() method</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+
+<script>
+
+var manager = new MediaTestManager;
+
+var tokens = {
+ 0: ["play"],
+ "play": ["canplay"],
+ "canplay": ["playing"],
+ "playing": ["canplay", "canplaythrough"],
+ "canplaythrough": ["canplay", "canplaythrough"]
+};
+
+function gotPlayEvent(event) {
+ var v = event.target;
+ ok(tokens[v._state].indexOf(event.type) >= 0,
+ "Check expected event got " + event.type + " at " + v._state + " for " + v.src +
+ " uneval(event.type)=" + uneval(event.type) + " typeof(event.type)=" + typeof(event.type) +
+ " uneval(v._state)=" + uneval(v._state) + " typeof(v._state)=" + typeof(v._state) +
+ " tokens["+v._state+"]=" + tokens[v._state] +
+ " tokens["+v._state+"].indexOf(event.type)=" + tokens[v._state].indexOf(event.type));
+ v._state = event.type;
+}
+
+function ended(event) {
+ var v = event.target;
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+}
+
+function initTest(test, token) {
+ var v = document.createElement('video');
+ v.token = token;
+ manager.started(token);
+ v._state = 0;
+
+ ["play", "canplay", "playing", "canplaythrough"].forEach(function (e) {
+ v.addEventListener(e, gotPlayEvent, false);
+ });
+
+ v.addEventListener("ended", ended, false);
+
+ v.src = test.name;
+ document.body.appendChild(v); // Causes load.
+ v.play();
+}
+
+manager.runTests(gSmallTests, initTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_play_events_2.html b/dom/media/test/test_play_events_2.html
new file mode 100644
index 000000000..6689851df
--- /dev/null
+++ b/dom/media/test/test_play_events_2.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: play() method via DOM 0 handlers</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+
+<script>
+var manager = new MediaTestManager;
+
+var tokens = {
+ 0: ["play"],
+ "play": ["canplay"],
+ "canplay": ["playing"],
+ "playing": ["canplay", "canplaythrough"],
+ "canplaythrough": ["canplay", "canplaythrough"]
+};
+
+function gotPlayEvent(event) {
+ var v = event.target;
+ ok(tokens[v._state].indexOf(event.type) >= 0,
+ "Check expected event got " + event.type + " at " + v._state + " for " + v.src);
+ v._state = event.type;
+}
+
+function ended(event) {
+ var v = event.target;
+ v._finished = true;
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+}
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ v.token = token;
+ manager.started(token);
+ v._state = 0;
+ v._finished = false;
+
+ ["play", "canplay", "playing", "canplaythrough"].forEach(function (e) {
+ v["on" + e] = gotPlayEvent;
+ });
+
+ v.onended = ended;
+
+ v.src = test.name;
+ document.body.appendChild(v); // Causes load.
+ v.play();
+}
+
+manager.runTests(gSmallTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_play_twice.html b/dom/media/test/test_play_twice.html
new file mode 100644
index 000000000..a1dd07e67
--- /dev/null
+++ b/dom/media/test/test_play_twice.html
@@ -0,0 +1,95 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test playback of media files that should play OK</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ v.token = token;
+ manager.started(token);
+ v.src = test.name;
+ v.name = test.name;
+ v.playingCount = 0;
+ v._playedOnce = false;
+
+ var check = function(test, v) { return function() {
+ checkMetadata(test.name, v, test);
+ }}(test, v);
+
+ var noLoad = function(test, v) { return function() {
+ ok(false, test.name + " should not fire 'load' event");
+ }}(test, v);
+
+ function finish(v) {
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+ }
+
+ function mayFinish(v) {
+ if (v.seenEnded && v.seenSuspend) {
+ finish(v);
+ }
+ }
+
+ var checkEnded = function(test, v) { return function() {
+ if (test.duration) {
+ ok(Math.abs(v.currentTime - test.duration) < 0.1,
+ test.name + " current time at end: " + v.currentTime);
+ }
+
+ is(v.readyState, v.HAVE_CURRENT_DATA, test.name + " checking readyState");
+ ok(v.ended, test.name + " checking playback has ended");
+ ok(v.playingCount > 0, "Expect at least one playing event");
+ v.playingCount = 0;
+
+ if (v._playedOnce) {
+ v.seenEnded = true;
+ mayFinish(v);
+ } else {
+ v._playedOnce = true;
+ v.play();
+ }
+ }}(test, v);
+
+ var checkSuspended = function(test, v) { return function() {
+ if (v.seenSuspend) {
+ return;
+ }
+
+ v.seenSuspend = true;
+ ok(true, test.name + " got suspend");
+ mayFinish(v);
+ }}(test, v);
+
+ var checkPlaying = function(test, v) { return function() {
+ is(test.name, v.name, "Should be testing file we think we're testing...");
+ v.playingCount++;
+ }}(test, v);
+
+ v.addEventListener("load", noLoad, false);
+ v.addEventListener("loadedmetadata", check, false);
+ v.addEventListener("playing", checkPlaying, false);
+
+ // We should get "ended" and "suspend" events for every resource
+ v.addEventListener("ended", checkEnded, false);
+ v.addEventListener("suspend", checkSuspended, false);
+
+ document.body.appendChild(v);
+ v.play();
+}
+
+manager.runTests(gReplayTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_playback.html b/dom/media/test/test_playback.html
new file mode 100644
index 000000000..2df6df85f
--- /dev/null
+++ b/dom/media/test/test_playback.html
@@ -0,0 +1,123 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test playback of media files that should play OK</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// longer timeout for slow platforms
+if (isSlowPlatform()) {
+ SimpleTest.requestLongerTimeout(3);
+ SimpleTest.requestCompleteLog();
+}
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ v.preload = "metadata";
+ v.token = token;
+ v.prevTime = 0;
+ v.seenEnded = false;
+ v.seenSuspend = false;
+
+ var handler = {
+ "ontimeout": function() {
+ Log(token, "timed out: ended=" + v.seenEnded + ", suspend=" + v.seenSuspend);
+ }
+ };
+ manager.started(token, handler);
+
+ v.src = test.name;
+ v.name = test.name;
+
+ var check = function(test, v) { return function() {
+ is(test.name, v.name, test.name + ": Name should match #1");
+ checkMetadata(test.name, v, test);
+ }}(test, v);
+
+ var noLoad = function(test, v) { return function() {
+ ok(false, test.name + " should not fire 'load' event");
+ }}(test, v);
+
+ var finish = function() {
+ v.finished = true;
+ v.removeEventListener("timeupdate", timeUpdate, false);
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+ }
+
+ // We should get "ended" and "suspend" events to finish the test.
+ var mayFinish = function() {
+ if (v.seenEnded && v.seenSuspend) {
+ finish();
+ }
+ }
+
+ var checkEnded = function(test, v) { return function() {
+ is(test.name, v.name, test.name + ": Name should match #2");
+ checkMetadata(test.name, v, test);
+ is(v.readyState, v.HAVE_CURRENT_DATA, test.name + " checking readyState");
+ ok(v.ended, test.name + " checking playback has ended");
+ ok(!v.finished, test.name + " shouldn't be finished");
+ ok(!v.seenEnded, test.name + " shouldn't be ended");
+
+ v.seenEnded = true;
+ mayFinish();
+ }}(test, v);
+
+ var checkSuspended = function(test, v) { return function() {
+ if (v.seenSuspend) {
+ return;
+ }
+ is(test.name, v.name, test.name + ": Name should match #3");
+
+ v.seenSuspend = true;
+ mayFinish();
+ }}(test, v);
+
+ var timeUpdate = function(test, v) { return function() {
+ if (v.prevTime > v.currentTime) {
+ ok(false, test.name + " time should run forwards: p=" +
+ v.prevTime + " c=" + v.currentTime);
+ }
+ v.prevTime = v.currentTime;
+ }}(test, v);
+
+ v.addEventListener("load", noLoad, false);
+ v.addEventListener("loadedmetadata", check, false);
+ v.addEventListener("timeupdate", timeUpdate, false);
+
+ // We should get "ended" and "suspend" events for every resource
+ v.addEventListener("ended", checkEnded, false);
+ v.addEventListener("suspend", checkSuspended, false);
+
+ document.body.appendChild(v);
+ v.play();
+
+ // Debug timeouts on slow platforms.
+ if (isSlowPlatform()) {
+ var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
+ "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
+ "waiting", "pause"];
+ function logEvent(e) {
+ var v = e.target;
+ Log(e.target.token, "got " + e.type);
+ }
+ events.forEach(function(e) {
+ v.addEventListener(e, logEvent, false);
+ });
+ }
+}
+
+manager.runTests(gPlayTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_playback_errors.html b/dom/media/test/test_playback_errors.html
new file mode 100644
index 000000000..02915fb25
--- /dev/null
+++ b/dom/media/test/test_playback_errors.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test playback of media files that should have errors</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ manager.started(token);
+ v._errorCount = 0;
+ v._ignore = false;
+ function endedTest(v) {
+ if (v._ignore)
+ return;
+ v._ignore = true;
+ v.parentNode.removeChild(v);
+ manager.finished(token);
+ }
+ var checkError = function(test, v) { return function(evt) {
+ v._errorCount++;
+ is(v._errorCount, 1, test.name + " only one error fired");
+ endedTest(v);
+ }}(test, v);
+ var checkEnded = function(test, v) { return function() {
+ ok(false, test.name + " successfully played");
+ endedTest(v);
+ }}(test, v);
+ v.addEventListener("error", checkError, false);
+ v.addEventListener("ended", checkEnded, false);
+ v.src = test.name;
+ document.body.appendChild(v);
+ v.play();
+}
+
+manager.runTests(gErrorTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_playback_rate.html b/dom/media/test/test_playback_rate.html
new file mode 100644
index 000000000..a81e7b800
--- /dev/null
+++ b/dom/media/test/test_playback_rate.html
@@ -0,0 +1,175 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for the playbackRate property </title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type='application/javascript;version=1.8'>
+
+let manager = new MediaTestManager;
+
+function rangeCheck(lhs, rhs, threshold) {
+ var diff = Math.abs(lhs - rhs);
+ if (diff < threshold) {
+ return true;
+ }
+ return false;
+}
+
+function checkPlaybackRate(wallclock, media, expected, threshold) {
+ if (rangeCheck(media / wallclock, expected, threshold)) {
+ return true;
+ }
+ return false;
+}
+
+// Those value are expected to match those at the top of HTMLMediaElement.cpp.
+let VERY_SLOW_RATE = 0.1,
+ SLOW_RATE = 0.25,
+ FAST_RATE = 5,
+ VERY_FAST_RATE = 20,
+ NULL_RATE = 0.0;
+
+function ontimeupdate(e) {
+ var t = e.target;
+ // Skip short files for SoundTouch doesn't work well on small number of samples.
+ if (t.gotEnded || t.duration < 2) {
+ return;
+ }
+ t.testedForSlowdown = true;
+ if (t.currentTime > t.duration / 2) {
+ t.oldCurrentTime = t.currentTime;
+ t.timestamp = Date.now();
+ var delta = t.oldCurrentTime,
+ delta_wallclock = (t.timestamp - t.startTimestamp - t.bufferingTime) / 1000;
+
+ t.mozPreservesPitch = false;
+ is(t.mozPreservesPitch, false, t.name + ": If we disable the pitch preservation, it should appear as such.");
+
+ t.bufferingTime = 0;
+
+ is(t.playbackRate, SLOW_RATE, t.name + ": The playback rate shoud be "+SLOW_RATE+".");
+ ok(checkPlaybackRate(delta_wallclock, delta, SLOW_RATE, 0.25), t.name + ": We are effectively slowing down playback. (" + delta_wallclock + ", " + delta + ")");
+ t.removeEventListener("timeupdate", ontimeupdate);
+ t.addEventListener("pause", onpaused);
+ t.playbackRate = NULL_RATE;
+ t.oldCurrentTime = t.currentTime;
+ setTimeout(function() {
+ afterNullPlaybackRate(e);
+ }, 100);
+ }
+}
+
+function onpaused(e) {
+ var t = e.target;
+ t.pausedReceived = true;
+}
+
+function afterNullPlaybackRate(e) {
+ var t = e.target;
+
+ // skip if we have received 'ended' event or 'ended' event is pending.
+ if (t.gotEnded || t.ended) {
+ return;
+ }
+
+ t.testedForNull = true;
+
+ ok(t.currentTime == t.oldCurrentTime, t.name + ": Current time should not change when playbackRate is null (" + t.currentTime + " " + t.oldCurrentTime + ").");
+ ok(!t.paused, t.name + ": The element should not be in paused state.");
+ t.removeEventListener("paused", onpaused);
+ is(t.pausedReceived, undefined, t.name + ": Paused event should not have been received.");
+ t.timestamp = Date.now();
+ t.oldCurrentTime = t.currentTime;
+ t.playbackRate = VERY_FAST_RATE;
+ is(t.playbackRate, FAST_RATE, t.name + ": Playback rate should be clamped to " + FAST_RATE + ".");
+}
+
+function onended(e) {
+ var t = e.target;
+ t.gotEnded = true;
+
+ t.bufferingTime = 0;
+ // If we got "ended" too early, skip these tests.
+ if (t.testedForSlowdown && t.testedForNull) {
+ is(t.playbackRate, FAST_RATE, t.name + ": The playback rate should still be "+FAST_RATE+".");
+ ok(!t.muted, t.name + ": The audio should be muted when playing at high speed, but should not appear as such.");
+ is(t.currentTime, t.duration, t.name + ": Current time should be equal to the duration (not change by playback rate).");
+ }
+ finish_test(t);
+}
+
+function onratechange(e) {
+ if (!e.target.ratechangecount) {
+ e.target.ratechangecount = 0;
+ }
+ e.target.ratechangecount++;
+}
+
+function finish_test(element) {
+ removeNodeAndSource(element);
+ manager.finished(element.token);
+}
+
+// These two functions handle the case when the playback pauses for buffering. It
+// adjusts the timestamps to be accurate. Despite the fact that the web servers
+// is supposed to be on the same machine, buffering pauses can occur (rarely,
+// but still).
+function onplaying(e) {
+ var t = e.target;
+ if (t.bufferingTimestamp != undefined) {
+ t.bufferingTime += (Date.now() - t.bufferingTimestamp);
+ t.bufferingTimestamp = undefined;
+ }
+}
+
+function onwaiting(e) {
+ var t = e.target;
+ t.bufferingTimestamp = Date.now();
+}
+
+function onvolumechange(e) {
+ ok(false, e.target.name + ": We should not receive a volumechange event when changing the playback rate.");
+}
+
+function startTest(test, token) {
+ let elemType = /^audio/.test(test.type) ? "audio" : "video";
+ let element = document.createElement(elemType);
+ element.src = test.name;
+ element.name = test.name;
+ element.preload = "metadata";
+ element.token = token;
+ element.controls = true;
+ element.bufferingTime = 0;
+ document.body.appendChild(element);
+ element.addEventListener("ratechange", onratechange);
+ element.addEventListener("timeupdate", ontimeupdate);
+ element.addEventListener("ended", onended);
+ element.addEventListener("waiting", onwaiting);
+ element.addEventListener("playing", onplaying);
+ element.addEventListener("volumechange", onvolumechange);
+ manager.started(token);
+ element.startTimestamp = Date.now();
+ is(element.mozPreservesPitch, true, test.name + ": Pitch preservation should be enabled by default.");
+ element.addEventListener("loadedmetadata", function() {
+ is(element.playbackRate, 1.0, test.name + ": playbackRate should be initially 1.0");
+ is(element.defaultPlaybackRate, 1.0, test.name + ": defaultPlaybackRate should be initially 1.0");
+ element.playbackRate = VERY_SLOW_RATE;
+ is(element.playbackRate, SLOW_RATE, test.name + ": PlaybackRate should be clamped to " + SLOW_RATE + ".");
+ element.play();
+ element.playbackRate = SLOW_RATE;
+ });
+}
+
+manager.runTests(gPlayedTests, startTest);
+
+</script>
+</pre>
+<div id="elements">
+</div>
+</body>
+</html>
diff --git a/dom/media/test/test_playback_rate_playpause.html b/dom/media/test/test_playback_rate_playpause.html
new file mode 100644
index 000000000..dcf852a8f
--- /dev/null
+++ b/dom/media/test/test_playback_rate_playpause.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test that the playbackRate property is not reset when resuming the playback</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type='application/javascript;version=1.8'>
+
+let manager = new MediaTestManager;
+
+function ontimeupdate(e) {
+ var t = e.target;
+ if (t.currentTime != 0.0) {
+ dump(t.token + " t.currentTime != 0.0.\n");
+ t.removeEventListener("timeupdate", ontimeupdate);
+ t.pause();
+ is(t.playbackRate, 0.5, "PlaybackRate should not have changed after pause.");
+ } else {
+ dump(t.token + " t.currentTime == 0.0.\n");
+ }
+}
+
+function onpaused(e) {
+ var t = e.target;
+ dump(t.token + " onpaused.\n");
+ t.play();
+ is(t.playbackRate, 0.5, "PlaybackRate should not have changed after resuming playback.");
+ finish_test(t);
+}
+
+function finish_test(element) {
+ dump(element.token + " finish_test.\n");
+ removeNodeAndSource(element);
+ manager.finished(element.token);
+}
+
+function startTest(test, token) {
+ let elemType = /^audio/.test(test.type) ? "audio" : "video";
+ let element = document.createElement(elemType);
+ element.src = test.name;
+ element.token = token;
+ element.controls = true;
+ element.playbackRate = 0.5;
+ element.preload = "metadata";
+ element.addEventListener("timeupdate", ontimeupdate);
+ element.addEventListener("pause", onpaused);
+ element.addEventListener("loadedmetadata", function() {
+ dump(element.token + " loadedmetadata\n");
+ element.play();
+ });
+ document.body.appendChild(element);
+ manager.started(token);
+}
+
+manager.runTests(gPlayedTests, startTest);
+
+</script>
+</pre>
+<div id="elements">
+</div>
+</body>
+</html>
diff --git a/dom/media/test/test_playback_reactivate.html b/dom/media/test/test_playback_reactivate.html
new file mode 100644
index 000000000..8b768c8e7
--- /dev/null
+++ b/dom/media/test/test_playback_reactivate.html
@@ -0,0 +1,97 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test playback with dormant of media files that should play OK</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/* This testcase wants to test a video element's playback is not break
+ by dormant.
+ When the metadata is loaded, we remove the video element to trigger dormant.
+ Then set a timer to append the video element back and play it.
+ Test pass if the video plays to the end.
+*/
+
+// longer timeout for slow platforms
+if (isSlowPlatform()) {
+ SimpleTest.requestLongerTimeout(1.5);
+ SimpleTest.requestCompleteLog();
+}
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ v.preload = "metadata";
+ v.token = token;
+
+ var handler = {
+ "ontimeout": function() {
+ Log(token, "timed out: ended=" + v.seenEnded + ", suspend=" + v.seenSuspend);
+ }
+ };
+ manager.started(token, handler);
+
+ v.src = test.name;
+ v.name = test.name;
+
+ var check = function(test, v) { return function() {
+ is(test.name, v.name, test.name + ": Name should match #1");
+ Log(v.token, "removeChild: " + v.name);
+ document.body.removeChild(v);
+ var appendAndPlayElement = function() {
+ Log(v.token, "appendChild: " + v.name);
+ document.body.appendChild(v);
+ Log(v.token, "Element play: " + v.name);
+ v.play();
+ }
+ setTimeout(appendAndPlayElement, 2000);
+ }}(test, v);
+
+ var finish = function() {
+ v.finished = true;
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+ }
+
+ var checkEnded = function(test, v) { return function() {
+ is(test.name, v.name, test.name + ": Name should match #2");
+ checkMetadata(test.name, v, test);
+ is(v.readyState, v.HAVE_CURRENT_DATA, test.name + " checking readyState");
+ ok(v.ended, test.name + " checking playback has ended");
+
+ finish();
+ }}(test, v);
+
+
+ v.addEventListener("loadedmetadata", check, false);
+ v.addEventListener("ended", checkEnded, false);
+
+ document.body.appendChild(v);
+
+ // Debug timeouts on slow platforms.
+ if (isSlowPlatform()) {
+ var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
+ "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
+ "waiting", "pause"];
+ function logEvent(e) {
+ var v = e.target;
+ Log(e.target.token, "got " + e.type);
+ }
+ events.forEach(function(e) {
+ v.addEventListener(e, logEvent, false);
+ });
+ }
+}
+
+manager.runTests(gSmallTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_played.html b/dom/media/test/test_played.html
new file mode 100644
index 000000000..52d3ab45f
--- /dev/null
+++ b/dom/media/test/test_played.html
@@ -0,0 +1,250 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Test played member for media elements</title>
+<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id='test'>
+<script class="testbody" type='application/javascript;version=1.8'>
+//longer timeout for sometimes B2G emulator runs very slowly
+if (SpecialPowers.Services.appinfo.name == "B2G") {
+ SimpleTest.requestLongerTimeout(3);
+}
+
+SimpleTest.requestCompleteLog();
+let manager = new MediaTestManager;
+
+function finish_test(element) {
+ removeNodeAndSource(element);
+ manager.finished(element.token);
+}
+
+// Check that a file has been played in its entirety.
+function check_full_file_played(element) {
+ element.addEventListener('ended', (function(e) {
+ let interval_count = e.target.played.length;
+ is(interval_count, 1, element.token + ": played.length must be 1");
+ is(element.played.start(0), 0, element.token + ": start time shall be 0");
+ is(element.played.end(0), e.target.duration, element.token + ": end time shall be duration");
+ finish_test(e.target);
+ }), false);
+}
+
+var tests = [
+// Without playing, check that player.played.length == 0.
+{
+ setup : function(element) {
+ element.addEventListener("loadedmetadata", function() {
+ is(element.played.length, 0, element.token + ": initial played.length equals zero");
+ finish_test(element);
+ });
+ },
+ name: "test1"
+},
+// Play the file, test the range we have.
+{
+ setup : function(element) {
+ check_full_file_played(element);
+ element.play();
+ },
+ name: "test2"
+},
+
+// Play the second half of the file, pause, play
+// an check we have only one range.
+{
+ setup : function (element) {
+ element.onended = function (e) {
+ var t = e.target;
+ t.onended = null;
+ check_full_file_played(t);
+ t.pause();
+ t.currentTime = 0;
+ t.play();
+ };
+ element.addEventListener("loadedmetadata", function() {
+ element.currentTime = element.duration / 2;
+ element.play();
+ }, false);
+ },
+ name: "test3"
+},
+
+// Play the first half of the file, seek back, while
+// continuing to play. We shall have only one range.
+{
+ setup : function (element) {
+ let onTimeUpdate = function() {
+ if (element.currentTime > element.duration / 2) {
+ info(element.token + ": currentTime=" + element.currentTime + ", duration=" + element.duration);
+ element.removeEventListener("timeupdate", onTimeUpdate, false);
+ element.pause();
+ var oldEndRange = element.played.end(0);
+ element.currentTime = element.duration / 4;
+ is(element.played.end(0), oldEndRange,
+ element.token + ": When seeking back, |played| should not be changed");
+ element.play();
+ }
+ }
+ element.addEventListener("timeupdate", onTimeUpdate, false);
+ check_full_file_played(element);
+ element.play();
+ },
+ name: "test4"
+},
+
+// Play and seek to have two ranges, and check that, as well a
+// boundaries.
+{
+ setup : function (element) {
+ let seekTarget = 0;
+ let onTimeUpdate = function() {
+ if (element.currentTime > element.duration / 2) {
+ info(element.token + ": currentTime=" + element.currentTime + ", duration=" + element.duration);
+ element.removeEventListener("timeupdate", onTimeUpdate, false);
+ element.pause();
+ // Remember seek target for later comparison since duration may change
+ // during playback.
+ seekTarget = element.currentTime = element.duration / 10;
+ element.currentTime = seekTarget;
+ element.play();
+ }
+ }
+
+ element.addEventListener("loadedmetadata", function() {
+ element.addEventListener("timeupdate", onTimeUpdate, false);
+ }, false);
+
+
+ element.addEventListener("ended", (function() {
+ if(element.played.length > 1) {
+ is(element.played.length, 2, element.token + ": element.played.length == 2");
+ is(element.played.start(1), seekTarget, element.token + ": we should have seeked forward by one tenth of the duration");
+ is(element.played.end(1), element.duration, element.token + ": end of second range shall be the total duration");
+ }
+ is(element.played.start(0), 0, element.token + ": start of first range shall be 0");
+ finish_test(element);
+ }), false);
+
+ element.play();
+ },
+ name: "test5"
+},
+
+// Play to create two ranges, in the reverse order. check that they are sorted.
+{
+ setup : function (element) {
+ function end() {
+ element.pause();
+ let p = element.played;
+ ok(p.length >= 1, element.token + ": There should be at least one range=" + p.length);
+ is(p.start(0), seekTarget, element.token + ": Start of first range should be the sixth of the duration");
+ ok(p.end(p.length - 1) > 5 * element.duration / 6, element.token + ": End of last range should be greater that five times the sixth of the duration");
+ finish_test(element);
+ }
+
+ let seekTarget = 0;
+ function pauseseekrestart() {
+ element.pause();
+ // Remember seek target for later comparison since duration may change
+ // during playback.
+ seekTarget = element.duration / 6;
+ element.currentTime = seekTarget;
+ element.play();
+ }
+
+ function onTimeUpdate_pauseseekrestart() {
+ if (element.currentTime > 5 * element.duration / 6) {
+ element.removeEventListener("timeupdate", onTimeUpdate_pauseseekrestart, false);
+ pauseseekrestart();
+ element.addEventListener("timeupdate", onTimeUpdate_end, false);
+ }
+ }
+
+ function onTimeUpdate_end() {
+ if (element.currentTime > 3 * element.duration / 6) {
+ element.removeEventListener("timeupdate", onTimeUpdate_end, false);
+ end();
+ }
+ }
+
+ element.addEventListener("timeupdate", onTimeUpdate_pauseseekrestart, false);
+
+ element.addEventListener('loadedmetadata', function() {
+ element.currentTime = 4 * element.duration / 6;
+ element.play();
+ }, false);
+ },
+ name: "test6"
+},
+// Seek repeatedly without playing. No range should appear.
+{
+ setup : function(element) {
+ let index = 1;
+
+ element.addEventListener('seeked', function() {
+ index++;
+ element.currentTime = index * element.duration / 5;
+ is(element.played.length, 0, element.token + ": played.length should be 0");
+ if (index == 5) {
+ finish_test(element);
+ }
+ }, false);
+
+ element.addEventListener('loadedmetadata', function() {
+ element.currentTime = element.duration / 5;
+ }, false);
+ },
+ name: "test7"
+}
+];
+
+function createTestArray() {
+ var A = [];
+ for (var i=0; i<tests.length; i++) {
+ for (var k=0; k<gPlayedTests.length; k++) {
+ var t = new Object();
+ t.setup = tests[i].setup;
+ t.name = tests[i].name + "-" + gPlayedTests[k].name;
+ t.type = gPlayedTests[k].type;
+ t.src = gPlayedTests[k].name;
+ A.push(t);
+ }
+ }
+ return A;
+}
+
+function startTest(test, token) {
+ var elemType = getMajorMimeType(test.type);
+ var element = document.createElement(elemType);
+ element.src = test.src;
+ element.token = token;
+ element.preload = "metadata";
+ test.setup(element);
+ manager.started(token);
+
+ // Log events for debugging.
+ var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
+ "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
+ "waiting", "pause"];
+ function logEvent(e) {
+ var v = e.target;
+ info(v.token + ": got " + e.type);
+ }
+ events.forEach(function(e) {
+ element.addEventListener(e, logEvent, false);
+ });
+
+}
+
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_preload_actions.html b/dom/media/test/test_preload_actions.html
new file mode 100644
index 000000000..1dbe1b0a1
--- /dev/null
+++ b/dom/media/test/test_preload_actions.html
@@ -0,0 +1,618 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=548523
+-->
+<head>
+ <title>Test for Bug 548523</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=548523">Mozilla Bug 548523</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<!-- <button onClick="SimpleTest.finish();">Finish</button> -->
+<div>Tests complete: <span id="log" style="font-size: small;"></span></div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 548523 **/
+
+SimpleTest.requestCompleteLog();
+var manager = new MediaTestManager;
+
+manager.onFinished = function() {
+ is(gotLoadEvent, true, "Should not have delayed the load event indefinitely");
+};
+
+var test = getPlayableVideo(gSeekTests);
+var baseName = test.name;
+var gTest = test;
+var bogusSrc = "bogus.duh";
+var bogusType = "video/bogus";
+var gotLoadEvent = false;
+var finished = false;
+
+addLoadEvent(function() {gotLoadEvent=true;});
+
+function log(m) {
+ var l = document.getElementById("log");
+ l.innerHTML += m;
+}
+
+function maybeFinish(v, n) {
+ if (v._finished) {
+ return;
+ }
+ v._finished = true;
+ log(n + ",");
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+}
+
+function filename(uri) {
+ return uri.substr(uri.lastIndexOf("/")+1);
+}
+
+// Every test must have a setup(v) function, and must call maybeFinish() when test is complete.
+var tests = [
+ {
+ // 1. Add preload:none video with src to document. Load should halt at NETWORK_IDLE and HAVE_NOTHING,
+ // after receiving a suspend event. Should not receive loaded events until after we call load().
+ // Note the suspend event is explictly sent by our "stop the load" code, but other tests can't rely
+ // on it for the preload:metadata case, as there can be multiple suspend events when loading metadata.
+ suspend:
+ function(e) {
+ var v = e.target;
+ is(v._gotLoadStart, true, "(1) Must get loadstart.");
+ is(v._gotLoadedMetaData, false, "(1) Must not get loadedmetadata.");
+ is(v.readyState, v.HAVE_NOTHING, "(1) ReadyState must be HAVE_NOTHING");
+ // bug 962949
+ // is(v.networkState, v.NETWORK_IDLE, "(1) NetworkState must be NETWORK_IDLE");
+ maybeFinish(v, 1);
+ },
+
+ setup:
+ function(v) {
+ v._gotLoadStart = false;
+ v._gotLoadedMetaData = false;
+ v.preload = "none";
+ v.addEventListener("loadedmetadata", function(e){v._gotLoadedMetaData = true;}, false);
+ v.addEventListener("loadstart", function(e){v._gotLoadStart = true;}, false);
+ v.addEventListener("suspend", this.suspend, false);
+ v.src = test.name;
+ document.body.appendChild(v); // Causes implicit load, which will be halted due to preload:none.
+ },
+
+ name: "test1",
+ },
+ {
+ // 2. Add preload:metadata video with src to document. Should halt with NETWORK_IDLE, HAVE_CURRENT_DATA
+ // after suspend event and after loadedmetadata.
+ loadeddata:
+ function(e) {
+ var v = e.target;
+ is(v._gotLoadStart, true, "(2) Must get loadstart.");
+ is(v._gotLoadedMetaData, true, "(2) Must get loadedmetadata.");
+ ok(v.readyState >= v.HAVE_CURRENT_DATA, "(2) ReadyState must be >= HAVE_CURRENT_DATA");
+ // bug 962949
+ // is(v.networkState, v.NETWORK_IDLE, "(2) NetworkState must be NETWORK_IDLE");
+ maybeFinish(v, 2);
+ },
+
+ setup:
+ function(v) {
+ v._gotLoadStart = false;
+ v._gotLoadedMetaData = false;
+ v.preload = "metadata";
+ v.addEventListener("loadstart", function(e){v._gotLoadStart = true;}, false);
+ v.addEventListener("loadedmetadata", function(e){v._gotLoadedMetaData = true;}, false);
+ v.addEventListener("loadeddata", this.loadeddata, false);
+ v.src = test.name;
+ document.body.appendChild(v); // Causes implicit load, which will be halted after
+ // metadata due to preload:metadata.
+ },
+
+ name: "test2",
+ },
+ {
+ // 3. Add preload:auto to document. Should receive canplaythrough eventually.
+ canplaythrough:
+ function(e) {
+ var v = e.target;
+ is(v._gotLoadStart, true, "(3) Must get loadstart.");
+ is(v._gotLoadedMetaData, true, "(3) Must get loadedmetadata.");
+ maybeFinish(v, 3);
+ },
+
+ setup:
+ function(v) {
+ v._gotLoadStart = false;
+ v._gotLoadedMetaData = false;
+ v.preload = "auto";
+ v.addEventListener("loadstart", function(e){v._gotLoadStart = true;}, false);
+ v.addEventListener("loadedmetadata", function(e){v._gotLoadedMetaData = true;}, false);
+ v.addEventListener("canplaythrough", this.canplaythrough, false);
+ v.src = test.name; // Causes implicit load.
+ document.body.appendChild(v);
+ },
+
+ name: "test3",
+ },
+ {
+ // 4. Add preload:none video to document. Call play(), should load then play through.
+ suspend:
+ function(e) {
+ var v = e.target;
+ if (v._gotSuspend) {
+ return; // We can receive multiple suspend events, like the one after download completes.
+ }
+ v._gotSuspend = true;
+ is(v._gotLoadStart, true, "(4) Must get loadstart.");
+ is(v._gotLoadedMetaData, false, "(4) Must not get loadedmetadata.");
+ is(v.readyState, v.HAVE_NOTHING, "(4) ReadyState must be HAVE_NOTHING");
+ // bug 962949
+ // is(v.networkState, v.NETWORK_IDLE, "(4) NetworkState must be NETWORK_IDLE");
+ v.play(); // Should load and play through.
+ },
+
+ ended:
+ function(e) {
+ ok(true, "(4) Got playback ended");
+ maybeFinish(e.target, 4);
+ },
+
+ setup:
+ function(v) {
+ v._gotLoadStart = false;
+ v._gotLoadedMetaData = false;
+ v._gotSuspend = false;
+ v.preload = "none";
+ v.addEventListener("loadedmetadata", function(e){v._gotLoadedMetaData = true;}, false);
+ v.addEventListener("loadstart", function(e){v._gotLoadStart = true;}, false);
+ v.addEventListener("suspend", this.suspend, false);
+ v.addEventListener("ended", this.ended, false);
+ v.src = test.name;
+ document.body.appendChild(v);
+ },
+
+ name: "test4",
+ },
+ {
+ // 5. preload:none video without resource, add to document, will implicitly start a
+ // preload:none load. Add a src, it shouldn't load.
+ suspend:
+ function(e) {
+ var v = e.target;
+ is(v._gotLoadStart, true, "(5) Must get loadstart.");
+ is(v._gotLoadedMetaData, false, "(5) Must not get loadedmetadata.");
+ is(v.readyState, v.HAVE_NOTHING, "(5) ReadyState must be HAVE_NOTHING");
+ // bug 962949
+ // is(v.networkState, v.NETWORK_IDLE, "(5) NetworkState must be NETWORK_IDLE");
+ maybeFinish(v, 5);
+ },
+
+ setup:
+ function(v) {
+ v._gotLoadStart = false;
+ v._gotLoadedMetaData = false;
+ v.preload = "none";
+ v.addEventListener("loadedmetadata", function(e){v._gotLoadedMetaData = true;}, false);
+ v.addEventListener("loadstart", function(e){v._gotLoadStart = true;}, false);
+ v.addEventListener("suspend", this.suspend, false);
+ document.body.appendChild(v); // Causes implicit load, which will be halted due to no resource.
+ v.src = test.name; // Load should start, and halt at preload:none.
+ },
+
+ name: "test5",
+ },
+ {
+ // 6. preload:none video without resource, add to document, will implicitly start a
+ // preload:none load. Add a source, it shouldn't load.
+ suspend:
+ function(e) {
+ var v = e.target;
+ is(v._gotLoadStart, true, "(6) Must get loadstart.");
+ is(v._gotLoadedMetaData, false, "(6) Must not get loadedmetadata.");
+ is(v.readyState, v.HAVE_NOTHING, "(6) ReadyState must be HAVE_NOTHING");
+ // bug 962949
+ // is(v.networkState, v.NETWORK_IDLE, "(6) NetworkState must be NETWORK_IDLE");
+ maybeFinish(v, 6);
+ },
+
+ setup:
+ function(v) {
+ v._gotLoadStart = false;
+ v._gotLoadedMetaData = false;
+ v.preload = "none";
+ v.addEventListener("loadedmetadata", function(e){v._gotLoadedMetaData = true;}, false);
+ v.addEventListener("loadstart", function(e){v._gotLoadStart = true;}, false);
+ v.addEventListener("suspend", this.suspend, false);
+ document.body.appendChild(v); // Causes implicit load, which will be halted due to no resource.
+ var s = document.createElement("source");
+ s.src = test.name;
+ s.type = test.type;
+ v.appendChild(s); // Load should start, and halt at preload:none.
+ },
+
+ name: "test6",
+ },
+ {
+ // 7. create a preload:none document with multiple sources, the first of which is invalid.
+ // Add to document, then play. It should load and play through the second source.
+ suspend:
+ function(e) {
+ var v = e.target;
+ if (v._gotSuspend)
+ return; // We can receive multiple suspend events, like the one after download completes.
+ v._gotSuspend = true;
+ is(v._gotLoadStart, true, "(7) Must get loadstart.");
+ is(v._gotLoadedMetaData, false, "(7) Must not get loadedmetadata.");
+ is(v.readyState, v.HAVE_NOTHING, "(7) ReadyState must be HAVE_NOTHING");
+ // bug 962949
+ // is(v.networkState, v.NETWORK_IDLE, "(7) NetworkState must be NETWORK_IDLE");
+ v.play(); // Should load and play through.
+ },
+
+ ended:
+ function(e) {
+ ok(true, "(7) Got playback ended");
+ var v = e.target;
+ is(v._gotErrorEvent, true, "(7) Should get error event from first source load failure");
+ maybeFinish(v, 7);
+ },
+
+ setup:
+ function(v) {
+ v._gotLoadStart = false;
+ v._gotLoadedMetaData = false;
+ v.preload = "none";
+ v._gotErrorEvent = false;
+ v.addEventListener("loadedmetadata", function(e){v._gotLoadedMetaData = true;}, false);
+ v.addEventListener("loadstart", function(e){v._gotLoadStart = true;}, false);
+ v.addEventListener("suspend", this.suspend, false);
+ v.addEventListener("ended", this.ended, false);
+ var s1 = document.createElement("source");
+ s1.src = "not-a-real-file.404"
+ s1.type = test.type;
+ s1.addEventListener("error", function(e){v._gotErrorEvent = true;}, false);
+ v.appendChild(s1);
+ var s2 = document.createElement("source");
+ s2.src = test.name;
+ s2.type = test.type;
+ v.appendChild(s2);
+ document.body.appendChild(v); // Causes implicit load, which will be halt at preload:none on the second resource.
+ },
+
+ name: "test7",
+ },
+ {
+ // 8. Change preload value from none to metadata should cause metadata to be loaded.
+ loadeddata:
+ function(e) {
+ var v = e.target;
+ is(v._gotLoadedMetaData, true, "(8) Must get loadedmetadata.");
+ ok(v.readyState >= v.HAVE_CURRENT_DATA, "(8) ReadyState must be >= HAVE_CURRENT_DATA on suspend.");
+ // bug 962949
+ // is(v.networkState, v.NETWORK_IDLE, "(8) NetworkState must be NETWORK_IDLE when load is halted");
+ maybeFinish(v, 8);
+ },
+
+ setup:
+ function(v) {
+ v._gotLoadedMetaData = false;
+ v.preload = "none";
+ v.addEventListener("loadstart", function(e){v.preload = "metadata";}, false);
+ v.addEventListener("loadedmetadata", function(e){v._gotLoadedMetaData = true;}, false);
+ v.addEventListener("loadeddata", this.loadeddata, false);
+ v.src = test.name; // Causes implicit load.
+ document.body.appendChild(v);
+ },
+
+ name: "test8",
+ },
+ /*{
+ // 9. Change preload value from metadata to auto should cause entire media to be loaded.
+ // For some reason we don't always receive the canplaythrough event, particuarly on this test.
+ // We've disabled this test until bug 568402 is fixed.
+ canplaythrough:
+ function(e) {
+ var v = e.target;
+ is(v._gotLoadStart, true, "(9) Must get loadstart.");
+ is(v._gotLoadedMetaData, true, "(9) Must get loadedmetadata.");
+ maybeFinish(v, 9);
+ },
+
+ setup:
+ function(v) {
+ v._gotLoadStart = false;
+ v._gotLoadedMetaData = false;
+ v.preload = "metadata";
+ v.addEventListener("loadstart", function(e){v._gotLoadStart = true;}, false);
+ v.addEventListener("loadedmetadata", function(e){v._gotLoadedMetaData = true;}, false);
+ v.addEventListener("loadeddata", function(){v.preload = "auto"}, false);
+ v.addEventListener("canplaythrough", this.canplaythrough, false);
+ v.src = test.name; // Causes implicit load.
+ document.body.appendChild(v);
+ },
+ },*/
+ {
+ // 10. Change preload value from none to auto should cause entire media to be loaded.
+ canplaythrough:
+ function(e) {
+ var v = e.target;
+ is(v._gotLoadedMetaData, true, "(10) Must get loadedmetadata.");
+ maybeFinish(v, 10);
+ },
+
+ setup:
+ function(v) {
+ v._gotLoadedMetaData = false;
+ v.preload = "none";
+ v.addEventListener("loadstart", function(e){v.preload = "auto";}, false);
+ v.addEventListener("loadedmetadata", function(e){v._gotLoadedMetaData = true;}, false);
+ v.addEventListener("canplaythrough", this.canplaythrough, false);
+ v.src = test.name; // Causes implicit load.
+ document.body.appendChild(v);
+ },
+
+ name: "test10",
+ },
+ {
+ // 11. Change preload value from none to metadata should cause metadata to load.
+ loadeddata:
+ function(e) {
+ var v = e.target;
+ is(v._gotLoadedMetaData, true, "(11) Must get loadedmetadata.");
+ ok(v.readyState >= v.HAVE_CURRENT_DATA, "(11) ReadyState must be >= HAVE_CURRENT_DATA.");
+ // bug 962949
+ // is(v.networkState, v.NETWORK_IDLE, "(11) NetworkState must be NETWORK_IDLE.");
+ maybeFinish(v, 11);
+ },
+
+ setup:
+ function(v) {
+ v._gotLoadedMetaData = false;
+ v.preload = "none";
+ v.addEventListener("loadstart", function(e){v.preload = "metadata";}, false);
+ v.addEventListener("loadedmetadata", function(e){v._gotLoadedMetaData = true;}, false);
+ v.addEventListener("loadeddata", this.loadeddata, false);
+ v.src = test.name; // Causes implicit load.
+ document.body.appendChild(v);
+ },
+
+ name: "test11",
+ },
+ {
+ // 13. Change preload value from auto to none after specifying a src
+ // should load according to preload none, no buffering should have taken place
+ suspend:
+ function(e) {
+ var v = e.target;
+ is(v._gotLoadStart, true, "(13) Must get loadstart.");
+ is(v._gotLoadedMetaData, false, "(13) Must not get loadedmetadata.");
+ is(v.readyState, v.HAVE_NOTHING, "(13) ReadyState must be HAVE_NOTHING");
+ // bug 962949
+ // is(v.networkState, v.NETWORK_IDLE, "(13) NetworkState must be NETWORK_IDLE");
+ maybeFinish(v, 13);
+ },
+
+ setup:
+ function(v) {
+ v._gotLoadStart = false;
+ v._gotLoadedMetaData = false;
+ v.preload = "auto";
+ v.src = test.name;
+ v.preload = "none";
+ v.addEventListener("loadedmetadata", function(e){v._gotLoadedMetaData = true;}, false);
+ v.addEventListener("loadstart", function(e){v._gotLoadStart = true;}, false);
+ v.addEventListener("suspend", this.suspend, false);
+ document.body.appendChild(v); // Causes implicit load, should load according to preload none
+ var s = document.createElement("source");
+ },
+
+ name: "test13",
+ },
+ {
+ // 14. Add preload:metadata video with src to document. Play(), should play through.
+ loadeddata:
+ function(e) {
+ var v = e.target;
+ is(v._gotLoadStart, true, "(14) Must get loadstart.");
+ is(v._gotLoadedMetaData, true, "(14) Must get loadedmetadata.");
+ ok(v.readyState >= v.HAVE_CURRENT_DATA, "(14) ReadyState must be >= HAVE_CURRENT_DATA");
+ // bug 962949
+ // is(v.networkState, v.NETWORK_IDLE, "(14) NetworkState must be NETWORK_IDLE");
+ v.play();
+ },
+
+ ended:
+ function(e) {
+ ok(true, "(14) Got playback ended");
+ var v = e.target;
+ maybeFinish(v, 14);
+ },
+
+ setup:
+ function(v) {
+ v._gotLoadStart = false;
+ v._gotLoadedMetaData = false;
+ v.preload = "metadata";
+ v.addEventListener("loadstart", function(e){v._gotLoadStart = true;}, false);
+ v.addEventListener("loadedmetadata", function(e){v._gotLoadedMetaData = true;}, false);
+ v.addEventListener("ended", this.ended, false);
+ v.addEventListener("loadeddata", this.loadeddata, false);
+ v.src = test.name;
+ document.body.appendChild(v); // Causes implicit load, which will be halted after
+ // metadata due to preload:metadata.
+ },
+
+ name: "test14",
+ },
+ {
+ // 15. Autoplay should override preload:none.
+ ended:
+ function(e) {
+ ok(true, "(15) Got playback ended.");
+ var v = e.target;
+ maybeFinish(v, 15);
+ },
+
+ setup:
+ function(v) {
+ v._gotLoadStart = false;
+ v._gotLoadedMetaData = false;
+ v.preload = "none";
+ v.autoplay = true;
+ v.addEventListener("loadstart", function(e){v._gotLoadStart = true;}, false);
+ v.addEventListener("loadedmetadata", function(e){v._gotLoadedMetaData = true;}, false);
+ v.addEventListener("ended", this.ended, false);
+ v.src = test.name; // Causes implicit load.
+ document.body.appendChild(v);
+
+ // Log events for debugging.
+ var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
+ "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
+ "waiting", "pause"];
+ function logEvent(e) {
+ var v = e.target;
+ info(e.target.token + ": got " + e.type);
+ }
+ events.forEach(function(e) {
+ v.addEventListener(e, logEvent, false);
+ });
+ },
+
+ name: "test15",
+ },
+ {
+ // 16. Autoplay should override preload:metadata.
+ ended:
+ function(e) {
+ ok(true, "(16) Got playback ended.");
+ var v = e.target;
+ maybeFinish(v, 16);
+ },
+
+ setup:
+ function(v) {
+ v.preload = "metadata";
+ v.autoplay = true;
+ v.addEventListener("ended", this.ended, false);
+ v.src = test.name; // Causes implicit load.
+ document.body.appendChild(v);
+ },
+
+ name: "test16",
+ },
+ {
+ // 17. On a preload:none video, adding autoplay should disable preload none, i.e. don't break autoplay!
+ ended:
+ function(e) {
+ ok(true, "(17) Got playback ended.");
+ var v = e.target;
+ maybeFinish(v, 17);
+ },
+
+ setup:
+ function(v) {
+ v.addEventListener("ended", this.ended, false);
+ v.preload = "none";
+ document.body.appendChild(v); // Causes implicit load, which will be halted due to preload:none.
+ v.autoplay = true;
+ v.src = test.name;
+ },
+
+ name: "test17",
+ },
+ {
+ // 18. On a preload='none' video, call play() before load algorithms's sync
+ // has run, the play() call should override preload='none'.
+ ended:
+ function(e) {
+ ok(true, "(18) Got playback ended.");
+ var v = e.target;
+ maybeFinish(v, 18);
+ },
+
+ setup:
+ function(v) {
+ v.addEventListener("ended", this.ended, false);
+ v.preload = "none";
+ v.src = test.name; // Schedules async section to continue load algorithm.
+ document.body.appendChild(v);
+ v.play(); // Should cause preload:none to be overridden.
+ },
+
+ name: "test18",
+ },
+ {
+ // 19. Set preload='auto' on first video source then switching preload='none' and swapping the video source to another.
+ // The second video should not start playing as it's preload state has been changed to 'none' from 'auto'
+ setup:
+ function(v) {
+ v.preload = "auto";
+ v.src = test.name;
+ // add a listener for when the video has loaded, so we know preload auto has worked
+ v.onloadedmetadata = function() {
+ is(v.preload, "auto", "(19) preload is initially auto");
+ // set preload state to none and switch video sources
+ v.preload="none";
+ v.src = test.name + "?asdf";
+
+ v.onloadedmetadata = function() {
+ ok(false, "(19) 'loadedmetadata' shouldn't fire when preload is none");
+ }
+
+ var ontimeout = function() {
+ v.removeEventListener("suspend", onsuspend, false);
+ ok(false, "(19) 'suspend' should've fired");
+ maybeFinish(v, 19);
+ }
+ var cancel = setTimeout(ontimeout, 10000);
+
+ var onsuspend = function() {
+ v.removeEventListener("suspend", onsuspend, false);
+ clearTimeout(cancel);
+ is(v.readyState, 0, "(19) no buffering has taken place");
+ maybeFinish(v, 19);
+ }
+ v.addEventListener("suspend", onsuspend, false);
+ }
+ document.body.appendChild(v);
+ },
+
+ name: "test19",
+ }
+];
+
+var iterationCount = 0;
+function startTest(test, token) {
+ if (test == tests[0]) {
+ ++iterationCount;
+ info("iterationCount=" + iterationCount);
+ }
+ if (iterationCount == 2) {
+ // Do this series of tests on logically different resources
+ test.name = baseName + "?" + Math.floor(Math.random()*100000);
+ }
+ var v = document.createElement("video");
+ v.token = token;
+ test.setup(v);
+ manager.started(token);
+}
+
+var twiceTests = tests.concat(tests);
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [["media.cache_size", 40000]]}, beginTest);
+function beginTest() {
+ manager.runTests(twiceTests, startTest);
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_preload_attribute.html b/dom/media/test/test_preload_attribute.html
new file mode 100644
index 000000000..685ad969c
--- /dev/null
+++ b/dom/media/test/test_preload_attribute.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=479863
+-->
+<head>
+ <title>Test for Bug 479863</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=479863">Mozilla Bug 479863</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+
+<video id='v1'></video><audio id='a1'></audio>
+<video id='v2' preload="auto"></video><audio id='a2' preload="auto"></audio>
+
+<pre id="test">
+<script type="application/javascript">
+var v1 = document.getElementById('v1');
+var a1 = document.getElementById('a1');
+var v2 = document.getElementById('v2');
+var a2 = document.getElementById('a2');
+is(v1.getAttribute("preload"), null, "video preload via getAttribute should be null by default");
+is(a1.getAttribute("preload"), null, "video preload via getAttribute should be null by default");
+is(v1.preload, "", "v1.preload should be empty by default");
+is(a1.preload, "", "a1.preload should be empty by default");
+is(v2.preload, "auto", "v2.preload should be auto");
+is(a2.preload, "auto", "a2.preload should be auto");
+
+v1.preload = "auto";
+a1.preload = "auto";
+is(v1.preload, "auto", "video.preload should be auto");
+is(a1.preload, "auto", "audio.preload should be auto");
+is(v1.getAttribute("preload"), "auto", "video preload attribute should be auto");
+is(a1.getAttribute("preload"), "auto", "video preload attribute should be auto");
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_preload_suspend.html b/dom/media/test/test_preload_suspend.html
new file mode 100644
index 000000000..4a9478462
--- /dev/null
+++ b/dom/media/test/test_preload_suspend.html
@@ -0,0 +1,112 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 479863</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function checkSuspendCount(evt) {
+ var v = evt.target;
+ ++v.suspendCount;
+ is(v.networkState, v.NETWORK_IDLE, v.name + " got suspended, count=" + v.suspendCount);
+ if (v.suspendCount == v.expectedSuspendCount) {
+ removeNodeAndSource(v);
+ manager.finished(v.name);
+ }
+ if (v.suspendCount > v.expectedSuspendCount) {
+ ok(false, v.name + " got too many suspend events");
+ }
+}
+
+var tests = [
+ {
+ name: 'v1',
+ preload: 'none',
+ expectedSuspendCount: 2,
+ onsuspend: function(evt) {
+ checkSuspendCount(evt);
+ if (evt.target.suspendCount == 1) {
+ evt.target.preload = 'auto';
+ }
+ }
+ },
+ {
+ name: 'v2',
+ preload: 'auto',
+ expectedSuspendCount: 1,
+ onsuspend: checkSuspendCount
+ },
+ {
+ name: 'v3',
+ preload: 'none',
+ autoplay: true,
+ expectedSuspendCount: 1,
+ onsuspend: checkSuspendCount
+ },
+ {
+ name: 'v4',
+ preload: 'none',
+ expectedSuspendCount: 2,
+ onsuspend: function(evt) {
+ checkSuspendCount(evt);
+ if (evt.target.suspendCount == 1) {
+ evt.target.play();
+ }
+ }
+ },
+ // disable v5 since media element doesn't support 'load' event anymore.
+ /*{
+ name: 'v5',
+ preload: 'none',
+ expectedSuspendCount: 2,
+ onsuspend: function(evt) {
+ checkSuspendCount(evt);
+ if (evt.target.suspendCount == 1) {
+ evt.target.currentTime = 0.1;
+ }
+ }
+ },*/
+ {
+ name: 'v6',
+ preload: 'none',
+ expectedSuspendCount: 2,
+ onsuspend: function(evt) {
+ checkSuspendCount(evt);
+ if (evt.target.suspendCount == 1) {
+ evt.target.autoplay = true;
+ }
+ }
+ }
+];
+
+function startTest(test, token) {
+ var v = document.createElement("video");
+ v.name = test.name;
+ var key = Math.random();
+ v.src = "seek.ogv?key=" + key + "&id=" + v.name;
+ v.preload = test.preload;
+ v.suspendCount = 0;
+ v.expectedSuspendCount = test.expectedSuspendCount;
+ if (test.autoplay) {
+ v.autoplay = true;
+ }
+ v.onsuspend = test.onsuspend;
+ document.body.appendChild(v);
+ manager.started(v.name);
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [["media.cache_size", 40000]]}, function() {
+ manager.runTests(tests, startTest);
+});
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_preserve_playbackrate_after_ui_play.html b/dom/media/test/test_preserve_playbackrate_after_ui_play.html
new file mode 100644
index 000000000..628d5c0c7
--- /dev/null
+++ b/dom/media/test/test_preserve_playbackrate_after_ui_play.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title> Bug 1013933 - preserve playbackRate after clicking play button </title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<div id="content">
+ <video width="320" height="240" id="video" controls mozNoDynamicControls preload="auto"></video>
+</div>
+
+<script type="text/javascript">
+/*
+ * Positions of the UI elements, relative to the upper-left corner of the
+ * <video> box.
+ */
+const videoHeight = 240;
+const playButtonWidth = 28;
+const playButtonHeight = 28;
+const playButtonCenterX = 0 + Math.round(playButtonWidth / 2);
+const playButtonCenterY = videoHeight - Math.round(playButtonHeight / 2);
+
+var expectedPlaybackRate = 0.5
+
+function runTest() {
+ var video = document.getElementById("video");
+ video.src = "audio.wav";
+ video.loop = true;
+ video.playbackRate = expectedPlaybackRate;
+
+ video.oncanplaythrough = function() {
+ video.oncanplaythrough = null;
+ is(video.paused, true, "video is not playing yet.");
+ is(video.playbackRate, expectedPlaybackRate,
+ "playbackRate is correct before clicking play button.");
+
+ // Click the play button
+ synthesizeMouse(video, playButtonCenterX, playButtonCenterY, { });
+ };
+
+ video.onplay = function() {
+ video.onplay = null;
+ is(video.paused, false, "video starts playing.");
+ is(video.playbackRate, expectedPlaybackRate,
+ "playbackRate is correct after clicking play button.");
+ video.pause();
+ SimpleTest.finish();
+ };
+}
+
+window.addEventListener("load", runTest, false);
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_progress.html b/dom/media/test/test_progress.html
new file mode 100644
index 000000000..846ecbd4f
--- /dev/null
+++ b/dom/media/test/test_progress.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: progress events</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function do_progress(e) {
+ var v = e.target;
+ ok(!v._finished, "Check no progress events after completed for " + v._name);
+}
+
+function do_ended(e) {
+ var v = e.target;
+ ok(!v._finished, "Only one ended event for " + v._name);
+ v._finished = true;
+ v.removeEventListener("ended", do_ended, false);
+ v.removeEventListener("progress", do_progress, false);
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+}
+
+function startTest(test, token) {
+ var type = /^video/.test(test.type) ? "video" : "audio";
+ var v = document.createElement(type);
+ v.token = token;
+ manager.started(token);
+ v.src = test.name;
+ v.autoplay = true;
+ v._name = test.name;
+ v._finished = false;
+ v.addEventListener("ended", do_ended, false);
+ v.addEventListener("progress", do_progress, false);
+ document.body.appendChild(v);
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [["media.cache_size", 40000]]}, beginTest);
+function beginTest() {
+ manager.runTests(gProgressTests, startTest);
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_reactivate.html b/dom/media/test/test_reactivate.html
new file mode 100644
index 000000000..fd876660c
--- /dev/null
+++ b/dom/media/test/test_reactivate.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test reactivation of a media element from a dead document</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+
+<iframe id="frame" src="reactivate_helper.html"></iframe>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var elements;
+
+function playElement(e) {
+ // All elements played out, finish the test case.
+ if (!e) {
+ SimpleTest.finish();
+ return;
+ }
+
+ e.play();
+ info("Element play: " + e._name);
+ var reviveElement = function() {
+ document.body.appendChild(e);
+ e.onended = function() {
+ info("Element ended: " + e._name);
+ removeNodeAndSource(e);
+ // Play next element.
+ playElement(elements.pop());
+ }
+ }
+ setTimeout(reviveElement, 2000);
+}
+
+function loadedAll(elementList) {
+ elements = elementList;
+
+ // Log events for debugging.
+ var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
+ "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
+ "waiting", "pause"];
+ function logEvent(e) {
+ info(e.target._name + ": got " + e.type);
+ }
+ elementList.forEach(function(element) {
+ events.forEach(function(evt) {
+ element.addEventListener(evt, logEvent, false);
+ });
+ });
+
+ // Blow away the subframe
+ document.body.removeChild(document.getElementById("frame"));
+
+ // Play elements one by one to avoid hitting bug 847903 on MacOSX.
+ playElement(elements.pop());
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_readyState.html b/dom/media/test/test_readyState.html
new file mode 100644
index 000000000..caa244b6d
--- /dev/null
+++ b/dom/media/test/test_readyState.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: readyState</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<video id='v1'></video><audio id='a1'></audio>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+"use strict";
+var v1 = document.getElementById('v1');
+var a1 = document.getElementById('a1');
+var passed = "truthy";
+
+is(v1.readyState, 0);
+is(a1.readyState, 0);
+
+try {
+ v1.readyState = 0;
+} catch (e) {
+ passed = !passed;
+}
+try {
+ a1.readyState = 0;
+} catch (e) {
+ passed = !passed;
+}
+ok(passed === true,
+ "Setting readyState throws in strict mode (readonly attribute)");
+</script>
+
+<script class="testbody" type="text/javascript">
+var v1 = document.getElementById('v1');
+var a1 = document.getElementById('a1');
+var passed = false;
+
+is(v1.readyState, 0);
+is(a1.readyState, 0);
+
+try {
+ v1.readyState = 1;
+ a1.readyState = 1;
+ passed = v1.readyState === 0 && a1.readyState === 0;
+} catch(e) { }
+ok(passed, "Should not be able to set readyState (readonly attribute)");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_referer.html b/dom/media/test/test_referer.html
new file mode 100644
index 000000000..4af45ab19
--- /dev/null
+++ b/dom/media/test/test_referer.html
@@ -0,0 +1,88 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=584480
+-->
+<head>
+ <title>Test for Bug 584480</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=584480">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+var media = [];
+
+function checkComplete() {
+ for (var i=0; i<media.length; ++i) {
+ if (!media[i]._complete) {
+ return;
+ }
+ }
+
+ SimpleTest.finish();
+}
+
+function removeNode(v) {
+ v.removeEventListener("error", loadError, false);
+ v.removeEventListener("loadedmetadata", loadedMetadata, false);
+ v.remove();
+ v.src = "";
+}
+
+function loadError(evt) {
+ // If no referer is sent then the sjs returns an error
+ ok(false, "check referer is sent with media request");
+ evt.target._complete = true;
+ checkComplete();
+ removeNode(evt.target);
+}
+
+function loadedMetadata(evt) {
+ // If a referer is sent then the sjs returns a valid media
+ ok(true, "check referer is sent with media request");
+ evt.target._complete = true;
+ checkComplete();
+ removeNode(evt.target);
+}
+
+// Create all media objects.
+for (var i=0; i<gSmallTests.length; ++i) {
+ var test = gSmallTests[i];
+ var type;
+ if (/^video/.test(test.type)) {
+ type = "video"
+ } else {
+ type = "audio";
+ }
+ var v = document.createElement(type);
+ if (!v.canPlayType(test.type)) {
+ continue;
+ }
+ // ensure metadata is loaded for default preload is none on b2g
+ v.preload = "metadata";
+ v.autoplay = "true";
+ v._complete = false;
+ v.addEventListener("error", loadError, false);
+ v.addEventListener("loadedmetadata", loadedMetadata, false);
+ v.src = 'referer.sjs?name=' + test.name + '&type=' + test.type;
+ document.body.appendChild(v); // Will start load.
+ media.push(v);
+}
+
+if (media.length == 0) {
+ todo(false, "No types supported");
+} else {
+ SimpleTest.waitForExplicitFinish();
+}
+</script>
+</pre>
+
+</body>
+</html>
diff --git a/dom/media/test/test_replay_metadata.html b/dom/media/test/test_replay_metadata.html
new file mode 100644
index 000000000..312a38197
--- /dev/null
+++ b/dom/media/test/test_replay_metadata.html
@@ -0,0 +1,120 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=467972
+-->
+<head>
+ <title>Test for Bug 467972</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=467972">Mozilla Bug 467972</a>
+
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+// Test for Bug 467972. Tests that when we play to end, seek to 0, and play again, that we don't
+// send/receive multiple loadeddata and loadedmetadata events.
+
+var manager = new MediaTestManager;
+
+function seekStarted(evt) {
+ var v = evt.target;
+ v._gotSeekStarted = true;
+}
+
+function seekEnded(evt) {
+ var v = evt.target;
+ v._gotSeekEnded = true;
+ v.play();
+}
+
+function loadedData(evt) {
+ var v = evt.target;
+ v._loadedDataCount++;
+ ok(v._loadedDataCount <= 1, "No more than 1 onloadeddata event for " + v._name);
+}
+
+function loadedMetaData(evt) {
+ var v = evt.target;
+ v._loadedMetaDataCount++;
+ ok(v._loadedMetaDataCount <= 1, "No more than 1 onloadedmetadata event for " + v._name);
+ checkMetadata(v._name, v, v._test);
+ v.play();
+}
+
+function playing(evt) {
+ evt.target._playingCount++;
+}
+
+function removeNodeAndListener(n) {
+ n.removeEventListener("loadedmetadata", loadedMetaData, false);
+ n.removeEventListener("ended", playbackEnded, false);
+ n.removeEventListener("playing", playing, false);
+ n.removeEventListener("loadeddata", loadedData, false);
+ n.removeEventListener("seeking", seekStarted, false);
+ n.removeEventListener("seeked", seekEnded, false);
+ removeNodeAndSource(n);
+}
+
+function playbackEnded(evt) {
+ var v = evt.target;
+ v._endCount++;
+ ok(v.currentTime >= v.duration-0.1 && v.currentTime <= v.duration + 0.1,
+ "CurrentTime (" + v.currentTime + ") should be around " + v.duration
+ + " for " + v._name);
+ if (!v._playedOnce) {
+ v.currentTime = 0;
+ ok(v.seeking, "seeking should be true for " + v._name);
+ ok(!v.ended, "ended shouldn't be true once seeking has begun for " + v._name);
+ v._playedOnce = true;
+ } else {
+ ok(v._gotSeekEnded, "Should have received seekended for " + v._name);
+ ok(v._gotSeekStarted, "Should have received seekstarted for " + v._name);
+ is(v._loadedDataCount, 1, "Should have 1 onloadeddata event for " + v._name);
+ is(v._loadedMetaDataCount, 1, "Should have 1 onloadedmetadata event for " + v._name);
+ is(v._endCount, 2, "Should have received two ended events for " + v._name);
+ ok(v._playingCount > 0, "Should have at least one playing event for " + v._name);
+ v._finished = true;
+ removeNodeAndListener(v);
+ manager.finished(v.token);
+ }
+}
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ v.preload = "auto";
+ v.token = token;
+ manager.started(token);
+ v.src = test.name;
+ v._name = test.name;
+ v._playedOnce = false;
+ v._gotSeekEnded = false;
+ v._gotSeekStarted = false;
+ v._loadedDataCount = 0;
+ v._loadedMetaDataCount = 0;
+ v._playingCount = 0;
+ v._endCount = 0;
+ v._test = test;
+ v._finished = false;
+ v.addEventListener("loadedmetadata", loadedMetaData, false);
+ v.addEventListener("ended", playbackEnded, false);
+ v.addEventListener("playing", playing, false);
+ v.addEventListener("loadeddata", loadedData, false);
+ v.addEventListener("seeking", seekStarted, false);
+ v.addEventListener("seeked", seekEnded, false);
+ document.body.appendChild(v);
+}
+
+manager.runTests(gSmallTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_reset_events_async.html b/dom/media/test/test_reset_events_async.html
new file mode 100644
index 000000000..d47f33d32
--- /dev/null
+++ b/dom/media/test/test_reset_events_async.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=975270
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug </title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript" src="manifest.js"></script>
+ <script type="application/javascript">
+
+ /** Test for Bug 975270 **/
+ // Test that 'emptied' and 'abort' events are fired asynchronously when re-starting
+ // media load.
+ SimpleTest.waitForExplicitFinish();
+
+ var a = document.createElement("audio");
+ a._abort = 0;
+ a._emptied = 0;
+ a.preload = "metadata"; // On B2G we default to preload:none.
+
+ is(a.networkState, HTMLMediaElement.NETWORK_EMPTY, "Shouldn't be loading");
+
+ a.addEventListener("abort", function(e) { a._abort++; });
+ a.addEventListener("emptied", function(e) { a._emptied++; });
+ a.addEventListener("loadedmetadata",
+ function(e) {
+ is(a._abort, 0, "Should not have received 'abort' before 'loadedmetadata");
+ is(a._emptied, 0, "Should not have received 'emptied' before 'loadedmetadata");
+
+ a.addEventListener("loadstart",
+ function(e) {
+ is(a._abort, 1, "Should have received 'abort' before 'loadstart");
+ is(a._emptied, 1, "Should have received 'emptied' before 'loadstart");
+ SimpleTest.finish();
+ });
+
+ a.src = "";
+ is(a._abort, 0, "Should not have received 'abort' during setting a.src=''");
+ is(a._emptied, 0, "Should not have received 'emptied' during setting a.src=''");
+ });
+
+ a.src = getPlayableAudio(gSmallTests).name;
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_reset_src.html b/dom/media/test/test_reset_src.html
new file mode 100644
index 000000000..0b05eba49
--- /dev/null
+++ b/dom/media/test/test_reset_src.html
@@ -0,0 +1,98 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=804875
+-->
+
+<head>
+ <title>Test for bug 804875</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="manifest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank"
+href="https://bugzilla.mozilla.org/show_bug.cgi?id=804875">Mozilla Bug 804875</a>
+
+<canvas></canvas>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function finish(v) {
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+}
+
+function onLoadedData_Audio(e) {
+ var t = e.target;
+ is(t.videoHeight, 0, t.name + ": videoHeight should be zero when there is no video.");
+ is(t.videoWidth, 0, t.name + ": videoWidth should be zero when there is no video.");
+ is(t.mozPaintedFrames, 0, t.name + ": mozPaintedFrames should be zero when there is no video.");
+ is(t.mozFrameDelay, 0, t.name + ": mozFrameDelay should be zero when there is no video.");
+ var c = document.getElementsByTagName("canvas")[0].getContext("2d");
+ try {
+ c.drawImage(t, 0, 0, t.videoHeight, t.videoWidth);
+ } catch (e) {
+ ok(true, t.name + ": Trying to draw to a canvas should throw, since we don't have a frame anymore");
+ finish(t);
+ return;
+ }
+ ok(false, t.name + ": We should not succeed to draw a video frame on the canvas.");
+ finish(t);
+}
+
+function onTimeUpdate_Video(e) {
+ var t = e.target;
+ if (t.currentTime < t.duration / 4) {
+ return;
+ }
+ t.removeEventListener("timeupdate", onTimeUpdate_Video);
+ // There's no guarantee that a video frame composite notification reaches
+ // us before timeupdate fires.
+ ok(t.mozPaintedFrames >= 0, t.name + ": mozPaintedFrames should be positive or zero, is " + t.mozPaintedFrames + ".");
+ ok(t.mozFrameDelay >= 0, t.name + ": mozFrameDelay should be positive or zero, is " + t.mozFrameDelay + ".");
+
+ if (t._firstTime) {
+ t.src = t.src;
+ t._firstTime = false;
+ } else {
+ var source = getPlayableAudio(gPlayTests);
+ if (!source) {
+ todo("No audio file available.")
+ finish(t);
+ } else {
+ t.removeEventListener("loadeddata", onLoadedData_Video);
+ t.addEventListener("loadeddata", onLoadedData_Audio);
+ t.src = source.name;
+ }
+ }
+}
+
+function onLoadedData_Video(e) {
+ var t = e.target;
+ isnot(t.videoHeight, 0, t.name + ": We should have a videoHeight.");
+ isnot(t.videoWidth, 0, t.name + ": We should have a videoWidth.");
+ t.addEventListener("timeupdate", onTimeUpdate_Video);
+ t.play();
+}
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ document.body.appendChild(v);
+ v._firstTime = true;
+ v.addEventListener("loadeddata", onLoadedData_Video);
+ v.src = test.name;
+ v.token = token;
+ v.name = test.name;
+ v.play();
+ manager.started(token);
+}
+
+manager.runTests(getPlayableVideos(gSmallTests.concat(gSeekTests)), startTest);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_resolution_change.html b/dom/media/test/test_resolution_change.html
new file mode 100644
index 000000000..e1b8c2476
--- /dev/null
+++ b/dom/media/test/test_resolution_change.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test playback of files with resolution changes</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function loadedData(e) {
+ var v = e.target;
+ v.addEventListener("resize", resize, false);
+ v.play();
+}
+
+function resize(e) {
+ var v = e.target;
+ v.seenResolutionChange = true;
+}
+
+function ended(e) {
+ var v = e.target;
+ ok(v.seenResolutionChange, v.token + ": A resolution change should have ocurred by the end of playback");
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+}
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ v.preload = "metadata";
+ v.token = token;
+ v.src = test.name;
+ v.seenResolutionChange = false;
+
+ v.addEventListener("loadeddata", loadedData, false)
+ v.addEventListener("ended", ended, false);
+
+ manager.started(token);
+ document.body.appendChild(v);
+}
+
+manager.runTests(gResolutionChangeTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_resume.html b/dom/media/test/test_resume.html
new file mode 100644
index 000000000..c5dcb67d1
--- /dev/null
+++ b/dom/media/test/test_resume.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: Test resume of server-dropped connections</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<audio preload="auto" id="a"></audio>
+<iframe id="f"></iframe>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var key = Math.round(Math.random()*1000000000);
+var a = document.getElementById("a");
+var f = document.getElementById("f");
+
+function didEnd() {
+ ok(a.currentTime > 2.26, "Reached correct end time (got " + a.currentTime + ", expected > 2.26");
+ SimpleTest.finish();
+}
+
+function didSendCancel() {
+ a.addEventListener("ended", didEnd, false);
+ a.play();
+}
+
+function didSuspend() {
+ a.removeEventListener("suspend", didSuspend, false);
+
+ // Cache must have filled up, or something. Tell the Web server to drop
+ // our connection.
+ f.addEventListener("load", didSendCancel, false);
+ f.src = "cancellable_request.sjs?cancelkey=" + key;
+}
+
+if (!a.canPlayType("audio/wave")) {
+ todo(false, "Test requires support for audio/wave");
+} else {
+ a.addEventListener("suspend", didSuspend, false);
+ a.src = "cancellable_request.sjs?key=" + key;
+ SimpleTest.waitForExplicitFinish();
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seek-1.html b/dom/media/test/test_seek-1.html
new file mode 100644
index 000000000..accf38a8e
--- /dev/null
+++ b/dom/media/test/test_seek-1.html
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seek tests</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="seek_support.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// The data being used in these tests is specified in manifest.js.
+// The functions to build the test array and to run a specific test are in
+// seek_support.js.
+
+const SEEK_TEST_NUMBER = 1;
+
+function test_seek1(v, seekTime, is, ok, finish) {
+
+var startPassed = false;
+var endPassed = false;
+var seekFlagStart = false;
+var seekFlagEnd = false;
+var readonly = true;
+var completed = false;
+
+function startTest() {
+ ok(!completed, "Should not be completed yet");
+ ok(!v.seeking, "seeking should default to false");
+ try {
+ v.seeking = true;
+ readonly = v.seeking === false;
+ }
+ catch(e) {
+ readonly = "threw exception: " + e;
+ }
+ is(readonly, true, "seeking should be readonly");
+
+ v.currentTime = seekTime;
+ seekFlagStart = v.seeking;
+}
+
+function seekStarted() {
+ ok(!completed, "should not be completed yet");
+ ok(Math.abs(v.currentTime - seekTime) < 0.1,
+ "Video currentTime should be around " + seekTime + ": " + v.currentTime + " (seeking)");
+ startPassed = true;
+}
+
+function seekEnded() {
+ ok(!completed, "shuld not be completed yet");
+ ok(Math.abs(v.currentTime - seekTime) < 0.1,
+ "Video currentTime should be around " + seekTime + ": " + v.currentTime + " (seeked)");
+ endPassed = true;
+ seekFlagEnd = v.seeking;
+ v.play();
+}
+
+function playbackEnded() {
+ ok(!completed, "should not be completed yet");
+
+ completed = true;
+ ok(startPassed, "seeking event");
+ ok(endPassed, "seeked event");
+ ok(seekFlagStart, "seeking flag on start should be true");
+ ok(!seekFlagEnd, "seeking flag on end should be false");
+ finish();
+}
+
+once(v, "ended", playbackEnded);
+once(v, "loadedmetadata", startTest);
+once(v, "seeking", seekStarted);
+once(v, "seeked", seekEnded);
+
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seek-10.html b/dom/media/test/test_seek-10.html
new file mode 100644
index 000000000..7a16397b3
--- /dev/null
+++ b/dom/media/test/test_seek-10.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seek tests</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="seek_support.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// The data being used in these tests is specified in manifest.js.
+// The functions to build the test array and to run a specific test are in
+// seek_support.js.
+
+const SEEK_TEST_NUMBER = 10;
+
+function test_seek10(v, seekTime, is, ok, finish) {
+
+// Test bug 523335 - ensure that if we close a stream while seeking, we
+// don't hang during shutdown. This test won't "fail" per se if it's regressed,
+// it will instead start to cause random hangs in the mochitest harness on
+// shutdown.
+
+function startTest() {
+ // Must be duration*0.9 rather than seekTime, else we don't hit that problem.
+ // This is probably due to the seek bisection finishing too quickly, before
+ // we can close the stream.
+ v.currentTime = v.duration * 0.9;
+}
+
+function done(evt) {
+ ok(true, "We don't acutally test anything...");
+ finish();
+}
+
+function seeking() {
+ ok(v.currentTime >= seekTime - 0.1, "Video currentTime should be around " + seekTime + ": " + v.currentTime);
+ v.onerror = done;
+ v.src = "not a valid video file.";
+ v.load(); // Cause the existing stream to close.
+}
+
+v.addEventListener("loadeddata", startTest, false);
+v.addEventListener("seeking", seeking, false);
+
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seek-11.html b/dom/media/test/test_seek-11.html
new file mode 100644
index 000000000..53b9a3269
--- /dev/null
+++ b/dom/media/test/test_seek-11.html
@@ -0,0 +1,76 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seek tests</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="seek_support.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// The data being used in these tests is specified in manifest.js.
+// The functions to build the test array and to run a specific test are in
+// seek_support.js.
+
+PARALLEL_TESTS = 1;
+const SEEK_TEST_NUMBER = 11;
+
+function test_seek11(v, seekTime, is, ok, finish) {
+
+// Test for bug 476973, multiple seeks to the same position shouldn't cause problems.
+
+var seekedNonZero = false;
+var completed = false;
+var target = 0;
+
+function startTest() {
+ if (completed)
+ return;
+ target = v.duration / 2;
+ v.currentTime = target;
+ v.currentTime = target;
+ v._seekTarget = target;
+}
+
+function startSeeking() {
+ ok(v.currentTime >= v._seekTarget - 0.1,
+ "Video currentTime should be around " + v._seekTarget + ": " + v.currentTime);
+ if (!seekedNonZero) {
+ v.currentTime = target;
+ v._seekTarget = target;
+ seekedNonZero = true;
+ }
+}
+
+function seekEnded() {
+ if (completed)
+ return;
+
+ if (v.currentTime > 0) {
+ ok(v.currentTime > target - 0.1 && v.currentTime < target + 0.1,
+ "Seek to wrong destination " + v.currentTime);
+ v.currentTime = 0.0;
+ v._seekTarget = 0.0;
+ } else {
+ ok(seekedNonZero, "Successfully seeked to nonzero");
+ ok(true, "Seek back to zero was successful");
+ completed = true;
+ finish();
+ }
+}
+
+v.addEventListener("loadedmetadata", startTest, false);
+v.addEventListener("seeking", startSeeking, false);
+v.addEventListener("seeked", seekEnded, false);
+
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seek-12.html b/dom/media/test/test_seek-12.html
new file mode 100644
index 000000000..66c4c342c
--- /dev/null
+++ b/dom/media/test/test_seek-12.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seek tests</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="seek_support.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// The data being used in these tests is specified in manifest.js.
+// The functions to build the test array and to run a specific test are in
+// seek_support.js.
+
+const SEEK_TEST_NUMBER = 12;
+
+function test_seek12(v, seekTime, is, ok, finish) {
+var completed = false;
+
+function startTest() {
+ if (completed)
+ return;
+ ok(!v.seeking, "seeking should default to false");
+ v.currentTime = seekTime;
+ is(v.currentTime, seekTime, "currentTime must report seek target immediately");
+ is(v.seeking, true, "seeking flag on start should be true");
+}
+
+function seekStarted() {
+ if (completed)
+ return;
+ //is(v.currentTime, seekTime, "seeking: currentTime must be seekTime");
+ ok(Math.abs(v.currentTime - seekTime) < 0.01, "seeking: currentTime must be seekTime");
+}
+
+function seekEnded() {
+ if (completed)
+ return;
+ completed = true;
+ //is(v.currentTime, seekTime, "seeked: currentTime must be seekTime");
+ ok(Math.abs(v.currentTime - seekTime) < 0.01, "seeked: currentTime must be seekTime");
+ is(v.seeking, false, "seeking flag on end should be false");
+ finish();
+}
+
+v.addEventListener("loadedmetadata", startTest, false);
+v.addEventListener("seeking", seekStarted, false);
+v.addEventListener("seeked", seekEnded, false);
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seek-13.html b/dom/media/test/test_seek-13.html
new file mode 100644
index 000000000..810957c51
--- /dev/null
+++ b/dom/media/test/test_seek-13.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seek tests</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="seek_support.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// The data being used in these tests is specified in manifest.js.
+// The functions to build the test array and to run a specific test are in
+// seek_support.js.
+
+const SEEK_TEST_NUMBER = 13;
+
+function test_seek13(v, seekTime, is, ok, finish) {
+var completed = false;
+
+function startTest() {
+ if (completed)
+ return;
+ ok(!v.seeking, "seeking should default to false");
+ v.currentTime = v.duration;
+ is(v.currentTime, v.duration, "currentTime must report seek target immediately");
+ is(v.seeking, true, "seeking flag on start should be true");
+}
+
+function seekStarted() {
+ if (completed)
+ return;
+ //is(v.currentTime, v.duration, "seeking: currentTime must be duration");
+ ok(Math.abs(v.currentTime - v.duration) < 0.01,
+ "seeking: currentTime (" + v.currentTime + ") must be duration (" + v.duration + ")");
+}
+
+function seekEnded() {
+ if (completed)
+ return;
+ //is(v.currentTime, v.duration, "seeked: currentTime must be duration");
+ ok(Math.abs(v.currentTime - v.duration) < 0.01,
+ "seeked: currentTime (" + v.currentTime + ") must be duration (" + v.duration + ")");
+ is(v.seeking, false, "seeking flag on end should be false");
+}
+
+function playbackEnded() {
+ if (completed)
+ return;
+ completed = true;
+ //is(v.currentTime, v.duration, "ended: currentTime must be duration");
+ ok(Math.abs(v.currentTime - v.duration) < 0.01,
+ "ended: currentTime (" + v.currentTime + ") must be duration (" + v.duration + ")");
+ is(v.seeking, false, "seeking flag on end should be false");
+ is(v.ended, true, "ended must be true");
+ finish();
+}
+
+v.addEventListener("loadedmetadata", startTest, false);
+v.addEventListener("seeking", seekStarted, false);
+v.addEventListener("seeked", seekEnded, false);
+v.addEventListener("ended", playbackEnded, false);
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seek-2.html b/dom/media/test/test_seek-2.html
new file mode 100644
index 000000000..69484f0be
--- /dev/null
+++ b/dom/media/test/test_seek-2.html
@@ -0,0 +1,76 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seek tests</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="seek_support.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// The data being used in these tests is specified in manifest.js.
+// The functions to build the test array and to run a specific test are in
+// seek_support.js.
+
+PARALLEL_TESTS = 1;
+const SEEK_TEST_NUMBER = 2;
+
+function test_seek2(v, seekTime, is, ok, finish) {
+
+// Test seeking works if current time is set before video is
+// playing.
+var startPassed = false;
+var endPassed = false;
+var completed = false;
+
+function startTest() {
+ if (completed)
+ return;
+
+ v.currentTime=seekTime;
+ v.play();
+}
+
+function seekStarted() {
+ if (completed)
+ return;
+
+ ok(v.currentTime >= seekTime - 0.1, "Video currentTime should be around " + seekTime + ": " + v.currentTime);
+ startPassed = true;
+}
+
+function seekEnded() {
+ if (completed)
+ return;
+
+ endPassed = true;
+}
+
+function playbackEnded() {
+ if (completed)
+ return;
+
+ completed = true;
+ ok(startPassed, "send seeking event");
+ ok(endPassed, "send seeked event");
+ ok(v.ended, "Checking playback has ended");
+ ok(Math.abs(v.currentTime - v.duration) <= 0.1, "Checking currentTime at end: " + v.currentTime);
+ finish();
+}
+
+v.addEventListener("ended", playbackEnded, false);
+v.addEventListener("loadedmetadata", startTest, false);
+v.addEventListener("seeking", seekStarted, false);
+v.addEventListener("seeked", seekEnded, false);
+
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seek-3.html b/dom/media/test/test_seek-3.html
new file mode 100644
index 000000000..04e5176e9
--- /dev/null
+++ b/dom/media/test/test_seek-3.html
@@ -0,0 +1,70 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seek tests</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="seek_support.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// The data being used in these tests is specified in manifest.js.
+// The functions to build the test array and to run a specific test are in
+// seek_support.js.
+
+const SEEK_TEST_NUMBER = 3;
+
+function test_seek3(v, seekTime, is, ok, finish) {
+
+// Test seeking works if current time is set but video is not played.
+var startPassed = false;
+var completed = false;
+var gotTimeupdate = false;
+
+function startTest() {
+ if (completed)
+ return;
+
+ v.currentTime=seekTime;
+}
+
+function timeupdate() {
+ gotTimeupdate = true;
+ v.removeEventListener("timeupdate", timeupdate, false);
+}
+
+function seekStarted() {
+ if (completed)
+ return;
+
+ ok(v.currentTime >= seekTime - 0.1, "Video currentTime should be around " + seekTime + ": " + v.currentTime);
+ v.addEventListener("timeupdate", timeupdate, false);
+ startPassed = true;
+}
+
+function seekEnded() {
+ if (completed)
+ return;
+
+ var t = v.currentTime;
+ ok(Math.abs(t - seekTime) <= 0.1, "Video currentTime should be around " + seekTime + ": " + t);
+ ok(gotTimeupdate, "Should have got timeupdate between seeking and seekended");
+ completed = true;
+ finish();
+}
+
+v.addEventListener("loadedmetadata", startTest, false);
+v.addEventListener("seeking", seekStarted, false);
+v.addEventListener("seeked", seekEnded, false);
+
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seek-4.html b/dom/media/test/test_seek-4.html
new file mode 100644
index 000000000..4d34e3e58
--- /dev/null
+++ b/dom/media/test/test_seek-4.html
@@ -0,0 +1,70 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seek tests</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="seek_support.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// The data being used in these tests is specified in manifest.js.
+// The functions to build the test array and to run a specific test are in
+// seek_support.js.
+
+const SEEK_TEST_NUMBER = 4;
+
+function test_seek4(v, seekTime, is, ok, finish) {
+
+// Test for a seek, followed by another seek before the first is complete.
+var seekCount = 0;
+var completed = false;
+
+function startTest() {
+ if (completed)
+ return;
+
+ v.currentTime=seekTime;
+ v._seekTarget=seekTime;
+}
+
+function seekStarted() {
+ if (completed)
+ return;
+
+ seekCount += 1;
+
+ ok(v.currentTime >= v._seekTarget - 0.1,
+ "Video currentTime should be around " + v._seekTarget + ": " + v.currentTime);
+ if (seekCount == 1) {
+ v.currentTime=seekTime/2;
+ v._seekTarget=seekTime/2;
+ }
+}
+
+function seekEnded() {
+ if (completed)
+ return;
+
+ if (seekCount == 2) {
+ ok(Math.abs(v.currentTime - seekTime/2) <= 0.1, "seek on target: " + v.currentTime);
+ completed = true;
+ finish();
+ }
+}
+
+v.addEventListener("loadedmetadata", startTest, false);
+v.addEventListener("seeking", seekStarted, false);
+v.addEventListener("seeked", seekEnded, false);
+
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seek-5.html b/dom/media/test/test_seek-5.html
new file mode 100644
index 000000000..c045070d2
--- /dev/null
+++ b/dom/media/test/test_seek-5.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seek tests</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="seek_support.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// The data being used in these tests is specified in manifest.js.
+// The functions to build the test array and to run a specific test are in
+// seek_support.js.
+
+const SEEK_TEST_NUMBER = 5;
+
+function test_seek5(v, seekTime, is, ok, finish) {
+
+// Test for a seek, followed by a play before the seek completes, ensure we play at the end of the seek.
+var startPassed = false;
+var endPassed = false;
+var completed = false;
+
+function startTest() {
+ if (completed)
+ return;
+
+ v.currentTime=seekTime;
+}
+
+function seekStarted() {
+ if (completed)
+ return;
+ ok(v.currentTime >= seekTime - 0.1, "Video currentTime should be around " + seekTime + ": " + v.currentTime);
+ startPassed = true;
+ v.play();
+}
+
+function seekEnded() {
+ if (completed)
+ return;
+ endPassed = true;
+}
+
+function playbackEnded() {
+ if (completed)
+ return;
+ ok(startPassed, "Got seeking event");
+ ok(endPassed, "Got seeked event");
+ completed = true;
+ finish();
+}
+
+v.addEventListener("ended", playbackEnded, false);
+v.addEventListener("loadedmetadata", startTest, false);
+v.addEventListener("seeking", seekStarted, false);
+v.addEventListener("seeked", seekEnded, false);
+
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seek-6.html b/dom/media/test/test_seek-6.html
new file mode 100644
index 000000000..2c1063dd4
--- /dev/null
+++ b/dom/media/test/test_seek-6.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seek tests</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="seek_support.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// The data being used in these tests is specified in manifest.js.
+// The functions to build the test array and to run a specific test are in
+// seek_support.js.
+
+const SEEK_TEST_NUMBER = 6;
+
+function test_seek6(v, seekTime, is, ok, finish) {
+
+// Test for bug identified by Chris Pearce in comment 40 on
+// bug 449159.
+var seekCount = 0;
+var completed = false;
+var interval;
+var sum = 0;
+
+function poll() {
+ sum += v.currentTime;
+}
+
+function startTest() {
+ if (completed)
+ return;
+ interval = setInterval(poll, 10);
+ v.currentTime = Math.random() * v.duration;
+}
+
+function seekEnded() {
+ if (completed)
+ return;
+
+ seekCount++;
+ ok(true, "Seek " + seekCount);
+ if (seekCount == 3) {
+ clearInterval(interval);
+ completed = true;
+ finish();
+ } else {
+ v.currentTime = Math.random() * v.duration;
+ }
+}
+
+v.addEventListener("loadedmetadata", startTest, false);
+v.addEventListener("seeked", seekEnded, false);
+
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seek-7.html b/dom/media/test/test_seek-7.html
new file mode 100644
index 000000000..faef7f80e
--- /dev/null
+++ b/dom/media/test/test_seek-7.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seek tests</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="seek_support.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// The data being used in these tests is specified in manifest.js.
+// The functions to build the test array and to run a specific test are in
+// seek_support.js.
+
+const SEEK_TEST_NUMBER = 7;
+
+function test_seek7(v, seekTime, is, ok, finish) {
+
+// If a NaN is passed to currentTime, make sure this is caught
+// otherwise an infinite loop in the Ogg backend occurs.
+var completed = false;
+var thrown1 = false;
+var thrown2 = false;
+var thrown3 = false;
+
+function startTest() {
+ if (completed)
+ return;
+
+ try {
+ v.currentTime = NaN;
+ } catch(e) {
+ thrown1 = true;
+ }
+
+ try {
+ v.currentTime = Math.random;
+ } catch(e) {
+ thrown3 = true;
+ }
+
+ completed = true;
+ ok(thrown1, "Setting currentTime to invalid value of NaN");
+ ok(thrown3, "Setting currentTime to invalid value of a function");
+ finish();
+}
+
+v.addEventListener("loadedmetadata", startTest, false);
+
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seek-8.html b/dom/media/test/test_seek-8.html
new file mode 100644
index 000000000..23ea32f17
--- /dev/null
+++ b/dom/media/test/test_seek-8.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seek tests</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="seek_support.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// The data being used in these tests is specified in manifest.js.
+// The functions to build the test array and to run a specific test are in
+// seek_support.js.
+
+const SEEK_TEST_NUMBER = 8;
+
+function test_seek8(v, seekTime, is, ok, finish) {
+
+function startTest() {
+ v.currentTime = 1000;
+}
+
+function seekEnded() {
+ ok(Math.abs(v.currentTime - v.duration) < 0.2,
+ "currentTime " + v.currentTime + " close to " + v.duration);
+ finish();
+}
+
+v.addEventListener("loadedmetadata", startTest, false);
+v.addEventListener("seeked", seekEnded, false);
+
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seek-9.html b/dom/media/test/test_seek-9.html
new file mode 100644
index 000000000..69562ac4b
--- /dev/null
+++ b/dom/media/test/test_seek-9.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seek tests</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="text/javascript" src="seek_support.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+// The data being used in these tests is specified in manifest.js.
+// The functions to build the test array and to run a specific test are in
+// seek_support.js.
+
+const SEEK_TEST_NUMBER = 9;
+
+function test_seek9(v, seekTime, is, ok, finish) {
+
+function startTest() {
+ v.currentTime = -1000;
+}
+
+function seekEnded() {
+ is(v.currentTime, 0, "currentTime clamped to 0");
+ finish();
+}
+
+v.addEventListener("loadedmetadata", startTest, false);
+v.addEventListener("seeked", seekEnded, false);
+
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seekLies.html b/dom/media/test/test_seekLies.html
new file mode 100644
index 000000000..3c4231434
--- /dev/null
+++ b/dom/media/test/test_seekLies.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: server lies about range requests</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="manifest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onunload="mediaTestCleanup();">
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function on_metadataloaded() {
+ var v = document.getElementById('v');
+ var d = Math.round(v.duration*1000);
+ ok(d == 4000, "Checking duration: " + d);
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+<video id='v'
+ preload="metadata"
+ src='seekLies.sjs'
+ onloadedmetadata='on_metadataloaded();'></video>
+</body>
+</html>
diff --git a/dom/media/test/test_seekToNextFrame.html b/dom/media/test/test_seekToNextFrame.html
new file mode 100644
index 000000000..b6869556c
--- /dev/null
+++ b/dom/media/test/test_seekToNextFrame.html
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test seekToNextFrame of media files that should play OK</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ v.preload = "metadata";
+ v.token = token;
+ v.seenSeeking = false;
+ v.seenEnded = false;
+
+ var handler = {
+ "ontimeout": function() {
+ Log(token, "timed out: ended=" + v.seenEnded);
+ }
+ };
+ manager.started(token, handler);
+
+ v.src = test.name;
+ v.name = test.name;
+
+ function callSeekToNextFrame() {
+ v.seekToNextFrame().then(
+ () => {
+ ok(v.seenSeeking, "Should have already received seeking event.")
+ v.seenSeeking = false;
+ if (!v.seenEnded)
+ callSeekToNextFrame();
+ },
+ () => {
+ ok(false, "seekToNextFrame() failed.");
+ }
+ );
+ }
+
+ var onLoadedmetadata = function(test, v) { return function() {
+ callSeekToNextFrame();
+ }}(test, v);
+
+ var finish = function() {
+ v.finished = true;
+ v.removeEventListener("loadedmetadata", onLoadedmetadata, false);
+ v.removeEventListener("seeking", onSeeking, false);
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+ }
+
+ var onEnded = function(test, v) { return function() {
+ v.seenEnded = true;
+ finish();
+ }}(test, v);
+
+ var onSeeking = function(test, v) { return function() {
+ ok(!v.seenSeeking, "Should yet receive seeking event.")
+ v.seenSeeking = true;
+ }}(test, v);
+
+ v.addEventListener("loadedmetadata", onLoadedmetadata, false);
+ v.addEventListener("seeking", onSeeking, false);
+ v.addEventListener("ended", onEnded, false);
+
+ document.body.appendChild(v);
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv(
+ {
+ "set": [["media.seekToNextFrame.enabled", true ]]
+ },
+ function() {
+ manager.runTests(gSeekToNextFrameTests, startTest);
+ });
+
+</script>
+</pre>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/media/test/test_seek_negative.html b/dom/media/test/test_seek_negative.html
new file mode 100644
index 000000000..e87d1ae4b
--- /dev/null
+++ b/dom/media/test/test_seek_negative.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seeking to a negative time with readyState HAVE_NOTHING</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function startTest(test, token) {
+ var type = getMajorMimeType(test.type);
+ var v = document.createElement(type);
+ v.token = token;
+ manager.started(token);
+
+ // Seek to negative start time.
+ v.currentTime = -123;
+ is(v.readyState, v.HAVE_NOTHING, "readyState is HAVE_NOTHING");
+ ok(!v.seeking, "can't be seeking prior src defined");
+ is(v.currentTime, -123, "currentTime is original seek time");
+
+ v.src = test.name;
+
+ // Initialize running variables.
+ v._name = test.name;
+ v._seekStarted = false;
+ v._seekCompleted = false;
+ v._metadata = false;
+
+ var events = [ "suspend", "play", "canplay", "canplaythrough", "loadstart",
+ "loadedmetadata", "loadeddata", "playing", "ended", "error",
+ "stalled", "emptied", "abort", "waiting", "pause" ];
+ function logEvent(e) {
+ var v = e.target;
+ Log(e.target.token, "got " + e.type + " with currentTime = " + v.currentTime);
+ }
+ events.forEach(function(e) {
+ v.addEventListener(e, logEvent, false);
+ });
+
+ once(v, "seeking", function() {
+ v._seekStarted = true;
+ ok(v.currentTime >= 0, "currentTime should be positive");
+ });
+ once(v, "seeked", function() {
+ v._seekCompleted = true;
+ ok(v.currentTime >= 0, "currentTime should be positive");
+ });
+ once(v, "loadedmetadata", function() {
+ v._metadata = true;
+ ok(v.seeking, "element is seeking once readyState is HAVE_METADATA");
+ ok(v.currentTime >= 0, "currentTime should be positive");
+ });
+ once(v, "ended", function() {
+ ok(v._seekStarted, "seek should have started");
+ ok(v._seekCompleted, "seek should have completed");
+ ok(v._metadata, "loadedmetadata fired");
+ ok(v.currentTime >= 0, "currentTime should be positive");
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+ });
+
+ v.play();
+}
+
+
+manager.runTests(gSmallTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seek_nosrc.html b/dom/media/test/test_seek_nosrc.html
new file mode 100644
index 000000000..8fc92b443
--- /dev/null
+++ b/dom/media/test/test_seek_nosrc.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seek tests</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var SEEK_TIME = 3.5;
+var seekStarted = false;
+var seekCompleted = false;
+var metadata = false;
+
+var v = document.createElement('video');
+document.body.appendChild(v);
+SimpleTest.registerCleanupFunction(function () {
+ v.remove();
+});
+
+try {
+ v.currentTime = SEEK_TIME;
+} catch (e) {
+ ok(false, "should not fire '" + e + "' event");
+}
+is(v.readyState, v.HAVE_NOTHING, "readyState is HAVE_NOTHING");
+ok(!v.seeking, "can't be seeking prior src defined");
+is(v.currentTime, SEEK_TIME, "currentTime is default playback start position");
+once(v, "seeking", function() {
+ seekStarted = true;
+});
+once(v, "seeked", function() {
+ seekCompleted = true;
+});
+once(v, "loadedmetadata", function() {
+ metadata = true;
+ ok(v.seeking, "element is seeking once readyState is HAVE_METADATA");
+});
+once(v, "ended", function() {
+ ok(seekStarted, "seek should have started");
+ ok(seekCompleted, "seek should have completed");
+ ok(metadata, "loadedmetadata fired");
+ ok(v.currentTime >= SEEK_TIME, "currentTime should be after seek time");
+ SimpleTest.finish();
+});
+
+v.src = "seek.webm";
+v.play();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seek_out_of_range.html b/dom/media/test/test_seek_out_of_range.html
new file mode 100644
index 000000000..210f6c3df
--- /dev/null
+++ b/dom/media/test/test_seek_out_of_range.html
@@ -0,0 +1,82 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: seeking off the end of a file</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+if (navigator.platform.startsWith("Win")) {
+ SimpleTest.expectAssertions(0, 10);
+}
+
+var manager = new MediaTestManager;
+
+// Test if the ended event works correctly.
+
+function startTest(e) {
+ var v = e.target;
+ checkMetadata(v._name, v, v._test);
+ is(v._loadedMetadata, false, "Should only receive one loadedmetadata event for " + v._name);
+ v._loadedMetadata = true;
+ v.currentTime = 3.0 * v.duration;
+}
+
+function playbackEnded(e) {
+ var v = e.target;
+ // We should have dispatched an ended event when we seeked to the end of
+ // media, but we want the ended event which dispatches once playback has
+ // completed after the seek to the beginning.
+ if (!v._played)
+ return;
+ ok(v.ended, "Checking ended set after seeking to EOF and playing for " + v._name);
+ ok(!v._finished, "Should only hit the end once for " + v._name);
+ v._finished = true;
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+}
+
+function endSeek(e) {
+ var v = e.target;
+ if (v._seeked)
+ return;
+ v._seeked = true;
+ ok(Math.abs(v.duration - v.currentTime) < 0.1,
+ "Should be at end of media for " + v._name + " t=" + v.currentTime + " d=" + v.duration);
+ v.play();
+}
+
+function playing(e) {
+ e.target._played = true;
+}
+
+function initTest(test, token) {
+ var type = getMajorMimeType(test.type);
+ var v = document.createElement(type);
+ v.preload = "auto";
+ v.token = token;
+ manager.started(token);
+ v.src = test.name;
+ v._name = test.name;
+ v._finished = false;
+ v._test = test;
+ v._loadedMetadata = false;
+ v._seeked = false;
+ v._played = false;
+ v.addEventListener("loadedmetadata", startTest, false);
+ v.addEventListener("playing", playing, false);
+ v.addEventListener("seeked", endSeek, false);
+ v.addEventListener("ended", playbackEnded, false);
+ document.body.appendChild(v);
+}
+
+manager.runTests(gSmallTests, initTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_seekable1.html b/dom/media/test/test_seekable1.html
new file mode 100644
index 000000000..f63e0a634
--- /dev/null
+++ b/dom/media/test/test_seekable1.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>Test seekable member for media elements</title>
+<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id='test'>
+<script class="testbody" type='application/javascript;version=1.8'>
+
+let manager = new MediaTestManager;
+
+function finish_test(element) {
+ if (element.parentNode)
+ element.parentNode.removeChild(element);
+ element.src="";
+ manager.finished(element.token);
+}
+
+var tests = [
+// Test using a finite media stream, and a server supporting range requests
+{
+setup : function(element) {
+ is(element.seekable.length, 0, "seekable.length should be initialy 0.");
+ element.addEventListener("loadedmetadata", function() {
+ is(element.seekable.length, 1, "seekable.length should be 1 for a server supporting range requests.");
+
+ is(element.seekable.start(0), 0.0, "The start of the first range should be the initialTime.");
+ is(element.seekable.end(0), element.duration, "The end of the first range should be the duration.")
+ finish_test(element);
+ }, false);
+ }
+}
+];
+
+function createTestArray() {
+ var A = [];
+ for (var k=0; k < gProgressTests.length; k++) {
+ var t = new Object();
+ t.setup = tests[0].setup;
+ t.name = gProgressTests[k].name;
+ t.type = gProgressTests[k].type;
+ A.push(t);
+ }
+ return A;
+}
+
+function startTest(test, token) {
+ var elemType = getMajorMimeType(test.type);
+ var element = document.createElement(elemType);
+ element.preload = "auto";
+ element.src = test.name;
+ element.token = token;
+ test.setup(element);
+ manager.started(token);
+}
+
+manager.runTests(createTestArray(), startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_source.html b/dom/media/test/test_source.html
new file mode 100644
index 000000000..f64c0a3f7
--- /dev/null
+++ b/dom/media/test/test_source.html
@@ -0,0 +1,92 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: append source child</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<video id="v1"></video>
+<audio id="a1"></audio>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var v1 = document.getElementById("v1");
+var a1 = document.getElementById("a1");
+v1.preload = "auto";
+a1.preload = "auto";
+
+is(v1.src, "", "src should be null");
+is(a1.src, "", "src should be null");
+is(v1.currentSrc, "", "currentSrc should be null");
+is(a1.currentSrc, "", "currentSrc should be null");
+is(v1.childNodes.length, 0, "should have no children");
+is(a1.childNodes.length, 0, "should have no children");
+
+function newSource(filter) {
+ var test = null;
+ var candidates = gSmallTests.filter(function(x){return filter.test(x.type);});
+ if (candidates.length > 0) {
+ var e = document.createElement("source");
+ e.type = candidates[0].type;
+ e.src = candidates[0].name;
+ return e;
+ } else {
+ return null
+ }
+}
+
+var audioLoaded = false;
+var videoLoaded = false;
+
+function loaded(e) {
+ var media = e.target;
+ ok(media.networkState > 0, "networkState should be > 0");
+ is(media.childNodes.length, 1, "should have 1 child");
+ var sourceFile = media.currentSrc.substring(media.currentSrc.lastIndexOf('/')+1);
+ var resource = media.firstChild.src.substring(media.firstChild.src.lastIndexOf('/')+1);
+ is(sourceFile, resource, "loaded wrong resource!");
+ if (media == a1)
+ audioLoaded = true;
+ else if (media == v1)
+ videoLoaded = true;
+ if (audioLoaded && videoLoaded) {
+ SimpleTest.finish();
+ }
+}
+
+v1.addEventListener('loadeddata', loaded, false);
+a1.addEventListener('loadeddata', loaded, false);
+
+var videoSource = newSource(/^video/);
+if (videoSource) {
+ v1.appendChild(videoSource);
+ v1.load();
+} else {
+ // No video backends? Don't test anything.
+ videoLoaded = true;
+}
+
+var audioSource = newSource(/^audio/);
+if (audioSource) {
+ a1.appendChild(audioSource);
+ a1.load();
+} else {
+ audioLoaded = true;
+}
+
+if (!audioLoaded && !videoLoaded) {
+ SimpleTest.waitForExplicitFinish();
+} else {
+ if (audioLoaded) {
+ todo(false, "No audio types supported");
+ }
+ if (videoLoaded) {
+ todo(false, "No video types supported");
+ }
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_source_media.html b/dom/media/test/test_source_media.html
new file mode 100644
index 000000000..0889ef050
--- /dev/null
+++ b/dom/media/test/test_source_media.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Media test: media attribute for the source element.</title>
+<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script type="text/javascript" src="manifest.js"></script>
+<script type="text/javascript" src="../../../dom/html/test/reflect.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="text/javascript">
+ var testCount = 0;
+ function notifyFinished() {
+ testCount++;
+ if (testCount == 2) {
+ SimpleTest.finish();
+ }
+ }
+
+ function clearNode(n) {
+ n.remove();
+ n.src = "";
+ while (n.firstChild) {
+ n.removeChild(n.firstChild);
+ }
+ }
+
+ SimpleTest.waitForExplicitFinish();
+
+ reflectString({
+ element: document.createElement("source"),
+ attribute: "media",
+ });
+
+ var media = getPlayableVideo(gSmallTests);
+
+ if (media == null) {
+ todo(false, "No media supported.");
+ SimpleTest.finish();
+ } else {
+ var v = document.createElement('video');
+ v.preload = "metadata";
+ v.innerHTML = "<source src=\"" + media.name + "?fail\" media=\"not all\">" +
+ "<source src=\""+ media.name + "?pass\" media=\"all\">";
+ var v2 = document.createElement("video");
+ v2.preload = "metadata";
+ v2.innerHTML = "<source src=\""+ media.name +"?pass\">" +
+ "<source src=\""+ media.name + "?fail\" media=\"all\">";
+ document.body.appendChild(v);
+ document.body.appendChild(v2);
+
+ v.addEventListener("loadedmetadata", function(e) {
+ ok(/pass/.test(e.target.currentSrc),
+ "The source has been chosen according to the media attribute.");
+ clearNode(e.target);
+ notifyFinished();
+ });
+ v2.addEventListener("loadedmetadata", function(e) {
+ ok(/pass/.test(e.target.currentSrc),
+ "If no media attribute is specified, it defaults to \'all\'.")
+ clearNode(e.target);
+ notifyFinished();
+ });
+ }
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_source_null.html b/dom/media/test/test_source_null.html
new file mode 100644
index 000000000..e6a536749
--- /dev/null
+++ b/dom/media/test/test_source_null.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=752087
+-->
+<head>
+ <title>Test for Bug 752087</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=752087">Mozilla Bug 752087</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+
+<video id="v">
+<script>
+var v = document.getElementById('v');
+v.src = null; // crashes on NULL access if not handled
+
+ok(true, "setting video.src to null didn't crash!");
+</script>
+</video>
+</body>
+</html>
diff --git a/dom/media/test/test_source_write.html b/dom/media/test/test_source_write.html
new file mode 100644
index 000000000..6c55f8fdd
--- /dev/null
+++ b/dom/media/test/test_source_write.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=462455
+-->
+<head>
+ <title>Test for Bug 462455</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=462455">Mozilla Bug 462455</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+
+<video id="v">
+<script>
+var loadStarted = false;
+document.write('Pause parsing!');
+var v = document.getElementById('v');
+
+var resource = getPlayableVideo(gSmallTests);
+if (resource != null) {
+ var s = document.createElement("source");
+ s.src = resource.name;
+ s.type = resource.type;
+ v.appendChild(s);
+}
+
+ok(v.networkState == HTMLMediaElement.NETWORK_NO_SOURCE,
+ "We shouldn't start network load until the current task returns.");
+</script>
+</video>
+</body>
+</html>
diff --git a/dom/media/test/test_standalone.html b/dom/media/test/test_standalone.html
new file mode 100644
index 000000000..65733a19f
--- /dev/null
+++ b/dom/media/test/test_standalone.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: standalone video documents</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body onload="doTest()">
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var iframes = [];
+
+for (var i=0; i<gSmallTests.length; ++i) {
+ var test = gSmallTests[i];
+
+ // We can't play WAV files in stand alone documents, so just don't
+ // run the test on non-video content types.
+ var tag = getMajorMimeType(test.type);
+ if (tag != "video" || !document.createElement("video").canPlayType(test.type))
+ continue;
+
+ var f = document.createElement("iframe");
+ f.src = test.name;
+ f._test = test;
+ f.id = "frame" + i;
+ iframes.push(f);
+ document.body.appendChild(f);
+}
+
+
+function filename(uri) {
+ return uri.substr(uri.lastIndexOf("/")+1);
+}
+
+function doTest()
+{
+ for (var i=0; i<iframes.length; ++i) {
+ var f = document.getElementById(iframes[i].id);
+ var v = f.contentDocument.body.firstChild;
+ is(v.tagName.toLowerCase(), "video", "Is video element");
+ var src = filename(v.currentSrc);
+ is(src, iframes[i]._test.name, "Name ("+src+") should match ("+iframes[i]._test.name+")");
+ is(v.controls, true, "Controls set (" + src + ")");
+ is(v.autoplay, true, "Autoplay set (" + src + ")");
+ }
+ SimpleTest.finish();
+}
+
+if (iframes.length == 0) {
+ todo(false, "No types supported");
+} else {
+ SimpleTest.waitForExplicitFinish();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_streams_autoplay.html b/dom/media/test/test_streams_autoplay.html
new file mode 100644
index 000000000..75f0579e6
--- /dev/null
+++ b/dom/media/test/test_streams_autoplay.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test that a MediaStream source triggers autoplay</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var media = getPlayableVideo(gSmallTests);
+
+if (media == null) {
+ todo(false, "No media supported.");
+ SimpleTest.finish();
+} else {
+ function startTest() {
+ var v1 = document.createElement('video');
+ var v2 = document.createElement('video');
+ v1.preload = 'metadata';
+ v2.autoplay = true;
+ document.body.appendChild(v1);
+ document.body.appendChild(v2);
+
+ v1.src = media.name;
+ v1.onloadedmetadata = function() {
+ v2.srcObject = v1.mozCaptureStream();
+ v1.play();
+ };
+
+ v2.addEventListener('playing', function() {
+ ok(true, "playback started");
+ SimpleTest.finish();
+ }, {once: true});
+ }
+
+ startTest();
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_streams_capture_origin.html b/dom/media/test/test_streams_capture_origin.html
new file mode 100644
index 000000000..916163e9c
--- /dev/null
+++ b/dom/media/test/test_streams_capture_origin.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 1189506</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1189506">Mozilla Bug 1189506</a>
+<p id="display"></p>
+<video id="vin"></video>
+<video id="vout" style="position:absolute; top:0; left:0"></video>
+<canvas id="c"></canvas>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 1189506 **/
+
+SimpleTest.waitForExplicitFinish();
+
+var resource = getPlayableVideo(gSmallTests).name;
+
+vin.src = "http://example.org:8000/tests/dom/media/test/" + resource;
+vin.preload = "metadata";
+
+vin.onloadedmetadata = function () {
+ vout.srcObject = vin.mozCaptureStreamUntilEnded();
+ vin.play();
+ vout.play();
+};
+
+vout.onended = function() {
+ var ctx = SpecialPowers.wrap(c.getContext("2d"));
+ ctx.drawWindow(window, 0, 0, 10, 10, "rgb(255, 255, 0)", 0);
+ var data = ctx.getImageData(2, 2, 1, 1);
+ // Captured cross-origin video streams should render entirely black.
+ is(data.data.join(','), "0,0,0,255", "expected black");
+ vout.style.position = "";
+ SimpleTest.finish();
+};
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_streams_element_capture.html b/dom/media/test/test_streams_element_capture.html
new file mode 100644
index 000000000..5e30a3ce4
--- /dev/null
+++ b/dom/media/test/test_streams_element_capture.html
@@ -0,0 +1,98 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test that a MediaStream captured from one element plays back in another</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+// longer timeout for slow platforms
+if (isSlowPlatform()) {
+ SimpleTest.requestLongerTimeout(3);
+ SimpleTest.requestCompleteLog();
+}
+
+function checkDrawImage(vout) {
+ var canvas = document.createElement("canvas");
+ var ctx = canvas.getContext("2d");
+ ctx.drawImage(vout, 0, 0);
+ var imgData = ctx.getImageData(0, 0, 1, 1);
+ is(imgData.data[3], 255, "Check video frame pixel has been drawn");
+}
+
+function isGreaterThanOrEqualEps(a, b, msg) {
+ ok(a >= b - 0.01,
+ "Got " + a + ", expected at least " + b + "; " + msg);
+}
+
+function startTest(test) {
+ var v = document.createElement('video');
+ var vout = document.createElement('video');
+
+ v.src = test.name;
+ var stream;
+
+ var checkEnded = function() {
+ is(stream.currentTime, vout.currentTime, test.name + " stream final currentTime");
+ if (test.duration) {
+ isGreaterThanOrEqualEps(vout.currentTime, test.duration,
+ test.name + " current time at end");
+ }
+ is(vout.readyState, vout.HAVE_CURRENT_DATA, test.name + " checking readyState");
+ ok(vout.ended, test.name + " checking playback has ended");
+ if (test.type.match(/^video/)) {
+ checkDrawImage(vout);
+ }
+ vout.parentNode.removeChild(vout);
+ removeNodeAndSource(v);
+ SimpleTest.finish();
+ };
+ vout.addEventListener("ended", checkEnded, false);
+
+ document.body.appendChild(vout);
+
+ var onloadedmetadata = function (ev) {
+ stream = v.mozCaptureStreamUntilEnded();
+ is(stream.currentTime, 0, test.name + " stream initial currentTime");
+ vout.srcObject = stream;
+ is(vout.srcObject, stream, test.name + " set output element .srcObject correctly");
+ v.play();
+ vout.play();
+ }
+
+ v.preload = 'metadata';
+ v.addEventListener('loadedmetadata', onloadedmetadata, false);
+
+ // Log events for debugging.
+ var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
+ "loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
+ "waiting", "pause"];
+ function logEvent(e) {
+ Log(e.target.name, "got " + e.type);
+ }
+ events.forEach(function(e) {
+ v.addEventListener(e, logEvent, false);
+ vout.addEventListener(e, logEvent, false);
+ });
+
+}
+
+// We only test one playable video because for some of the audio files
+// --- small-shot.mp3.mp4 and small-shot.m4a --- GStreamer doesn't decode
+// as much data as indicated by the duration, causing this test to fail on
+// Linux. See bug 1084185.
+var testVideo = getPlayableVideo(gSmallTests);
+if (testVideo) {
+ startTest(testVideo);
+} else {
+ todo(false, "No playable video");
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_streams_element_capture_createObjectURL.html b/dom/media/test/test_streams_element_capture_createObjectURL.html
new file mode 100644
index 000000000..d5d7efc5c
--- /dev/null
+++ b/dom/media/test/test_streams_element_capture_createObjectURL.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test that a MediaStream captured from one element plays back in another</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var manager = new MediaTestManager;
+
+function checkDrawImage(vout) {
+ var canvas = document.createElement("canvas");
+ var ctx = canvas.getContext("2d");
+ ctx.drawImage(vout, 0, 0);
+ var imgData = ctx.getImageData(0, 0, 1, 1);
+ is(imgData.data[3], 255, "Check video frame pixel has been drawn");
+}
+
+function isGreaterThanOrEqualEps(a, b, msg) {
+ ok(a >= b - 0.01,
+ "Got " + a + ", expected at least " + b + "; " + msg);
+}
+
+function startTest(test, token) {
+ manager.started(token);
+
+ var v = document.createElement('video');
+ var vout = document.createElement('video');
+ vout.token = token;
+
+ v.src = test.name;
+ v.preload = "metadata"
+ var stream;
+
+ var checkEnded = function() {
+ is(stream.currentTime, vout.currentTime, test.name + " stream final currentTime");
+ if (test.duration) {
+ isGreaterThanOrEqualEps(vout.currentTime, test.duration,
+ test.name + " current time at end");
+ }
+ is(vout.readyState, vout.HAVE_CURRENT_DATA, test.name + " checking readyState");
+ ok(vout.ended, test.name + " checking playback has ended");
+ if (test.type.match(/^video/)) {
+ checkDrawImage(vout);
+ }
+ vout.parentNode.removeChild(vout);
+ URL.revokeObjectURL(vout.src);
+ manager.finished(vout.token);
+ };
+ vout.addEventListener("ended", checkEnded, false);
+
+ document.body.appendChild(vout);
+ v.onloadedmetadata = function () {
+ stream = v.mozCaptureStreamUntilEnded();
+ is(stream.currentTime, 0, test.name + " stream initial currentTime");
+ vout.src = URL.createObjectURL(stream);
+ v.play();
+ vout.play();
+ };
+}
+
+manager.runTests([getPlayableVideo(gSmallTests)], startTest);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_streams_element_capture_playback.html b/dom/media/test/test_streams_element_capture_playback.html
new file mode 100644
index 000000000..a49c38735
--- /dev/null
+++ b/dom/media/test/test_streams_element_capture_playback.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test that capturing a stream doesn't stop the underlying element from firing events</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<audio id="a"></audio>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var a = document.getElementById('a');
+var validTimeUpdate = false;
+
+function startTest() {
+ a.src = "big.wav";
+ var context = new AudioContext();
+ var node = context.createMediaElementSource(a);
+ node.connect(context.destination);
+ a.addEventListener("timeupdate", function() {
+ if (a.currentTime > 0.0 && a.currentTime < 5.0 && !validTimeUpdate) {
+ validTimeUpdate = true;
+ ok(true, "Received reasonable currentTime in a timeupdate");
+ SimpleTest.finish();
+ }
+ });
+ a.addEventListener("ended", function() {
+ if (!validTimeUpdate) {
+ ok(false, "Received reasonable currentTime in a timeupdate");
+ SimpleTest.finish();
+ }
+ });
+ a.play();
+}
+
+if (a.canPlayType("audio/wave")) {
+ startTest();
+} else {
+ todo(false, "No playable audio");
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_streams_element_capture_reset.html b/dom/media/test/test_streams_element_capture_reset.html
new file mode 100644
index 000000000..888c3bec9
--- /dev/null
+++ b/dom/media/test/test_streams_element_capture_reset.html
@@ -0,0 +1,134 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test that reloading and seeking in a media element that's being captured doesn't crash</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<video id="v"></video>
+<video id="vout"></video>
+<video id="vout_untilended"></video>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var v = document.getElementById('v');
+var vout = document.getElementById('vout');
+var vout_untilended = document.getElementById('vout_untilended');
+
+function dumpEvent(event) {
+ var v = event.target;
+ info(v.name + " GOT EVENT " + event.type +
+ " currentTime=" + v.currentTime +
+ " paused=" + v.paused +
+ " ended=" + v.ended +
+ " readyState=" + v.readyState);
+}
+
+var events = ["timeupdate", "seeking", "seeked", "ended", "playing", "pause"];
+for (var i = 0; i < events.length; ++i) {
+ v.addEventListener(events[i], dumpEvent, false);
+}
+
+function isWithinEps(a, b, msg) {
+ ok(Math.abs(a - b) < 0.01,
+ "Got " + a + ", expected " + b + "; " + msg);
+}
+
+function isGreaterThanOrEqualEps(a, b, msg) {
+ ok(a >= b - 0.01,
+ "Got " + a + ", expected at least " + b + "; " + msg);
+}
+
+function startTest(test) {
+ var seekTime = test.duration/2;
+
+ function endedAfterReplay() {
+ isGreaterThanOrEqualEps(v.currentTime, test.duration, "checking v.currentTime at third 'ended' event");
+ isGreaterThanOrEqualEps(vout.currentTime, (test.duration - seekTime) + test.duration*2,
+ "checking vout.currentTime after seeking, playing through and reloading");
+ SimpleTest.finish();
+ };
+
+ function endedAfterSeek() {
+ isGreaterThanOrEqualEps(v.currentTime, test.duration, "checking v.currentTime at second 'ended' event");
+ isGreaterThanOrEqualEps(vout.currentTime, (test.duration - seekTime) + test.duration,
+ "checking vout.currentTime after seeking and playing through again");
+ v.removeEventListener("ended", endedAfterSeek, false);
+ v.addEventListener("ended", endedAfterReplay, false);
+ v.src = test.name + "?1";
+ v.play();
+ };
+
+ function seeked() {
+ isGreaterThanOrEqualEps(v.currentTime, seekTime, "Finished seeking");
+ isGreaterThanOrEqualEps(vout.currentTime, test.duration,
+ "checking vout.currentTime has not changed after seeking");
+ v.removeEventListener("seeked", seeked, false);
+ function dontPlayAgain() {
+ ok(false, "vout_untilended should not play again");
+ }
+ vout_untilended.addEventListener("playing", dontPlayAgain, false);
+ vout_untilended.addEventListener("ended", dontPlayAgain, false);
+ v.addEventListener("ended", endedAfterSeek, false);
+ v.play();
+ };
+
+ function ended() {
+ // Don't compare current time until both v and vout_untilended are ended,
+ // otherwise, current time could be smaller than the duration.
+ if (!v.ended || !vout_untilended.ended) {
+ return;
+ }
+
+ isGreaterThanOrEqualEps(vout.currentTime, test.duration, "checking vout.currentTime at first 'ended' event");
+ isGreaterThanOrEqualEps(v.currentTime, test.duration, "checking v.currentTime at first 'ended' event");
+ is(vout.ended, false, "checking vout has not ended");
+ is(vout_untilended.ended, true, "checking vout_untilended has actually ended");
+
+ v.removeEventListener("ended", ended, false);
+ vout_untilended.removeEventListener("ended", ended, false);
+
+ v.pause();
+ v.currentTime = seekTime;
+ v.addEventListener("seeked", seeked, false);
+ };
+
+ v.addEventListener("ended", ended, false);
+ vout_untilended.addEventListener("ended", ended, false);
+
+ function checkNoEnded() {
+ ok(false, "ended event received unexpectedly");
+ };
+
+ vout.addEventListener("ended", checkNoEnded, false);
+
+ v.src = test.name;
+ v.name = test.name;
+ v.preload = "metadata";
+
+ function loadedmetadata() {
+ vout.srcObject = v.mozCaptureStream();
+ vout.play();
+
+ vout_untilended.srcObject = v.mozCaptureStreamUntilEnded();
+ vout_untilended.play();
+
+ v.play();
+ };
+
+ v.addEventListener("loadedmetadata", loadedmetadata, {once: true});
+}
+
+var testVideo = getPlayableVideo(gSmallTests);
+if (testVideo) {
+ startTest(testVideo);
+} else {
+ todo(false, "No playable video");
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_streams_gc.html b/dom/media/test/test_streams_gc.html
new file mode 100644
index 000000000..e7a356099
--- /dev/null
+++ b/dom/media/test/test_streams_gc.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test garbage collection of captured stream (bug 806754)</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body onload="doTest()">
+<audio id="a" preload="metadata"></audio>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var a = document.getElementById('a');
+a.src = getPlayableAudio(gSmallTests).name;
+
+function forceGC() {
+ SpecialPowers.gc();
+ SpecialPowers.forceGC();
+ SpecialPowers.forceCC();
+}
+
+function doTest() {
+ a.mozCaptureStreamUntilEnded();
+
+ a.addEventListener("seeked", function() {
+ a.play();
+
+ a.addEventListener("play", function() {
+ a.addEventListener("ended", function() {
+ ok(true, "GC completed OK");
+ SimpleTest.finish();
+ }, false);
+ }, false);
+ }, false);
+
+ a.currentTime = a.duration;
+ setTimeout(forceGC, 0);
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_streams_individual_pause.html b/dom/media/test/test_streams_individual_pause.html
new file mode 100644
index 000000000..a6abc65ff
--- /dev/null
+++ b/dom/media/test/test_streams_individual_pause.html
@@ -0,0 +1,79 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for bug 1073406. Pausing a video element should not pause another playing the same stream.</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<video id="video1" autoplay></video>
+<video id="video2" autoplay></video>
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var getVideoImagePixelData = function(v) {
+ var canvas = document.createElement("canvas");
+ var ctx = canvas.getContext("2d");
+ ctx.drawImage(v, 0, 0);
+ var imgData = ctx.getImageData(canvas.width/2, canvas.height/2, 1, 1).data;
+ return "r" + imgData[0] +
+ "g" + imgData[1] +
+ "b" + imgData[2] +
+ "a" + imgData[3];
+}
+
+// This test does not appear to work with the "Dummy video source" provided on
+// linux through the "media.video_loopback_dev" pref in the tree test environment.
+// We force a stream always by requesting `fake: true` here.
+
+navigator.mozGetUserMedia({video: true, fake: true },
+ function(stream) {
+ var stream = stream;
+ var video1 = document.getElementById('video1');
+ var video2 = document.getElementById('video2');
+
+ var src = URL.createObjectURL(stream);
+ video1.src = src;
+ video2.src = src;
+
+ video1.onplaying = () => video1.pause();
+
+ var v1PausedImageData;
+ var v2PausedImageData;
+
+ video1.onpause = function() {
+ v1PausedImageData = getVideoImagePixelData(video1);
+ v2PausedImageData = getVideoImagePixelData(video2);
+ v2TimesToTest = 3;
+ video2.ontimeupdate = function() {
+ if (getVideoImagePixelData(video2) === v2PausedImageData) {
+ // Wait until video2 has progressed it's video.
+ // If it doesn't, we'll time out and fail.
+ info("video2 has not progressed. Waiting.");
+ return;
+ }
+
+ if (--v2TimesToTest > 0) {
+ // Wait for a while to be sure video1 would have gotten a frame
+ // if it is playing.
+ info("video2 progressed OK");
+ return;
+ }
+
+ video2.ontimeupdate = null;
+ ok(true, "video2 is playing");
+ isnot(video1.currentTime, video2.currentTime,
+ "v1 and v2 should not be at the same currentTime");
+ is(v1PausedImageData, getVideoImagePixelData(video1),
+ "video1 video frame should not have updated since video1 paused");
+ SimpleTest.finish();
+ };
+ };
+}, function(error) {
+ ok(false, "getUserMedia should not fail, got " + error.name);
+ SimpleTest.finish();
+});
+</script>
+</body>
+</html>
diff --git a/dom/media/test/test_streams_srcObject.html b/dom/media/test/test_streams_srcObject.html
new file mode 100644
index 000000000..a5a4205cd
--- /dev/null
+++ b/dom/media/test/test_streams_srcObject.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test interactions of src and srcObject</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body onload="doTests()">
+<audio id="a1"></audio>
+<audio id="a2"></audio>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var doTest = srcObject => new Promise(resolve => {
+ var a = document.getElementById('a1');
+ a.src = getPlayableAudio(gSmallTests).name;
+ var b = new Audio();
+
+ var newSrc = a.src + "?2";
+ b.src = newSrc;
+ is(b[srcObject], null, "Initial srcObject is null");
+ var stream = a.mozCaptureStream();
+ b[srcObject] = stream;
+ is(b[srcObject], stream, "Stream set correctly");
+ try {
+ b[srcObject] = "invalid";
+ ok(false, "Setting srcObject to an invalid value should throw.");
+ } catch (e) {
+ ok(e instanceof TypeError, "Exception should be a TypeError");
+ }
+ is(b[srcObject], stream, "Stream not set to invalid value");
+ is(b.src, newSrc, "src attribute not affected by setting srcObject");
+ var step = 0;
+ b.addEventListener("loadedmetadata", function() {
+ if (step == 0) {
+ is(b.currentSrc, "", "currentSrc set to empty string while playing srcObject");
+ b[srcObject] = null;
+ is(b[srcObject], null, "Stream set to null");
+ // The resource selection algorithm will run again and choose b.src
+ } else if (step == 1) {
+ is(b.currentSrc, b.src, "currentSrc set to src now that srcObject is null");
+ resolve();
+ }
+ ++step;
+ });
+ a.play();
+ b.play();
+});
+
+// TODO: remove prefixed version soon (1183495).
+
+var doTests = () => doTest("srcObject").then(() => doTest("mozSrcObject"))
+ .catch(e => ok(false, "Unexpected error: " + e))
+ .then(() => SimpleTest.finish())
+ .catch(e => ok(false, "Coding error: " + e));
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_streams_tracks.html b/dom/media/test/test_streams_tracks.html
new file mode 100644
index 000000000..4157f25d5
--- /dev/null
+++ b/dom/media/test/test_streams_tracks.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaStreamTrack interfaces</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+function testTracks(tracks, hasTrack, kind, src) {
+ is(tracks.length, hasTrack ? 1 : 0, "Correct track count for " + src);
+ for (var i = 0; i < tracks.length; ++i) {
+ var track = tracks[i];
+ is(track.kind, kind, "Correct track kind for track " + i + " of " + src);
+ var id = track.id;
+ ok(/\{........-....-....-....-............\}/.test(track.id),
+ "id " + track.id + " for track " + i + " of " + src + " has correct form");
+ }
+}
+
+function onended(e) {
+ var t = e.target;
+ var audioTracks = t.stream.getAudioTracks();
+ var videoTracks = t.stream.getVideoTracks();
+
+ testTracks(audioTracks, t.test.hasAudio, "audio", t.src);
+ testTracks(videoTracks, t.test.hasVideo, "video", t.src);
+
+ manager.finished(t.token);
+}
+
+function startTest(test, token) {
+ var element = document.createElement("video");
+
+ element.token = token;
+ manager.started(token);
+
+ element.src = test.name;
+ element.test = test;
+ element.stream = element.mozCaptureStreamUntilEnded();
+ element.addEventListener("ended", onended, false);
+
+ element.play();
+}
+
+manager.runTests(gTrackTests, startTest);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_temporary_file_blob_video_plays.html b/dom/media/test/test_temporary_file_blob_video_plays.html
new file mode 100644
index 000000000..c1c1867e7
--- /dev/null
+++ b/dom/media/test/test_temporary_file_blob_video_plays.html
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test MediaRecorder Recording canvas stream</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/dom/canvas/test/captureStream_common.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<div id="content">
+</div>
+<script class="testbody" type="text/javascript">
+
+function startTest() {
+ var canvas = document.createElement("canvas");
+ canvas.width = canvas.height = 100;
+ document.getElementById("content").appendChild(canvas);
+
+ var helper = new CaptureStreamTestHelper2D(100, 100);
+ helper.drawColor(canvas, helper.red);
+
+ var stream = canvas.captureStream(0);
+
+ var blob;
+
+ mediaRecorder = new MediaRecorder(stream);
+ is(mediaRecorder.stream, stream,
+ "Media recorder stream = canvas stream at the start of recording");
+
+ mediaRecorder.onwarning = () => ok(false, "warning unexpectedly fired");
+
+ mediaRecorder.onerror = () => ok(false, "Recording failed");
+
+ mediaRecorder.ondataavailable = ev => {
+ is(blob, undefined, "Should only get one dataavailable event");
+ blob = ev.data;
+ };
+
+ mediaRecorder.onstart = () => {
+ info("Got 'start' event");
+ // We just want one frame encoded, to see that the recorder produces something readable.
+ mediaRecorder.stop();
+ };
+
+ mediaRecorder.onstop = () => {
+ info("Got 'stop' event");
+ ok(blob, "Should have gotten a data blob");
+
+ var video = document.createElement("video");
+ video.id = "recorded-video";
+ video.src = URL.createObjectURL(blob);
+ video.play();
+ video.onerror = err => {
+ ok(false, "Should be able to play the recording. Got error. code=" + video.error.code);
+ SimpleTest.finish();
+ };
+ document.getElementById("content").appendChild(video);
+ helper.waitForPixelColor(video, helper.red, 128, "Should become red")
+ .then(SimpleTest.finish);
+ };
+
+ mediaRecorder.start();
+ is(mediaRecorder.state, "recording", "Media recorder should be recording");
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({set:[["media.recorder.max_memory", 1]]}, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_texttrack.html b/dom/media/test/test_texttrack.html
new file mode 100644
index 000000000..f40552c6d
--- /dev/null
+++ b/dom/media/test/test_texttrack.html
@@ -0,0 +1,126 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=833386
+-->
+<head>
+ <meta charset='utf-8'>
+ <title>Test for Bug 833386 - TextTrackList</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [["media.webvtt.regions.enabled", true]]},
+ function() {
+ var video = document.createElement("video");
+
+ isnot(video.textTracks, undefined, "HTMLMediaElement::TextTrack() property should be available.")
+
+ var trackList = video.textTracks;
+ is(trackList.length, 0, "Length should be 0.");
+
+ ok(typeof video.addTextTrack == "function", "HTMLMediaElement::AddTextTrack() function should be available.")
+ video.addTextTrack("subtitles", "third", "en-CA");
+ is(trackList.length, 1, "Length should be 1.");
+
+ var textTrack = video.textTracks[0];
+ is(textTrack.label, "third", "Label should be set to third.");
+ is(textTrack.language, "en-CA", "Language should be en-CA.");
+ is(textTrack.kind, "subtitles", "Default kind should be subtitles.");
+ is(textTrack.mode, "hidden", "Default mode should be hidden.");
+
+ // Mode should not allow a bogus value.
+ textTrack.mode = 'bogus';
+ is(textTrack.mode, 'hidden', "Mode should be not allow a bogus value.");
+
+ // Should allow all these values for mode.
+ checkMode("showing", "Mode should allow \"showing\"");
+ checkMode("disabled", "Mode should allow \"disabled\"");
+ checkMode("hidden", "Mode should allow \"hidden\"");
+
+ // All below are read-only properties and so should not allow setting.
+ textTrack.label = "French subtitles";
+ is(textTrack.label, "third", "Label is read-only so should still be \"label\".");
+
+ textTrack.language = "en";
+ is(textTrack.language, "en-CA", "Language is read-only so should still be \"en-CA\".");
+
+ textTrack.kind = "captions";
+ is(textTrack.kind, "subtitles", "Kind is read-only so should still be \"subtitles\"");
+
+ function checkMode(value, message) {
+ textTrack.mode = value;
+ is(textTrack.mode, value, message);
+ }
+
+ // Insert some tracks in an order that is not sorted, we will test if they
+ // are sorted later.
+ var trackOne = document.createElement("track");
+ trackOne.label = "first";
+ trackOne.src = "basic.vtt";
+ trackOne.default = true;
+ trackOne.id = "2";
+ video.appendChild(trackOne);
+
+ video.addTextTrack("subtitles", "fourth", "en-CA");
+
+ var trackTwo = document.createElement("track");
+ trackTwo.label = "second";
+ trackTwo.src = "basic.vtt";
+ trackTwo.default = true;
+ video.appendChild(trackTwo);
+
+ video.src = "seek.webm";
+ video.preload = "metadata";
+
+ document.getElementById("content").appendChild(video);
+
+ video.addEventListener("loadedmetadata", function run_tests() {
+ // Re-que run_tests() at the end of the event loop until the track
+ // element has loaded its data.
+ if (trackOne.readyState == 1 || trackTwo.readyState == 1) {
+ setTimeout(run_tests, 0);
+ return;
+ }
+ is(trackOne.readyState, 2, "First Track::ReadyState should be set to LOADED.");
+ is(trackTwo.readyState, 2, "Second Track::ReadyState should be set to LOADED.");
+
+ // We're testing two things here, firstly that tracks created from a track
+ // element have a default mode 'disabled' and tracks created with the
+ // 'addTextTrack' method have a default mode of 'hidden'.
+ // Secondly we're testing that the tracks are sorted properly.
+ // For the tracks to be sorted the first two tracks, added through a
+ // TrackElement, must occupy the first two indexes in their TrackElement
+ // tree order. The second two tracks, added through the 'addTextTrack'
+ // method, will occupy the last two indexes in the order that they were
+ // added in.
+ var trackData = [
+ { label: "first", mode: "showing", id: "2" },
+ { label: "second", mode: "disabled", id: "" },
+ { label: "third", mode: "hidden", id: "" },
+ { label: "fourth", mode: "hidden", id: "" }
+ ];
+ is(video.textTracks.length, trackData.length, "TextTracks length should be " + trackData.length);
+ for (var i = 0; i < trackData.length; i++) {
+ var track = video.textTracks[i];
+ isnot(track, null, "Video should have a text track at index " + i);
+ var info = trackData[i];
+ for (var key in info) {
+ is(track[key], info[key], "Track at index " + i + " should have a '" + key + "'' property " +
+ "with a value of '" + info[key] + "'.");
+ }
+ }
+ SimpleTest.finish();
+ });
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_texttrack_moz.html b/dom/media/test/test_texttrack_moz.html
new file mode 100644
index 000000000..0b319746a
--- /dev/null
+++ b/dom/media/test/test_texttrack_moz.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=881976
+-->
+<head>
+ <meta charset='utf-8'>
+ <title>Test for Bug 881976 - TextTrackCue Computed Position</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+ SpecialPowers.pushPrefEnv({"set": [["media.webvtt.regions.enabled", true]]},
+ function() {
+ var video = document.createElement("video");
+
+ // Check if adding a text track manually sets the TextTrackList correctly.
+
+ // HTMLTrackElement.textTrackList is an extension available only to
+ // privileged code, so we need to access it through the SpecialPowers
+ // object.
+ video.addTextTrack("subtitles", "", "");
+ is(SpecialPowers.unwrap(SpecialPowers.wrap(video.textTracks[0]).textTrackList),
+ video.textTracks,
+ "The Track's TextTrackList should be the Video's TextTrackList.");
+
+
+ // Check if loading a Track via a TrackElement sets the TextTrackList correctly.
+ video.src = "seek.webm";
+ video.preload = "auto";
+
+ var trackElement = document.createElement("track");
+ trackElement.src = "basic.vtt";
+ trackElement.kind = "subtitles";
+
+ video.appendChild(trackElement);
+ document.getElementById("content").appendChild(video);
+
+ video.addEventListener("loadedmetadata", function run_tests() {
+ // Re-que run_tests() at the end of the event loop until the track
+ // element has loaded its data.
+ if (trackElement.readyState == HTMLTrackElement.LOADING) {
+ setTimeout(run_tests, 0);
+ return;
+ }
+ is(trackElement.readyState, HTMLTrackElement.LOADED,
+ "Track::ReadyState should be set to LOADED.");
+ is(SpecialPowers.unwrap(SpecialPowers.wrap(trackElement.track).textTrackList),
+ video.textTracks,
+ "TrackElement's Track's TextTrackList should be the Video's TextTrackList.");
+
+ SimpleTest.finish();
+ });
+ }
+ );
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_texttrackcue.html b/dom/media/test/test_texttrackcue.html
new file mode 100644
index 000000000..bfb109ea6
--- /dev/null
+++ b/dom/media/test/test_texttrackcue.html
@@ -0,0 +1,269 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=833386
+-->
+<head>
+ <meta charset='utf-8'>
+ <title>Test for Bug 833386 - HTMLTrackElement</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [["media.webvtt.regions.enabled", true]]},
+ function() {
+ var video = document.createElement("video");
+ video.src = "seek.webm";
+ video.preload = "metadata";
+
+ var trackElement = document.createElement("track");
+ trackElement.src = "basic.vtt";
+ trackElement.kind = "subtitles";
+
+ document.getElementById("content").appendChild(video);
+ video.appendChild(trackElement);
+ video.addEventListener("loadedmetadata", function run_tests() {
+ // Re-que run_tests() at the end of the event loop until the track
+ // element has loaded its data.
+ if (trackElement.readyState == 1) {
+ setTimeout(run_tests, 0);
+ return;
+ }
+
+ is(trackElement.readyState, 2, "Track::ReadyState should be set to LOADED.");
+ // Set mode to hidden so that the active cue lists are being updated.
+ trackElement.track.mode = "hidden";
+
+ var cueList = trackElement.track.cues;
+ is(cueList.length, 6, "Cue list length should be 6.");
+
+ // Check that the typedef of TextTrackCue works in Gecko.
+ isnot(window.TextTrackCue, undefined, "TextTrackCue should be defined.");
+ isnot(window.VTTCue, undefined, "VTTCue should be defined.");
+
+ // Check if first cue was parsed correctly.
+ var cue = cueList[0];
+ ok(cue instanceof TextTrackCue, "Cue should be an instanceof TextTrackCue.");
+ ok(cue instanceof VTTCue, "Cue should be an instanceof VTTCue.");
+ is(cue.id, "1", "Cue's ID should be 1.");
+ is(cue.startTime, 0.5, "Cue's start time should be 0.5.");
+ is(cue.endTime, 0.7, "Cue's end time should be 0.7.");
+ is(cue.pauseOnExit, false, "Cue's pause on exit flag should be false.");
+ is(cue.text, "This", "Cue's text should be set correctly.");
+ is(cue.track, trackElement.track, "Cue's track should be defined.");
+
+ cue.track = null;
+ isnot(cue.track, null, "Cue's track should not be able to be set.");
+
+ // Check that all cue times were not rounded
+ is(cueList[1].startTime, 1.2, "Second cue's start time should be 1.2.");
+ is(cueList[1].endTime, 2.4, "Second cue's end time should be 2.4.");
+ is(cueList[2].startTime, 2, "Third cue's start time should be 2.");
+ is(cueList[2].endTime, 3.5, "Third cue's end time should be 3.5.");
+ is(cueList[3].startTime, 2.71, "Fourth cue's start time should be 2.71.");
+ is(cueList[3].endTime, 2.91, "Fourth cue's end time should be 2.91.");
+ is(cueList[4].startTime, 3.217, "Fifth cue's start time should be 3.217.");
+ is(cueList[4].endTime, 3.989, "Fifth cue's end time should be 3.989.");
+ is(cueList[5].startTime, 3.217, "Sixth cue's start time should be 3.217.");
+ is(cueList[5].endTime, 3.989, "Sixth cue's end time should be 3.989.");
+
+ // Check that Cue setters are working correctly.
+ cue.id = "Cue 01";
+ is(cue.id, "Cue 01", "Cue's ID should be 'Cue 01'.");
+ cue.startTime = 0.51;
+ is(cue.startTime, 0.51, "Cue's start time should be 0.51.");
+ cue.endTime = 0.71;
+ is(cue.endTime, 0.71, "Cue's end time should be 0.71.");
+ cue.pauseOnExit = true;
+ is(cue.pauseOnExit, true, "Cue's pause on exit flag should be true.");
+ video.addEventListener("pause", function pauseOnExit() {
+ video.removeEventListener("pause", pauseOnExit, false);
+ video.play();
+ });
+
+ var exceptionHappened;
+ function checkPercentageValue(prop, initialVal) {
+ ok(prop in cue, prop + " should be a property on VTTCue.");
+ cue[prop] = initialVal;
+ is(cue[prop], initialVal, "Cue's " + prop + " should initially be " + initialVal);
+ [ 101, -1 ].forEach(function(val) {
+ exceptionHappened = false;
+ try {
+ cue[prop] = val;
+ } catch(e) {
+ exceptionHappened = true;
+ is(e.name, "IndexSizeError", "Should have thrown IndexSizeError.");
+ }
+ ok(exceptionHappened, "Exception should have happened.");
+ });
+ }
+
+ checkPercentageValue("size", 100.0);
+ cue.size = 50.5;
+ is(cue.size, 50.5, "Cue's size should be 50.5.")
+
+ // Check cue.position
+ checkPercentageValue("position", "auto");
+ cue.position = 50.5;
+ is(cue.position, 50.5, "Cue's position value should now be 50.5.");
+
+ ok(cue.snapToLines, "Cue's snapToLines should be set by set.");
+ cue.snapToLines = false;
+ ok(!cue.snapToLines, "Cue's snapToLines should not be set.");
+
+ function checkEnumValue(prop, initialVal, acceptedValues) {
+ ok(prop in cue, prop + " should be a property on VTTCue.");
+ is(cue[prop], initialVal, "Cue's " + prop + " should be " + initialVal);
+ cue[prop] = "bogus";
+ is(cue[prop], initialVal, "Cue's " + prop + " should be " + initialVal);
+ acceptedValues.forEach(function(val) {
+ cue[prop] = val;
+ is(cue[prop], val, "Cue's " + prop + " should be " + val);
+ if (typeof val === "string") {
+ cue[prop] = val.toUpperCase();
+ is(cue[prop], val, "Cue's " + prop + " should be " + val);
+ }
+ });
+ }
+
+ checkEnumValue("align", "center", [ "start", "left", "center", "right", "end" ]);
+ checkEnumValue("lineAlign", "start", [ "start", "center", "end" ]);
+ checkEnumValue("vertical", "", [ "", "lr", "rl" ]);
+
+ cue.lineAlign = "center";
+ is(cue.lineAlign, "center", "Cue's line align should be center.");
+ cue.lineAlign = "START";
+ is(cue.lineAlign, "center", "Cue's line align should be center.");
+ cue.lineAlign = "end";
+ is(cue.lineAlign, "end", "Cue's line align should be end.");
+
+ // Check that cue position align works properly
+ is(cue.positionAlign, "center", "Cue's default position alignment should be center.");
+
+ cue.positionAlign = "line-left";
+ is(cue.positionAlign, "line-left", "Cue's position align should be line-left.");
+ cue.positionAlign = "auto";
+ is(cue.positionAlign, "auto", "Cue's position align should be auto.");
+ cue.positionAlign = "line-right";
+ is(cue.positionAlign, "line-right", "Cue's position align should be line-right.");
+
+ // Check cue.line
+ is(cue.line, "auto", "Cue's line value should initially be auto.");
+ cue.line = 0.5;
+ is(cue.line, 0.5, "Cue's line value should now be 0.5.");
+ cue.line = "auto";
+ is(cue.line, "auto", "Cue's line value should now be auto.");
+
+ // Check that we can create and add new VTTCues
+ var vttCue = new VTTCue(3.999, 4, "foo");
+ is(vttCue.track, null, "Cue's track should be null.");
+ trackElement.track.addCue(vttCue);
+ is(cue.track, trackElement.track, "Cue's track should be defined.");
+ is(cueList.length, 7, "Cue list length should now be 7.");
+
+ // Check that new VTTCue was added correctly
+ cue = cueList[6];
+ is(cue.startTime, 3.999, "Cue's start time should be 3.999.");
+ is(cue.endTime, 4, "Cue's end time should be 4.");
+ is(cue.text, "foo", "Cue's text should be foo.");
+
+ // Adding the same cue again should not increase the cue count.
+ trackElement.track.addCue(vttCue);
+ is(cueList.length, 7, "Cue list length should be 7.");
+
+ // Check that we are able to remove cues.
+ trackElement.track.removeCue(cue);
+ is(cueList.length, 6, "Cue list length should be 6.");
+
+ exceptionHappened = false;
+ try {
+ // We should not be able to remove a cue that is not in the list.
+ cue = new VTTCue(1, 2, "foo");
+ trackElement.track.removeCue(cue);
+ } catch (e) {
+ // "NotFoundError" should be thrown when trying to remove a cue that is
+ // not in the list.
+ is(e.name, "NotFoundError", "Should have thrown NotFoundError.");
+ exceptionHappened = true;
+ }
+ // If this is false then we did not throw an error and probably removed a cue
+ // when we shouln't have.
+ ok(exceptionHappened, "Exception should have happened.");
+
+ is(cueList.length, 6, "Cue list length should be 6.");
+
+ video.currentTime = 2;
+ isnot(trackElement.track.activeCues, null);
+
+ trackElement.track.mode = "disabled";
+ is(trackElement.track.activeCues, null);
+
+ trackElement.track.mode = "showing";
+ video.currentTime = 0;
+
+ var regionInfo = [
+ { lines: 2, width: 30 },
+ { lines: 4, width: 20 },
+ { lines: 2, width: 30 }
+ ];
+
+ for (var i = 0; i < regionInfo.length; i++) {
+ var cue = cueList[i];
+ isnot(cue.region, null, "Cue at " + i + " should have a region.");
+ for (var key in regionInfo[i]) {
+ is(cue.region[key], regionInfo[i][key], "Region should have a " + key +
+ " property with a value of " + regionInfo[i][key])
+ }
+ }
+
+ // Test TextTrack::ActiveCues.
+ var cueInfo = [
+ { startTime: 0.51, endTime: 0.71, ids: ["Cue 01"] },
+ { startTime: 0.72, endTime: 1.19, ids: [] },
+ { startTime: 1.2, endTime: 1.9, ids: [2] },
+ { startTime: 2, endTime: 2.4, ids: [2, 2.5] },
+ { startTime: 2.41, endTime: 2.70, ids: [2.5] },
+ { startTime: 2.71, endTime: 2.91, ids: [2.5, 3] },
+ { startTime: 2.92, endTime: 3.216, ids: [2.5] },
+ { startTime: 3.217, endTime: 3.5, ids: [2.5, 4, 5] },
+ { startTime: 3.51, endTime: 3.989, ids: [4, 5] },
+ { startTime: 3.99, endTime: 4, ids: [] }
+ ];
+
+ video.addEventListener("timeupdate", function() {
+ var activeCues = trackElement.track.activeCues,
+ found = false,
+ playbackTime = video.currentTime;
+
+ for (var i = 0; i < cueInfo.length; i++) {
+ var cue = cueInfo[i];
+ if (playbackTime >= cue.startTime && playbackTime <= cue.endTime) {
+ is(activeCues.length, cue.ids.length, "There should be " + cue.ids.length + " currently active cue(s).");
+ for (var j = 0; j < cue.ids.length; j++) {
+ isnot(activeCues.getCueById(cue.ids[j]), undefined, "The cue with ID " + cue.ids[j] + " should be active.");
+ }
+ break;
+ }
+ }
+ });
+
+ video.addEventListener("ended", function(){
+ SimpleTest.finish();
+ });
+
+ video.play();
+ });
+ }
+);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_texttrackcue_moz.html b/dom/media/test/test_texttrackcue_moz.html
new file mode 100644
index 000000000..97f8b9120
--- /dev/null
+++ b/dom/media/test/test_texttrackcue_moz.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=967157
+-->
+<head>
+ <meta charset='utf-8'>
+ <title>Test for Bug 967157 - Setting TextTrackCue::DisplayState should set TextTrackCue::HasBeenReset to false</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+ SimpleTest.waitForExplicitFinish();
+
+ var cue = SpecialPowers.wrap(new VTTCue(0, 1, "Some text."));
+ is(cue.hasBeenReset, false, "Cue's hasBeenReset flag should be false.");
+ is(cue.displayState, null, "Cue's displayState should be null.");
+
+ cue.startTime = 0.5;
+ is(cue.hasBeenReset, true, "Cue's hasBeenReset flag should now be true.");
+
+ cue.displayState = document.createElement("div");
+ is(cue.hasBeenReset, false, "Cue's hasBeenReset flag should now be false.");
+
+ SimpleTest.finish();
+</script>
+</body>
+</html>
diff --git a/dom/media/test/test_texttrackevents_video.html b/dom/media/test/test_texttrackevents_video.html
new file mode 100644
index 000000000..b187a91dc
--- /dev/null
+++ b/dom/media/test/test_texttrackevents_video.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Tests for TextTrack DOM Events</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var video = document.createElement("video");
+video.src = "vp9cake.webm";
+video.preload = "auto";
+video.controls = true;
+var trackElement = document.createElement("track");
+trackElement.src = "sequential.vtt";
+trackElement.kind = "subtitles";
+trackElement.default = true;
+document.getElementById("content").appendChild(video);
+video.appendChild(trackElement);
+
+var trackElementCueChangeCount = 0;
+var trackCueChangeCount = 0;
+var cueEnterCount = 0;
+var cueExitCount = 0;
+
+video.addEventListener("loadedmetadata", function run_tests() {
+ // Re-queue run_tests() at the end of the event loop until the track
+ // element has loaded its data.
+ if (trackElement.readyState == 1) {
+ return setTimeout(run_tests, 0);
+ }
+ is(trackElement.readyState, 2, "Track::ReadyState should be set to LOADED.");
+ ok('oncuechange' in trackElement.track, "Track::OnCueChange should exist.");
+
+ var textTrack = trackElement.track;
+ is(textTrack.cues.length, 3, "textTrack.cues.length should 3.");
+ textTrack.cues[0].onenter = function() {
+ ++cueEnterCount;
+ };
+ textTrack.cues[0].onexit = function() {
+ ++cueExitCount;
+ };
+ textTrack.cues[1].onenter = function() {
+ ++cueEnterCount;
+ };
+ textTrack.cues[1].onexit = function() {
+ ++cueExitCount;
+ };
+ textTrack.cues[2].onenter = function() {
+ ++cueEnterCount;
+ };
+ textTrack.cues[2].onexit = function() {
+ ++cueExitCount;
+ };
+
+ trackElement.track.oncuechange = function() {
+ ++trackElementCueChangeCount;
+ };
+
+ trackElement.addEventListener("cuechange", function() {
+ ++trackCueChangeCount;
+ });
+
+ video.play();
+});
+
+video.addEventListener('ended', function() {
+ // Should be fired 1 to 6 times, as there are 3 cues,
+ // with a change event for when it is activated/deactivated
+ // (6 events at most).
+ isnot(trackElementCueChangeCount, 0, "TrackElement should fire cue change at least one time.");
+ ok(trackElementCueChangeCount <= 6, 'trackElementCueChangeCount should <= 6');
+ isnot(trackCueChangeCount, 0, "TrackElement.track should fire cue change at least one time.");
+ ok(trackCueChangeCount <= 6, 'trackCueChangeCount should <= 6');
+ is(cueEnterCount, 3, "cueEnterCount should fire three times.");
+ is(cueExitCount, 3, "cueExitCount should fire three times.");
+ SimpleTest.finish()
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_texttracklist.html b/dom/media/test/test_texttracklist.html
new file mode 100644
index 000000000..a9f41ed06
--- /dev/null
+++ b/dom/media/test/test_texttracklist.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=882703
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Media test: TextTrackList change event</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+video = document.createElement("video");
+
+isnot(video.textTracks, null, "Video should have a list of TextTracks.");
+
+video.addTextTrack("subtitles", "", "");
+
+track = video.textTracks[0];
+video.textTracks.addEventListener("change", changed);
+
+is(track.mode, "hidden", "New TextTrack's mode should be hidden.");
+track.mode = "showing";
+// Bug882674: change the mode again to see if we receive only one
+// change event.
+track.mode = "hidden";
+
+var eventCount = 0;
+function changed(event) {
+ eventCount++;
+ is(eventCount, 1, "change event dispatched multiple times.");
+ is(event.target, video.textTracks, "change event's target should be video.textTracks.");
+ ok(event instanceof window.Event, "change event should be a simple event.");
+ ok(!event.bubbles, "change event should not bubble.");
+ ok(event.isTrusted, "change event should be trusted.");
+ ok(!event.cancelable, "change event should not be cancelable.");
+
+ // Delay the finish function call for testing the change event count.
+ setTimeout(SimpleTest.finish, 0);
+}
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_texttracklist_moz.html b/dom/media/test/test_texttracklist_moz.html
new file mode 100644
index 000000000..e889f7910
--- /dev/null
+++ b/dom/media/test/test_texttracklist_moz.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=881976
+-->
+<head>
+ <meta charset='utf-8'>
+ <title>Test for Bug 881976 - TextTrackCue Computed Position</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var video = document.createElement("video");
+var trackList = video.textTracks;
+ok(trackList instanceof TextTrackList,
+ "Video's textTracks should be a TextTrackList");
+var trackParent = SpecialPowers.unwrap(
+ SpecialPowers.wrap(trackList).mediaElement
+);
+is(trackParent, video,
+ "Video's TextTrackList's MediaElement reference should be set to the video.");
+SimpleTest.finish();
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_texttrackregion.html b/dom/media/test/test_texttrackregion.html
new file mode 100644
index 000000000..57689b88a
--- /dev/null
+++ b/dom/media/test/test_texttrackregion.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=917945
+-->
+<head>
+ <meta charset='utf-8'>
+ <title>Test for Bug 917945 - VTTRegion</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [["media.webvtt.regions.enabled", true]]},
+ function() {
+ var video = document.createElement("video");
+ video.src = "seek.webm";
+ video.preload = "auto";
+
+ var trackElement = document.createElement("track");
+ trackElement.src = "region.vtt";
+ trackElement.kind = "subtitles";
+
+ document.getElementById("content").appendChild(video);
+ video.appendChild(trackElement);
+ video.addEventListener("loadedmetadata", function run_tests() {
+ // Re-que run_tests() at the end of the event loop until the track
+ // element has loaded its data.
+ if (trackElement.readyState == 1) {
+ setTimeout(run_tests, 0);
+ return;
+ }
+ is(trackElement.readyState, 2, "Track::ReadyState should be set to LOADED.");
+
+ // Set mode to hidden so that the active cue lists are being updated.
+ trackElement.track.mode = "hidden";
+
+ var cues = trackElement.track.cues;
+ is(cues.length, 1, "Cue list length should be 1.");
+
+ var region = cues[0].region;
+ isnot(region, null, "Region should not be null.");
+ is(region.width, 62, "Region width should be 50.");
+ is(region.lines, 5, "Region lines should be 5.");
+ is(region.regionAnchorX, 4, "Region regionAnchorX should be 4.");
+ is(region.regionAnchorY, 78, "Region regionAnchorY should be 78.");
+ is(region.viewportAnchorX, 10, "Region viewportAnchorX should be 10.");
+ is(region.viewportAnchorY, 90, "Region viewportAnchorY should be 90.");
+ is(region.scroll, "up", "Region scroll should be 'up'");
+
+ SimpleTest.finish();
+ });
+ }
+);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_timeupdate_small_files.html b/dom/media/test/test_timeupdate_small_files.html
new file mode 100644
index 000000000..9eac499e2
--- /dev/null
+++ b/dom/media/test/test_timeupdate_small_files.html
@@ -0,0 +1,88 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=495319
+-->
+
+<head>
+ <title>Bug 495319 - playing back small audio files should fire timeupdate</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=495319">Mozilla Bug 495319</a>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function ended(e) {
+ var v = e.target;
+ ++v.counter["ended"];
+ is(v.counter["ended"], 1, v._name + " should see ended only once");
+ ok(v.counter["timeupdate"] > 0, v._name + " should see at least one timeupdate: " + v.currentTime);
+
+ // Rest event counters for we don't allow events after ended.
+ eventsToLog.forEach(function(e) {
+ v.counter[e] = 0;
+ });
+
+ // Finish the test after 500ms. We shouldn't receive any timeupdate events
+ // after the ended event, so this gives time for any pending timeupdate events
+ // to fire so we can ensure we don't regress behaviour.
+ setTimeout(
+ function() {
+ // Remove the event listeners before removing the video from the document.
+ // We should receive a timeupdate and pause event when we remove the element
+ // from the document (as the element is specified to behave as if pause() was
+ // invoked when it's removed from a document), and we don't want those
+ // confusing the test results.
+ v.removeEventListener("ended", ended, false);
+ eventsToLog.forEach(function(e) {
+ v.removeEventListener(e, logEvent, false);
+ });
+ removeNodeAndSource(v);
+ manager.finished(v.token);
+ },
+ 500);
+}
+
+var eventsToLog = ["play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
+ "loadeddata", "playing", "timeupdate", "error", "stalled", "emptied", "abort",
+ "waiting", "pause"];
+
+function logEvent(event) {
+ var v = event.target;
+ ++v.counter[event.type];
+ if (v.counter["ended"] > 0) {
+ is(v.counter[event.type], 0, v._name + " got unexpected " + event.type + " after ended");
+ }
+}
+
+function startTest(test, token) {
+ var type = getMajorMimeType(test.type);
+ var v = document.createElement(type);
+ v.token = token;
+ manager.started(token);
+ v.src = test.name;
+ v._name = test.name;
+
+ // Keep how many events received for each event type.
+ v.counter = {};
+ eventsToLog.forEach(function(e) {
+ v.addEventListener(e, logEvent, false);
+ v.counter[e] = 0;
+ });
+ v.addEventListener("ended", ended, false);
+ v.counter["ended"] = 0;
+ document.body.appendChild(v);
+ v.play();
+}
+
+manager.runTests(gSmallTests, startTest);
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_trackelementevent.html b/dom/media/test/test_trackelementevent.html
new file mode 100644
index 000000000..18dbdfa93
--- /dev/null
+++ b/dom/media/test/test_trackelementevent.html
@@ -0,0 +1,69 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 882677 - Implement the 'sourcing out of band text tracks' algorithm</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [["media.webvtt.regions.enabled", true]]},
+ function() {
+ var video = document.createElement("video");
+ video.src = "seek.webm";
+ video.preload = "auto";
+
+ var trackOne = document.createElement("track");
+ trackOne.src = "basic.vtt";
+ trackOne.kind = "subtitles";
+
+ var trackTwo = document.createElement("track");
+ trackTwo.src = "bad-signature.vtt";
+ trackTwo.kind = "captions";
+
+ var trackThree = document.createElement("track");
+ trackThree.src = "bad.vtt";
+ trackThree.kind = "chapters";
+
+ var events = 0;
+ function trackOneEvent() {
+ ok(true, "A load event for trackOne should have happened.");
+ events++ && events == 3 && SimpleTest.finish();
+ }
+ function trackTwoEvent() {
+ ok(true, "An error event for trackTwo should have happened.");
+ events++ && events == 3 && SimpleTest.finish();
+ }
+ function trackThreeEvent() {
+ ok(true, "An error event for trackThree should have happened.");
+ events++ && events == 3 && SimpleTest.finish();
+ }
+
+ function shouldNotBeCalled() {
+ ok(false, "Event should not have been called.");
+ }
+
+ trackOne.addEventListener("load", trackOneEvent);
+ trackOne.addEventListener("error", shouldNotBeCalled)
+ trackTwo.addEventListener("load", shouldNotBeCalled);
+ trackTwo.addEventListener("error", trackTwoEvent);
+ trackThree.addEventListener("load", shouldNotBeCalled);
+ trackThree.addEventListener("error", trackThreeEvent);
+
+ document.getElementById("content").appendChild(video);
+ video.appendChild(trackOne);
+ video.appendChild(trackTwo);
+ video.appendChild(trackThree);
+ }
+);
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/media/test/test_trackelementsrc.html b/dom/media/test/test_trackelementsrc.html
new file mode 100644
index 000000000..31f78ee7b
--- /dev/null
+++ b/dom/media/test/test_trackelementsrc.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1281418 - Change the src attribue for TrackElement.</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv({"set": [["media.webvtt.regions.enabled", true]]},
+ function() {
+ var video = document.createElement("video");
+ video.src = "seek.webm";
+ video.preload = "metadata";
+ var trackElement = document.createElement("track");
+ trackElement.src = "basic.vtt";
+ trackElement.default = true;
+
+ document.getElementById("content").appendChild(video);
+ video.appendChild(trackElement);
+
+ video.addEventListener("loadedmetadata", function metadata() {
+ if (trackElement.readyState <= 1) {
+ return setTimeout(metadata, 0);
+ }
+ is(video.textTracks.length, 1, "Length should be 1.");
+ is(video.textTracks[0].cues.length, 6, "Cue length should be 6.");
+
+ trackElement.src = "sequential.vtt";
+ trackElement.track.mode = "showing";
+ video.play();
+ });
+
+ video.addEventListener("ended", function end() {
+ is(trackElement.readyState, 2, "readyState should be 2.")
+ is(video.textTracks.length, 1, "Length should be 1.");
+ is(video.textTracks[0].cues.length, 3, "Cue length should be 3.");
+ SimpleTest.finish();
+ });
+});
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/media/test/test_trackevent.html b/dom/media/test/test_trackevent.html
new file mode 100644
index 000000000..e09db8336
--- /dev/null
+++ b/dom/media/test/test_trackevent.html
@@ -0,0 +1,70 @@
+
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Bug 893309 - Implement TrackEvent</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var video = document.createElement("video");
+isnot(video.textTracks, undefined, "HTMLMediaElement::TextTrack() property should be available.")
+ok(typeof video.addTextTrack == "function", "HTMLMediaElement::AddTextTrack() function should be available.")
+
+var trackList = video.textTracks;
+is(trackList.length, 0, "Length should be 0.");
+
+var evtTextTrack, numOfCalls = 0, tt;
+trackList.onaddtrack = function(event) {
+ ok(event instanceof TrackEvent, "Fired event from onaddtrack should be a TrackEvent");
+ is(event.type, "addtrack", "Event type should be addtrack");
+ ok(event.isTrusted, "Event should be trusted!");
+ ok(!event.bubbles, "Event shouldn't bubble!");
+ ok(!event.cancelable, "Event shouldn't be cancelable!");
+
+ evtTextTrack = event.track;
+ tt = textTrack[numOfCalls].track || textTrack[numOfCalls];
+
+ ok(tt === evtTextTrack, "Text tracks should be the same");
+ is(evtTextTrack.label, label[numOfCalls], "Label should be set to "+ label[numOfCalls]);
+ is(evtTextTrack.language, language[numOfCalls], "Language should be " + language[numOfCalls]);
+ is(evtTextTrack.kind, kind[numOfCalls], "Kind should be " + kind[numOfCalls]);
+
+ if (++numOfCalls == 4) {
+ SimpleTest.finish();
+ }
+};
+
+var label = ["Oasis", "Coldplay", "t.A.T.u", ""];
+language = ["en-CA", "en-GB", "ru", ""];
+kind = ["subtitles", "captions", "chapters", "subtitles"];
+
+var textTrack = new Array(4);
+for (var i = 0; i < 3; ++i) {
+ textTrack[i] = video.addTextTrack(kind[i], label[i], language[i]);
+ is(trackList.length, i + 1, "Length should be " + (i+1));
+}
+
+video.src = "seek.webm";
+video.preload = "auto";
+var trackElement = document.createElement("track");
+trackElement.src = "basic.vtt";
+textTrack[3] = trackElement;
+
+document.getElementById("content").appendChild(video);
+video.appendChild(trackElement);
+
+//TODO: Tests for removetrack event to be added along with bug 882677
+</script>
+</pre>
+</body>
+</html>
+
diff --git a/dom/media/test/test_unseekable.html b/dom/media/test/test_unseekable.html
new file mode 100644
index 000000000..a1b8820b2
--- /dev/null
+++ b/dom/media/test/test_unseekable.html
@@ -0,0 +1,101 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: unseekable</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/*
+
+Test that unseekable media can't be seeked. We load a media that shouldn't
+be seekable, and play through once. While playing through we repeatedly try
+to seek and check that nothing happens when we do. We also verify that the
+seekable ranges are empty.
+
+*/
+
+var manager = new MediaTestManager;
+
+var onseeking = function(event) {
+ var v = event.target;
+ v.actuallySeeked = true;
+};
+
+var onseeked = function(event) {
+ var v = event.target;
+ v.actuallySeeked = true;
+};
+
+var ontimeupdate = function(event) {
+ var v = event.target;
+
+ // Check that when we seek nothing happens.
+ var t = v.currentTime;
+ v.currentTime = v.currentTime /= 2;
+ ok(Math.abs(t - v.currentTime) < 0.01, "Current time shouldn't change when seeking in unseekable media: " + v.name);
+
+ // Check that the seekable ranges are empty.
+ is(v.seekable.length, 0, "Should have no seekable ranges in unseekable media: " + v.name);
+};
+
+var onended = function(event) {
+ var v = event.target;
+
+ // Remove the event listeners so that they can't run if there are any pending
+ // events.
+ v.removeEventListener("seeking", onseeking, false);
+ v.removeEventListener("seeked", onseeked, false);
+ v.removeEventListener("timeupdate", ontimeupdate, false);
+ v.removeEventListener("ended", onended, false);
+
+ v.src = "";
+ if (v.parentNode) {
+ v.parentNode.removeChild(v);
+ }
+
+ // Verify that none of the seeks we did in timeupdate actually seeked.
+ ok(!v.actuallySeeked, "Should not be able to seek in unseekable media: " + v.name);
+
+ manager.finished(v.token);
+}
+
+function startTest(test, token) {
+ var v = document.createElement('video');
+ manager.started(token);
+ v.name = test.name;
+ v.src = test.name;
+ v.token = token;
+ v.autoplay = "true";
+
+ v.actuallySeeked = false;
+
+ v.addEventListener("seeking", onseeking, false);
+ v.addEventListener("seeked", onseeked, false);
+ v.addEventListener("timeupdate", ontimeupdate, false);
+ v.addEventListener("ended", onended, false);
+
+ document.body.appendChild(v);
+}
+
+function canPlay(candidates) {
+ var v = document.createElement("video");
+ var resources = candidates.filter(function(x){return v.canPlayType(x.type);});
+ return (resources.length > 0);
+}
+
+if (canPlay(gUnseekableTests)) {
+ manager.runTests(gUnseekableTests, startTest);
+} else {
+ todo(false, "No files of supported format to test");
+}
+
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_videoDocumentTitle.html b/dom/media/test/test_videoDocumentTitle.html
new file mode 100644
index 000000000..c231582d3
--- /dev/null
+++ b/dom/media/test/test_videoDocumentTitle.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=463830
+-->
+<head>
+ <title>Test for Bug 463830</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=463830">Mozilla Bug 463830</a>
+<p id="display"></p>
+<iframe id="i"></iframe>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 463830 **/
+
+var gTests = [
+ { file: "320x240.ogv", title: "320x240.ogv" },
+ { file: "bug461281.ogg", title: "bug461281.ogg" },
+];
+
+var gTestNum = 0;
+
+addLoadEvent(runTest);
+
+var title;
+var i = document.getElementById("i");
+
+function runTest() {
+ if (gTestNum == gTests.length) {
+ SimpleTest.finish();
+ return;
+ }
+ if (gTestNum == 0) {
+ i.addEventListener("load", function() {
+ is(i.contentDocument.title, title, "Doc title incorrect");
+ setTimeout(runTest, 0);
+ }, false);
+ }
+
+ title = gTests[gTestNum].title;
+ i.src = gTests[gTestNum].file;
+ gTestNum++;
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_video_dimensions.html b/dom/media/test/test_video_dimensions.html
new file mode 100644
index 000000000..87a6a37cf
--- /dev/null
+++ b/dom/media/test/test_video_dimensions.html
@@ -0,0 +1,96 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test that a video element has set video dimensions on loadedmetadata</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var manager = new MediaTestManager;
+
+var startTest = function(test, token) {
+ manager.started(token);
+ var v1 = document.createElement('video');
+ var v2 = document.createElement('video');
+ var vout = document.createElement('video');
+
+ // Avoid a race for hardware resources between v1 and v2 on platforms with
+ // a hardware decoder, like B2G.
+ v1.preload = 'none';
+ v2.preload = 'none';
+
+ var numVideoElementsFinished = 0;
+
+ var ondurationchange = function(ev) {
+ var v = ev.target;
+ info(v.testName + " got durationchange");
+ v.durationchange = true;
+ };
+ var onresize = function(ev) {
+ var v = ev.target;
+ info(v.testName + " got resize");
+ ok(!v.resize, v.testName + " should only fire resize once for same size");
+ v.resize = true;
+ ok(v.durationchange, v.testName +
+ " durationchange event should have been emitted before resize");
+ is(v.videoWidth, test.width, v.testName + " width should be set on resize");
+ is(v.videoHeight, test.height, v.testName + " height should be set on resize");
+ };
+ var onloadedmetadata = function(ev) {
+ var v = ev.target;
+ info(v.testName + " got loadedmetadata");
+ ok(!v.loadedmetadata, v.testName + " should only fire loadedmetadata once");
+ v.loadedmetadata = true;
+ ok(v.resize, v.testName +
+ " resize event should have been emitted before loadedmetadata");
+
+ numVideoElementsFinished += 1;
+ if (v === v1) {
+ removeNodeAndSource(v1);
+ v2.load();
+ }
+
+ if (v === v2) {
+ vout.src = URL.createObjectURL(v2.mozCaptureStreamUntilEnded());
+ v2.play();
+ vout.play();
+ }
+
+ if (numVideoElementsFinished === 3) {
+ removeNodeAndSource(v2);
+ removeNodeAndSource(vout);
+ manager.finished(token);
+ }
+ };
+ var setupElement = function(v, id) {
+ v.durationchange = false;
+ v.ondurationchange = ondurationchange;
+ v.resize = false;
+ v.onresize = onresize;
+ v.loadedmetadata = false;
+ v.onloadedmetadata = onloadedmetadata;
+ document.body.appendChild(v);
+ };
+
+ v1.testName = test.name;
+ v2.testName = test.name + " (Captured)";
+ vout.testName = test.name + " (Stream)";
+
+ v1.src = test.name;
+ v2.src = test.name;
+
+ setupElement(v1, "v1");
+ setupElement(v2, "v2");
+ setupElement(vout, "vout");
+
+ v1.play();
+};
+
+manager.runTests(getPlayableVideos(gSmallTests), startTest);
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_video_in_audio_element.html b/dom/media/test/test_video_in_audio_element.html
new file mode 100644
index 000000000..45e6a8166
--- /dev/null
+++ b/dom/media/test/test_video_in_audio_element.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1060896
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1060896</title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="text/javascript" src="manifest.js"></script>
+ <script type="application/javascript">
+
+ /**
+ * Test for Bug 1060896; tests that loading a video inside an audio element works.
+ **/
+
+ var manager = new MediaTestManager;
+
+ function error(event) {
+ var a = event.target;
+ ok(!a.mozHasAudio, "Media must've had no active tracks to play");
+ a.removeEventListener("error", error);
+ a.removeEventListener("ended", ended);
+ removeNodeAndSource(a);
+ manager.finished(a.token);
+ }
+
+ function ended(event) {
+ var a = event.target;
+ a.removeEventListener("error", error);
+ a.removeEventListener("ended", ended);
+ removeNodeAndSource(a);
+ manager.finished(a.token);
+ }
+
+ function initTest(test, token) {
+ var a = document.createElement('audio');
+ a.token = token;
+ manager.started(token);
+ a.autoplay = true;
+
+ a.addEventListener("error", error);
+ a.addEventListener("ended", ended);
+
+ a.src = test.name;
+ }
+
+ var videos = getPlayableVideos(gSmallTests);
+ // Bug 1216012, skip the test on emulator-kk.
+ if (getAndroidVersion() == 19) {
+ todo(false, "Test disabled on emulator-kk.");
+ } else {
+ manager.runTests(videos, initTest);
+ }
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1060896">Mozilla Bug 1060896</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_video_to_canvas.html b/dom/media/test/test_video_to_canvas.html
new file mode 100644
index 000000000..b4a9f3752
--- /dev/null
+++ b/dom/media/test/test_video_to_canvas.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=486646
+-->
+
+<head>
+ <title>Test for Bug 486646</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+var manager = new MediaTestManager;
+
+function loaded(e) {
+ var v = e.target;
+ ok(v.readyState >= v.HAVE_CURRENT_DATA,
+ "readyState must be >= HAVE_CURRENT_DATA for " + v._name);
+
+ var canvas = document.createElement("canvas");
+ canvas.width = v.videoWidth;
+ canvas.height = v.videoHeight;
+ document.body.appendChild(canvas);
+ var ctx = canvas.getContext("2d");
+ try {
+ ctx.drawImage(v, 0, 0);
+ ok(true, "Shouldn't throw exception while drawing to canvas from video for " + v._name);
+ } catch (ex) {
+ ok(false, "Shouldn't throw exception while drawing to canvas from video for " + v._name);
+ }
+
+ v._finished = true;
+ v.parentNode.removeChild(v);
+ manager.finished(v.token);
+}
+
+function startTest(test, token) {
+ var type = getMajorMimeType(test.type);
+ if (type != "video")
+ return;
+
+ var v = document.createElement('video');
+ v.token = token;
+ manager.started(token);
+ v.src = test.name;
+ v._name = test.name;
+ v._finished = false;
+ v.autoplay = true;
+ v.style.display = "none";
+ v.addEventListener("ended", loaded, false);
+ document.body.appendChild(v);
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [["media.cache_size", 40000]]}, beginTest);
+function beginTest() {
+ manager.runTests(gSmallTests, startTest);
+}
+
+</script>
+</pre>
+
+</body>
+</html>
diff --git a/dom/media/test/test_volume.html b/dom/media/test/test_volume.html
new file mode 100644
index 000000000..07f51f52a
--- /dev/null
+++ b/dom/media/test/test_volume.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Media test: volume attribute set</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<video id='v1'></video><audio id='a1'></audio>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function test(element, value, shouldThrow) {
+ var threw = null;
+ try {
+ element.volume = value;
+ } catch (ex) {
+ threw = ex.name;
+ }
+ is(shouldThrow, threw, "Case: " +element.id+ " setVolume=" + value);
+}
+
+
+var ids = new Array(document.getElementById('v1'), document.getElementById('a1'));
+
+for (i=0; i<ids.length; i++) {
+ var element = ids[i];
+ test(element, 0.0, null);
+ test(element, 1.0, null);
+ test(element, -0.1, "IndexSizeError");
+ test(element, 1.1, "IndexSizeError");
+ test(element, undefined, "TypeError");
+ test(element, NaN, "TypeError");
+}
+
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_vttparser.html b/dom/media/test/test_vttparser.html
new file mode 100644
index 000000000..b727080ef
--- /dev/null
+++ b/dom/media/test/test_vttparser.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset='utf-8'>
+ <title>WebVTT Parser Regression Tests</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var video = document.createElement("video");
+video.src = "seek.webm";
+video.preload = "auto";
+
+var trackElement = document.createElement("track");
+trackElement.src = "parser.vtt";
+trackElement.kind = "subtitles";
+trackElement.default = true;
+
+document.getElementById("content").appendChild(video);
+video.appendChild(trackElement);
+video.addEventListener("loadedmetadata", function run_tests() {
+ // Re-que run_tests() at the end of the event loop until the track
+ // element has loaded its data.
+ if (trackElement.readyState == 1) {
+ setTimeout(run_tests, 0);
+ return;
+ }
+
+ is(trackElement.readyState, 2, "Track::ReadyState should be set to LOADED.");
+ is(trackElement.track.cues.length, 2, "Track should have two Cues.");
+ SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/media/test/test_wav_ended1.html b/dom/media/test/test_wav_ended1.html
new file mode 100644
index 000000000..7680e136f
--- /dev/null
+++ b/dom/media/test/test_wav_ended1.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Wave Media test: ended</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+// Test if the ended event works correctly.
+var endPassed = false;
+var completed = false;
+
+function startTest() {
+ if (completed)
+ return;
+ var v = document.getElementById('v');
+ v.play();
+}
+
+function playbackEnded() {
+ if (completed)
+ return;
+
+ var v = document.getElementById('v');
+ completed = true;
+ ok(v.currentTime >= 0.9 && v.currentTime <= 1.1,
+ "Checking currentTime at end: " + v.currentTime);
+ ok(v.ended, "Checking playback has ended");
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+<audio id='v'
+ onloadedmetadata='return startTest();'
+ onended='return playbackEnded();'>
+ <source type='audio/x-wav' src='r11025_s16_c1.wav'>
+</audio>
+</body>
+</html>
diff --git a/dom/media/test/test_wav_ended2.html b/dom/media/test/test_wav_ended2.html
new file mode 100644
index 000000000..44a6d9867
--- /dev/null
+++ b/dom/media/test/test_wav_ended2.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Wave Media test: ended and replaying</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<!-- try with autoplay and no v.play in starttest, also with both -->
+<pre id="test">
+<script class="testbody" type="text/javascript">
+// Test if audio can be replayed after ended.
+var completed = false;
+var playingCount = 0;
+var endCount = 0;
+
+function startTest() {
+ if (completed)
+ return;
+
+ var v = document.getElementById('v');
+ v.play();
+}
+
+function playbackStarted() {
+ if (completed)
+ return;
+
+ playingCount++;
+}
+
+function playbackEnded() {
+ if (completed)
+ return;
+
+ endCount++;
+ var v = document.getElementById('v');
+ ok(v.currentTime >= 0.9 && v.currentTime <= 1.1,
+ "Checking currentTime at end: " + v.currentTime);
+ ok(v.ended, "Checking playback has ended");
+ ok(playingCount > 0, "Expect at least one playing event");
+ playingCount = 0;
+ if (endCount < 2) {
+ v.play();
+ } else {
+ ok(endCount == 2, "Check playback after ended event");
+ completed = true;
+ SimpleTest.finish();
+ }
+}
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+<audio id='v'
+ onloadedmetadata='return startTest();'
+ onplaying='return playbackStarted();'
+ onended='return playbackEnded();'>
+ <source type='audio/x-wav' src='r11025_s16_c1.wav'>
+</audio>
+</body>
+</html>
diff --git a/dom/media/test/test_webvtt_empty_displaystate.html b/dom/media/test/test_webvtt_empty_displaystate.html
new file mode 100644
index 000000000..54de86e61
--- /dev/null
+++ b/dom/media/test/test_webvtt_empty_displaystate.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset='utf-8'>
+ <title>WebVTT : cue's displaystate should be empty when its active flag is unset</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<div id="content">
+</div>
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var isReceivedOnEnterEvent = false;
+var isReceivedOnExitEvent = false;
+
+function checkCueEvents() {
+ ok(isReceivedOnEnterEvent, "Already received cue's onEnter event.");
+ ok(isReceivedOnExitEvent, "Already received cue's onExit event.");
+ SimpleTest.finish();
+}
+
+function checkCueDisplayState(cue, expectedState) {
+ var cueChrome = SpecialPowers.wrap(cue);
+ if (expectedState) {
+ ok(cueChrome.displayState, "Cue's displayState shouldn't be empty.");
+ } else {
+ ok(!cueChrome.displayState, "Cue's displayState should be empty.");
+ }
+}
+
+function runTest() {
+ info("--- create video ---");
+ var video = document.createElement("video");
+ video.src = "seek.webm";
+ video.autoplay = true;
+ document.getElementById("content").appendChild(video);
+
+ video.onended = function () {
+ video.onended = null;
+ checkCueEvents();
+ };
+
+ video.onpause = function () {
+ video.onpause = null;
+ checkCueEvents();
+ }
+
+ info("--- create the type of track ---");
+ isnot(window.TextTrack, undefined, "TextTrack should be defined.");
+
+ var track = video.addTextTrack("subtitles", "A", "en");
+ track.mode = "showing";
+ ok(track instanceof TextTrack, "Track should be an instanceof TextTrack.");
+
+ info("--- check the type of cue ---");
+ isnot(window.TextTrackCue, undefined, "TextTrackCue should be defined.");
+ isnot(window.VTTCue, undefined, "VTTCue should be defined.");
+
+ var cue = new VTTCue(0, 1, "Test cue");
+ ok(cue instanceof TextTrackCue, "Cue should be an instanceof TextTrackCue.");
+ ok(cue instanceof VTTCue, "Cue should be an instanceof VTTCue.");
+
+ info("--- add cue ---");
+ track.addCue(cue);
+
+ cue.onenter = function () {
+ cue.onenter = null;
+ isReceivedOnEnterEvent = true;
+ checkCueDisplayState(cue, true /* has display-state */);
+
+ cue.onexit = function () {
+ cue.onexit = null;
+ isReceivedOnExitEvent = true;
+ checkCueDisplayState(cue, false /* no display-state */);
+ video.pause();
+ }
+ }
+}
+
+onload = runTest;
+</script>
+</body>
+</html>
diff --git a/dom/media/test/test_webvtt_positionalign.html b/dom/media/test/test_webvtt_positionalign.html
new file mode 100644
index 000000000..47593bdf9
--- /dev/null
+++ b/dom/media/test/test_webvtt_positionalign.html
@@ -0,0 +1,95 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset='utf-8'>
+ <title>WebVTT : position align test</title>
+ <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<div id="content">
+</div>
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+var video = document.createElement("video");
+var trackElement = document.createElement("track");
+var cuesNumber = 8;
+
+function isTrackElemenLoaded() {
+ // Re-que isTrackElemenLoaded() at the end of the event loop until the track
+ // element has loaded its data.
+ if (trackElement.readyState == 1) {
+ setTimeout(isTrackElemenLoaded, 0);
+ return;
+ }
+
+ is(trackElement.readyState, 2, "Track::ReadyState should be set to LOADED.");
+ runTest();
+}
+
+function runTest() {
+ info("--- check cues number ---");
+ var cues = trackElement.track.cues;
+ is(cues.length, cuesNumber, "Cues number is correct.");
+
+ info("--- check the typedef of TextTrackCue and VTTCue ---");
+ isnot(window.TextTrackCue, undefined, "TextTrackCue should be defined.");
+ isnot(window.VTTCue, undefined, "VTTCue should be defined.");
+
+ info("--- check the type of first parsed cue ---");
+ ok(cues[0] instanceof TextTrackCue, "Cue should be an instanceof TextTrackCue.");
+ ok(cues[0] instanceof VTTCue, "Cue should be an instanceof VTTCue.");
+
+ info("--- check the cue's position alignment ---");
+ is(cues[0].positionAlign, "center", cues[0].text);
+ is(cues[1].positionAlign, "line-left", cues[1].text);
+ is(cues[2].positionAlign, "center", cues[2].text);
+ is(cues[3].positionAlign, "line-right", cues[3].text);
+ is(cues[4].positionAlign, "auto", cues[4].text);
+
+ info("--- check the cue's computed position alignment ---");
+ // The "computedPositionAlign" is the chrome-only attributes, we need to get
+ // the chrome privilege for cues.
+ cuesChrome = SpecialPowers.wrap(cues);
+ is(cuesChrome[5].computedPositionAlign, "line-left", cuesChrome[5].text);
+ is(cuesChrome[6].computedPositionAlign, "line-right", cuesChrome[6].text);
+ is(cuesChrome[7].computedPositionAlign, "center", cuesChrome[7].text);
+
+ info("--- check the cue's computed position alignment from DOM API ---");
+ is(cuesChrome[0].computedPositionAlign, "center", "Cue's computedPositionAlign align is center.");
+
+ cuesChrome[0].positionAlign = "auto";
+ is(cuesChrome[0].positionAlign, "auto", "Change cue's position align to \"auto\"");
+
+ cuesChrome[0].align = "left";
+ is(cuesChrome[0].align, "left", "Change cue's align to \"left\".");
+
+ is(cuesChrome[0].computedPositionAlign, "line-left", "Cue's computedPositionAlign becomes to \"line-left\"");
+
+ info("--- finish test ---");
+ SimpleTest.finish();
+}
+
+function setupTest() {
+ info("--- setup test ---");
+ video.src = "seek.webm";
+ video.preload = "auto";
+
+ trackElement.src = "vttPositionAlign.vtt";
+ trackElement.kind = "subtitles";
+ trackElement.default = true;
+
+ document.getElementById("content").appendChild(video);
+ video.appendChild(trackElement);
+ video.addEventListener("loadedmetadata", function() {
+ video.removeEventListener("loadedmetadata", runTest);
+ isTrackElemenLoaded();
+ });
+}
+
+onload = setupTest;
+</script>
+</body>
+</html>
diff --git a/dom/media/test/variable-channel.ogg b/dom/media/test/variable-channel.ogg
new file mode 100644
index 000000000..77e116889
--- /dev/null
+++ b/dom/media/test/variable-channel.ogg
Binary files differ
diff --git a/dom/media/test/variable-channel.ogg^headers^ b/dom/media/test/variable-channel.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/variable-channel.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/variable-channel.opus b/dom/media/test/variable-channel.opus
new file mode 100644
index 000000000..76b899116
--- /dev/null
+++ b/dom/media/test/variable-channel.opus
Binary files differ
diff --git a/dom/media/test/variable-channel.opus^headers^ b/dom/media/test/variable-channel.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/variable-channel.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/variable-preskip.opus b/dom/media/test/variable-preskip.opus
new file mode 100644
index 000000000..a82e831ce
--- /dev/null
+++ b/dom/media/test/variable-preskip.opus
Binary files differ
diff --git a/dom/media/test/variable-preskip.opus^headers^ b/dom/media/test/variable-preskip.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/variable-preskip.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/variable-samplerate.ogg b/dom/media/test/variable-samplerate.ogg
new file mode 100644
index 000000000..0c2726e83
--- /dev/null
+++ b/dom/media/test/variable-samplerate.ogg
Binary files differ
diff --git a/dom/media/test/variable-samplerate.ogg^headers^ b/dom/media/test/variable-samplerate.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/variable-samplerate.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/variable-samplerate.opus b/dom/media/test/variable-samplerate.opus
new file mode 100644
index 000000000..1d1517079
--- /dev/null
+++ b/dom/media/test/variable-samplerate.opus
Binary files differ
diff --git a/dom/media/test/variable-samplerate.opus^headers^ b/dom/media/test/variable-samplerate.opus^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/variable-samplerate.opus^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/vbr-head.mp3 b/dom/media/test/vbr-head.mp3
new file mode 100644
index 000000000..35f410549
--- /dev/null
+++ b/dom/media/test/vbr-head.mp3
Binary files differ
diff --git a/dom/media/test/vbr-head.mp3^headers^ b/dom/media/test/vbr-head.mp3^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/vbr-head.mp3^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/vbr.mp3 b/dom/media/test/vbr.mp3
new file mode 100644
index 000000000..38eb376a9
--- /dev/null
+++ b/dom/media/test/vbr.mp3
Binary files differ
diff --git a/dom/media/test/vbr.mp3^headers^ b/dom/media/test/vbr.mp3^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/vbr.mp3^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/video-overhang.ogg b/dom/media/test/video-overhang.ogg
new file mode 100644
index 000000000..e11b28fb5
--- /dev/null
+++ b/dom/media/test/video-overhang.ogg
Binary files differ
diff --git a/dom/media/test/video-overhang.ogg^headers^ b/dom/media/test/video-overhang.ogg^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/video-overhang.ogg^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/vp9-short.webm b/dom/media/test/vp9-short.webm
new file mode 100644
index 000000000..16d32abee
--- /dev/null
+++ b/dom/media/test/vp9-short.webm
Binary files differ
diff --git a/dom/media/test/vp9-short.webm^headers^ b/dom/media/test/vp9-short.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/vp9-short.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/vp9.webm b/dom/media/test/vp9.webm
new file mode 100644
index 000000000..221877e30
--- /dev/null
+++ b/dom/media/test/vp9.webm
Binary files differ
diff --git a/dom/media/test/vp9.webm^headers^ b/dom/media/test/vp9.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/vp9.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/vp9cake-short.webm b/dom/media/test/vp9cake-short.webm
new file mode 100644
index 000000000..2d353d98a
--- /dev/null
+++ b/dom/media/test/vp9cake-short.webm
Binary files differ
diff --git a/dom/media/test/vp9cake-short.webm^headers^ b/dom/media/test/vp9cake-short.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/vp9cake-short.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/vp9cake.webm b/dom/media/test/vp9cake.webm
new file mode 100644
index 000000000..4ea70ed30
--- /dev/null
+++ b/dom/media/test/vp9cake.webm
Binary files differ
diff --git a/dom/media/test/vp9cake.webm^headers^ b/dom/media/test/vp9cake.webm^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/vp9cake.webm^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/vttPositionAlign.vtt b/dom/media/test/vttPositionAlign.vtt
new file mode 100644
index 000000000..79f7c49f8
--- /dev/null
+++ b/dom/media/test/vttPositionAlign.vtt
@@ -0,0 +1,25 @@
+WEBVTT
+
+00:00.000 --> 00:00.500
+Cue 0 : PositionAlign should be "center".
+
+00:00.700 --> 00:00.800 position:50%,line-left
+Cue 1 : PositionAlign should be "line-left".
+
+00:00.700 --> 00:00.800 position:50%,center
+Cue 2 : PositionAlign should be "center".
+
+00:00.700 --> 00:00.800 position:50%,line-right
+Cue 3 : PositionAlign should be "line-right".
+
+00:00.700 --> 00:00.800 position:50%,auto
+Cue 4 : PositionAlign should be "auto"
+
+00:00.700 --> 00:00.800 position:50%,auto align:left
+Cue 5 : PositionAlign should be "auto", but computedPositionAlign should be "line-left".
+
+00:00.700 --> 00:00.800 position:50%,auto align:right
+Cue 6 : PositionAlign should be "auto", but computedPositionAlign should be "line-right".
+
+00:00.700 --> 00:00.800 position:50%,auto align:middle
+Cue 7 : PositionAlign should be "auto", but computedPositionAlign should be "center". \ No newline at end of file
diff --git a/dom/media/test/wave_metadata.wav b/dom/media/test/wave_metadata.wav
new file mode 100644
index 000000000..5e17547c3
--- /dev/null
+++ b/dom/media/test/wave_metadata.wav
Binary files differ
diff --git a/dom/media/test/wave_metadata.wav^headers^ b/dom/media/test/wave_metadata.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/wave_metadata.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/wave_metadata_bad_len.wav b/dom/media/test/wave_metadata_bad_len.wav
new file mode 100644
index 000000000..b89c4818b
--- /dev/null
+++ b/dom/media/test/wave_metadata_bad_len.wav
Binary files differ
diff --git a/dom/media/test/wave_metadata_bad_len.wav^headers^ b/dom/media/test/wave_metadata_bad_len.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/wave_metadata_bad_len.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/wave_metadata_bad_no_null.wav b/dom/media/test/wave_metadata_bad_no_null.wav
new file mode 100644
index 000000000..18063048c
--- /dev/null
+++ b/dom/media/test/wave_metadata_bad_no_null.wav
Binary files differ
diff --git a/dom/media/test/wave_metadata_bad_no_null.wav^headers^ b/dom/media/test/wave_metadata_bad_no_null.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/wave_metadata_bad_no_null.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/wave_metadata_bad_utf8.wav b/dom/media/test/wave_metadata_bad_utf8.wav
new file mode 100644
index 000000000..b6f2a675b
--- /dev/null
+++ b/dom/media/test/wave_metadata_bad_utf8.wav
Binary files differ
diff --git a/dom/media/test/wave_metadata_bad_utf8.wav^headers^ b/dom/media/test/wave_metadata_bad_utf8.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/wave_metadata_bad_utf8.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/wave_metadata_unknown_tag.wav b/dom/media/test/wave_metadata_unknown_tag.wav
new file mode 100644
index 000000000..b19fb5170
--- /dev/null
+++ b/dom/media/test/wave_metadata_unknown_tag.wav
Binary files differ
diff --git a/dom/media/test/wave_metadata_unknown_tag.wav^headers^ b/dom/media/test/wave_metadata_unknown_tag.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/wave_metadata_unknown_tag.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/wave_metadata_utf8.wav b/dom/media/test/wave_metadata_utf8.wav
new file mode 100644
index 000000000..352db285b
--- /dev/null
+++ b/dom/media/test/wave_metadata_utf8.wav
Binary files differ
diff --git a/dom/media/test/wave_metadata_utf8.wav^headers^ b/dom/media/test/wave_metadata_utf8.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/wave_metadata_utf8.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/wavedata_alaw.wav b/dom/media/test/wavedata_alaw.wav
new file mode 100644
index 000000000..ef090d16e
--- /dev/null
+++ b/dom/media/test/wavedata_alaw.wav
Binary files differ
diff --git a/dom/media/test/wavedata_alaw.wav^headers^ b/dom/media/test/wavedata_alaw.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/wavedata_alaw.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/wavedata_s16.wav b/dom/media/test/wavedata_s16.wav
new file mode 100644
index 000000000..6a69cd78f
--- /dev/null
+++ b/dom/media/test/wavedata_s16.wav
Binary files differ
diff --git a/dom/media/test/wavedata_s16.wav^headers^ b/dom/media/test/wavedata_s16.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/wavedata_s16.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/wavedata_s24.wav b/dom/media/test/wavedata_s24.wav
new file mode 100644
index 000000000..dbdb6aac1
--- /dev/null
+++ b/dom/media/test/wavedata_s24.wav
Binary files differ
diff --git a/dom/media/test/wavedata_s24.wav^headers^ b/dom/media/test/wavedata_s24.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/wavedata_s24.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/wavedata_u8.wav b/dom/media/test/wavedata_u8.wav
new file mode 100644
index 000000000..1d895c2ce
--- /dev/null
+++ b/dom/media/test/wavedata_u8.wav
Binary files differ
diff --git a/dom/media/test/wavedata_u8.wav^headers^ b/dom/media/test/wavedata_u8.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/wavedata_u8.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store
diff --git a/dom/media/test/wavedata_ulaw.wav b/dom/media/test/wavedata_ulaw.wav
new file mode 100644
index 000000000..0874face2
--- /dev/null
+++ b/dom/media/test/wavedata_ulaw.wav
Binary files differ
diff --git a/dom/media/test/wavedata_ulaw.wav^headers^ b/dom/media/test/wavedata_ulaw.wav^headers^
new file mode 100644
index 000000000..4030ea1d3
--- /dev/null
+++ b/dom/media/test/wavedata_ulaw.wav^headers^
@@ -0,0 +1 @@
+Cache-Control: no-store