summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webcodecs/audio-encoder-codec-specific.https.any.js
blob: 28c75d2a606679f605a7063aeeed57134c3f65fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// 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.');