| Index: media/audio/mac/audio_low_latency_input_mac.cc
|
| diff --git a/media/audio/mac/audio_low_latency_input_mac.cc b/media/audio/mac/audio_low_latency_input_mac.cc
|
| index 15640a57ca94816cdef601122bef988982cf6150..f0dc947ce779c5011879411c30146d3f96879eb7 100644
|
| --- a/media/audio/mac/audio_low_latency_input_mac.cc
|
| +++ b/media/audio/mac/audio_low_latency_input_mac.cc
|
| @@ -29,32 +29,11 @@ const int kNumberOfBlocksBufferInFifo = 2;
|
| // The stream will be stopped as soon as this time limit is passed.
|
| const int kMaxErrorTimeoutInSeconds = 1;
|
|
|
| -// A repeating timer is created and started in Start() and it triggers calls
|
| -// to CheckIfInputStreamIsAlive() where we do periodic checks to see if the
|
| -// input data callback sequence is active or not. If the stream seems dead,
|
| -// up to |kMaxNumberOfRestartAttempts| restart attempts tries to bring the
|
| -// stream back to life.
|
| -const int kCheckInputIsAliveTimeInSeconds = 5;
|
| -
|
| -// Number of restart indications required to actually trigger a restart
|
| -// attempt.
|
| -const int kNumberOfIndicationsToTriggerRestart = 1;
|
| -
|
| -// Max number of times we try to restart a stream when it has been categorized
|
| -// as dead. Note that we can do many restarts during an audio session and this
|
| -// limitation is per detected problem. Once a restart has succeeded, a new
|
| -// sequence of |kMaxNumberOfRestartAttempts| number of restart attempts can be
|
| -// done.
|
| -const int kMaxNumberOfRestartAttempts = 1;
|
| -
|
| // A one-shot timer is created and started in Start() and it triggers
|
| // CheckInputStartupSuccess() after this amount of time. UMA stats marked
|
| // Media.Audio.InputStartupSuccessMac is then updated where true is added
|
| -// if input callbacks have started, and false otherwise. Note that the value
|
| -// is larger than |kCheckInputIsAliveTimeInSeconds| to ensure that at least one
|
| -// restart attempt can be done before storing the result.
|
| -const int kInputCallbackStartTimeoutInSeconds =
|
| - kCheckInputIsAliveTimeInSeconds + 3;
|
| +// if input callbacks have started, and false otherwise.
|
| +const int kInputCallbackStartTimeoutInSeconds = 5;
|
|
|
| // Returns true if the format flags in |format_flags| has the "non-interleaved"
|
| // flag (kAudioFormatFlagIsNonInterleaved) cleared (set to 0).
|
| @@ -255,6 +234,7 @@ AUAudioInputStream::AUAudioInputStream(
|
| fifo_(input_params.channels(),
|
| number_of_frames_,
|
| kNumberOfBlocksBufferInFifo),
|
| + got_input_callback_(false),
|
| input_callback_is_active_(false),
|
| start_was_deferred_(false),
|
| buffer_size_was_changed_(false),
|
| @@ -265,9 +245,6 @@ AUAudioInputStream::AUAudioInputStream(
|
| total_lost_frames_(0),
|
| largest_glitch_frames_(0),
|
| glitches_detected_(0),
|
| - number_of_restart_indications_(0),
|
| - number_of_restart_attempts_(0),
|
| - total_number_of_restart_attempts_(0),
|
| log_callback_(log_callback),
|
| weak_factory_(this) {
|
| DCHECK(manager_);
|
| @@ -543,7 +520,6 @@ void AUAudioInputStream::Start(AudioInputCallback* callback) {
|
|
|
| sink_ = callback;
|
| last_success_time_ = base::TimeTicks::Now();
|
| - last_callback_time_ = base::TimeTicks::Now();
|
| audio_unit_render_has_worked_ = false;
|
| StartAgc();
|
| OSStatus result = AudioOutputUnitStart(audio_unit_);
|
| @@ -565,14 +541,6 @@ void AUAudioInputStream::Start(AudioInputCallback* callback) {
|
| base::TimeDelta::FromSeconds(kInputCallbackStartTimeoutInSeconds), this,
|
| &AUAudioInputStream::CheckInputStartupSuccess);
|
| DCHECK(input_callback_timer_->IsRunning());
|
| -
|
| - // Also create and start a timer that provides periodic callbacks used to
|
| - // monitor if the input stream is alive or not.
|
| - check_alive_timer_.reset(new base::RepeatingTimer());
|
| - check_alive_timer_->Start(
|
| - FROM_HERE, base::TimeDelta::FromSeconds(kCheckInputIsAliveTimeInSeconds),
|
| - this, &AUAudioInputStream::CheckIfInputStreamIsAlive);
|
| - DCHECK(check_alive_timer_->IsRunning());
|
| }
|
|
|
| void AUAudioInputStream::Stop() {
|
| @@ -580,10 +548,6 @@ void AUAudioInputStream::Stop() {
|
| deferred_start_cb_.Cancel();
|
| DVLOG(1) << "Stop";
|
| StopAgc();
|
| - if (check_alive_timer_ != nullptr) {
|
| - check_alive_timer_->Stop();
|
| - check_alive_timer_.reset();
|
| - }
|
| if (input_callback_timer_ != nullptr) {
|
| input_callback_timer_->Stop();
|
| input_callback_timer_.reset();
|
| @@ -611,18 +575,23 @@ void AUAudioInputStream::Stop() {
|
| sink_ = nullptr;
|
| fifo_.Clear();
|
| io_buffer_frame_size_ = 0;
|
| + got_input_callback_ = false;
|
| }
|
|
|
| void AUAudioInputStream::Close() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| DVLOG(1) << "Close";
|
| +
|
| // It is valid to call Close() before calling open or Start().
|
| // It is also valid to call Close() after Start() has been called.
|
| Stop();
|
| +
|
| // Uninitialize and dispose the audio unit.
|
| CloseAudioUnit();
|
| +
|
| // Disable the listener for device property changes.
|
| DeRegisterDeviceChangeListener();
|
| +
|
| // Add more UMA stats but only if AGC was activated, i.e. for e.g. WebRTC
|
| // audio input streams.
|
| if (GetAutomaticGainControl()) {
|
| @@ -640,13 +609,8 @@ void AUAudioInputStream::Close() {
|
| // only when input audio fails to start.
|
| UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputBufferSizeWasChangedAudioWorkedMac",
|
| buffer_size_was_changed_);
|
| - // Logs the total number of times RestartAudio() has been called.
|
| - DVLOG(1) << "Total number of restart attempts: "
|
| - << total_number_of_restart_attempts_;
|
| - UMA_HISTOGRAM_COUNTS_1000("Media.Audio.InputRestartAttemptsMac",
|
| - total_number_of_restart_attempts_);
|
| - // TODO(henrika): possibly add more values here...
|
| }
|
| +
|
| // Inform the audio manager that we have been closed. This will cause our
|
| // destruction.
|
| manager_->ReleaseInputStream(this);
|
| @@ -818,20 +782,12 @@ OSStatus AUAudioInputStream::OnDataIsAvailable(
|
| UInt32 bus_number,
|
| UInt32 number_of_frames) {
|
| TRACE_EVENT0("audio", "AUAudioInputStream::OnDataIsAvailable");
|
| - // Update |last_callback_time_| on the main browser thread. Its value is used
|
| - // by CheckIfInputStreamIsAlive() to detect if the stream is dead or alive.
|
| - manager_->GetTaskRunner()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&AUAudioInputStream::UpdateDataCallbackTimeOnMainThread,
|
| - weak_factory_.GetWeakPtr(), base::TimeTicks::Now()));
|
|
|
| - // Indicate that input callbacks have started on the internal AUHAL IO
|
| - // thread. The |input_callback_is_active_| member is read from the creating
|
| - // thread when a timer fires once and set to false in Stop() on the same
|
| - // thread. It means that this thread is the only writer of
|
| - // |input_callback_is_active_| once the tread starts and it should therefore
|
| - // be safe to modify.
|
| - SetInputCallbackIsActive(true);
|
| + // Indicate that input callbacks have started.
|
| + if (!got_input_callback_) {
|
| + got_input_callback_ = true;
|
| + SetInputCallbackIsActive(true);
|
| + }
|
|
|
| // Update the |mDataByteSize| value in the audio_buffer_list() since
|
| // |number_of_frames| can be changed on the fly.
|
| @@ -1227,72 +1183,6 @@ void AUAudioInputStream::CheckInputStartupSuccess() {
|
| }
|
| }
|
|
|
| -void AUAudioInputStream::UpdateDataCallbackTimeOnMainThread(
|
| - base::TimeTicks now_tick) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - last_callback_time_ = now_tick;
|
| -}
|
| -
|
| -void AUAudioInputStream::CheckIfInputStreamIsAlive() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - // Avoid checking stream state if we are suspended.
|
| - if (manager_->IsSuspending())
|
| - return;
|
| - // Restrict usage of the restart mechanism to "AGC streams" only.
|
| - // TODO(henrika): if the restart scheme works well, we might include it
|
| - // for all types of input streams.
|
| - if (!GetAutomaticGainControl())
|
| - return;
|
| -
|
| - // Clear this counter here when audio is active instead of in Start(),
|
| - // otherwise it would be cleared at each restart attempt and that would break
|
| - // the current design where only a certain number of restart attempts is
|
| - // allowed.
|
| - if (GetInputCallbackIsActive())
|
| - number_of_restart_attempts_ = 0;
|
| -
|
| - // Measure time since last callback. |last_callback_time_| is set the first
|
| - // time in Start() and then updated in each data callback, hence if
|
| - // |time_since_last_callback| is large (>1) and growing for each check, the
|
| - // callback sequence has stopped. A typical value under normal/working
|
| - // conditions is a few milliseconds.
|
| - base::TimeDelta time_since_last_callback =
|
| - base::TimeTicks::Now() - last_callback_time_;
|
| - DVLOG(2) << "time since last callback: "
|
| - << time_since_last_callback.InSecondsF();
|
| -
|
| - // Increase a counter if it has been too long since the last data callback.
|
| - // A non-zero value of this counter is a strong indication of a "dead" input
|
| - // stream. Reset the same counter if the stream is alive.
|
| - if (time_since_last_callback.InSecondsF() >
|
| - 0.5 * kCheckInputIsAliveTimeInSeconds) {
|
| - ++number_of_restart_indications_;
|
| - } else {
|
| - number_of_restart_indications_ = 0;
|
| - }
|
| -
|
| - // Restart the audio stream if two conditions are met. First, the number of
|
| - // restart indicators must be larger than a threshold, and secondly, only a
|
| - // fixed number of restart attempts is allowed.
|
| - // Note that, the threshold is different depending on if the stream is seen
|
| - // as dead directly at the first call to Start() (i.e. it has never started)
|
| - // or if the stream has started OK at least once but then stopped for some
|
| - // reason (e.g by placing the device in sleep mode). One restart indication
|
| - // is sufficient for the first case (threshold is zero), while a larger value
|
| - // (threshold > 0) is required for the second case to avoid false alarms when
|
| - // e.g. resuming from a suspended state.
|
| - const size_t restart_threshold =
|
| - GetInputCallbackIsActive() ? kNumberOfIndicationsToTriggerRestart : 0;
|
| - if (number_of_restart_indications_ > restart_threshold &&
|
| - number_of_restart_attempts_ < kMaxNumberOfRestartAttempts) {
|
| - SetInputCallbackIsActive(false);
|
| - ++total_number_of_restart_attempts_;
|
| - ++number_of_restart_attempts_;
|
| - number_of_restart_indications_ = 0;
|
| - RestartAudio();
|
| - }
|
| -}
|
| -
|
| void AUAudioInputStream::CloseAudioUnit() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| DVLOG(1) << "CloseAudioUnit";
|
| @@ -1307,26 +1197,6 @@ void AUAudioInputStream::CloseAudioUnit() {
|
| audio_unit_ = 0;
|
| }
|
|
|
| -void AUAudioInputStream::RestartAudio() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - DVLOG(1) << "RestartAudio";
|
| - LOG_IF(ERROR, IsRunning())
|
| - << "Stream is reported dead but actually seems alive";
|
| - if (!audio_unit_)
|
| - return;
|
| -
|
| - // Store the existing callback instance for upcoming call to Start().
|
| - AudioInputCallback* sink = sink_;
|
| - // Do a best-effort attempt to restart the presumably dead input audio stream.
|
| - // TODO(henrika): initial tests shows that the scheme below works well but
|
| - // there might be corner cases that I have missed.
|
| - Stop();
|
| - CloseAudioUnit();
|
| - DeRegisterDeviceChangeListener();
|
| - Open();
|
| - Start(sink);
|
| -}
|
| -
|
| void AUAudioInputStream::AddHistogramsForFailedStartup() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| UMA_HISTOGRAM_BOOLEAN("Media.Audio.InputStartWasDeferredMac",
|
|
|