| // META: global=window |
| // META: script=/webcodecs/utils.js |
| |
| function make_silent_audio_data(timestamp, channels, sampleRate, frames) { |
| let data = new Float32Array(frames*channels); |
| |
| return new AudioData({ |
| timestamp: timestamp, |
| data: data, |
| numberOfChannels: channels, |
| numberOfFrames: frames, |
| sampleRate: sampleRate, |
| format: "f32-planar", |
| }); |
| } |
| |
| // The Opus DTX flag (discontinuous transmission) reduces the encoding bitrate |
| // for silence. This test ensures the DTX flag is working properly by encoding |
| // almost 10s of silence and comparing the bitrate with and without the flag. |
| promise_test(async t => { |
| let sample_rate = 48000; |
| let total_duration_s = 10; |
| let data_count = 100; |
| let normal_outputs = []; |
| let dtx_outputs = []; |
| |
| let normal_encoder = new AudioEncoder({ |
| error: e => { |
| assert_unreached('error: ' + e); |
| }, |
| output: chunk => { |
| normal_outputs.push(chunk); |
| } |
| }); |
| |
| let dtx_encoder = new AudioEncoder({ |
| error: e => { |
| assert_unreached('error: ' + e); |
| }, |
| output: chunk => { |
| dtx_outputs.push(chunk); |
| } |
| }); |
| |
| let config = { |
| codec: 'opus', |
| sampleRate: sample_rate, |
| numberOfChannels: 2, |
| bitrate: 256000, // 256kbit |
| }; |
| |
| let normal_config = {...config, opus: {usedtx: false}}; |
| let dtx_config = {...config, opus: {usedtx: true}}; |
| |
| let normal_config_support = await AudioEncoder.isConfigSupported(normal_config); |
| assert_implements_optional(normal_config_support.supported, "Opus not supported"); |
| |
| let dtx_config_support = await AudioEncoder.isConfigSupported(dtx_config); |
| assert_implements_optional(dtx_config_support.supported, "Opus DTX not supported"); |
| |
| // Configure one encoder with and one without the DTX flag |
| normal_encoder.configure(normal_config); |
| dtx_encoder.configure(dtx_config); |
| |
| let timestamp_us = 0; |
| let data_duration_s = total_duration_s / data_count; |
| let data_length = data_duration_s * config.sampleRate; |
| for (let i = 0; i < data_count; i++) { |
| let data; |
| |
| if (i == 0 || i == (data_count - 1)) { |
| // Send real data for the first and last 100ms. |
| data = make_audio_data( |
| timestamp_us, config.numberOfChannels, config.sampleRate, |
| data_length); |
| |
| } else { |
| // Send silence for the rest of the 10s. |
| data = make_silent_audio_data( |
| timestamp_us, config.numberOfChannels, config.sampleRate, |
| data_length); |
| } |
| |
| normal_encoder.encode(data); |
| dtx_encoder.encode(data); |
| data.close(); |
| |
| timestamp_us += data_duration_s * 1_000_000; |
| } |
| |
| await Promise.all([normal_encoder.flush(), dtx_encoder.flush()]) |
| |
| normal_encoder.close(); |
| dtx_encoder.close(); |
| |
| // We expect a significant reduction in the number of packets, over ~10s of silence. |
| assert_less_than(dtx_outputs.length, (normal_outputs.length / 2)); |
| }, 'Test the Opus DTX flag works.'); |