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

Unified Diff: media/audio/audio_input_controller.cc

Issue 2624403002: Refactor AudioInputController and related interfaces. (Closed)
Patch Set: Address comments Created 3 years, 11 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/audio/audio_input_controller.h ('k') | media/audio/audio_input_controller_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/audio/audio_input_controller.cc
diff --git a/media/audio/audio_input_controller.cc b/media/audio/audio_input_controller.cc
index 878daf2bd97b546b51c0766d21bc7a020f2ac379..04636f3b96524b8e34f7cc584f678dc9d7e71a65 100644
--- a/media/audio/audio_input_controller.cc
+++ b/media/audio/audio_input_controller.cc
@@ -4,6 +4,8 @@
#include "media/audio/audio_input_controller.h"
+#include <inttypes.h>
+
#include <algorithm>
#include <limits>
#include <utility>
@@ -20,6 +22,7 @@
#include "media/audio/audio_file_writer.h"
#include "media/base/user_input_monitor.h"
+namespace media {
namespace {
const int kMaxInputChannels = 3;
@@ -49,7 +52,7 @@ void LogMicrophoneMuteResult(MicrophoneMuteResult result) {
// Helper method which calculates the average power of an audio bus. Unit is in
// dBFS, where 0 dBFS corresponds to all channels and samples equal to 1.0.
-float AveragePower(const media::AudioBus& buffer) {
+float AveragePower(const AudioBus& buffer) {
const int frames = buffer.frames();
const int channels = buffer.channels();
if (frames <= 0 || channels <= 0)
@@ -81,22 +84,125 @@ float AveragePower(const media::AudioBus& buffer) {
} // namespace
-namespace media {
+// Private subclass of AIC that covers the state while capturing audio.
+// This class implements the callback interface from the lower level audio
+// layer and gets called back on the audio hw thread.
+// We implement this in a sub class instead of directly in the AIC so that
+// - The AIC itself is not an AudioInputCallback.
+// - The lifetime of the AudioCallback is shorter than the AIC
+// - How tasks are posted to the AIC from the hw callback thread, is different
+// than how tasks are posted from the AIC to itself from the main thread.
+// So, this difference is isolated to the subclass (see below).
+// - The callback class can gather information on what happened during capture
+// and store it in a state that can be fetched after stopping capture
+// (received_callback, error_during_callback).
+// The AIC itself must not be AddRef-ed on the hw callback thread so that we
+// can be guaranteed to not receive callbacks generated by the hw callback
+// thread after Close() has been called on the audio manager thread and
+// the callback object deleted. To avoid AddRef-ing the AIC and to cancel
+// potentially pending tasks, we use a weak pointer to the AIC instance
+// when posting.
+class AudioInputController::AudioCallback
+ : public AudioInputStream::AudioInputCallback {
+ public:
+ explicit AudioCallback(AudioInputController* controller)
+ : controller_(controller),
+ weak_controller_(controller->weak_ptr_factory_.GetWeakPtr()) {}
+ ~AudioCallback() override {}
+
+ bool received_callback() const { return received_callback_; }
+ bool error_during_callback() const { return error_during_callback_; }
+
+ private:
+ void OnData(AudioInputStream* stream,
+ const AudioBus* source,
+ uint32_t hardware_delay_bytes,
+ double volume) override {
+ TRACE_EVENT0("audio", "AC::OnData");
+
+ received_callback_ = true;
+
+ DeliverDataToSyncWriter(source, hardware_delay_bytes, volume);
+ PerformOptionalDebugRecording(source);
+ }
+
+ void OnError(AudioInputStream* stream) override {
+ error_during_callback_ = true;
+ controller_->task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AudioInputController::DoReportError, weak_controller_));
+ }
+
+ void PerformOptionalDebugRecording(const AudioBus* source) {
+ // Called on the hw callback thread while recording is enabled.
+ if (!controller_->debug_writer_ || !controller_->debug_writer_->WillWrite())
+ return;
+
+ // TODO(tommi): This is costly. AudioBus heap allocs and we create a new
+ // one for every callback. We could instead have a pool of bus objects
+ // that get returned to us somehow.
+ // We should also avoid calling PostTask here since the implementation
+ // of the debug writer will basically do a PostTask straight away anyway.
+ // Might require some modifications to AudioInputDebugWriter though since
+ // there are some threading concerns there and AudioInputDebugWriter's
+ // lifetime guarantees need to be longer than that of associated active
+ // audio streams.
+ std::unique_ptr<AudioBus> source_copy =
+ AudioBus::Create(source->channels(), source->frames());
+ source->CopyTo(source_copy.get());
+ controller_->task_runner_->PostTask(
+ FROM_HERE, base::Bind(&AudioInputController::WriteInputDataForDebugging,
+ weak_controller_, base::Passed(&source_copy)));
+ }
+
+ void DeliverDataToSyncWriter(const AudioBus* source,
+ uint32_t hardware_delay_bytes,
+ double volume) {
+ bool key_pressed = controller_->CheckForKeyboardInput();
+ controller_->sync_writer_->Write(source, volume, key_pressed,
+ hardware_delay_bytes);
+
+ // The way the two classes interact here, could be done in a nicer way.
+ // As is, we call the AIC here to check the audio power, return and then
+ // post a task to the AIC based on what the AIC said.
+ // The reason for this is to keep all PostTask calls from the hw callback
+ // thread to the AIC, that use a weak pointer, in the same class.
+ float average_power_dbfs;
+ int mic_volume_percent;
+ if (controller_->CheckAudioPower(source, volume, &average_power_dbfs,
+ &mic_volume_percent)) {
+ // Use event handler on the audio thread to relay a message to the ARIH
+ // in content which does the actual logging on the IO thread.
+ controller_->task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AudioInputController::DoLogAudioLevels, weak_controller_,
+ average_power_dbfs, mic_volume_percent));
+ }
+ }
+
+ AudioInputController* const controller_;
+ // We do not want any pending posted tasks generated from the callback class
+ // to keep the controller object alive longer than it should. So we use
+ // a weak ptr whenever we post, we use this weak pointer.
+ base::WeakPtr<AudioInputController> weak_controller_;
+ bool received_callback_ = false;
+ bool error_during_callback_ = false;
+};
// static
AudioInputController::Factory* AudioInputController::factory_ = nullptr;
AudioInputController::AudioInputController(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
EventHandler* handler,
SyncWriter* sync_writer,
std::unique_ptr<AudioFileWriter> debug_writer,
UserInputMonitor* user_input_monitor,
const bool agc_is_enabled)
: creator_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ task_runner_(std::move(task_runner)),
handler_(handler),
stream_(nullptr),
- should_report_stats(0),
- state_(CLOSED),
sync_writer_(sync_writer),
max_volume_(0.0),
user_input_monitor_(user_input_monitor),
@@ -107,36 +213,42 @@ AudioInputController::AudioInputController(
silence_state_(SILENCE_STATE_NO_MEASUREMENT),
#endif
prev_key_down_count_(0),
- debug_writer_(std::move(debug_writer)) {
+ debug_writer_(std::move(debug_writer)),
+ weak_ptr_factory_(this) {
DCHECK(creator_task_runner_.get());
+ DCHECK(handler_);
+ DCHECK(sync_writer_);
}
AudioInputController::~AudioInputController() {
- DCHECK_EQ(state_, CLOSED);
+ DCHECK(!audio_callback_);
+ DCHECK(!stream_);
}
// static
scoped_refptr<AudioInputController> AudioInputController::Create(
AudioManager* audio_manager,
EventHandler* event_handler,
+ SyncWriter* sync_writer,
const AudioParameters& params,
const std::string& device_id,
UserInputMonitor* user_input_monitor) {
DCHECK(audio_manager);
+ DCHECK(event_handler);
+ DCHECK(sync_writer);
if (!params.IsValid() || (params.channels() > kMaxInputChannels))
return nullptr;
if (factory_) {
- return factory_->Create(audio_manager->GetTaskRunner(),
- /*sync_writer*/ nullptr, audio_manager,
- event_handler, params, user_input_monitor);
+ return factory_->Create(audio_manager->GetTaskRunner(), sync_writer,
+ audio_manager, event_handler, params,
+ user_input_monitor);
}
scoped_refptr<AudioInputController> controller(new AudioInputController(
- event_handler, nullptr, nullptr, user_input_monitor, false));
-
- controller->task_runner_ = audio_manager->GetTaskRunner();
+ audio_manager->GetTaskRunner(), event_handler, sync_writer, nullptr,
+ user_input_monitor, false));
// Create and open a new audio input stream from the existing
// audio-device thread.
@@ -165,6 +277,7 @@ scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency(
const bool agc_is_enabled) {
DCHECK(audio_manager);
DCHECK(sync_writer);
+ DCHECK(event_handler);
if (!params.IsValid() || (params.channels() > kMaxInputChannels))
return nullptr;
@@ -178,9 +291,8 @@ scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency(
// Create the AudioInputController object and ensure that it runs on
// the audio-manager thread.
scoped_refptr<AudioInputController> controller(new AudioInputController(
- event_handler, sync_writer, std::move(debug_writer), user_input_monitor,
- agc_is_enabled));
- controller->task_runner_ = audio_manager->GetTaskRunner();
+ audio_manager->GetTaskRunner(), event_handler, sync_writer,
+ std::move(debug_writer), user_input_monitor, agc_is_enabled));
// Create and open a new audio input stream from the existing
// audio-device thread. Use the provided audio-input device.
@@ -207,19 +319,19 @@ scoped_refptr<AudioInputController> AudioInputController::CreateForStream(
UserInputMonitor* user_input_monitor) {
DCHECK(sync_writer);
DCHECK(stream);
+ DCHECK(event_handler);
if (factory_) {
return factory_->Create(
task_runner, sync_writer, AudioManager::Get(), event_handler,
- media::AudioParameters::UnavailableDeviceParams(), user_input_monitor);
+ AudioParameters::UnavailableDeviceParams(), user_input_monitor);
}
// Create the AudioInputController object and ensure that it runs on
// the audio-manager thread.
scoped_refptr<AudioInputController> controller(new AudioInputController(
- event_handler, sync_writer, std::move(debug_writer), user_input_monitor,
- false));
- controller->task_runner_ = task_runner;
+ task_runner, event_handler, sync_writer, std::move(debug_writer),
+ user_input_monitor, false));
if (!controller->task_runner_->PostTask(
FROM_HERE,
@@ -233,6 +345,7 @@ scoped_refptr<AudioInputController> AudioInputController::CreateForStream(
}
void AudioInputController::Record() {
+ DCHECK(creator_task_runner_->BelongsToCurrentThread());
task_runner_->PostTask(FROM_HERE, base::Bind(
&AudioInputController::DoRecord, this));
}
@@ -246,6 +359,7 @@ void AudioInputController::Close(const base::Closure& closed_task) {
}
void AudioInputController::SetVolume(double volume) {
+ DCHECK(creator_task_runner_->BelongsToCurrentThread());
task_runner_->PostTask(FROM_HERE, base::Bind(
&AudioInputController::DoSetVolume, this, volume));
}
@@ -254,9 +368,9 @@ void AudioInputController::DoCreate(AudioManager* audio_manager,
const AudioParameters& params,
const std::string& device_id) {
DCHECK(task_runner_->BelongsToCurrentThread());
+ DCHECK(!stream_);
SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime");
- if (handler_)
- handler_->OnLog(this, "AIC::DoCreate");
+ handler_->OnLog(this, "AIC::DoCreate");
#if defined(AUDIO_POWER_MONITORING)
// Disable power monitoring for streams that run without AGC enabled to
@@ -266,6 +380,8 @@ void AudioInputController::DoCreate(AudioManager* audio_manager,
silence_state_ = SILENCE_STATE_NO_MEASUREMENT;
#endif
+ // MakeAudioInputStream might fail and return nullptr. If so,
+ // DoCreateForStream will handle and report it.
DoCreateForStream(audio_manager->MakeAudioInputStream(
params, device_id, base::Bind(&AudioInputController::LogMessage, this)));
}
@@ -289,99 +405,94 @@ void AudioInputController::DoCreateForLowLatency(AudioManager* audio_manager,
void AudioInputController::DoCreateForStream(
AudioInputStream* stream_to_control) {
DCHECK(task_runner_->BelongsToCurrentThread());
-
DCHECK(!stream_);
- stream_ = stream_to_control;
- should_report_stats = 1;
- if (!stream_) {
- if (handler_)
- handler_->OnError(this, STREAM_CREATE_ERROR);
+ if (!stream_to_control) {
LogCaptureStartupResult(CAPTURE_STARTUP_CREATE_STREAM_FAILED);
+ handler_->OnError(this, STREAM_CREATE_ERROR);
return;
}
- if (stream_ && !stream_->Open()) {
- stream_->Close();
- stream_ = nullptr;
- if (handler_)
- handler_->OnError(this, STREAM_OPEN_ERROR);
+ if (!stream_to_control->Open()) {
+ stream_to_control->Close();
LogCaptureStartupResult(CAPTURE_STARTUP_OPEN_STREAM_FAILED);
+ handler_->OnError(this, STREAM_OPEN_ERROR);
return;
}
// Set AGC state using mode in |agc_is_enabled_| which can only be enabled in
// CreateLowLatency().
#if defined(AUDIO_POWER_MONITORING)
- bool agc_is_supported = false;
- agc_is_supported = stream_->SetAutomaticGainControl(agc_is_enabled_);
+ bool agc_is_supported =
+ stream_to_control->SetAutomaticGainControl(agc_is_enabled_);
// Disable power measurements on platforms that does not support AGC at a
// lower level. AGC can fail on platforms where we don't support the
// functionality to modify the input volume slider. One such example is
// Windows XP.
power_measurement_is_enabled_ &= agc_is_supported;
#else
- stream_->SetAutomaticGainControl(agc_is_enabled_);
+ stream_to_control->SetAutomaticGainControl(agc_is_enabled_);
#endif
-
- state_ = CREATED;
- if (handler_)
- handler_->OnCreated(this);
-
- if (user_input_monitor_) {
- user_input_monitor_->EnableKeyPressMonitoring();
- prev_key_down_count_ = user_input_monitor_->GetKeyPressCount();
- }
+ // Finally, keep the stream pointer around, update the state and notify.
+ stream_ = stream_to_control;
+ handler_->OnCreated(this);
}
void AudioInputController::DoRecord() {
DCHECK(task_runner_->BelongsToCurrentThread());
SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.RecordTime");
- if (state_ != CREATED)
+ if (!stream_ || audio_callback_)
return;
- {
- base::AutoLock auto_lock(lock_);
- state_ = RECORDING;
- }
+ handler_->OnLog(this, "AIC::DoRecord");
- if (handler_)
- handler_->OnLog(this, "AIC::DoRecord");
+ if (user_input_monitor_) {
+ user_input_monitor_->EnableKeyPressMonitoring();
+ prev_key_down_count_ = user_input_monitor_->GetKeyPressCount();
+ }
- stream_->Start(this);
+ audio_callback_.reset(new AudioCallback(this));
+ stream_->Start(audio_callback_.get());
}
void AudioInputController::DoClose() {
DCHECK(task_runner_->BelongsToCurrentThread());
SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime");
- // If we have already logged something, this does nothing.
- // Otherwise, we haven't recieved data.
- LogCaptureStartupResult(CAPTURE_STARTUP_NEVER_GOT_DATA);
- if (state_ == CLOSED)
+ if (!stream_)
return;
- // If this is a low-latency stream, log the total duration (since DoCreate)
- // and add it to a UMA histogram.
- if (!low_latency_create_time_.is_null()) {
- base::TimeDelta duration =
- base::TimeTicks::Now() - low_latency_create_time_;
- UMA_HISTOGRAM_LONG_TIMES("Media.InputStreamDuration", duration);
- if (handler_) {
- std::string log_string =
- base::StringPrintf("AIC::DoClose: stream duration=");
- log_string += base::Int64ToString(duration.InSeconds());
- log_string += " seconds";
- handler_->OnLog(this, log_string);
+ // Allow calling unconditionally and bail if we don't have a stream to close.
+ if (audio_callback_) {
+ stream_->Stop();
+
+ if (!low_latency_create_time_.is_null()) {
+ LogCaptureStartupResult(audio_callback_->received_callback()
+ ? CAPTURE_STARTUP_OK
+ : CAPTURE_STARTUP_NEVER_GOT_DATA);
+ UMA_HISTOGRAM_BOOLEAN("Media.Audio.Capture.CallbackError",
+ audio_callback_->error_during_callback());
+ if (audio_callback_->received_callback()) {
+ // Log the total duration (since DoCreate) and update the histogram.
+ const base::TimeDelta duration =
+ base::TimeTicks::Now() - low_latency_create_time_;
+ UMA_HISTOGRAM_LONG_TIMES("Media.InputStreamDuration", duration);
+ const std::string log_string = base::StringPrintf(
+ "AIC::DoClose: stream duration=%" PRId64 " seconds",
+ duration.InSeconds());
+ handler_->OnLog(this, log_string);
+ }
}
+
+ audio_callback_.reset();
}
- DoStopCloseAndClearStream();
+ stream_->Close();
+ stream_ = nullptr;
- if (SharedMemoryAndSyncSocketMode())
- sync_writer_->Close();
+ sync_writer_->Close();
if (user_input_monitor_)
user_input_monitor_->DisableKeyPressMonitoring();
@@ -396,13 +507,14 @@ void AudioInputController::DoClose() {
if (debug_writer_)
debug_writer_->Stop();
- state_ = CLOSED;
+ max_volume_ = 0.0;
+ low_latency_create_time_ = base::TimeTicks(); // Reset to null.
+ weak_ptr_factory_.InvalidateWeakPtrs();
}
void AudioInputController::DoReportError() {
DCHECK(task_runner_->BelongsToCurrentThread());
- if (handler_)
- handler_->OnError(this, STREAM_ERROR);
+ handler_->OnError(this, STREAM_ERROR);
}
void AudioInputController::DoSetVolume(double volume) {
@@ -410,7 +522,7 @@ void AudioInputController::DoSetVolume(double volume) {
DCHECK_GE(volume, 0);
DCHECK_LE(volume, 1.0);
- if (state_ != CREATED && state_ != RECORDING)
+ if (!stream_)
return;
// Only ask for the maximum volume at first call and use cached value
@@ -428,100 +540,11 @@ void AudioInputController::DoSetVolume(double volume) {
stream_->SetVolume(max_volume_ * volume);
}
-void AudioInputController::OnData(AudioInputStream* stream,
- const AudioBus* source,
- uint32_t hardware_delay_bytes,
- double volume) {
- TRACE_EVENT0("audio", "AudioInputController::OnData");
- if (debug_writer_ && debug_writer_->WillWrite()) {
- std::unique_ptr<AudioBus> source_copy =
- AudioBus::Create(source->channels(), source->frames());
- source->CopyTo(source_copy.get());
- task_runner_->PostTask(
- FROM_HERE,
- base::Bind(
- &AudioInputController::WriteInputDataForDebugging,
- this,
- base::Passed(&source_copy)));
- }
- // Now we have data, so we know for sure that startup was ok.
- LogCaptureStartupResult(CAPTURE_STARTUP_OK);
-
- {
- base::AutoLock auto_lock(lock_);
- if (state_ != RECORDING)
- return;
- }
-
- bool key_pressed = false;
- if (user_input_monitor_) {
- size_t current_count = user_input_monitor_->GetKeyPressCount();
- key_pressed = current_count != prev_key_down_count_;
- prev_key_down_count_ = current_count;
- DVLOG_IF(6, key_pressed) << "Detected keypress.";
- }
-
- // Use SharedMemory and SyncSocket if the client has created a SyncWriter.
- // Used by all low-latency clients except WebSpeech.
- if (SharedMemoryAndSyncSocketMode()) {
- sync_writer_->Write(source, volume, key_pressed, hardware_delay_bytes);
-
-#if defined(AUDIO_POWER_MONITORING)
- // Only do power-level measurements if DoCreate() has been called. It will
- // ensure that logging will mainly be done for WebRTC and WebSpeech
- // clients.
- if (!power_measurement_is_enabled_)
- return;
-
- // Perform periodic audio (power) level measurements.
- if ((base::TimeTicks::Now() - last_audio_level_log_time_).InSeconds() >
- kPowerMonitorLogIntervalSeconds) {
- // Calculate the average power of the signal, or the energy per sample.
- const float average_power_dbfs = AveragePower(*source);
-
- // Add current microphone volume to log and UMA histogram.
- const int mic_volume_percent = static_cast<int>(100.0 * volume);
-
- // Use event handler on the audio thread to relay a message to the ARIH
- // in content which does the actual logging on the IO thread.
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&AudioInputController::DoLogAudioLevels,
- this,
- average_power_dbfs,
- mic_volume_percent));
-
- last_audio_level_log_time_ = base::TimeTicks::Now();
- }
-#endif
- return;
- }
-
- // TODO(henrika): Investigate if we can avoid the extra copy here.
- // (see http://crbug.com/249316 for details). AFAIK, this scope is only
- // active for WebSpeech clients.
- std::unique_ptr<AudioBus> audio_data =
- AudioBus::Create(source->channels(), source->frames());
- source->CopyTo(audio_data.get());
-
- // Ownership of the audio buffer will be with the callback until it is run,
- // when ownership is passed to the callback function.
- task_runner_->PostTask(
- FROM_HERE,
- base::Bind(
- &AudioInputController::DoOnData, this, base::Passed(&audio_data)));
-}
-
-void AudioInputController::DoOnData(std::unique_ptr<AudioBus> data) {
- DCHECK(task_runner_->BelongsToCurrentThread());
- if (handler_)
- handler_->OnData(this, data.get());
-}
-
void AudioInputController::DoLogAudioLevels(float level_dbfs,
int microphone_volume_percent) {
#if defined(AUDIO_POWER_MONITORING)
DCHECK(task_runner_->BelongsToCurrentThread());
- if (!handler_)
+ if (!stream_)
return;
// Detect if the user has enabled hardware mute by pressing the mute
@@ -555,14 +578,9 @@ void AudioInputController::DoLogAudioLevels(float level_dbfs,
#endif
}
-void AudioInputController::OnError(AudioInputStream* stream) {
- // Handle error on the audio-manager thread.
- task_runner_->PostTask(FROM_HERE, base::Bind(
- &AudioInputController::DoReportError, this));
-}
-
void AudioInputController::EnableDebugRecording(
const base::FilePath& file_name) {
+ DCHECK(creator_task_runner_->BelongsToCurrentThread());
task_runner_->PostTask(
FROM_HERE, base::Bind(&AudioInputController::DoEnableDebugRecording, this,
file_name));
@@ -575,20 +593,6 @@ void AudioInputController::DisableDebugRecording() {
base::Bind(&AudioInputController::DoDisableDebugRecording, this));
}
-void AudioInputController::DoStopCloseAndClearStream() {
- DCHECK(task_runner_->BelongsToCurrentThread());
-
- // Allow calling unconditionally and bail if we don't have a stream to close.
- if (stream_ != nullptr) {
- stream_->Stop();
- stream_->Close();
- stream_ = nullptr;
- }
-
- // The event handler should not be touched after the stream has been closed.
- handler_ = nullptr;
-}
-
#if defined(AUDIO_POWER_MONITORING)
void AudioInputController::UpdateSilenceState(bool silence) {
if (silence) {
@@ -621,15 +625,8 @@ void AudioInputController::LogSilenceState(SilenceState value) {
void AudioInputController::LogCaptureStartupResult(
CaptureStartupResult result) {
- // Decrement shall_report_stats and check if it was 1 before decrement,
- // which would imply that this is the first time this method is called
- // after initialization. To avoid underflow, we
- // also check if should_report_stats is one before decrementing.
- if (base::AtomicRefCountIsOne(&should_report_stats) &&
- !base::AtomicRefCountDec(&should_report_stats)) {
- UMA_HISTOGRAM_ENUMERATION("Media.AudioInputControllerCaptureStartupSuccess",
- result, CAPTURE_STARTUP_RESULT_MAX + 1);
- }
+ UMA_HISTOGRAM_ENUMERATION("Media.AudioInputControllerCaptureStartupSuccess",
+ result, CAPTURE_STARTUP_RESULT_MAX + 1);
}
void AudioInputController::DoEnableDebugRecording(
@@ -657,4 +654,45 @@ void AudioInputController::LogMessage(const std::string& message) {
handler_->OnLog(this, message);
}
+bool AudioInputController::CheckForKeyboardInput() {
+ if (!user_input_monitor_)
+ return false;
+
+ const size_t current_count = user_input_monitor_->GetKeyPressCount();
+ const bool key_pressed = current_count != prev_key_down_count_;
+ prev_key_down_count_ = current_count;
+ DVLOG_IF(6, key_pressed) << "Detected keypress.";
+
+ return key_pressed;
+}
+
+bool AudioInputController::CheckAudioPower(const AudioBus* source,
+ double volume,
+ float* average_power_dbfs,
+ int* mic_volume_percent) {
+#if defined(AUDIO_POWER_MONITORING)
+ // Only do power-level measurements if DoCreate() has been called. It will
+ // ensure that logging will mainly be done for WebRTC and WebSpeech
+ // clients.
+ if (!power_measurement_is_enabled_)
+ return false;
+
+ // Perform periodic audio (power) level measurements.
+ const auto now = base::TimeTicks::Now();
+ if ((now - last_audio_level_log_time_).InSeconds() <=
+ kPowerMonitorLogIntervalSeconds) {
+ return false;
+ }
+
+ *average_power_dbfs = AveragePower(*source);
+ *mic_volume_percent = static_cast<int>(100.0 * volume);
+
+ last_audio_level_log_time_ = now;
+
+ return true;
+#else
+ return false;
+#endif
+}
+
} // namespace media
« no previous file with comments | « media/audio/audio_input_controller.h ('k') | media/audio/audio_input_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698