mediasource-webcodecs-addsourcebuffer.html (6753B)
1 <!DOCTYPE html> 2 <html> 3 <title>Test MediaSource addSourceBuffer overloads for WebCodecs Audio/VideoDecoderConfigs</title> 4 <script src="/resources/testharness.js"></script> 5 <script src="/resources/testharnessreport.js"></script> 6 <script> 7 8 setup(() => { 9 assert_implements( 10 SourceBuffer.prototype.hasOwnProperty('appendEncodedChunks'), 11 'SourceBuffer prototype hasOwnProperty "appendEncodedChunks", used ' + 12 'here to feature detect MSE-for-WebCodecs implementation.'); 13 }); 14 15 testInvalidArguments(); 16 testValidArguments(); 17 18 function getValidAudioConfig() { 19 // TODO(crbug.com/1144908): Consider confirming with WebCodecs' 20 // isConfigSupported() once that API is available. 21 return { 22 codec: 'opus', 23 sampleRate: 48000, 24 numberOfChannels: 2 25 }; 26 } 27 28 function getValidVideoConfig() { 29 // TODO(crbug.com/1144908): Consider confirming with WebCodecs' 30 // isConfigSupported() once that API is available. 31 return { codec: 'vp09.00.10.08' }; 32 } 33 34 function testInvalidArguments() { 35 const INVALID_CASES = [ 36 { arg: null, 37 name: 'null' }, 38 { arg: undefined, 39 name: 'undefined' }, 40 { arg: { }, 41 name: '{ empty dictionary }' }, 42 { 43 arg: { 44 audioConfig: getValidAudioConfig(), 45 videoConfig: getValidVideoConfig() 46 }, 47 name: '{ valid audioConfig and videoConfig }', 48 }, 49 { arg: { audioConfig: { sampleRate: 48000, numberOfChannels: 2 } }, 50 name: 'audio config missing required member "codec"' }, 51 { arg: { videoConfig: { } }, 52 name: 'video config missing required member "codec"' }, 53 ]; 54 55 [ 'closed', 'open', 'ended' ].forEach(readyStateScenario => { 56 INVALID_CASES.forEach(invalidCase => { 57 runAddSourceBufferTest(invalidCase['arg'] /* argument */, 58 false /* isValidArgument */, 59 invalidCase['name'] /* argumentDescription */, 60 readyStateScenario); 61 }); 62 }); 63 } 64 65 function testValidArguments() { 66 const VALID_CASES = [ 67 { 68 arg: { 69 audioConfig: getValidAudioConfig() 70 }, 71 name: 'valid audioConfig' 72 }, 73 { 74 arg: { 75 videoConfig: getValidVideoConfig() 76 }, 77 name: 'valid videoConfig' 78 }, 79 ]; 80 81 [ 'closed', 'open', 'ended' ].forEach(readyStateScenario => { 82 VALID_CASES.forEach(validCase => { 83 runAddSourceBufferTest( 84 validCase['arg'] /* argument */, 85 true /* isValidArgument */, 86 validCase['name'] /* argumentDescription */, 87 readyStateScenario); 88 }); 89 }); 90 } 91 92 async function getClosedMediaSource(test) { 93 let mediaSource = new MediaSource(); 94 assert_equals(mediaSource.readyState, 'closed'); 95 return mediaSource; 96 } 97 98 async function getOpenMediaSource(test) { 99 return new Promise(async resolve => { 100 const v = document.createElement('video'); 101 const mediaSource = new MediaSource(); 102 const url = URL.createObjectURL(mediaSource); 103 mediaSource.addEventListener('sourceopen', test.step_func(() => { 104 URL.revokeObjectURL(url); 105 assert_equals(mediaSource.readyState, 'open', 'MediaSource is open'); 106 resolve(mediaSource); 107 }), { once: true }); 108 v.src = url; 109 }); 110 } 111 112 async function getEndedMediaSource(test) { 113 let mediaSource = await getOpenMediaSource(test); 114 assert_equals(mediaSource.readyState, 'open', 'MediaSource is open'); 115 mediaSource.endOfStream(); 116 assert_equals(mediaSource.readyState, 'ended', 'MediaSource is ended'); 117 return mediaSource; 118 } 119 120 function runAddSourceBufferTest(argument, isValidArgument, argumentDescription, readyStateScenario) { 121 const testDescription = 'addSourceBuffer call with ' + 122 (isValidArgument ? 'valid' : 'invalid') + 123 ' argument ' + argumentDescription + ' while MediaSource readyState is ' + 124 readyStateScenario; 125 126 switch(readyStateScenario) { 127 case 'closed': 128 promise_test(async t => { 129 let mediaSource = await getClosedMediaSource(t); 130 assert_equals(mediaSource.readyState, 'closed'); 131 let sourceBuffer; 132 if (isValidArgument) { 133 assert_throws_dom('InvalidStateError', 134 () => { sourceBuffer = mediaSource.addSourceBuffer(argument); }, 135 'addSourceBuffer(valid config) throws InvalidStateError if MediaSource is "closed"'); 136 assert_equals(sourceBuffer, undefined, 137 'addSourceBuffer result for valid config while "closed" should be exception'); 138 } else { 139 assert_throws_js(TypeError, 140 () => { sourceBuffer = mediaSource.addSourceBuffer(argument); }, 141 'addSourceBuffer(invalid config) throws TypeError if MediaSource is "closed"'); 142 assert_equals(sourceBuffer, undefined, 143 'addSourceBuffer result for invalid config while "closed" should be exception'); 144 } 145 }, testDescription); 146 break; 147 case 'open': 148 promise_test(async t => { 149 let mediaSource = await getOpenMediaSource(t); 150 assert_equals(mediaSource.readyState, 'open', 'MediaSource is open'); 151 let sourceBuffer; 152 if (isValidArgument) { 153 sourceBuffer = mediaSource.addSourceBuffer(argument); 154 assert_true(sourceBuffer instanceof SourceBuffer, 155 'addSourceBuffer result for valid config while "open" should be a SourceBuffer instance'); 156 } else { 157 assert_throws_js(TypeError, 158 () => { sourceBuffer = mediaSource.addSourceBuffer(argument); }, 159 'addSourceBuffer(invalid config) throws TypeError if MediaSource is "open"'); 160 assert_equals(sourceBuffer, undefined, 161 'addSourceBufferResult for invalid config while "open" should be exception'); 162 } 163 }, testDescription); 164 break; 165 case 'ended': 166 promise_test(async t => { 167 let mediaSource = await getEndedMediaSource(t); 168 let sourceBuffer; 169 if (isValidArgument) { 170 assert_throws_dom('InvalidStateError', 171 () => { sourceBuffer = mediaSource.addSourceBuffer(argument); }, 172 'addSourceBuffer(valid config) throws InvalidStateError if MediaSource is "ended"'); 173 assert_equals(sourceBuffer, undefined, 174 'addSourceBuffer result for valid config while "ended" should be exception'); 175 } else { 176 assert_throws_js(TypeError, 177 () => { sourceBuffer = mediaSource.addSourceBuffer(argument); }, 178 'addSourceBuffer(invalid config) throws TypeError if MediaSource is "ended"'); 179 assert_equals(sourceBuffer, undefined, 180 'addSourceBuffer result for invalid config while "ended" should be exception'); 181 } 182 }, testDescription); 183 break; 184 default: 185 assert_unreached('Invalid readyStateScenario ' + readyStateScenario); 186 break; 187 } 188 } 189 190 </script> 191 </html>