Index: media/audio/audio_output_device.cc |
diff --git a/media/audio/audio_output_device.cc b/media/audio/audio_output_device.cc |
index a3effebfb43af118500197a6eed9a48093563f7d..12d102c4ad196911c9ddfb7430e60da7ca99093b 100644 |
--- a/media/audio/audio_output_device.cc |
+++ b/media/audio/audio_output_device.cc |
@@ -12,8 +12,10 @@ |
#include "base/callback_helpers.h" |
#include "base/macros.h" |
+#include "base/metrics/histogram_macros.h" |
#include "base/threading/thread_restrictions.h" |
#include "base/time/time.h" |
+#include "base/timer/timer.h" |
#include "base/trace_event/trace_event.h" |
#include "build/build_config.h" |
#include "media/audio/audio_device_description.h" |
@@ -52,7 +54,8 @@ AudioOutputDevice::AudioOutputDevice( |
const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, |
int session_id, |
const std::string& device_id, |
- const url::Origin& security_origin) |
+ const url::Origin& security_origin, |
+ base::TimeDelta authorization_timeout) |
: ScopedTaskRunnerObserver(io_task_runner), |
callback_(NULL), |
ipc_(std::move(ipc)), |
@@ -65,7 +68,8 @@ AudioOutputDevice::AudioOutputDevice( |
stopping_hack_(false), |
did_receive_auth_(base::WaitableEvent::ResetPolicy::MANUAL, |
base::WaitableEvent::InitialState::NOT_SIGNALED), |
- device_status_(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL) { |
+ device_status_(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL), |
+ auth_timeout_(authorization_timeout) { |
CHECK(ipc_); |
// The correctness of the code depends on the relative values assigned in the |
@@ -156,6 +160,16 @@ void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() { |
state_ = AUTHORIZING; |
ipc_->RequestDeviceAuthorization(this, session_id_, device_id_, |
security_origin_); |
+ |
+ // Create the timer on the thread it's used on. It's guaranteed to be |
+ // deleted on the same thread since users must call Stop() before deleting |
+ // AudioOutputDevice; see ShutDownOnIOThread(). |
+ auth_timeout_action_.reset(new base::OneShotTimer()); |
+ auth_timeout_action_->Start( |
+ FROM_HERE, auth_timeout_, |
+ base::Bind(&AudioOutputDevice::OnDeviceAuthorized, this, |
+ OUTPUT_DEVICE_STATUS_ERROR_TIMED_OUT, media::AudioParameters(), |
+ std::string())); |
} |
void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) { |
@@ -229,6 +243,9 @@ void AudioOutputDevice::ShutDownOnIOThread() { |
} |
start_on_authorized_ = false; |
+ // Destoy the timer on the thread it's used on. |
+ auth_timeout_action_.reset(); |
+ |
// We can run into an issue where ShutDownOnIOThread is called right after |
// OnStreamCreated is called in cases where Start/Stop are called before we |
// get the OnStreamCreated callback. To handle that corner case, we call |
@@ -285,6 +302,16 @@ void AudioOutputDevice::OnDeviceAuthorized( |
const media::AudioParameters& output_params, |
const std::string& matched_device_id) { |
DCHECK(task_runner()->BelongsToCurrentThread()); |
+ |
+ auth_timeout_action_.reset(); |
+ |
+ // Do nothing if late authorization is received after timeout. |
+ if (state_ == IPC_CLOSED) |
+ return; |
+ |
+ UMA_HISTOGRAM_BOOLEAN("Media.Audio.Render.OutputDeviceAuthorizationTimedOut", |
+ device_status == OUTPUT_DEVICE_STATUS_ERROR_TIMED_OUT); |
+ |
DCHECK_EQ(state_, AUTHORIZING); |
// It may happen that a second authorization is received as a result to a |