362 lines
8.2 KiB
JavaScript
362 lines
8.2 KiB
JavaScript
// META: global=window,dedicatedworker
|
|
// META: script=/webcodecs/utils.js
|
|
|
|
const invalidConfigs = [
|
|
{
|
|
comment: 'Missing codec',
|
|
config: {
|
|
sampleRate: 48000,
|
|
numberOfChannels: 2,
|
|
},
|
|
},
|
|
{
|
|
comment: 'Empty codec',
|
|
config: {
|
|
codec: '',
|
|
sampleRate: 48000,
|
|
numberOfChannels: 2,
|
|
},
|
|
},
|
|
{
|
|
comment: 'Missing sampleRate',
|
|
config: {
|
|
codec: 'opus',
|
|
sampleRate: 48000,
|
|
},
|
|
},
|
|
{
|
|
comment: 'Missing numberOfChannels',
|
|
config: {
|
|
codec: 'opus',
|
|
sampleRate: 48000,
|
|
},
|
|
},
|
|
{
|
|
comment: 'Zero sampleRate',
|
|
config: {
|
|
codec: 'opus',
|
|
sampleRate: 0,
|
|
numberOfChannels: 2,
|
|
},
|
|
},
|
|
{
|
|
comment: 'Zero channels',
|
|
config: {
|
|
codec: 'opus',
|
|
sampleRate: 8000,
|
|
numberOfChannels: 0,
|
|
},
|
|
},
|
|
{
|
|
comment: 'Bit rate too big',
|
|
config: {
|
|
codec: 'opus',
|
|
sampleRate: 8000,
|
|
numberOfChannels: 2,
|
|
bitrate: 6e9,
|
|
},
|
|
},
|
|
{
|
|
comment: 'Bit rate present but equal to zero',
|
|
config: {
|
|
codec: 'opus',
|
|
sampleRate: 8000,
|
|
numberOfChannels: 2,
|
|
bitrate: 0,
|
|
},
|
|
},
|
|
{
|
|
comment: 'Opus complexity too big',
|
|
config: {
|
|
codec: 'opus',
|
|
sampleRate: 8000,
|
|
numberOfChannels: 2,
|
|
opus: {
|
|
complexity: 11,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
comment: 'Opus packetlossperc too big',
|
|
config: {
|
|
codec: 'opus',
|
|
sampleRate: 8000,
|
|
numberOfChannels: 2,
|
|
opus: {
|
|
packetlossperc: 101,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
comment: 'Opus frame duration too small',
|
|
config: {
|
|
codec: 'opus',
|
|
sampleRate: 8000,
|
|
numberOfChannels: 2,
|
|
opus: {
|
|
frameDuration: 0,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
comment: 'Opus frame duration too big',
|
|
config: {
|
|
codec: 'opus',
|
|
sampleRate: 8000,
|
|
numberOfChannels: 2,
|
|
opus: {
|
|
frameDuration: 120 * 1000 + 1,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
comment: 'Invalid Opus frameDuration',
|
|
config: {
|
|
codec: 'opus',
|
|
sampleRate: 8000,
|
|
numberOfChannels: 2,
|
|
opus: {
|
|
frameDuration: 2501,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
comment: 'Bitrate is too low for Opus',
|
|
config: {
|
|
codec: 'opus',
|
|
sampleRate: 48000,
|
|
numberOfChannels: 2,
|
|
bitrate: 1,
|
|
},
|
|
},
|
|
];
|
|
|
|
invalidConfigs.forEach(entry => {
|
|
promise_test(
|
|
t => {
|
|
return promise_rejects_js(
|
|
t, TypeError, AudioEncoder.isConfigSupported(entry.config));
|
|
},
|
|
'Test that AudioEncoder.isConfigSupported() rejects invalid config: ' +
|
|
entry.comment);
|
|
});
|
|
|
|
invalidConfigs.forEach(entry => {
|
|
async_test(
|
|
t => {
|
|
let codec = new AudioEncoder(getDefaultCodecInit(t));
|
|
assert_throws_js(TypeError, () => {
|
|
codec.configure(entry.config);
|
|
});
|
|
t.done();
|
|
},
|
|
'Test that AudioEncoder.configure() rejects invalid config: ' +
|
|
entry.comment);
|
|
});
|
|
|
|
const validButUnsupportedConfigs = [
|
|
{
|
|
comment: 'Unrecognized codec',
|
|
config: {
|
|
codec: 'bogus',
|
|
sampleRate: 48000,
|
|
numberOfChannels: 2,
|
|
},
|
|
},
|
|
{
|
|
comment: 'Sample rate is too small',
|
|
config: {
|
|
codec: 'opus',
|
|
sampleRate: 1,
|
|
numberOfChannels: 2,
|
|
},
|
|
},
|
|
{
|
|
comment: 'Sample rate is too large',
|
|
config: {
|
|
codec: 'opus',
|
|
sampleRate: 10000000,
|
|
numberOfChannels: 2,
|
|
},
|
|
},
|
|
{
|
|
comment: 'Way too many channels',
|
|
config: {
|
|
codec: 'opus',
|
|
sampleRate: 8000,
|
|
numberOfChannels: 1024,
|
|
bitrate: 128000,
|
|
},
|
|
},
|
|
{
|
|
comment: 'Possible future opus codec string',
|
|
config: {
|
|
codec: 'opus.123',
|
|
sampleRate: 48000,
|
|
numberOfChannels: 2,
|
|
}
|
|
},
|
|
{
|
|
comment: 'Possible future aac codec string',
|
|
config: {
|
|
codec: 'mp4a.FF.9',
|
|
sampleRate: 48000,
|
|
numberOfChannels: 2,
|
|
}
|
|
},
|
|
{
|
|
comment: 'codec with spaces',
|
|
config: {
|
|
codec: ' opus ',
|
|
sampleRate: 48000,
|
|
numberOfChannels: 2,
|
|
}
|
|
},
|
|
];
|
|
|
|
validButUnsupportedConfigs.forEach(entry => {
|
|
promise_test(
|
|
async t => {
|
|
let support = await AudioEncoder.isConfigSupported(entry.config);
|
|
assert_false(support.supported);
|
|
|
|
let config = support.config;
|
|
assert_equals(config.codec, entry.config.codec);
|
|
assert_equals(config.sampleRate, entry.config.sampleRate);
|
|
assert_equals(config.numberOfChannels, entry.config.numberOfChannels);
|
|
},
|
|
'Test that AudioEncoder.isConfigSupported() doesn\'t support config: ' +
|
|
entry.comment);
|
|
});
|
|
|
|
validButUnsupportedConfigs.forEach(entry => {
|
|
promise_test(
|
|
t => {
|
|
let isErrorCallbackCalled = false;
|
|
let codec = new AudioEncoder({
|
|
output: t.unreached_func('unexpected output'),
|
|
error: t.step_func_done(e => {
|
|
isErrorCallbackCalled = true;
|
|
assert_true(e instanceof DOMException);
|
|
assert_equals(e.name, 'NotSupportedError');
|
|
assert_equals(codec.state, 'closed', 'state');
|
|
})
|
|
});
|
|
codec.configure(entry.config);
|
|
return codec.flush()
|
|
.then(t.unreached_func('flush succeeded unexpectedly'))
|
|
.catch(t.step_func(e => {
|
|
assert_true(isErrorCallbackCalled, "isErrorCallbackCalled");
|
|
assert_true(e instanceof DOMException);
|
|
assert_equals(e.name, 'NotSupportedError');
|
|
assert_equals(codec.state, 'closed', 'state');
|
|
}));
|
|
},
|
|
'Test that AudioEncoder.configure() doesn\'t support config: ' +
|
|
entry.comment);
|
|
});
|
|
|
|
const validConfigs = [
|
|
{
|
|
codec: 'opus',
|
|
sampleRate: 8000,
|
|
numberOfChannels: 1,
|
|
},
|
|
{
|
|
codec: 'opus',
|
|
sampleRate: 48000,
|
|
numberOfChannels: 2,
|
|
},
|
|
{
|
|
codec: 'opus',
|
|
sampleRate: 48000,
|
|
numberOfChannels: 2,
|
|
bitrate: 128000,
|
|
bitrateMode: "constant",
|
|
bogus: 123
|
|
},
|
|
{
|
|
codec: 'opus',
|
|
sampleRate: 48000,
|
|
numberOfChannels: 2,
|
|
bitrate: 128000,
|
|
bitrateMode: "variable",
|
|
bogus: 123
|
|
},
|
|
{
|
|
codec: 'opus',
|
|
sampleRate: 48000,
|
|
numberOfChannels: 2,
|
|
opus: {
|
|
complexity: 5,
|
|
signal: 'music',
|
|
application: 'audio',
|
|
frameDuration: 20000,
|
|
packetlossperc: 10,
|
|
useinbandfec: true,
|
|
},
|
|
},
|
|
{
|
|
codec: 'opus',
|
|
sampleRate: 48000,
|
|
numberOfChannels: 2,
|
|
opus: {
|
|
format: 'opus',
|
|
signal: 'voice',
|
|
application: 'lowdelay',
|
|
complexity: 10,
|
|
frameDuration: 60000,
|
|
packetlossperc: 20, // Irrelevant without useinbandfec, but still valid.
|
|
usedtx: true,
|
|
bogus: 456,
|
|
},
|
|
},
|
|
{
|
|
codec: 'opus',
|
|
sampleRate: 48000,
|
|
numberOfChannels: 2,
|
|
opus: {}, // Use default values.
|
|
},
|
|
];
|
|
|
|
validConfigs.forEach(config => {
|
|
promise_test(async t => {
|
|
let support = await AudioEncoder.isConfigSupported(config);
|
|
assert_true(support.supported);
|
|
|
|
let new_config = support.config;
|
|
assert_equals(new_config.codec, config.codec);
|
|
assert_equals(new_config.sampleRate, config.sampleRate);
|
|
assert_equals(new_config.numberOfChannels, config.numberOfChannels);
|
|
if (config.bitrate)
|
|
assert_equals(new_config.bitrate, config.bitrate);
|
|
|
|
if (config.opus) {
|
|
let opus_config = config.opus;
|
|
let new_opus_config = new_config.opus;
|
|
|
|
assert_equals(new_opus_config.format, opus_config.format ?? 'opus');
|
|
assert_equals(
|
|
new_opus_config.frameDuration, opus_config.frameDuration ?? 20000);
|
|
assert_equals(
|
|
new_opus_config.packetlossperc, opus_config.packetlossperc ?? 0);
|
|
assert_equals(
|
|
new_opus_config.useinbandfec, opus_config.useinbandfec ?? false);
|
|
assert_equals(new_opus_config.usedtx, opus_config.usedtx ?? false);
|
|
assert_false(new_opus_config.hasOwnProperty('bogus'));
|
|
|
|
if (opus_config.complexity) {
|
|
assert_equals(new_opus_config.complexity, opus_config.complexity);
|
|
} else {
|
|
// Default complexity is 5 for mobile/ARM platforms, and 9 otherwise.
|
|
assert_true(
|
|
new_opus_config.complexity == 5 || new_opus_config.complexity == 9);
|
|
}
|
|
|
|
} else {
|
|
assert_false(new_config.hasOwnProperty('opus'));
|
|
}
|
|
|
|
assert_false(new_config.hasOwnProperty('bogus'));
|
|
}, 'AudioEncoder.isConfigSupported() supports: ' + JSON.stringify(config));
|
|
});
|