summaryrefslogtreecommitdiffstats
path: root/dom/media/test/test_bug1431810_opus_downmix_to_mono.html
blob: 647ddf04896418fba5307e5f71f99a1a5ae76b1d (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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
<!DOCTYPE HTML>
<html>
<head>
  <title>Media test: disable phase inversion in opus decoder</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<audio preload=none id="a" controls></audio>
<audio preload=none id="b" controls></audio>
<script class="testbody" type="text/javascript">
/*
  This test makes use of an (stereo) opus file with phase inversion of 180 degrees (right = -left => right + left = 0).
  Firstly, the phase inversion is verified on a normal stereo playback.
  Secondly, mono playback is forced which results in the phase inversion being disabled (Bug 1431810).
*/
SimpleTest.waitForExplicitFinish();

/* global a, b */

function areChannelsInverted(b1, b2) {
  for (var i = 0; i < b1.length; i++) {
    if (Math.abs(b1[i] + b2[i]) > 9e-2) {
      return false;
    }
  }
  return true;
}

function areChannelsEqual(b1, b2) {
  for (var i = 0; i < b1.length; i++) {
    if (Math.abs(b1[i] - b2[i]) > 9e-3) {
      return false;
    }
  }
  return true;
}

function isSilent(b) {
  for (var i = 0; i < b.length; i++) {
    if (b[i] != 0.0) {
      return false;
    }
  }
  return true;
}

function mediaElementWithPhaseInversion(audioContext, mediaElement, success) {
  let audio_source = audioContext.createMediaElementSource(mediaElement);
  let script_processor = audioContext.createScriptProcessor();
  audio_source.connect(script_processor);

  mediaElement.onplay = () => {
    script_processor.onaudioprocess = (e) => {
      let right = e.inputBuffer.getChannelData(0);
      let left = e.inputBuffer.getChannelData(1);

      // This is leading or trailing silence
      // produced by ScriptProcessor.
      if (isSilent(right) && isSilent(left)) {
        return;
      }

      ok(areChannelsInverted(right, left), "Channels must be inverted");
    }
  }

  mediaElement.onended = () => {
    ok(true, "End of file.");
    mediaElement.onended = null;
    script_processor.onaudioprocess = null;
    success();
  }

  mediaElement.src = "test-stereo-phase-inversion-180.opus";
  // Normal playback channels will by inverted
  mediaElement.play();
}

function mediaElementWithPhaseInversionDisabled(audioContext, mediaElement, success) {
  let audio_source = audioContext.createMediaElementSource(mediaElement);
  let script_processor = audioContext.createScriptProcessor();
  audio_source.connect(script_processor);

  mediaElement.onplay = () => {
    script_processor.onaudioprocess = (e) => {
      let right = e.inputBuffer.getChannelData(0);
      let left = e.inputBuffer.getChannelData(1);

      // This is leading or trailing silence
      // produced by ScriptProcessor.
      if (isSilent(right) && isSilent(left)) {
        return;
      }

      ok(!areChannelsInverted(right, left), "Channels must not be inverted");
      ok(areChannelsEqual(right, left), "Channels must be equal");
    }
  }

  mediaElement.onended = () => {
    ok(true, "End of file.");
    mediaElement.onended = null;
    script_processor.onaudioprocess = null;
    success();
  }

  mediaElement.src = "test-stereo-phase-inversion-180.opus";

  // Downmix to mono will force to disable opus phase inversion
  SpecialPowers.pushPrefEnv({"set": [["accessibility.monoaudio.enable", true]]})
  .then(() => {
    mediaElement.play();
  });
}

let ac = new AudioContext();

function testPhaseInversion(mediaElement) {
  return new Promise((accept, reject) => {
    mediaElementWithPhaseInversion(ac, a, accept);
  });
}

function testPhaseInversionDisabled(mediaElement) {
  return new Promise((accept, reject) => {
    mediaElementWithPhaseInversionDisabled(ac, b, accept);
  });
}

// Start testing
testPhaseInversion(a)
.then( () => testPhaseInversionDisabled(b) )
.then( () => SimpleTest.finish() )

</script>
</pre>
</body>
</html>