blob: d5958520c2f0f8d65fea74e05c0e5347a6122a53 [file] [log] [blame]
<!doctype html>
<title>Test multichannel support.</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;
<h1>Test Multichannel Audio Output</h1>
<p>Tests that multichannel audio output (> 8 channels) is working correctly.
This test cannot be run with an offline audio context because it requires
an actual audio hardware with the multichannel capability.</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>Note that this test only works on OSX because CoreAudio driver supports
the multichannel streams (more than 2) on a single audio device whereas
other platforms do not.</p>
<p>CRBUG issue: <a href="" target="_blank">
<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>
<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 context = new AudioContext();
var maxChannelCount = context.destination.maxChannelCount;
// Sets the destination properties for multichannel access.
context.destination.channelCount = maxChannelCount;
context.destination.channelCountMode = 'explicit';
context.destination.channelInterpretation = 'discrete';
// The ChannelMerger for the individual channel access.
var merger = context.createChannelMerger(maxChannelCount);
merger.channelCountMode = 'explicit';
merger.channelInterpretation = 'discrete';
eMaxChannelCount.textContent = maxChannelCount;
// Convert the MIDI pitch to frequency.
function midi2freq(midiPitch) {
return 440 * Math.pow(2, (midiPitch - 69) / 12);
// 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();
amp.connect(merger, 0, channelIndex);
osc.onended = function () {
var nextChannelIndex = channelIndex + 1;
if (nextChannelIndex < maxChannelCount)
playTestToneAtChannel(nextChannelIndex, gain, duration);
// 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.stop(now + duration);
// 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';