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

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

Issue 2896423003: Remove Mac input audio restart mechanism and reduce time until startup success check. (Closed)
Patch Set: Created 3 years, 7 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 #include "media/audio/mac/audio_low_latency_input_mac.h" 4 #include "media/audio/mac/audio_low_latency_input_mac.h"
5 5
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/bind.h" 10 #include "base/bind.h"
(...skipping 11 matching lines...) Expand all
22 22
23 namespace media { 23 namespace media {
24 24
25 // Number of blocks of buffers used in the |fifo_|. 25 // Number of blocks of buffers used in the |fifo_|.
26 const int kNumberOfBlocksBufferInFifo = 2; 26 const int kNumberOfBlocksBufferInFifo = 2;
27 27
28 // Max length of sequence of TooManyFramesToProcessError errors. 28 // Max length of sequence of TooManyFramesToProcessError errors.
29 // The stream will be stopped as soon as this time limit is passed. 29 // The stream will be stopped as soon as this time limit is passed.
30 const int kMaxErrorTimeoutInSeconds = 1; 30 const int kMaxErrorTimeoutInSeconds = 1;
31 31
32 // A repeating timer is created and started in Start() and it triggers calls
33 // to CheckIfInputStreamIsAlive() where we do periodic checks to see if the
34 // input data callback sequence is active or not. If the stream seems dead,
35 // up to |kMaxNumberOfRestartAttempts| restart attempts tries to bring the
36 // stream back to life.
37 const int kCheckInputIsAliveTimeInSeconds = 5;
38
39 // Number of restart indications required to actually trigger a restart
40 // attempt.
41 const int kNumberOfIndicationsToTriggerRestart = 1;
42
43 // Max number of times we try to restart a stream when it has been categorized
44 // as dead. Note that we can do many restarts during an audio session and this
45 // limitation is per detected problem. Once a restart has succeeded, a new
46 // sequence of |kMaxNumberOfRestartAttempts| number of restart attempts can be
47 // done.
48 const int kMaxNumberOfRestartAttempts = 1;
49
50 // A one-shot timer is created and started in Start() and it triggers 32 // A one-shot timer is created and started in Start() and it triggers
51 // CheckInputStartupSuccess() after this amount of time. UMA stats marked 33 // CheckInputStartupSuccess() after this amount of time. UMA stats marked
52 // Media.Audio.InputStartupSuccessMac is then updated where true is added 34 // Media.Audio.InputStartupSuccessMac is then updated where true is added
53 // if input callbacks have started, and false otherwise. Note that the value 35 // if input callbacks have started, and false otherwise.
54 // is larger than |kCheckInputIsAliveTimeInSeconds| to ensure that at least one 36 const int kInputCallbackStartTimeoutInSeconds = 5;
55 // restart attempt can be done before storing the result.
56 const int kInputCallbackStartTimeoutInSeconds =
57 kCheckInputIsAliveTimeInSeconds + 3;
58 37
59 // Returns true if the format flags in |format_flags| has the "non-interleaved" 38 // Returns true if the format flags in |format_flags| has the "non-interleaved"
60 // flag (kAudioFormatFlagIsNonInterleaved) cleared (set to 0). 39 // flag (kAudioFormatFlagIsNonInterleaved) cleared (set to 0).
61 static bool FormatIsInterleaved(UInt32 format_flags) { 40 static bool FormatIsInterleaved(UInt32 format_flags) {
62 return !(format_flags & kAudioFormatFlagIsNonInterleaved); 41 return !(format_flags & kAudioFormatFlagIsNonInterleaved);
63 } 42 }
64 43
65 // Converts the 32-bit non-terminated 4 byte string into an std::string. 44 // Converts the 32-bit non-terminated 4 byte string into an std::string.
66 // Example: code=1735354734 <=> 'goin' <=> kAudioDevicePropertyDeviceIsRunning. 45 // Example: code=1735354734 <=> 'goin' <=> kAudioDevicePropertyDeviceIsRunning.
67 static std::string FourCharFormatCodeToString(UInt32 code) { 46 static std::string FourCharFormatCodeToString(UInt32 code) {
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 number_of_frames_provided_(0), 227 number_of_frames_provided_(0),
249 io_buffer_frame_size_(0), 228 io_buffer_frame_size_(0),
250 sink_(nullptr), 229 sink_(nullptr),
251 audio_unit_(0), 230 audio_unit_(0),
252 input_device_id_(audio_device_id), 231 input_device_id_(audio_device_id),
253 hardware_latency_frames_(0), 232 hardware_latency_frames_(0),
254 number_of_channels_in_frame_(0), 233 number_of_channels_in_frame_(0),
255 fifo_(input_params.channels(), 234 fifo_(input_params.channels(),
256 number_of_frames_, 235 number_of_frames_,
257 kNumberOfBlocksBufferInFifo), 236 kNumberOfBlocksBufferInFifo),
237 got_input_callback_(false),
258 input_callback_is_active_(false), 238 input_callback_is_active_(false),
259 start_was_deferred_(false), 239 start_was_deferred_(false),
260 buffer_size_was_changed_(false), 240 buffer_size_was_changed_(false),
261 audio_unit_render_has_worked_(false), 241 audio_unit_render_has_worked_(false),
262 device_listener_is_active_(false), 242 device_listener_is_active_(false),
263 last_sample_time_(0.0), 243 last_sample_time_(0.0),
264 last_number_of_frames_(0), 244 last_number_of_frames_(0),
265 total_lost_frames_(0), 245 total_lost_frames_(0),
266 largest_glitch_frames_(0), 246 largest_glitch_frames_(0),
267 glitches_detected_(0), 247 glitches_detected_(0),
268 number_of_restart_indications_(0),
269 number_of_restart_attempts_(0),
270 total_number_of_restart_attempts_(0),
271 log_callback_(log_callback), 248 log_callback_(log_callback),
272 weak_factory_(this) { 249 weak_factory_(this) {
273 DCHECK(manager_); 250 DCHECK(manager_);
274 CHECK(!log_callback_.Equals(AudioManager::LogCallback())); 251 CHECK(!log_callback_.Equals(AudioManager::LogCallback()));
275 252
276 // Set up the desired (output) format specified by the client. 253 // Set up the desired (output) format specified by the client.
277 format_.mSampleRate = input_params.sample_rate(); 254 format_.mSampleRate = input_params.sample_rate();
278 format_.mFormatID = kAudioFormatLinearPCM; 255 format_.mFormatID = kAudioFormatLinearPCM;
279 format_.mFormatFlags = 256 format_.mFormatFlags =
280 kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger; 257 kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger;
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 base::Unretained(this), callback)); 513 base::Unretained(this), callback));
537 manager_->GetTaskRunner()->PostDelayedTask( 514 manager_->GetTaskRunner()->PostDelayedTask(
538 FROM_HERE, deferred_start_cb_.callback(), 515 FROM_HERE, deferred_start_cb_.callback(),
539 base::TimeDelta::FromSeconds( 516 base::TimeDelta::FromSeconds(
540 AudioManagerMac::kStartDelayInSecsForPowerEvents)); 517 AudioManagerMac::kStartDelayInSecsForPowerEvents));
541 return; 518 return;
542 } 519 }
543 520
544 sink_ = callback; 521 sink_ = callback;
545 last_success_time_ = base::TimeTicks::Now(); 522 last_success_time_ = base::TimeTicks::Now();
546 last_callback_time_ = base::TimeTicks::Now();
547 audio_unit_render_has_worked_ = false; 523 audio_unit_render_has_worked_ = false;
548 StartAgc(); 524 StartAgc();
549 OSStatus result = AudioOutputUnitStart(audio_unit_); 525 OSStatus result = AudioOutputUnitStart(audio_unit_);
550 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) 526 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
551 << "Failed to start acquiring data"; 527 << "Failed to start acquiring data";
552 if (result != noErr) { 528 if (result != noErr) {
553 Stop(); 529 Stop();
554 return; 530 return;
555 } 531 }
556 DCHECK(IsRunning()) << "Audio unit started OK but is not yet running"; 532 DCHECK(IsRunning()) << "Audio unit started OK but is not yet running";
557 533
558 // For UMA stat purposes, start a one-shot timer which detects when input 534 // For UMA stat purposes, start a one-shot timer which detects when input
559 // callbacks starts indicating if input audio recording starts as intended. 535 // callbacks starts indicating if input audio recording starts as intended.
560 // CheckInputStartupSuccess() will check if |input_callback_is_active_| is 536 // CheckInputStartupSuccess() will check if |input_callback_is_active_| is
561 // true when the timer expires. 537 // true when the timer expires.
562 input_callback_timer_.reset(new base::OneShotTimer()); 538 input_callback_timer_.reset(new base::OneShotTimer());
563 input_callback_timer_->Start( 539 input_callback_timer_->Start(
564 FROM_HERE, 540 FROM_HERE,
565 base::TimeDelta::FromSeconds(kInputCallbackStartTimeoutInSeconds), this, 541 base::TimeDelta::FromSeconds(kInputCallbackStartTimeoutInSeconds), this,
566 &AUAudioInputStream::CheckInputStartupSuccess); 542 &AUAudioInputStream::CheckInputStartupSuccess);
567 DCHECK(input_callback_timer_->IsRunning()); 543 DCHECK(input_callback_timer_->IsRunning());
568
569 // Also create and start a timer that provides periodic callbacks used to
570 // monitor if the input stream is alive or not.
571 check_alive_timer_.reset(new base::RepeatingTimer());
572 check_alive_timer_->Start(
573 FROM_HERE, base::TimeDelta::FromSeconds(kCheckInputIsAliveTimeInSeconds),
574 this, &AUAudioInputStream::CheckIfInputStreamIsAlive);
575 DCHECK(check_alive_timer_->IsRunning());
576 } 544 }
577 545
578 void AUAudioInputStream::Stop() { 546 void AUAudioInputStream::Stop() {
579 DCHECK(thread_checker_.CalledOnValidThread()); 547 DCHECK(thread_checker_.CalledOnValidThread());
580 deferred_start_cb_.Cancel(); 548 deferred_start_cb_.Cancel();
581 DVLOG(1) << "Stop"; 549 DVLOG(1) << "Stop";
582 StopAgc(); 550 StopAgc();
583 if (check_alive_timer_ != nullptr) {
584 check_alive_timer_->Stop();
585 check_alive_timer_.reset();
586 }
587 if (input_callback_timer_ != nullptr) { 551 if (input_callback_timer_ != nullptr) {
588 input_callback_timer_->Stop(); 552 input_callback_timer_->Stop();
589 input_callback_timer_.reset(); 553 input_callback_timer_.reset();
590 } 554 }
591 555
592 if (audio_unit_ != nullptr) { 556 if (audio_unit_ != nullptr) {
593 // Stop the I/O audio unit. 557 // Stop the I/O audio unit.
594 OSStatus result = AudioOutputUnitStop(audio_unit_); 558 OSStatus result = AudioOutputUnitStop(audio_unit_);
595 DCHECK_EQ(result, noErr); 559 DCHECK_EQ(result, noErr);
596 // Add a DCHECK here just in case. AFAIK, the call to AudioOutputUnitStop() 560 // Add a DCHECK here just in case. AFAIK, the call to AudioOutputUnitStop()
597 // seems to set this state synchronously, hence it should always report 561 // seems to set this state synchronously, hence it should always report
598 // false after a successful call. 562 // false after a successful call.
599 DCHECK(!IsRunning()) << "Audio unit is stopped but still running"; 563 DCHECK(!IsRunning()) << "Audio unit is stopped but still running";
600 564
601 // Reset the audio unit’s render state. This function clears memory. 565 // Reset the audio unit’s render state. This function clears memory.
602 // It does not allocate or free memory resources. 566 // It does not allocate or free memory resources.
603 result = AudioUnitReset(audio_unit_, kAudioUnitScope_Global, 0); 567 result = AudioUnitReset(audio_unit_, kAudioUnitScope_Global, 0);
604 DCHECK_EQ(result, noErr); 568 DCHECK_EQ(result, noErr);
605 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) 569 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
606 << "Failed to stop acquiring data"; 570 << "Failed to stop acquiring data";
607 } 571 }
608 572
609 SetInputCallbackIsActive(false); 573 SetInputCallbackIsActive(false);
610 ReportAndResetStats(); 574 ReportAndResetStats();
611 sink_ = nullptr; 575 sink_ = nullptr;
612 fifo_.Clear(); 576 fifo_.Clear();
613 io_buffer_frame_size_ = 0; 577 io_buffer_frame_size_ = 0;
578 got_input_callback_ = false;
614 } 579 }
615 580
616 void AUAudioInputStream::Close() { 581 void AUAudioInputStream::Close() {
617 DCHECK(thread_checker_.CalledOnValidThread()); 582 DCHECK(thread_checker_.CalledOnValidThread());
618 DVLOG(1) << "Close"; 583 DVLOG(1) << "Close";
584
619 // It is valid to call Close() before calling open or Start(). 585 // It is valid to call Close() before calling open or Start().
620 // It is also valid to call Close() after Start() has been called. 586 // It is also valid to call Close() after Start() has been called.
621 Stop(); 587 Stop();
588
622 // Uninitialize and dispose the audio unit. 589 // Uninitialize and dispose the audio unit.
623 CloseAudioUnit(); 590 CloseAudioUnit();
591
624 // Disable the listener for device property changes. 592 // Disable the listener for device property changes.
625 DeRegisterDeviceChangeListener(); 593 DeRegisterDeviceChangeListener();
594
626 // Add more UMA stats but only if AGC was activated, i.e. for e.g. WebRTC 595 // Add more UMA stats but only if AGC was activated, i.e. for e.g. WebRTC
627 // audio input streams. 596 // audio input streams.
628 if (GetAutomaticGainControl()) { 597 if (GetAutomaticGainControl()) {
629 // Check if any device property changes are added by filtering out a 598 // Check if any device property changes are added by filtering out a
630 // selected set of the |device_property_changes_map_| map. Add UMA stats 599 // selected set of the |device_property_changes_map_| map. Add UMA stats
631 // if valuable data is found. 600 // if valuable data is found.
632 AddDevicePropertyChangesToUMA(false); 601 AddDevicePropertyChangesToUMA(false);
633 // Log whether call to Start() was deferred or not. To be compared with 602 // Log whether call to Start() was deferred or not. To be compared with
634 // Media.Audio.InputStartWasDeferredMac which logs the same value but only 603 // Media.Audio.InputStartWasDeferredMac which logs the same value but only
635 // when input audio fails to start. 604 // when input audio fails to start.
636 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartWasDeferredAudioWorkedMac", 605 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartWasDeferredAudioWorkedMac",
637 start_was_deferred_); 606 start_was_deferred_);
638 // Log if a change of I/O buffer size was required. To be compared with 607 // Log if a change of I/O buffer size was required. To be compared with
639 // Media.Audio.InputBufferSizeWasChangedMac which logs the same value but 608 // Media.Audio.InputBufferSizeWasChangedMac which logs the same value but
640 // only when input audio fails to start. 609 // only when input audio fails to start.
641 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputBufferSizeWasChangedAudioWorkedMac", 610 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputBufferSizeWasChangedAudioWorkedMac",
642 buffer_size_was_changed_); 611 buffer_size_was_changed_);
643 // Logs the total number of times RestartAudio() has been called.
644 DVLOG(1) << "Total number of restart attempts: "
645 << total_number_of_restart_attempts_;
646 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.InputRestartAttemptsMac",
647 total_number_of_restart_attempts_);
648 // TODO(henrika): possibly add more values here...
649 } 612 }
613
650 // Inform the audio manager that we have been closed. This will cause our 614 // Inform the audio manager that we have been closed. This will cause our
651 // destruction. 615 // destruction.
652 manager_->ReleaseInputStream(this); 616 manager_->ReleaseInputStream(this);
653 } 617 }
654 618
655 double AUAudioInputStream::GetMaxVolume() { 619 double AUAudioInputStream::GetMaxVolume() {
656 // Verify that we have a valid device. 620 // Verify that we have a valid device.
657 if (input_device_id_ == kAudioObjectUnknown) { 621 if (input_device_id_ == kAudioObjectUnknown) {
658 NOTREACHED() << "Device ID is unknown"; 622 NOTREACHED() << "Device ID is unknown";
659 return 0.0; 623 return 0.0;
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
811 return self->OnDataIsAvailable(flags, time_stamp, bus_number, 775 return self->OnDataIsAvailable(flags, time_stamp, bus_number,
812 number_of_frames); 776 number_of_frames);
813 } 777 }
814 778
815 OSStatus AUAudioInputStream::OnDataIsAvailable( 779 OSStatus AUAudioInputStream::OnDataIsAvailable(
816 AudioUnitRenderActionFlags* flags, 780 AudioUnitRenderActionFlags* flags,
817 const AudioTimeStamp* time_stamp, 781 const AudioTimeStamp* time_stamp,
818 UInt32 bus_number, 782 UInt32 bus_number,
819 UInt32 number_of_frames) { 783 UInt32 number_of_frames) {
820 TRACE_EVENT0("audio", "AUAudioInputStream::OnDataIsAvailable"); 784 TRACE_EVENT0("audio", "AUAudioInputStream::OnDataIsAvailable");
821 // Update |last_callback_time_| on the main browser thread. Its value is used
822 // by CheckIfInputStreamIsAlive() to detect if the stream is dead or alive.
823 manager_->GetTaskRunner()->PostTask(
824 FROM_HERE,
825 base::Bind(&AUAudioInputStream::UpdateDataCallbackTimeOnMainThread,
826 weak_factory_.GetWeakPtr(), base::TimeTicks::Now()));
827 785
828 // Indicate that input callbacks have started on the internal AUHAL IO 786 // Indicate that input callbacks have started.
829 // thread. The |input_callback_is_active_| member is read from the creating 787 if (!got_input_callback_) {
830 // thread when a timer fires once and set to false in Stop() on the same 788 got_input_callback_ = true;
831 // thread. It means that this thread is the only writer of 789 SetInputCallbackIsActive(true);
832 // |input_callback_is_active_| once the tread starts and it should therefore 790 }
833 // be safe to modify.
834 SetInputCallbackIsActive(true);
835 791
836 // Update the |mDataByteSize| value in the audio_buffer_list() since 792 // Update the |mDataByteSize| value in the audio_buffer_list() since
837 // |number_of_frames| can be changed on the fly. 793 // |number_of_frames| can be changed on the fly.
838 // |mDataByteSize| needs to be exactly mapping to |number_of_frames|, 794 // |mDataByteSize| needs to be exactly mapping to |number_of_frames|,
839 // otherwise it will put CoreAudio into bad state and results in 795 // otherwise it will put CoreAudio into bad state and results in
840 // AudioUnitRender() returning -50 for the new created stream. 796 // AudioUnitRender() returning -50 for the new created stream.
841 // We have also seen kAudioUnitErr_TooManyFramesToProcess (-10874) and 797 // We have also seen kAudioUnitErr_TooManyFramesToProcess (-10874) and
842 // kAudioUnitErr_CannotDoInCurrentContext (-10863) as error codes. 798 // kAudioUnitErr_CannotDoInCurrentContext (-10863) as error codes.
843 // See crbug/428706 for details. 799 // See crbug/428706 for details.
844 UInt32 new_size = number_of_frames * format_.mBytesPerFrame; 800 UInt32 new_size = number_of_frames * format_.mBytesPerFrame;
(...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after
1220 input_callback_is_active); 1176 input_callback_is_active);
1221 DVLOG(1) << "input_callback_is_active: " << input_callback_is_active; 1177 DVLOG(1) << "input_callback_is_active: " << input_callback_is_active;
1222 if (!input_callback_is_active) { 1178 if (!input_callback_is_active) {
1223 // Now when we know that startup has failed for some reason, add extra 1179 // Now when we know that startup has failed for some reason, add extra
1224 // UMA stats in an attempt to figure out the exact reason. 1180 // UMA stats in an attempt to figure out the exact reason.
1225 AddHistogramsForFailedStartup(); 1181 AddHistogramsForFailedStartup();
1226 } 1182 }
1227 } 1183 }
1228 } 1184 }
1229 1185
1230 void AUAudioInputStream::UpdateDataCallbackTimeOnMainThread(
1231 base::TimeTicks now_tick) {
1232 DCHECK(thread_checker_.CalledOnValidThread());
1233 last_callback_time_ = now_tick;
1234 }
1235
1236 void AUAudioInputStream::CheckIfInputStreamIsAlive() {
1237 DCHECK(thread_checker_.CalledOnValidThread());
1238 // Avoid checking stream state if we are suspended.
1239 if (manager_->IsSuspending())
1240 return;
1241 // Restrict usage of the restart mechanism to "AGC streams" only.
1242 // TODO(henrika): if the restart scheme works well, we might include it
1243 // for all types of input streams.
1244 if (!GetAutomaticGainControl())
1245 return;
1246
1247 // Clear this counter here when audio is active instead of in Start(),
1248 // otherwise it would be cleared at each restart attempt and that would break
1249 // the current design where only a certain number of restart attempts is
1250 // allowed.
1251 if (GetInputCallbackIsActive())
1252 number_of_restart_attempts_ = 0;
1253
1254 // Measure time since last callback. |last_callback_time_| is set the first
1255 // time in Start() and then updated in each data callback, hence if
1256 // |time_since_last_callback| is large (>1) and growing for each check, the
1257 // callback sequence has stopped. A typical value under normal/working
1258 // conditions is a few milliseconds.
1259 base::TimeDelta time_since_last_callback =
1260 base::TimeTicks::Now() - last_callback_time_;
1261 DVLOG(2) << "time since last callback: "
1262 << time_since_last_callback.InSecondsF();
1263
1264 // Increase a counter if it has been too long since the last data callback.
1265 // A non-zero value of this counter is a strong indication of a "dead" input
1266 // stream. Reset the same counter if the stream is alive.
1267 if (time_since_last_callback.InSecondsF() >
1268 0.5 * kCheckInputIsAliveTimeInSeconds) {
1269 ++number_of_restart_indications_;
1270 } else {
1271 number_of_restart_indications_ = 0;
1272 }
1273
1274 // Restart the audio stream if two conditions are met. First, the number of
1275 // restart indicators must be larger than a threshold, and secondly, only a
1276 // fixed number of restart attempts is allowed.
1277 // Note that, the threshold is different depending on if the stream is seen
1278 // as dead directly at the first call to Start() (i.e. it has never started)
1279 // or if the stream has started OK at least once but then stopped for some
1280 // reason (e.g by placing the device in sleep mode). One restart indication
1281 // is sufficient for the first case (threshold is zero), while a larger value
1282 // (threshold > 0) is required for the second case to avoid false alarms when
1283 // e.g. resuming from a suspended state.
1284 const size_t restart_threshold =
1285 GetInputCallbackIsActive() ? kNumberOfIndicationsToTriggerRestart : 0;
1286 if (number_of_restart_indications_ > restart_threshold &&
1287 number_of_restart_attempts_ < kMaxNumberOfRestartAttempts) {
1288 SetInputCallbackIsActive(false);
1289 ++total_number_of_restart_attempts_;
1290 ++number_of_restart_attempts_;
1291 number_of_restart_indications_ = 0;
1292 RestartAudio();
1293 }
1294 }
1295
1296 void AUAudioInputStream::CloseAudioUnit() { 1186 void AUAudioInputStream::CloseAudioUnit() {
1297 DCHECK(thread_checker_.CalledOnValidThread()); 1187 DCHECK(thread_checker_.CalledOnValidThread());
1298 DVLOG(1) << "CloseAudioUnit"; 1188 DVLOG(1) << "CloseAudioUnit";
1299 if (!audio_unit_) 1189 if (!audio_unit_)
1300 return; 1190 return;
1301 OSStatus result = AudioUnitUninitialize(audio_unit_); 1191 OSStatus result = AudioUnitUninitialize(audio_unit_);
1302 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) 1192 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
1303 << "AudioUnitUninitialize() failed."; 1193 << "AudioUnitUninitialize() failed.";
1304 result = AudioComponentInstanceDispose(audio_unit_); 1194 result = AudioComponentInstanceDispose(audio_unit_);
1305 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) 1195 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
1306 << "AudioComponentInstanceDispose() failed."; 1196 << "AudioComponentInstanceDispose() failed.";
1307 audio_unit_ = 0; 1197 audio_unit_ = 0;
1308 } 1198 }
1309 1199
1310 void AUAudioInputStream::RestartAudio() {
1311 DCHECK(thread_checker_.CalledOnValidThread());
1312 DVLOG(1) << "RestartAudio";
1313 LOG_IF(ERROR, IsRunning())
1314 << "Stream is reported dead but actually seems alive";
1315 if (!audio_unit_)
1316 return;
1317
1318 // Store the existing callback instance for upcoming call to Start().
1319 AudioInputCallback* sink = sink_;
1320 // Do a best-effort attempt to restart the presumably dead input audio stream.
1321 // TODO(henrika): initial tests shows that the scheme below works well but
1322 // there might be corner cases that I have missed.
1323 Stop();
1324 CloseAudioUnit();
1325 DeRegisterDeviceChangeListener();
1326 Open();
1327 Start(sink);
1328 }
1329
1330 void AUAudioInputStream::AddHistogramsForFailedStartup() { 1200 void AUAudioInputStream::AddHistogramsForFailedStartup() {
1331 DCHECK(thread_checker_.CalledOnValidThread()); 1201 DCHECK(thread_checker_.CalledOnValidThread());
1332 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartWasDeferredMac", 1202 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartWasDeferredMac",
1333 start_was_deferred_); 1203 start_was_deferred_);
1334 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputBufferSizeWasChangedMac", 1204 UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputBufferSizeWasChangedMac",
1335 buffer_size_was_changed_); 1205 buffer_size_was_changed_);
1336 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfOutputStreamsMac", 1206 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfOutputStreamsMac",
1337 manager_->output_streams()); 1207 manager_->output_streams());
1338 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfLowLatencyInputStreamsMac", 1208 UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfLowLatencyInputStreamsMac",
1339 manager_->low_latency_input_streams()); 1209 manager_->low_latency_input_streams());
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after
1668 1538
1669 number_of_frames_provided_ = 0; 1539 number_of_frames_provided_ = 0;
1670 glitches_detected_ = 0; 1540 glitches_detected_ = 0;
1671 last_sample_time_ = 0; 1541 last_sample_time_ = 0;
1672 last_number_of_frames_ = 0; 1542 last_number_of_frames_ = 0;
1673 total_lost_frames_ = 0; 1543 total_lost_frames_ = 0;
1674 largest_glitch_frames_ = 0; 1544 largest_glitch_frames_ = 0;
1675 } 1545 }
1676 1546
1677 } // namespace media 1547 } // 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