File: multichannel-mediastreamdestination.html

package info (click to toggle)
chromium-browser 57.0.2987.98-1~deb8u1
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 2,637,852 kB
  • ctags: 2,544,394
  • sloc: cpp: 12,815,961; ansic: 3,676,222; python: 1,147,112; asm: 526,608; java: 523,212; xml: 286,794; perl: 92,654; sh: 86,408; objc: 73,271; makefile: 27,698; cs: 18,487; yacc: 13,031; tcl: 12,957; pascal: 4,875; ml: 4,716; lex: 3,904; sql: 3,862; ruby: 1,982; lisp: 1,508; php: 1,368; exp: 404; awk: 325; csh: 117; jsp: 39; sed: 37
file content (156 lines) | stat: -rw-r--r-- 5,566 bytes parent folder | download
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
<!doctype html>
<html>
  <head>
    <title>Test multichannel support for MediaStreamDestination.</title>
    <style type="text/css">
      body {
        margin: 2em;
      }
      .manual-test-ui {
        font-family: Arial;
        padding: 1em;
        border: 1px solid #999;
      }
      .manual-test-ui button {
        padding: 1em;
        font-size: 1em;
      }
      #eError {
        font-family: Arial;
        margin: 0.75em;
        color: red;
      }
    </style>
  </head>

  <body>
    <h1>Test Multichannel Audio Output for MediaStreamDestination</h1>

    <p><strong>NOTE: This test requires HTTP server.</strong></p>

    <p>This test is for multichannel (&gt; 2 channels) support for
      MediaStreamDestination. This test cannot be run with an offline audio
      context because the node is not compatible with the offline context.</p>

    <p>Press "Start Test Tone" to run the test. You should hear an one-second
      sine tone from all the available audio output channels from the channel 1
      to the last channel.</p>

    <p>CRBUG issue: <a href="https://code.google.com/p/chromium/issues/detail?id=557185" target="_blank">
      557185</a></p>

    <div class="manual-test-ui">
      <p>Max Channel Count: <span id="eMaxChannelCount">2</span></p>
      <p>Currently playing: <span id="eChannelIndex">NONE</span></p>
      <button id="eButton" onclick="startTestTones()">Start Test Tone</button>
    </div>

    <div id="eError"></div>

    <script type="text/javascript">
      // Silent interval between the test tones.
      var testToneInterval = 0.1;

      // The safe range for the equal loudness of sinusoid is roughly between
      // 200 ~ 1000Hz, which is A3(57) ~ C6(84). In this test, the starting
      // pitch is 220Hz and the interval is the whole tone. (2 MIDI pitch)
      // With 16 speakers, the last test tone will play the MIDI pitch of
      // F6(89), which is 1396Hz.
      var startMIDIPitch = 57;

      var eMaxChannelCount = document.querySelector('#eMaxChannelCount');
      var eButton = document.querySelector('#eButton');
      var eChannelIndex = document.querySelector('#eChannelIndex');
      var eError = document.querySelector('#eError');

      var context = new AudioContext();
      var mediaStreamDestination = context.createMediaStreamDestination();

      var maxChannelCount = context.destination.maxChannelCount;

      try {
        mediaStreamDestination.channelCount = maxChannelCount;
      } catch (error) {
        eError.textContent = error;
      }

      var audioElement = new Audio();
      audioElement.src = URL.createObjectURL(mediaStreamDestination.stream);
      audioElement.play();

      // The ChannelMerger for the individual channel access.
      var merger = context.createChannelMerger(maxChannelCount);
      merger.channelCountMode = 'explicit';
      merger.channelInterpretation = 'discrete';
      merger.connect(mediaStreamDestination);

      eMaxChannelCount.textContent = maxChannelCount;

      // Convert the MIDI pitch to frequency.
      function midi2freq(midiPitch) {
        return 440 * Math.pow(2, (midiPitch - 69) / 12);
      }

      // A global storage to keep the OSC reference alive.
      var oscs = [];

      // Play a test tone for the specified amount of duration at the channel.
      function playTestToneAtChannel(channelIndex, gain, duration) {
        var osc = context.createOscillator();
        var amp = context.createGain();
        osc.connect(amp);
        amp.connect(merger, 0, channelIndex);

        osc.onended = function () {
          var nextChannelIndex = channelIndex + 1;
          if (nextChannelIndex < maxChannelCount)
            playTestToneAtChannel(nextChannelIndex, gain, duration);
          else
            endTestTone();
        };

        // The pitch for each speaker goes up as the channel index increases.
        // Note that the interval is 2, whole tone.
        osc.frequency.value = midi2freq(startMIDIPitch + channelIndex * 2);

        // The channel index starts from 1.
        eChannelIndex.textContent = 'Channel #' + (channelIndex + 1);

        var now = context.currentTime;
        var toneDuration = duration - testToneInterval;

        // Add fade in and out to avoid the click noise.
        amp.gain.setValueAtTime(0.0, now);
        amp.gain.linearRampToValueAtTime(gain, now + toneDuration * 0.1);
        amp.gain.setValueAtTime(gain, now + toneDuration * 0.9);
        amp.gain.linearRampToValueAtTime(0.0, now + toneDuration);

        osc.start(now);
        osc.stop(now + duration);

        // Push osc to keep the reference alive. Otherwise |osc| will be
        // collected and the |onended| event won't be fired.
        oscs.push(osc);
      }

      // When the button is clicked the button to produce the test sound,
      // the button is grayed out so one cannot press again until the tone is
      // over. (producing sounds multiple times in a short period time will
      // hurt the speaker).
      function startTestTones() {
        eButton.disabled = true;

        // Math.SQRT1_2(=0.707..) is -3dB. This is necessary because 1.0
        // amplitude can cause overload/distortion on some speakers.
        playTestToneAtChannel(0, Math.SQRT1_2, 1.0);
      }

      // The button needs to be active back again when the test tone is over.
      // The index number in DIV should also be reset.
      function endTestTone() {
        eButton.disabled = false;
        eChannelIndex.textContent = 'NONE';
      }
    </script>
  </body>
</html>