1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5// Audio test utilities. 6 7// GetStats reports audio output energy in the [0, 32768] range. 8var MAX_AUDIO_OUTPUT_ENERGY = 32768; 9 10// Queries WebRTC stats on |peerConnection| to find out whether audio is playing 11// on the connection. Note this does not necessarily mean the audio is actually 12// playing out (for instance if there's a bug in the WebRTC web media player). 13// If |beLenient| is true, we assume we're on a slow and unreliable bot and that 14// we should do a minimum of checking. 15function ensureAudioPlaying(peerConnection, beLenient) { 16 addExpectedEvent(); 17 18 // Gather 50 samples per second for 2 seconds. 19 gatherAudioLevelSamples(peerConnection, 100, 50, function(samples) { 20 identifyFakeDeviceSignal_(samples, beLenient); 21 eventOccured(); 22 }); 23} 24 25// Queries WebRTC stats on |peerConnection| to find out whether audio is muted 26// on the connection. 27function ensureSilence(peerConnection) { 28 addExpectedEvent(); 29 setTimeout(function() { 30 gatherAudioLevelSamples(peerConnection, 100, 50, function(samples) { 31 identifySilence_(samples); 32 eventOccured(); 33 }); 34 }, 500); 35} 36 37// Gathers |numSamples| samples at |frequency| number of times per second and 38// calls back |callback| with an array with numbers in the [0, 32768] range. 39function gatherAudioLevelSamples(peerConnection, numSamples, frequency, 40 callback) { 41 console.log('Gathering ' + numSamples + ' audio samples...'); 42 var audioLevelSamples = [] 43 var gatherSamples = setInterval(function() { 44 peerConnection.getStats(function(response) { 45 audioOutputLevels = getAudioLevelFromStats_(response); 46 if (audioOutputLevels.length == 0) { 47 // The call probably isn't up yet. 48 return; 49 } 50 51 // If more than one audio level is reported we get confused. 52 assertEquals(1, audioOutputLevels.length); 53 audioLevelSamples.push(audioOutputLevels[0]); 54 55 if (audioLevelSamples.length == numSamples) { 56 console.log('Gathered all samples.'); 57 clearInterval(gatherSamples); 58 callback(audioLevelSamples); 59 } 60 }); 61 }, 1000 / frequency); 62} 63 64/** 65* Tries to identify the beep-every-half-second signal generated by the fake 66* audio device in media/video/capture/fake_video_capture_device.cc. Fails the 67* test if we can't see a signal. The samples should have been gathered over at 68* least two seconds since we expect to see at least three "peaks" in there 69* (we should see either 3 or 4 depending on how things line up). 70* 71* If |beLenient| is specified, we assume we're running on a slow device or 72* or under TSAN, and relax the checks quite a bit. 73* 74* @private 75*/ 76function identifyFakeDeviceSignal_(samples, beLenient) { 77 var numPeaks = 0; 78 var threshold = MAX_AUDIO_OUTPUT_ENERGY * 0.7; 79 if (beLenient) 80 threshold = MAX_AUDIO_OUTPUT_ENERGY * 0.6; 81 var currentlyOverThreshold = false; 82 83 // Detect when we have been been over the threshold and is going back again 84 // (i.e. count peaks). We should see about one peak per second. 85 for (var i = 0; i < samples.length; ++i) { 86 if (currentlyOverThreshold && samples[i] < threshold) 87 numPeaks++; 88 currentlyOverThreshold = samples[i] >= threshold; 89 } 90 91 console.log('Number of peaks identified: ' + numPeaks); 92 93 var expectedPeaks = 2; 94 if (beLenient) 95 expectedPeaks = 1; 96 97 if (numPeaks < expectedPeaks) 98 failTest('Expected to see at least ' + expectedPeaks + ' peak(s) in ' + 99 'audio signal, got ' + numPeaks + '. Dumping samples for analysis: "' + 100 samples + '"'); 101} 102 103/** 104 * @private 105 */ 106function identifySilence_(samples) { 107 var average = 0; 108 for (var i = 0; i < samples.length; ++i) 109 average += samples[i] / samples.length; 110 111 // If silent (like when muted), we should get very near zero audio level. 112 console.log('Average audio level: ' + average); 113 if (average > 500) 114 failTest('Expected silence, but avg audio level was ' + average); 115} 116 117/** 118 * @private 119 */ 120function getAudioLevelFromStats_(response) { 121 var reports = response.result(); 122 var audioOutputLevels = []; 123 for (var i = 0; i < reports.length; ++i) { 124 var report = reports[i]; 125 if (report.names().indexOf('audioOutputLevel') != -1) { 126 audioOutputLevels.push(report.stat('audioOutputLevel')); 127 } 128 } 129 return audioOutputLevels; 130} 131