| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Audio test utilities. | 5 // Audio test utilities. |
| 6 | 6 |
| 7 // GetStats reports audio output energy in the [0, 32768] range. | 7 // GetStats reports audio output energy in the [0, 32768] range. |
| 8 var MAX_AUDIO_OUTPUT_ENERGY = 32768; | 8 var MAX_AUDIO_OUTPUT_ENERGY = 32768; |
| 9 | 9 |
| 10 // Queries WebRTC stats on |peerConnection| to find out whether audio is playing | 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 | 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). | 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 | 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. | 14 // we should do a minimum of checking. |
| 15 function ensureAudioPlaying(peerConnection, beLenient) { | 15 function ensureAudioPlaying(peerConnection, beLenient) { |
| 16 addExpectedEvent(); | 16 addExpectedEvent(); |
| 17 | 17 |
| 18 // Gather 50 samples per second for 2 seconds. | 18 gatherAudioLevelSamples(peerConnection, 3 * 1000, function(samples) { |
| 19 gatherAudioLevelSamples(peerConnection, 100, 50, function(samples) { | |
| 20 identifyFakeDeviceSignal_(samples, beLenient); | 19 identifyFakeDeviceSignal_(samples, beLenient); |
| 21 eventOccured(); | 20 eventOccured(); |
| 22 }); | 21 }); |
| 23 } | 22 } |
| 24 | 23 |
| 25 // Queries WebRTC stats on |peerConnection| to find out whether audio is muted | 24 // Queries WebRTC stats on |peerConnection| to find out whether audio is muted |
| 26 // on the connection. | 25 // on the connection. |
| 27 function ensureSilence(peerConnection) { | 26 function ensureSilence(peerConnection) { |
| 28 addExpectedEvent(); | 27 addExpectedEvent(); |
| 29 setTimeout(function() { | 28 setTimeout(function() { |
| 30 gatherAudioLevelSamples(peerConnection, 100, 50, function(samples) { | 29 gatherAudioLevelSamples(peerConnection, 1 * 1000, function(samples) { |
| 31 identifySilence_(samples); | 30 identifySilence_(samples); |
| 32 eventOccured(); | 31 eventOccured(); |
| 33 }); | 32 }); |
| 34 }, 500); | 33 }, 500); |
| 35 } | 34 } |
| 36 | 35 |
| 37 // Not sure if this is a bug, but sometimes we get several audio ssrc's where | 36 // Not sure if this is a bug, but sometimes we get several audio ssrc's where |
| 38 // just reports audio level zero. Think of the nonzero level as the more | 37 // just reports audio level zero. Think of the nonzero level as the more |
| 39 // credible one here. http://crbug.com/479147. | 38 // credible one here. http://crbug.com/479147. |
| 40 function workAroundSeveralReportsIssue(audioOutputLevels) { | 39 function workAroundSeveralReportsIssue(audioOutputLevels) { |
| 41 if (audioOutputLevels.length == 1) { | 40 if (audioOutputLevels.length == 1) { |
| 42 return audioOutputLevels[0]; | 41 return audioOutputLevels[0]; |
| 43 } | 42 } |
| 44 | 43 |
| 45 console.log("Hit issue where one report batch returns two or more reports " + | 44 console.log("Hit issue where one report batch returns two or more reports " + |
| 46 "with audioReportLevel; got " + audioOutputLevels); | 45 "with audioReportLevel; got " + audioOutputLevels); |
| 47 | 46 |
| 48 return Math.max(audioOutputLevels[0], audioOutputLevels[1]); | 47 return Math.max(audioOutputLevels[0], audioOutputLevels[1]); |
| 49 } | 48 } |
| 50 | 49 |
| 51 // Gathers |numSamples| samples at |frequency| number of times per second and | 50 // Gathers samples from WebRTC stats as fast as possible for |durationMs| |
| 52 // calls back |callback| with an array with numbers in the [0, 32768] range. | 51 // milliseconds and calls back |callback| with an array with numbers in the |
| 53 function gatherAudioLevelSamples(peerConnection, numSamples, frequency, | 52 // [0, 32768] range. There are no guarantees for how often we will be able to |
| 54 callback) { | 53 // collect values, but this function deliberately avoids setTimeout calls in |
| 55 console.log('Gathering ' + numSamples + ' audio samples...'); | 54 // order be as insensitive as possible to starvation (particularly when this |
| 55 // code runs in parallel with other tests on a heavily loaded bot). |
| 56 function gatherAudioLevelSamples(peerConnection, durationMs, callback) { |
| 57 console.log('Gathering audio samples for ' + durationMs + ' milliseconds...'); |
| 56 var audioLevelSamples = [] | 58 var audioLevelSamples = [] |
| 57 | 59 |
| 58 // If this times out and never found any audio output levels, the call | 60 // If this times out and never found any audio output levels, the call |
| 59 // probably doesn't have an audio stream. | 61 // probably doesn't have an audio stream. |
| 60 var gatherSamples = setInterval(function() { | 62 var startTime = new Date(); |
| 61 peerConnection.getStats(function(response) { | 63 var gotStats = function(response) { |
| 62 audioOutputLevels = getAudioLevelFromStats_(response); | 64 audioOutputLevels = getAudioLevelFromStats_(response); |
| 63 if (audioOutputLevels.length == 0) { | 65 if (audioOutputLevels.length == 0) { |
| 64 // The call probably isn't up yet. | 66 // The call probably isn't up yet. |
| 65 return; | 67 peerConnection.getStats(gotStats); |
| 66 } | 68 return; |
| 67 var outputLevel = workAroundSeveralReportsIssue(audioOutputLevels); | 69 } |
| 68 audioLevelSamples.push(outputLevel); | 70 var outputLevel = workAroundSeveralReportsIssue(audioOutputLevels); |
| 71 audioLevelSamples.push(outputLevel); |
| 69 | 72 |
| 70 if (audioLevelSamples.length == numSamples) { | 73 var elapsed = new Date() - startTime; |
| 71 console.log('Gathered all samples.'); | 74 if (elapsed > durationMs) { |
| 72 clearInterval(gatherSamples); | 75 console.log('Gathered all samples.'); |
| 73 callback(audioLevelSamples); | 76 callback(audioLevelSamples); |
| 74 } | 77 return; |
| 75 }); | 78 } |
| 76 }, 1000 / frequency); | 79 peerConnection.getStats(gotStats); |
| 80 } |
| 81 peerConnection.getStats(gotStats); |
| 77 } | 82 } |
| 78 | 83 |
| 79 /** | 84 /** |
| 80 * Tries to identify the beep-every-half-second signal generated by the fake | 85 * Tries to identify the beep-every-half-second signal generated by the fake |
| 81 * audio device in media/video/capture/fake_video_capture_device.cc. Fails the | 86 * audio device in media/video/capture/fake_video_capture_device.cc. Fails the |
| 82 * test if we can't see a signal. The samples should have been gathered over at | 87 * test if we can't see a signal. The samples should have been gathered over at |
| 83 * least two seconds since we expect to see at least three "peaks" in there | 88 * least two seconds since we expect to see at least three "peaks" in there |
| 84 * (we should see either 3 or 4 depending on how things line up). | 89 * (we should see either 3 or 4 depending on how things line up). |
| 85 * | 90 * |
| 86 * If |beLenient| is specified, we assume we're running on a slow device or | 91 * If |beLenient| is specified, we assume we're running on a slow device or |
| 87 * or under TSAN, and relax the checks quite a bit. | 92 * or under TSAN, and relax the checks quite a bit. |
| 88 * | 93 * |
| 89 * @private | 94 * @private |
| 90 */ | 95 */ |
| 91 function identifyFakeDeviceSignal_(samples, beLenient) { | 96 function identifyFakeDeviceSignal_(samples, beLenient) { |
| 92 var numPeaks = 0; | 97 var numPeaks = 0; |
| 93 var threshold = MAX_AUDIO_OUTPUT_ENERGY * 0.7; | 98 var threshold = MAX_AUDIO_OUTPUT_ENERGY * 0.7; |
| 94 if (beLenient) | 99 if (beLenient) |
| 95 threshold = MAX_AUDIO_OUTPUT_ENERGY * 0.6; | 100 threshold = MAX_AUDIO_OUTPUT_ENERGY * 0.6; |
| 96 var currentlyOverThreshold = false; | 101 var currentlyOverThreshold = false; |
| 97 | 102 |
| 98 // Detect when we have been been over the threshold and is going back again | 103 // Detect when we have been been over the threshold and is going back again |
| 99 // (i.e. count peaks). We should see about one peak per second. | 104 // (i.e. count peaks). We should see about two peaks per second. |
| 100 for (var i = 0; i < samples.length; ++i) { | 105 for (var i = 0; i < samples.length; ++i) { |
| 101 if (currentlyOverThreshold && samples[i] < threshold) | 106 if (currentlyOverThreshold && samples[i] < threshold) |
| 102 numPeaks++; | 107 numPeaks++; |
| 103 currentlyOverThreshold = samples[i] >= threshold; | 108 currentlyOverThreshold = samples[i] >= threshold; |
| 104 } | 109 } |
| 105 | 110 |
| 106 console.log('Number of peaks identified: ' + numPeaks); | 111 console.log('Number of peaks identified: ' + numPeaks); |
| 107 | 112 |
| 108 var expectedPeaks = 2; | 113 var expectedPeaks = 2; |
| 109 if (beLenient) | 114 if (beLenient) |
| (...skipping 26 matching lines...) Expand all Loading... |
| 136 var reports = response.result(); | 141 var reports = response.result(); |
| 137 var audioOutputLevels = []; | 142 var audioOutputLevels = []; |
| 138 for (var i = 0; i < reports.length; ++i) { | 143 for (var i = 0; i < reports.length; ++i) { |
| 139 var report = reports[i]; | 144 var report = reports[i]; |
| 140 if (report.names().indexOf('audioOutputLevel') != -1) { | 145 if (report.names().indexOf('audioOutputLevel') != -1) { |
| 141 audioOutputLevels.push(report.stat('audioOutputLevel')); | 146 audioOutputLevels.push(report.stat('audioOutputLevel')); |
| 142 } | 147 } |
| 143 } | 148 } |
| 144 return audioOutputLevels; | 149 return audioOutputLevels; |
| 145 } | 150 } |
| OLD | NEW |