Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(267)

Side by Side Diff: media/audio/mac/audio_low_latency_input_mac.cc

Issue 1736973002: Add UMA stats for OS input glitches on Mac. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/audio/mac/audio_low_latency_input_mac.h ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 #include "media/audio/mac/audio_low_latency_input_mac.h" 5 #include "media/audio/mac/audio_low_latency_input_mac.h"
6 #include <CoreServices/CoreServices.h> 6 #include <CoreServices/CoreServices.h>
7 #include <mach/mach.h> 7 #include <mach/mach.h>
8 #include <string> 8 #include <string>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 175
176 // See "Technical Note TN2091 - Device input using the HAL Output Audio Unit" 176 // See "Technical Note TN2091 - Device input using the HAL Output Audio Unit"
177 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html 177 // http://developer.apple.com/library/mac/#technotes/tn2091/_index.html
178 // for more details and background regarding this implementation. 178 // for more details and background regarding this implementation.
179 179
180 AUAudioInputStream::AUAudioInputStream(AudioManagerMac* manager, 180 AUAudioInputStream::AUAudioInputStream(AudioManagerMac* manager,
181 const AudioParameters& input_params, 181 const AudioParameters& input_params,
182 AudioDeviceID audio_device_id) 182 AudioDeviceID audio_device_id)
183 : manager_(manager), 183 : manager_(manager),
184 number_of_frames_(input_params.frames_per_buffer()), 184 number_of_frames_(input_params.frames_per_buffer()),
185 number_of_frames_provided_(0),
185 io_buffer_frame_size_(0), 186 io_buffer_frame_size_(0),
186 sink_(nullptr), 187 sink_(nullptr),
187 audio_unit_(0), 188 audio_unit_(0),
188 input_device_id_(audio_device_id), 189 input_device_id_(audio_device_id),
189 hardware_latency_frames_(0), 190 hardware_latency_frames_(0),
190 number_of_channels_in_frame_(0), 191 number_of_channels_in_frame_(0),
191 fifo_(input_params.channels(), 192 fifo_(input_params.channels(),
192 number_of_frames_, 193 number_of_frames_,
193 kNumberOfBlocksBufferInFifo), 194 kNumberOfBlocksBufferInFifo),
194 input_callback_is_active_(false), 195 input_callback_is_active_(false),
195 start_was_deferred_(false), 196 start_was_deferred_(false),
196 buffer_size_was_changed_(false), 197 buffer_size_was_changed_(false),
197 audio_unit_render_has_worked_(false), 198 audio_unit_render_has_worked_(false),
198 device_listener_is_active_(false) { 199 device_listener_is_active_(false),
200 last_sample_time_(0.0),
201 last_number_of_frames_(0),
202 total_lost_frames_(0),
203 largest_glitch_frames_(0),
204 glitches_detected_(0) {
199 DCHECK(manager_); 205 DCHECK(manager_);
200 206
201 // Set up the desired (output) format specified by the client. 207 // Set up the desired (output) format specified by the client.
202 format_.mSampleRate = input_params.sample_rate(); 208 format_.mSampleRate = input_params.sample_rate();
203 format_.mFormatID = kAudioFormatLinearPCM; 209 format_.mFormatID = kAudioFormatLinearPCM;
204 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked | 210 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked |
205 kLinearPCMFormatFlagIsSignedInteger; 211 kLinearPCMFormatFlagIsSignedInteger;
206 DCHECK(FormatIsInterleaved(format_.mFormatFlags)); 212 DCHECK(FormatIsInterleaved(format_.mFormatFlags));
207 format_.mBitsPerChannel = input_params.bits_per_sample(); 213 format_.mBitsPerChannel = input_params.bits_per_sample();
208 format_.mChannelsPerFrame = input_params.channels(); 214 format_.mChannelsPerFrame = input_params.channels();
(...skipping 22 matching lines...) Expand all
231 237
232 AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers; 238 AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers;
233 audio_buffer->mNumberChannels = input_params.channels(); 239 audio_buffer->mNumberChannels = input_params.channels();
234 audio_buffer->mDataByteSize = data_byte_size; 240 audio_buffer->mDataByteSize = data_byte_size;
235 audio_buffer->mData = audio_data_buffer_.get(); 241 audio_buffer->mData = audio_data_buffer_.get();
236 } 242 }
237 243
238 AUAudioInputStream::~AUAudioInputStream() { 244 AUAudioInputStream::~AUAudioInputStream() {
239 DVLOG(1) << "~dtor"; 245 DVLOG(1) << "~dtor";
240 DCHECK(!device_listener_is_active_); 246 DCHECK(!device_listener_is_active_);
247 ReportAndResetStats();
241 } 248 }
242 249
243 // Obtain and open the AUHAL AudioOutputUnit for recording. 250 // Obtain and open the AUHAL AudioOutputUnit for recording.
244 bool AUAudioInputStream::Open() { 251 bool AUAudioInputStream::Open() {
245 DCHECK(thread_checker_.CalledOnValidThread()); 252 DCHECK(thread_checker_.CalledOnValidThread());
246 DVLOG(1) << "Open"; 253 DVLOG(1) << "Open";
247 DCHECK(!audio_unit_); 254 DCHECK(!audio_unit_);
248 255
249 // Verify that we have a valid device. Send appropriate error code to 256 // Verify that we have a valid device. Send appropriate error code to
250 // HandleError() to ensure that the error type is added to UMA stats. 257 // HandleError() to ensure that the error type is added to UMA stats.
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
511 // seems to set this state synchronously, hence it should always report false 518 // seems to set this state synchronously, hence it should always report false
512 // after a successful call. 519 // after a successful call.
513 DCHECK(!IsRunning()) << "Audio unit is stopped but still running"; 520 DCHECK(!IsRunning()) << "Audio unit is stopped but still running";
514 521
515 // Reset the audio unit’s render state. This function clears memory. 522 // Reset the audio unit’s render state. This function clears memory.
516 // It does not allocate or free memory resources. 523 // It does not allocate or free memory resources.
517 result = AudioUnitReset(audio_unit_, kAudioUnitScope_Global, 0); 524 result = AudioUnitReset(audio_unit_, kAudioUnitScope_Global, 0);
518 DCHECK_EQ(result, noErr); 525 DCHECK_EQ(result, noErr);
519 526
520 SetInputCallbackIsActive(false); 527 SetInputCallbackIsActive(false);
528 ReportAndResetStats();
521 sink_ = nullptr; 529 sink_ = nullptr;
522 fifo_.Clear(); 530 fifo_.Clear();
523 io_buffer_frame_size_ = 0; 531 io_buffer_frame_size_ = 0;
524 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) 532 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
525 << "Failed to stop acquiring data"; 533 << "Failed to stop acquiring data";
526 } 534 }
527 535
528 void AUAudioInputStream::Close() { 536 void AUAudioInputStream::Close() {
529 DCHECK(thread_checker_.CalledOnValidThread()); 537 DCHECK(thread_checker_.CalledOnValidThread());
530 DVLOG(1) << "Close"; 538 DVLOG(1) << "Close";
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after
808 // Update time of successful call to AudioUnitRender(). 816 // Update time of successful call to AudioUnitRender().
809 last_success_time_ = base::TimeTicks::Now(); 817 last_success_time_ = base::TimeTicks::Now();
810 818
811 // Deliver recorded data to the consumer as a callback. 819 // Deliver recorded data to the consumer as a callback.
812 return Provide(number_of_frames, &audio_buffer_list_, time_stamp); 820 return Provide(number_of_frames, &audio_buffer_list_, time_stamp);
813 } 821 }
814 822
815 OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames, 823 OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames,
816 AudioBufferList* io_data, 824 AudioBufferList* io_data,
817 const AudioTimeStamp* time_stamp) { 825 const AudioTimeStamp* time_stamp) {
826 UpdateCaptureTimestamp(time_stamp);
827 last_number_of_frames_ = number_of_frames;
828
829 // TODO(grunell): We'll only care about the first buffer size change, any
830 // further changes will be ignored. This is in line with output side stats.
831 // It would be nice to have all changes reflected in UMA stats.
832 if (number_of_frames != number_of_frames_ && number_of_frames_provided_ == 0)
833 number_of_frames_provided_ = number_of_frames;
834
818 // Update the capture latency. 835 // Update the capture latency.
819 double capture_latency_frames = GetCaptureLatency(time_stamp); 836 double capture_latency_frames = GetCaptureLatency(time_stamp);
820 837
821 // The AGC volume level is updated once every second on a separate thread. 838 // The AGC volume level is updated once every second on a separate thread.
822 // Note that, |volume| is also updated each time SetVolume() is called 839 // Note that, |volume| is also updated each time SetVolume() is called
823 // through IPC by the render-side AGC. 840 // through IPC by the render-side AGC.
824 double normalized_volume = 0.0; 841 double normalized_volume = 0.0;
825 GetAgcVolume(&normalized_volume); 842 GetAgcVolume(&normalized_volume);
826 843
827 AudioBuffer& buffer = io_data->mBuffers[0]; 844 AudioBuffer& buffer = io_data->mBuffers[0];
(...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after
1227 break; 1244 break;
1228 } 1245 }
1229 DVLOG(1) << "property: " << device_property << " (" 1246 DVLOG(1) << "property: " << device_property << " ("
1230 << FourCharFormatCodeToString(device_property) << ")" 1247 << FourCharFormatCodeToString(device_property) << ")"
1231 << " changed: " << change_count; 1248 << " changed: " << change_count;
1232 LogDevicePropertyChange(startup_failed, uma_result); 1249 LogDevicePropertyChange(startup_failed, uma_result);
1233 } 1250 }
1234 device_property_changes_map_.clear(); 1251 device_property_changes_map_.clear();
1235 } 1252 }
1236 1253
1254 void AUAudioInputStream::UpdateCaptureTimestamp(
1255 const AudioTimeStamp* timestamp) {
1256 if ((timestamp->mFlags & kAudioTimeStampSampleTimeValid) == 0)
1257 return;
1258
1259 if (last_sample_time_) {
1260 DCHECK_NE(0U, last_number_of_frames_);
1261 UInt32 diff =
1262 static_cast<UInt32>(timestamp->mSampleTime - last_sample_time_);
1263 if (diff != last_number_of_frames_) {
1264 DCHECK_GT(diff, last_number_of_frames_);
1265 // We were given samples post what we expected. Update the glitch count
1266 // etc. and keep a record of the largest glitch.
1267 auto lost_frames = diff - last_number_of_frames_;
1268 total_lost_frames_ += lost_frames;
1269 if (lost_frames > largest_glitch_frames_)
1270 largest_glitch_frames_ = lost_frames;
1271 ++glitches_detected_;
1272 }
1273 }
1274
1275 // Store the last sample time for use next time we get called back.
1276 last_sample_time_ = timestamp->mSampleTime;
1277 }
1278
1279 void AUAudioInputStream::ReportAndResetStats() {
1280 if (last_sample_time_ == 0)
1281 return; // No stats gathered to report.
1282
1283 // A value of 0 indicates that we got the buffer size we asked for.
1284 UMA_HISTOGRAM_COUNTS_10000("Media.Audio.Capture.FramesProvided",
1285 number_of_frames_provided_);
1286 // Even if there aren't any glitches, we want to record it to get a feel for
1287 // how often we get no glitches vs the alternative.
1288 UMA_HISTOGRAM_COUNTS("Media.Audio.Capture.Glitches", glitches_detected_);
1289
1290 if (glitches_detected_ != 0) {
1291 auto lost_frames_ms = (total_lost_frames_ * 1000) / format_.mSampleRate;
1292 UMA_HISTOGRAM_LONG_TIMES("Media.Audio.Capture.LostFramesInMs",
1293 base::TimeDelta::FromMilliseconds(lost_frames_ms));
1294 auto largest_glitch_ms =
1295 (largest_glitch_frames_ * 1000) / format_.mSampleRate;
1296 UMA_HISTOGRAM_CUSTOM_TIMES(
1297 "Media.Audio.Capture.LargestGlitchMs",
1298 base::TimeDelta::FromMilliseconds(largest_glitch_ms),
1299 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1),
1300 50);
1301 DLOG(WARNING) << "Total glitches=" << glitches_detected_
1302 << ". Total frames lost=" << total_lost_frames_ << " ("
1303 << lost_frames_ms;
1304 }
1305
1306 number_of_frames_provided_ = 0;
1307 glitches_detected_ = 0;
1308 last_sample_time_ = 0;
1309 last_number_of_frames_ = 0;
1310 total_lost_frames_ = 0;
1311 largest_glitch_frames_ = 0;
1312 }
1313
1237 } // namespace media 1314 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/mac/audio_low_latency_input_mac.h ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698