| <!doctype html> |
| <html> |
| <head> |
| <title>MediaRecorder mimeType</title> |
| <link rel="help" href="https://w3c.github.io/mediacapture-record/MediaRecorder.html#dom-mediarecorder-mimeType"> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| </head> |
| <body> |
| <canvas id="canvas" width="200" height="200"> |
| </canvas> |
| <script> |
| function createAudioStream(t) { |
| const ac = new AudioContext(); |
| const dest = ac.createMediaStreamDestination(); |
| const osc = ac.createOscillator(); |
| osc.connect(dest); |
| osc.start(); |
| const [track] = dest.stream.getTracks(); |
| t.add_cleanup(() => track.stop()); |
| return dest.stream; |
| } |
| |
| function createVideoStream(t) { |
| const canvas = document.getElementById("canvas"); |
| const ctx = canvas.getContext('2d'); |
| const stream = canvas.captureStream(); |
| const [track] = stream.getTracks(); |
| t.add_cleanup(() => track.stop()); |
| ctx.fillStyle = 'green'; |
| requestAnimationFrame(function draw() { |
| ctx.fillRect(0, 0, canvas.width, canvas.height); |
| if (track.readyState == "live") { |
| requestAnimationFrame(draw); |
| } |
| }); |
| return stream; |
| } |
| |
| function createAudioVideoStream(t) { |
| return new MediaStream([ |
| ...createAudioStream(t).getTracks(), |
| ...createVideoStream(t).getTracks(), |
| ]); |
| } |
| |
| test(t => { |
| const recorder = new MediaRecorder(createAudioStream(t)); |
| assert_equals(recorder.mimeType, "", |
| "MediaRecorder has no default mimeType"); |
| }, "MediaRecorder sets no default mimeType in the constructor for audio"); |
| |
| test(t => { |
| const recorder = new MediaRecorder(createVideoStream(t)); |
| assert_equals(recorder.mimeType, "", |
| "MediaRecorder has no default mimeType"); |
| }, "MediaRecorder sets no default mimeType in the constructor for video"); |
| |
| test(t => { |
| const stream = createAudioVideoStream(t); |
| const recorder = new MediaRecorder(stream); |
| assert_equals(recorder.mimeType, "", |
| "MediaRecorder has no default mimeType"); |
| }, "MediaRecorder sets no default mimeType in the constructor for audio/video"); |
| |
| test(t => { |
| assert_throws_dom("NotSupportedError", |
| () => new MediaRecorder(new MediaStream(), {mimeType: "audio/banana"})); |
| }, "MediaRecorder invalid audio mimeType throws"); |
| |
| test(t => { |
| assert_false(MediaRecorder.isTypeSupported("audio/banana")); |
| }, "MediaRecorder invalid audio mimeType is unsupported"); |
| |
| test(t => { |
| assert_throws_dom("NotSupportedError", |
| () => new MediaRecorder(new MediaStream(), {mimeType: "video/pineapple"})); |
| }, "MediaRecorder invalid video mimeType throws"); |
| |
| test(t => { |
| assert_false(MediaRecorder.isTypeSupported("video/pineapple")); |
| }, "MediaRecorder invalid video mimeType is unsupported"); |
| |
| // New MIME types could be added to this list as needed. |
| for (const mimeType of [ |
| 'audio/mp4', |
| 'video/mp4', |
| 'audio/ogg', |
| 'audio/ogg; codecs="vorbis"', |
| 'audio/ogg; codecs="opus"', |
| 'audio/webm', |
| 'audio/webm; codecs="vorbis"', |
| 'audio/webm; codecs="opus"', |
| 'video/webm', |
| 'video/webm; codecs="vp8"', |
| 'video/webm; codecs="vp8, vorbis"', |
| 'video/webm; codecs="vp8, opus"', |
| 'video/webm; codecs="vp9"', |
| 'video/webm; codecs="vp9, vorbis"', |
| 'video/webm; codecs="vp9, opus"', |
| 'video/webm; codecs="av1"', |
| 'video/webm; codecs="av1, opus"', |
| ]) { |
| if (MediaRecorder.isTypeSupported(mimeType)) { |
| test(t => { |
| const recorder = new MediaRecorder(new MediaStream(), {mimeType}); |
| assert_equals(recorder.mimeType, mimeType, "Supported mimeType is set"); |
| }, `Supported mimeType ${mimeType} is set immediately after constructing`); |
| } else { |
| test(t => { |
| assert_throws_dom("NotSupportedError", |
| () => new MediaRecorder(new MediaStream(), {mimeType})); |
| }, `Unsupported mimeType ${mimeType} throws`); |
| } |
| } |
| |
| promise_test(async t => { |
| const recorder = new MediaRecorder(createAudioStream(t)); |
| recorder.start(); |
| await new Promise(r => recorder.onstart = r); |
| assert_not_equals(recorder.mimeType, ""); |
| }, "MediaRecorder sets a nonempty mimeType on 'onstart' for audio"); |
| |
| promise_test(async t => { |
| const recorder = new MediaRecorder(createVideoStream(t)); |
| recorder.start(); |
| await new Promise(r => recorder.onstart = r); |
| assert_not_equals(recorder.mimeType, ""); |
| }, "MediaRecorder sets a nonempty mimeType on 'onstart' for video"); |
| |
| promise_test(async t => { |
| const recorder = new MediaRecorder(createAudioVideoStream(t)); |
| recorder.start(); |
| await new Promise(r => recorder.onstart = r); |
| assert_not_equals(recorder.mimeType, ""); |
| }, "MediaRecorder sets a nonempty mimeType on 'onstart' for audio/video"); |
| |
| promise_test(async t => { |
| const recorder = new MediaRecorder(createAudioStream(t)); |
| recorder.start(); |
| assert_equals(recorder.mimeType, ""); |
| }, "MediaRecorder mimeType is not set before 'onstart' for audio"); |
| |
| promise_test(async t => { |
| const recorder = new MediaRecorder(createVideoStream(t)); |
| recorder.start(); |
| assert_equals(recorder.mimeType, ""); |
| }, "MediaRecorder mimeType is not set before 'onstart' for video"); |
| |
| promise_test(async t => { |
| const recorder = new MediaRecorder(createAudioVideoStream(t)); |
| recorder.start(); |
| assert_equals(recorder.mimeType, ""); |
| }, "MediaRecorder mimeType is not set before 'onstart' for audio/video"); |
| |
| promise_test(async t => { |
| const recorder = new MediaRecorder(createAudioStream(t)); |
| const onstartPromise = new Promise(resolve => { |
| recorder.onstart = () => { |
| recorder.onstart = () => t.step_func(() => { |
| assert_not_reached("MediaRecorder doesn't fire 'onstart' twice"); |
| }); |
| resolve(); |
| } |
| }); |
| recorder.start(); |
| await onstartPromise; |
| await new Promise(r => t.step_timeout(r, 1000)); |
| }, "MediaRecorder doesn't fire 'onstart' multiple times for audio"); |
| |
| promise_test(async t => { |
| const recorder = new MediaRecorder(createVideoStream(t)); |
| const onstartPromise = new Promise(resolve => { |
| recorder.onstart = () => { |
| recorder.onstart = () => t.step_func(() => { |
| assert_not_reached("MediaRecorder doesn't fire 'onstart' twice"); |
| }); |
| resolve(); |
| } |
| }); |
| recorder.start(); |
| await onstartPromise; |
| await new Promise(r => t.step_timeout(r, 1000)); |
| }, "MediaRecorder doesn't fire 'onstart' multiple times for video"); |
| |
| promise_test(async t => { |
| const recorder = new MediaRecorder(createAudioVideoStream(t)); |
| const onstartPromise = new Promise(resolve => { |
| recorder.onstart = () => { |
| recorder.onstart = () => t.step_func(() => { |
| assert_not_reached("MediaRecorder doesn't fire 'onstart' twice"); |
| }); |
| resolve(); |
| } |
| }); |
| recorder.start(); |
| await onstartPromise; |
| await new Promise(r => t.step_timeout(r, 1000)); |
| }, "MediaRecorder doesn't fire 'onstart' multiple times for audio/video"); |
| |
| promise_test(async t => { |
| const recorder = new MediaRecorder(createAudioStream(t)); |
| recorder.start(); |
| await new Promise(r => recorder.onstart = r); |
| assert_regexp_match(recorder.mimeType, /^audio\//, |
| "mimeType has an expected media type"); |
| assert_regexp_match(recorder.mimeType, /^[a-z]+\/[a-z]+/, |
| "mimeType has a container subtype"); |
| assert_regexp_match( |
| recorder.mimeType, /^[a-z]+\/[a-z]+;[ ]*codecs=[^,]+$/, |
| "mimeType has one codec a"); |
| }, "MediaRecorder formats mimeType well after 'start' for audio"); |
| |
| promise_test(async t => { |
| const recorder = new MediaRecorder(createVideoStream(t)); |
| recorder.start(); |
| await new Promise(r => recorder.onstart = r); |
| assert_regexp_match(recorder.mimeType, /^video\//, |
| "mimeType has an expected media type"); |
| assert_regexp_match(recorder.mimeType, /^[a-z]+\/[a-z]+/, |
| "mimeType has a container subtype"); |
| assert_regexp_match( |
| recorder.mimeType, /^[a-z]+\/[a-z]+;[ ]*codecs=[^,]+$/, |
| "mimeType has one codec a"); |
| }, "MediaRecorder formats mimeType well after 'start' for video"); |
| |
| promise_test(async t => { |
| const recorder = new MediaRecorder(createAudioVideoStream(t)); |
| recorder.start(); |
| await new Promise(r => recorder.onstart = r); |
| assert_regexp_match(recorder.mimeType, /^video\//, |
| "mimeType has an expected media type"); |
| assert_regexp_match(recorder.mimeType, /^[a-z]+\/[a-z]+/, |
| "mimeType has a container subtype"); |
| assert_regexp_match( |
| recorder.mimeType, /^[a-z]+\/[a-z]+;[ ]*codecs=[^,]+,[^,]+$/, |
| "mimeType has two codecs"); |
| }, "MediaRecorder formats mimeType well after 'start' for audio/video"); |
| </script> |
| </body> |
| </html> |