summaryrefslogtreecommitdiffstats
path: root/dom/media/webaudio/test/test_mediaElementAudioSourceNodeFidelity.html
blob: 42d6d6a045d7c9c1a9ba17562e08c2fb680f288d (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
<!DOCTYPE HTML>
<html>
<meta charset="utf-8">
<head>
  <title>Test MediaStreamAudioSourceNode doesn't get data from cross-origin media resources</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();

function binIndexForFrequency(frequency, analyser) {
  return 1 + Math.round(frequency *
                        analyser.fftSize /
                        analyser.context.sampleRate);
}

function debugCanvas(analyser) {
  var cvs = document.createElement("canvas");
  document.body.appendChild(cvs);

  // Easy: 1px per bin
  cvs.width = analyser.frequencyBinCount;
  cvs.height = 256;
  cvs.style.border = "1px solid red";

  var c = cvs.getContext('2d');
  var buf = new Uint8Array(analyser.frequencyBinCount);

  function render() {
    c.clearRect(0, 0, cvs.width, cvs.height);
    analyser.getByteFrequencyData(buf);
    for (var i = 0; i < buf.length; i++) {
      c.fillRect(i, (256 - (buf[i])), 1, 256);
    }
    requestAnimationFrame(render);
  }
  requestAnimationFrame(render);
}


function checkFrequency(an) {
  an.getFloatFrequencyData(frequencyArray);
  // We should have no energy when checking the data largely outside the index
  // for 440Hz (the frequency of the sine wave), start checking an octave above,
  // the Opus compression can add some harmonics to the pure since wave.
  var maxNoiseIndex = binIndexForFrequency(880, an);
  for (var i = maxNoiseIndex + 1; i < frequencyArray.length; i++) {
    if (frequencyArray[i] > frequencyArray[maxNoiseIndex]) {
       maxNoiseIndex = i;
    }
  }

  // On the other hand, we should find a peak at 440Hz. Our sine wave is not
  // attenuated, we're expecting the peak to reach 0dBFs.
  var index = binIndexForFrequency(440, an);
  info("energy at 440: " + frequencyArray[index] +
       ", threshold " + (an.maxDecibels - 10) +
       "; max noise at index " + maxNoiseIndex +
       ": " + frequencyArray[maxNoiseIndex] );
  if (frequencyArray[index] < (an.maxDecibels - 10)) {
    return false;
  }
  // Let some slack, there might be some noise here because of int -> float
  // conversion or the Opus encoding.
  if (frequencyArray[maxNoiseIndex] > an.minDecibels + 40) {
    return false;
  }

  return true;
}

var audioElement = new Audio();
audioElement.src = 'sine-440-10s.opus'
audioElement.loop = true;
var ac = new AudioContext();
var mediaElementSource = ac.createMediaElementSource(audioElement);
var an = ac.createAnalyser();
// Use no smoothing as this would just average with previous
// getFloatFrequencyData() calls.  Non-seamless looping would introduce noise,
// and smoothing would spread this into calls after the loop point.
an.smoothingTimeConstant = 0;
frequencyArray = new Float32Array(an.frequencyBinCount);

// Uncomment this to check what the analyser is doing.
// debugCanvas(an);

mediaElementSource.connect(an)

audioElement.play();
// We want to check the we have the expected audio for at least two loop of
// the HTMLMediaElement, piped into an AudioContext. The file is ten seconds,
// and we use the default FFT size.
var lastCurrentTime = 0;
var loopCount = 0;
audioElement.onplaying = function() {
  audioElement.ontimeupdate = function() {
    // We don't run the analysis when close to loop point or at the
    // beginning, since looping is not seamless, there could be an
    // unpredictable amount of silence
    var rv = checkFrequency(an);
    info("currentTime: " + audioElement.currentTime);
    if (audioElement.currentTime < 4 ||
        audioElement.currentTime > 8){
      return;
    }
    if (!rv) {
      ok(false, "Found unexpected noise during analysis.");
      audioElement.ontimeupdate = null;
      audioElement.onplaying = null;
      ac.close();
      audioElement.src = '';
      SimpleTest.finish()
      return;
    }
    ok(true, "Found correct audio signal during analysis");
    info(lastCurrentTime + " " + audioElement.currentTime);
    if (lastCurrentTime > audioElement.currentTime) {
      info("loopCount: " + loopCount);
      if (loopCount > 1) {
        audioElement.ontimeupdate = null;
        audioElement.onplaying = null;
        ac.close();
        audioElement.src = '';
        SimpleTest.finish();
      }
      lastCurrentTime = audioElement.currentTime;
      loopCount++;
    } else {
      lastCurrentTime = audioElement.currentTime;
    }
  }
}

</script>