audio-encoder-config.https.any.js (8687B)
1 // META: global=window,dedicatedworker 2 // META: script=/webcodecs/utils.js 3 4 const invalidConfigs = [ 5 { 6 comment: 'Missing codec', 7 config: { 8 sampleRate: 48000, 9 numberOfChannels: 2, 10 }, 11 }, 12 { 13 comment: 'Empty codec', 14 config: { 15 codec: '', 16 sampleRate: 48000, 17 numberOfChannels: 2, 18 }, 19 }, 20 { 21 comment: 'Missing sampleRate', 22 config: { 23 codec: 'opus', 24 sampleRate: 48000, 25 }, 26 }, 27 { 28 comment: 'Missing numberOfChannels', 29 config: { 30 codec: 'opus', 31 sampleRate: 48000, 32 }, 33 }, 34 { 35 comment: 'Zero sampleRate', 36 config: { 37 codec: 'opus', 38 sampleRate: 0, 39 numberOfChannels: 2, 40 }, 41 }, 42 { 43 comment: 'Zero channels', 44 config: { 45 codec: 'opus', 46 sampleRate: 8000, 47 numberOfChannels: 0, 48 }, 49 }, 50 { 51 comment: 'Bit rate too big', 52 config: { 53 codec: 'opus', 54 sampleRate: 8000, 55 numberOfChannels: 2, 56 bitrate: 6e9, 57 }, 58 }, 59 { 60 comment: 'Bit rate present but equal to zero', 61 config: { 62 codec: 'opus', 63 sampleRate: 8000, 64 numberOfChannels: 2, 65 bitrate: 0, 66 }, 67 }, 68 { 69 comment: 'Opus complexity too big', 70 config: { 71 codec: 'opus', 72 sampleRate: 8000, 73 numberOfChannels: 2, 74 opus: { 75 complexity: 11, 76 }, 77 }, 78 }, 79 { 80 comment: 'Opus packetlossperc too big', 81 config: { 82 codec: 'opus', 83 sampleRate: 8000, 84 numberOfChannels: 2, 85 opus: { 86 packetlossperc: 101, 87 }, 88 }, 89 }, 90 { 91 comment: 'Opus frame duration too small', 92 config: { 93 codec: 'opus', 94 sampleRate: 8000, 95 numberOfChannels: 2, 96 opus: { 97 frameDuration: 0, 98 }, 99 }, 100 }, 101 { 102 comment: 'Opus frame duration too big', 103 config: { 104 codec: 'opus', 105 sampleRate: 8000, 106 numberOfChannels: 2, 107 opus: { 108 frameDuration: 120 * 1000 + 1, 109 }, 110 }, 111 }, 112 { 113 comment: 'Invalid Opus frameDuration', 114 config: { 115 codec: 'opus', 116 sampleRate: 8000, 117 numberOfChannels: 2, 118 opus: { 119 frameDuration: 2501, 120 }, 121 }, 122 }, 123 { 124 comment: 'Bitrate is too low for Opus', 125 config: { 126 codec: 'opus', 127 sampleRate: 48000, 128 numberOfChannels: 2, 129 bitrate: 1, 130 }, 131 }, 132 ]; 133 134 invalidConfigs.forEach(entry => { 135 promise_test( 136 t => { 137 return promise_rejects_js( 138 t, TypeError, AudioEncoder.isConfigSupported(entry.config)); 139 }, 140 'Test that AudioEncoder.isConfigSupported() rejects invalid config: ' + 141 entry.comment); 142 }); 143 144 invalidConfigs.forEach(entry => { 145 async_test( 146 t => { 147 let codec = new AudioEncoder(getDefaultCodecInit(t)); 148 assert_throws_js(TypeError, () => { 149 codec.configure(entry.config); 150 }); 151 t.done(); 152 }, 153 'Test that AudioEncoder.configure() rejects invalid config: ' + 154 entry.comment); 155 }); 156 157 const validButUnsupportedConfigs = [ 158 { 159 comment: 'Unrecognized codec', 160 config: { 161 codec: 'bogus', 162 sampleRate: 48000, 163 numberOfChannels: 2, 164 }, 165 }, 166 { 167 comment: 'Sample rate is too small', 168 config: { 169 codec: 'opus', 170 sampleRate: 1, 171 numberOfChannels: 2, 172 }, 173 }, 174 { 175 comment: 'Sample rate is too large', 176 config: { 177 codec: 'opus', 178 sampleRate: 10000000, 179 numberOfChannels: 2, 180 }, 181 }, 182 { 183 comment: 'Way too many channels', 184 config: { 185 codec: 'opus', 186 sampleRate: 8000, 187 numberOfChannels: 1024, 188 bitrate: 128000, 189 }, 190 }, 191 { 192 comment: 'Possible future opus codec string', 193 config: { 194 codec: 'opus.123', 195 sampleRate: 48000, 196 numberOfChannels: 2, 197 } 198 }, 199 { 200 comment: 'Possible future aac codec string', 201 config: { 202 codec: 'mp4a.FF.9', 203 sampleRate: 48000, 204 numberOfChannels: 2, 205 } 206 }, 207 { 208 comment: 'codec with spaces', 209 config: { 210 codec: ' opus ', 211 sampleRate: 48000, 212 numberOfChannels: 2, 213 } 214 }, 215 ]; 216 217 validButUnsupportedConfigs.forEach(entry => { 218 promise_test( 219 async t => { 220 let support = await AudioEncoder.isConfigSupported(entry.config); 221 assert_false(support.supported); 222 223 let config = support.config; 224 assert_equals(config.codec, entry.config.codec); 225 assert_equals(config.sampleRate, entry.config.sampleRate); 226 assert_equals(config.numberOfChannels, entry.config.numberOfChannels); 227 }, 228 'Test that AudioEncoder.isConfigSupported() doesn\'t support config: ' + 229 entry.comment); 230 }); 231 232 validButUnsupportedConfigs.forEach(entry => { 233 promise_test( 234 t => { 235 let isErrorCallbackCalled = false; 236 let codec = new AudioEncoder({ 237 output: t.unreached_func('unexpected output'), 238 error: t.step_func_done(e => { 239 isErrorCallbackCalled = true; 240 assert_true(e instanceof DOMException); 241 assert_equals(e.name, 'NotSupportedError'); 242 assert_equals(codec.state, 'closed', 'state'); 243 }) 244 }); 245 codec.configure(entry.config); 246 return codec.flush() 247 .then(t.unreached_func('flush succeeded unexpectedly')) 248 .catch(t.step_func(e => { 249 assert_true(isErrorCallbackCalled, "isErrorCallbackCalled"); 250 assert_true(e instanceof DOMException); 251 assert_equals(e.name, 'NotSupportedError'); 252 assert_equals(codec.state, 'closed', 'state'); 253 })); 254 }, 255 'Test that AudioEncoder.configure() doesn\'t support config: ' + 256 entry.comment); 257 }); 258 259 const validConfigs = [ 260 { 261 codec: 'opus', 262 sampleRate: 8000, 263 numberOfChannels: 1, 264 }, 265 { 266 codec: 'opus', 267 sampleRate: 48000, 268 numberOfChannels: 2, 269 }, 270 { 271 codec: 'opus', 272 sampleRate: 48000, 273 numberOfChannels: 2, 274 bitrate: 128000, 275 bitrateMode: "constant", 276 bogus: 123 277 }, 278 { 279 codec: 'opus', 280 sampleRate: 48000, 281 numberOfChannels: 2, 282 bitrate: 128000, 283 bitrateMode: "variable", 284 bogus: 123 285 }, 286 { 287 codec: 'opus', 288 sampleRate: 48000, 289 numberOfChannels: 2, 290 opus: { 291 complexity: 5, 292 signal: 'music', 293 application: 'audio', 294 frameDuration: 20000, 295 packetlossperc: 10, 296 useinbandfec: true, 297 }, 298 }, 299 { 300 codec: 'opus', 301 sampleRate: 48000, 302 numberOfChannels: 2, 303 opus: { 304 format: 'opus', 305 signal: 'voice', 306 application: 'lowdelay', 307 complexity: 10, 308 frameDuration: 60000, 309 packetlossperc: 20, // Irrelevant without useinbandfec, but still valid. 310 usedtx: true, 311 bogus: 456, 312 }, 313 }, 314 { 315 codec: 'opus', 316 sampleRate: 48000, 317 numberOfChannels: 2, 318 opus: {}, // Use default values. 319 }, 320 { 321 codec: 'opus', 322 sampleRate: 48000, 323 numberOfChannels: 2, 324 opus: { 325 frameDuration: 7500, // Test multiples of valid Opus frame durations. 326 } 327 }, 328 { 329 codec: 'opus', 330 sampleRate: 48000, 331 numberOfChannels: 2, 332 opus: { 333 frameDuration: 120000, 334 } 335 }, 336 ]; 337 338 validConfigs.forEach(config => { 339 promise_test(async t => { 340 let support = await AudioEncoder.isConfigSupported(config); 341 assert_true(support.supported); 342 343 let new_config = support.config; 344 assert_equals(new_config.codec, config.codec); 345 assert_equals(new_config.sampleRate, config.sampleRate); 346 assert_equals(new_config.numberOfChannels, config.numberOfChannels); 347 if (config.bitrate) 348 assert_equals(new_config.bitrate, config.bitrate); 349 350 if (config.opus) { 351 let opus_config = config.opus; 352 let new_opus_config = new_config.opus; 353 354 assert_equals(new_opus_config.format, opus_config.format ?? 'opus'); 355 assert_equals( 356 new_opus_config.frameDuration, opus_config.frameDuration ?? 20000); 357 assert_equals( 358 new_opus_config.packetlossperc, opus_config.packetlossperc ?? 0); 359 assert_equals( 360 new_opus_config.useinbandfec, opus_config.useinbandfec ?? false); 361 assert_equals(new_opus_config.usedtx, opus_config.usedtx ?? false); 362 assert_false(new_opus_config.hasOwnProperty('bogus')); 363 364 if (opus_config.complexity) { 365 assert_equals(new_opus_config.complexity, opus_config.complexity); 366 } else { 367 // Default complexity is 5 for mobile/ARM platforms, and 9 otherwise. 368 assert_true( 369 new_opus_config.complexity == 5 || new_opus_config.complexity == 9); 370 } 371 372 } else { 373 assert_false(new_config.hasOwnProperty('opus')); 374 } 375 376 assert_false(new_config.hasOwnProperty('bogus')); 377 }, 'AudioEncoder.isConfigSupported() supports: ' + JSON.stringify(config)); 378 });