Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/audio_output_device.h" | 5 #include "media/audio/audio_output_device.h" |
| 6 | 6 |
| 7 #include <string> | |
| 8 | |
| 9 #include "base/callback_helpers.h" | 7 #include "base/callback_helpers.h" |
| 10 #include "base/threading/thread_restrictions.h" | 8 #include "base/threading/thread_restrictions.h" |
| 11 #include "base/time/time.h" | 9 #include "base/time/time.h" |
| 12 #include "base/trace_event/trace_event.h" | 10 #include "base/trace_event/trace_event.h" |
| 13 #include "media/audio/audio_output_controller.h" | 11 #include "media/audio/audio_output_controller.h" |
| 14 #include "media/base/limits.h" | 12 #include "media/base/limits.h" |
| 15 | 13 |
| 16 namespace media { | 14 namespace media { |
| 17 | 15 |
| 18 // Takes care of invoking the render callback on the audio thread. | 16 // Takes care of invoking the render callback on the audio thread. |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 35 private: | 33 private: |
| 36 AudioRendererSink::RenderCallback* render_callback_; | 34 AudioRendererSink::RenderCallback* render_callback_; |
| 37 scoped_ptr<AudioBus> output_bus_; | 35 scoped_ptr<AudioBus> output_bus_; |
| 38 uint64 callback_num_; | 36 uint64 callback_num_; |
| 39 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); | 37 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); |
| 40 }; | 38 }; |
| 41 | 39 |
| 42 AudioOutputDevice::AudioOutputDevice( | 40 AudioOutputDevice::AudioOutputDevice( |
| 43 scoped_ptr<AudioOutputIPC> ipc, | 41 scoped_ptr<AudioOutputIPC> ipc, |
| 44 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) | 42 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) |
| 43 : AudioOutputDevice(ipc.Pass(), | |
| 44 io_task_runner, | |
| 45 0, | |
| 46 std::string(), | |
| 47 GURL::EmptyGURL()) {} | |
| 48 | |
| 49 AudioOutputDevice::AudioOutputDevice( | |
| 50 scoped_ptr<AudioOutputIPC> ipc, | |
| 51 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, | |
| 52 int session_id, | |
| 53 const std::string& device_id, | |
| 54 const GURL& security_origin) | |
| 45 : ScopedTaskRunnerObserver(io_task_runner), | 55 : ScopedTaskRunnerObserver(io_task_runner), |
| 46 callback_(NULL), | 56 callback_(NULL), |
| 47 ipc_(ipc.Pass()), | 57 ipc_(ipc.Pass()), |
| 48 state_(IDLE), | 58 state_(IDLE), |
| 49 play_on_start_(true), | 59 play_on_start_(true), |
| 50 session_id_(-1), | 60 session_id_(session_id), |
| 61 device_id_(device_id), | |
| 62 security_origin_(security_origin), | |
| 51 stopping_hack_(false), | 63 stopping_hack_(false), |
| 52 current_switch_request_id_(0) { | 64 switch_output_device_on_start_(false), |
| 65 did_set_output_params_(true, false), | |
| 66 authorization_failed_(false) { | |
|
DaleCurtis
2015/09/09 01:31:57
Should this be another state? That avoid mixing tw
Guido Urdaneta
2015/09/09 16:22:23
Done. Now we have NOT_AUTHORIZED and AUTHORIZED as
| |
| 53 CHECK(ipc_); | 67 CHECK(ipc_); |
| 54 | 68 |
| 55 // The correctness of the code depends on the relative values assigned in the | 69 // The correctness of the code depends on the relative values assigned in the |
| 56 // State enum. | 70 // State enum. |
| 57 static_assert(IPC_CLOSED < IDLE, "invalid enum value assignment 0"); | 71 static_assert(IPC_CLOSED < IDLE, "invalid enum value assignment 0"); |
| 58 static_assert(IDLE < CREATING_STREAM, "invalid enum value assignment 1"); | 72 static_assert(IDLE < AUTHORIZING, "invalid enum value assignment 1"); |
| 59 static_assert(CREATING_STREAM < PAUSED, "invalid enum value assignment 2"); | 73 static_assert(AUTHORIZING < CREATING_STREAM, |
|
DaleCurtis
2015/09/09 01:31:57
Seems there should be an authorized state?
Guido Urdaneta
2015/09/09 16:22:23
Done.
| |
| 60 static_assert(PAUSED < PLAYING, "invalid enum value assignment 3"); | 74 "invalid enum value assignment 2"); |
| 75 static_assert(CREATING_STREAM < PAUSED, "invalid enum value assignment 3"); | |
| 76 static_assert(PAUSED < PLAYING, "invalid enum value assignment 4"); | |
| 61 } | 77 } |
| 62 | 78 |
| 63 void AudioOutputDevice::InitializeWithSessionId(const AudioParameters& params, | 79 void AudioOutputDevice::Initialize(const AudioParameters& params, |
| 64 RenderCallback* callback, | 80 RenderCallback* callback) { |
| 65 int session_id) { | |
| 66 DCHECK(!callback_) << "Calling InitializeWithSessionId() twice?"; | 81 DCHECK(!callback_) << "Calling InitializeWithSessionId() twice?"; |
| 67 DCHECK(params.IsValid()); | 82 DCHECK(params.IsValid()); |
| 68 audio_parameters_ = params; | 83 audio_parameters_ = params; |
| 69 callback_ = callback; | 84 callback_ = callback; |
| 70 session_id_ = session_id; | |
| 71 } | |
| 72 | |
| 73 void AudioOutputDevice::Initialize(const AudioParameters& params, | |
| 74 RenderCallback* callback) { | |
| 75 InitializeWithSessionId(params, callback, 0); | |
| 76 } | 85 } |
| 77 | 86 |
| 78 AudioOutputDevice::~AudioOutputDevice() { | 87 AudioOutputDevice::~AudioOutputDevice() { |
| 79 // The current design requires that the user calls Stop() before deleting | 88 // The current design requires that the user calls Stop() before deleting |
| 80 // this class. | 89 // this class. |
| 81 DCHECK(audio_thread_.IsStopped()); | 90 DCHECK(audio_thread_.IsStopped()); |
| 82 | 91 |
| 83 // The following makes it possible for |current_switch_callback_| to release | 92 // The following makes it possible for |current_switch_callback_| to release |
| 84 // its bound parameters in the correct thread instead of implicitly releasing | 93 // its bound parameters in the correct thread instead of implicitly releasing |
| 85 // them in the thread where this destructor runs. | 94 // them in the thread where this destructor runs. |
| 86 if (!current_switch_callback_.is_null()) { | 95 if (!current_switch_callback_.is_null()) { |
| 87 base::ResetAndReturn(¤t_switch_callback_).Run( | 96 base::ResetAndReturn(¤t_switch_callback_) |
| 88 SWITCH_OUTPUT_DEVICE_RESULT_ERROR_OBSOLETE); | 97 .Run(SWITCH_OUTPUT_DEVICE_RESULT_ERROR_INTERNAL); |
| 89 } | 98 } |
| 90 } | 99 } |
| 91 | 100 |
| 101 void AudioOutputDevice::RequestDeviceAuthorization() { | |
| 102 task_runner()->PostTask( | |
| 103 FROM_HERE, | |
| 104 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread, | |
| 105 this)); | |
| 106 } | |
| 107 | |
| 92 void AudioOutputDevice::Start() { | 108 void AudioOutputDevice::Start() { |
| 93 DCHECK(callback_) << "Initialize hasn't been called"; | 109 DCHECK(callback_) << "Initialize hasn't been called"; |
| 94 task_runner()->PostTask(FROM_HERE, | 110 task_runner()->PostTask(FROM_HERE, |
| 95 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, | 111 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, |
| 96 audio_parameters_)); | 112 audio_parameters_)); |
| 97 } | 113 } |
| 98 | 114 |
| 99 void AudioOutputDevice::Stop() { | 115 void AudioOutputDevice::Stop() { |
| 100 { | 116 { |
| 101 base::AutoLock auto_lock(audio_thread_lock_); | 117 base::AutoLock auto_lock(audio_thread_lock_); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 130 } | 146 } |
| 131 | 147 |
| 132 OutputDevice* AudioOutputDevice::GetOutputDevice() { | 148 OutputDevice* AudioOutputDevice::GetOutputDevice() { |
| 133 return this; | 149 return this; |
| 134 } | 150 } |
| 135 | 151 |
| 136 void AudioOutputDevice::SwitchOutputDevice( | 152 void AudioOutputDevice::SwitchOutputDevice( |
| 137 const std::string& device_id, | 153 const std::string& device_id, |
| 138 const GURL& security_origin, | 154 const GURL& security_origin, |
| 139 const SwitchOutputDeviceCB& callback) { | 155 const SwitchOutputDeviceCB& callback) { |
| 140 DVLOG(1) << __FUNCTION__ << "(" << device_id << ")"; | |
| 141 task_runner()->PostTask( | 156 task_runner()->PostTask( |
| 142 FROM_HERE, base::Bind(&AudioOutputDevice::SwitchOutputDeviceOnIOThread, | 157 FROM_HERE, base::Bind(&AudioOutputDevice::SwitchOutputDeviceOnIOThread, |
| 143 this, device_id, security_origin, callback)); | 158 this, device_id, security_origin, callback)); |
| 144 } | 159 } |
| 145 | 160 |
| 146 void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) { | 161 AudioParameters AudioOutputDevice::GetOutputParameters() { |
| 162 CHECK(!task_runner()->BelongsToCurrentThread()); | |
| 163 did_set_output_params_.Wait(); | |
| 164 return output_params_; | |
| 165 } | |
| 166 | |
| 167 void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() { | |
| 147 DCHECK(task_runner()->BelongsToCurrentThread()); | 168 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 169 // Request authorization only if the stream is stopped | |
| 148 if (state_ == IDLE) { | 170 if (state_ == IDLE) { |
|
DaleCurtis
2015/09/09 01:31:57
DCHECK_EQ? Nothing should be calling this before t
Guido Urdaneta
2015/09/09 16:22:23
Done.
| |
| 149 state_ = CREATING_STREAM; | 171 state_ = AUTHORIZING; |
| 150 ipc_->CreateStream(this, params, session_id_); | 172 ipc_->RequestDeviceAuthorization(this, session_id_, device_id_, |
| 173 security_origin_); | |
| 151 } | 174 } |
| 152 } | 175 } |
| 153 | 176 |
| 177 void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) { | |
| 178 DCHECK(task_runner()->BelongsToCurrentThread()); | |
| 179 if (authorization_failed_) { | |
| 180 callback_->OnRenderError(); | |
| 181 return; | |
| 182 } | |
| 183 | |
| 184 // Request device authorization again if the stream was stopped | |
|
DaleCurtis
2015/09/09 01:31:57
Why when stopped? Shouldn't authorization persist
Guido Urdaneta
2015/09/09 16:22:23
For practical reasons, authorization also ends at
| |
| 185 RequestDeviceAuthorizationOnIOThread(); | |
|
DaleCurtis
2015/09/09 01:31:57
Why is this necessary? If it's a non-default devic
Guido Urdaneta
2015/09/09 16:22:23
I guess my comment above explains why it is necess
| |
| 186 | |
|
DaleCurtis
2015/09/09 01:31:57
DCHECK(state_ == AUTHORIZING || state_ == AUTHORIZ
Guido Urdaneta
2015/09/09 16:22:23
Can also be NOT_AUTHORIZED, or IDLE after a Stop()
| |
| 187 if (state_ == AUTHORIZING) { | |
| 188 state_ = CREATING_STREAM; | |
| 189 ipc_->CreateStream(this, params); | |
| 190 } | |
| 191 } | |
| 192 | |
| 154 void AudioOutputDevice::PlayOnIOThread() { | 193 void AudioOutputDevice::PlayOnIOThread() { |
| 155 DCHECK(task_runner()->BelongsToCurrentThread()); | 194 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 156 if (state_ == PAUSED) { | 195 if (state_ == PAUSED) { |
| 157 TRACE_EVENT_ASYNC_BEGIN0( | 196 TRACE_EVENT_ASYNC_BEGIN0( |
| 158 "audio", "StartingPlayback", audio_callback_.get()); | 197 "audio", "StartingPlayback", audio_callback_.get()); |
| 159 ipc_->PlayStream(); | 198 ipc_->PlayStream(); |
| 160 state_ = PLAYING; | 199 state_ = PLAYING; |
| 161 play_on_start_ = false; | 200 play_on_start_ = false; |
| 162 } else { | 201 } else { |
| 163 play_on_start_ = true; | 202 play_on_start_ = true; |
| 164 } | 203 } |
| 165 } | 204 } |
| 166 | 205 |
| 167 void AudioOutputDevice::PauseOnIOThread() { | 206 void AudioOutputDevice::PauseOnIOThread() { |
| 168 DCHECK(task_runner()->BelongsToCurrentThread()); | 207 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 169 if (state_ == PLAYING) { | 208 if (state_ == PLAYING) { |
| 170 TRACE_EVENT_ASYNC_END0( | 209 TRACE_EVENT_ASYNC_END0( |
| 171 "audio", "StartingPlayback", audio_callback_.get()); | 210 "audio", "StartingPlayback", audio_callback_.get()); |
| 172 ipc_->PauseStream(); | 211 ipc_->PauseStream(); |
| 173 state_ = PAUSED; | 212 state_ = PAUSED; |
| 174 } | 213 } |
| 175 play_on_start_ = false; | 214 play_on_start_ = false; |
| 176 } | 215 } |
| 177 | 216 |
| 178 void AudioOutputDevice::ShutDownOnIOThread() { | 217 void AudioOutputDevice::ShutDownOnIOThread() { |
| 179 DCHECK(task_runner()->BelongsToCurrentThread()); | 218 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 180 | 219 |
| 181 // Close the stream, if we haven't already. | 220 // Close the stream, if we haven't already. |
| 182 if (state_ >= CREATING_STREAM) { | 221 if (state_ > IDLE) { |
| 183 ipc_->CloseStream(); | 222 ipc_->CloseStream(); |
| 184 state_ = IDLE; | 223 state_ = IDLE; |
| 185 } | 224 } |
| 186 | 225 |
| 187 // We can run into an issue where ShutDownOnIOThread is called right after | 226 // We can run into an issue where ShutDownOnIOThread is called right after |
| 188 // OnStreamCreated is called in cases where Start/Stop are called before we | 227 // OnStreamCreated is called in cases where Start/Stop are called before we |
| 189 // get the OnStreamCreated callback. To handle that corner case, we call | 228 // get the OnStreamCreated callback. To handle that corner case, we call |
| 190 // Stop(). In most cases, the thread will already be stopped. | 229 // Stop(). In most cases, the thread will already be stopped. |
| 191 // | 230 // |
| 192 // Another situation is when the IO thread goes away before Stop() is called | 231 // Another situation is when the IO thread goes away before Stop() is called |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 203 DCHECK(task_runner()->BelongsToCurrentThread()); | 242 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 204 if (state_ >= CREATING_STREAM) | 243 if (state_ >= CREATING_STREAM) |
| 205 ipc_->SetVolume(volume); | 244 ipc_->SetVolume(volume); |
| 206 } | 245 } |
| 207 | 246 |
| 208 void AudioOutputDevice::SwitchOutputDeviceOnIOThread( | 247 void AudioOutputDevice::SwitchOutputDeviceOnIOThread( |
| 209 const std::string& device_id, | 248 const std::string& device_id, |
| 210 const GURL& security_origin, | 249 const GURL& security_origin, |
| 211 const SwitchOutputDeviceCB& callback) { | 250 const SwitchOutputDeviceCB& callback) { |
| 212 DCHECK(task_runner()->BelongsToCurrentThread()); | 251 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 213 DVLOG(1) << __FUNCTION__ << "(" << device_id << "," << security_origin << ")"; | 252 |
| 253 // Do not allow concurrent SwitchOutputDevice requests | |
| 254 if (!current_switch_callback_.is_null()) { | |
| 255 callback.Run(SWITCH_OUTPUT_DEVICE_RESULT_ERROR_INTERNAL); | |
| 256 return; | |
| 257 } | |
| 258 | |
| 259 current_switch_callback_ = callback; | |
| 260 current_switch_device_id_ = device_id; | |
| 261 current_switch_security_origin_ = security_origin; | |
| 214 if (state_ >= CREATING_STREAM) { | 262 if (state_ >= CREATING_STREAM) { |
|
DaleCurtis
2015/09/09 01:31:57
I think this code should instead store the current
Guido Urdaneta
2015/09/09 16:22:23
We still have the shared memory size issue.
The or
| |
| 215 SetCurrentSwitchRequest(callback); | 263 ipc_->SwitchOutputDevice(current_switch_device_id_, |
| 216 ipc_->SwitchOutputDevice(device_id, security_origin, | 264 current_switch_security_origin_); |
| 217 current_switch_request_id_); | |
| 218 } else { | 265 } else { |
| 219 callback.Run(SWITCH_OUTPUT_DEVICE_RESULT_ERROR_NOT_SUPPORTED); | 266 switch_output_device_on_start_ = true; |
|
DaleCurtis
2015/09/09 01:31:57
Instead of having this, can we set the state back
Guido Urdaneta
2015/09/09 16:22:23
This isn't intended to address authorization probl
| |
| 220 } | 267 } |
| 221 } | 268 } |
| 222 | 269 |
| 223 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) { | 270 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) { |
| 224 DCHECK(task_runner()->BelongsToCurrentThread()); | 271 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 225 | 272 |
| 226 // Do nothing if the stream has been closed. | 273 // Do nothing if the stream has been closed. |
| 227 if (state_ < CREATING_STREAM) | 274 if (state_ < CREATING_STREAM) |
| 228 return; | 275 return; |
| 229 | 276 |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 243 // a callback object via Start() and clear it in Stop(). | 290 // a callback object via Start() and clear it in Stop(). |
| 244 if (!audio_thread_.IsStopped()) | 291 if (!audio_thread_.IsStopped()) |
| 245 callback_->OnRenderError(); | 292 callback_->OnRenderError(); |
| 246 break; | 293 break; |
| 247 default: | 294 default: |
| 248 NOTREACHED(); | 295 NOTREACHED(); |
| 249 break; | 296 break; |
| 250 } | 297 } |
| 251 } | 298 } |
| 252 | 299 |
| 300 void AudioOutputDevice::OnDeviceAuthorized( | |
| 301 bool success, | |
| 302 const media::AudioParameters& output_params) { | |
| 303 DCHECK(task_runner()->BelongsToCurrentThread()); | |
| 304 if (success) { | |
| 305 SetOutputParams(output_params); | |
|
DaleCurtis
2015/09/09 01:31:57
Seems small to be its own function, just inline?
Guido Urdaneta
2015/09/09 16:22:23
Done.
| |
| 306 return; | |
| 307 } | |
| 308 | |
| 309 authorization_failed_ = true; | |
| 310 if (callback_) | |
| 311 callback_->OnRenderError(); | |
| 312 } | |
| 313 | |
| 253 void AudioOutputDevice::OnStreamCreated( | 314 void AudioOutputDevice::OnStreamCreated( |
| 254 base::SharedMemoryHandle handle, | 315 base::SharedMemoryHandle handle, |
| 255 base::SyncSocket::Handle socket_handle, | 316 base::SyncSocket::Handle socket_handle, |
| 256 int length) { | 317 int length) { |
| 257 DCHECK(task_runner()->BelongsToCurrentThread()); | 318 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 258 DCHECK(base::SharedMemory::IsHandleValid(handle)); | 319 DCHECK(base::SharedMemory::IsHandleValid(handle)); |
| 259 #if defined(OS_WIN) | 320 #if defined(OS_WIN) |
| 260 DCHECK(socket_handle); | 321 DCHECK(socket_handle); |
| 261 #else | 322 #else |
| 262 DCHECK_GE(socket_handle, 0); | 323 DCHECK_GE(socket_handle, 0); |
| 263 #endif | 324 #endif |
| 264 DCHECK_GT(length, 0); | 325 DCHECK_GT(length, 0); |
| 265 | 326 |
| 266 if (state_ != CREATING_STREAM) | 327 if (state_ != CREATING_STREAM) |
| 267 return; | 328 return; |
| 268 | 329 |
| 269 // We can receive OnStreamCreated() on the IO thread after the client has | 330 // We can receive OnStreamCreated() on the IO thread after the client has |
| 270 // called Stop() but before ShutDownOnIOThread() is processed. In such a | 331 // called Stop() but before ShutDownOnIOThread() is processed. In such a |
| 271 // situation |callback_| might point to freed memory. Instead of starting | 332 // situation |callback_| might point to freed memory. Instead of starting |
| 272 // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called. | 333 // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called. |
| 273 // | 334 // |
| 274 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact | 335 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact |
| 275 // that |callback_| (which should own and outlive this object!) can point to | 336 // that |callback_| (which should own and outlive this object!) can point to |
| 276 // freed memory is a mess. AudioRendererSink should be non-refcounted so that | 337 // freed memory is a mess. AudioRendererSink should be non-refcounted so that |
| 277 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and | 338 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and |
| 278 // delete as they see fit. AudioOutputDevice should internally use WeakPtr | 339 // delete as they see fit. AudioOutputDevice should internally use WeakPtr |
| 279 // to handle teardown and thread hopping. See http://crbug.com/151051 for | 340 // to handle teardown and thread hopping. See http://crbug.com/151051 for |
| 280 // details. | 341 // details. |
| 281 base::AutoLock auto_lock(audio_thread_lock_); | 342 { |
| 282 if (stopping_hack_) | 343 base::AutoLock auto_lock(audio_thread_lock_); |
| 283 return; | 344 if (stopping_hack_) |
| 345 return; | |
| 284 | 346 |
| 285 DCHECK(audio_thread_.IsStopped()); | 347 DCHECK(audio_thread_.IsStopped()); |
| 286 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( | 348 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( |
| 287 audio_parameters_, handle, length, callback_)); | 349 audio_parameters_, handle, length, callback_)); |
| 288 audio_thread_.Start( | 350 audio_thread_.Start(audio_callback_.get(), socket_handle, |
| 289 audio_callback_.get(), socket_handle, "AudioOutputDevice", true); | 351 "AudioOutputDevice", true); |
| 290 state_ = PAUSED; | 352 state_ = PAUSED; |
| 291 | 353 |
| 292 // We handle the case where Play() and/or Pause() may have been called | 354 // We handle the case where Play() and/or Pause() may have been called |
| 293 // multiple times before OnStreamCreated() gets called. | 355 // multiple times before OnStreamCreated() gets called. |
| 294 if (play_on_start_) | 356 if (play_on_start_) |
| 295 PlayOnIOThread(); | 357 PlayOnIOThread(); |
| 296 } | 358 } |
| 297 | 359 |
| 298 void AudioOutputDevice::SetCurrentSwitchRequest( | 360 if (switch_output_device_on_start_) { |
|
DaleCurtis
2015/09/09 01:31:57
Hmm, at this point the stream needs to be shutdown
Guido Urdaneta
2015/09/09 16:22:23
Why does the stream need to be shutdown and restar
| |
| 299 const SwitchOutputDeviceCB& callback) { | 361 ipc_->SwitchOutputDevice(current_switch_device_id_, |
| 300 DCHECK(task_runner()->BelongsToCurrentThread()); | 362 current_switch_security_origin_); |
| 301 DVLOG(1) << __FUNCTION__; | |
| 302 // If there is a previous unresolved request, resolve it as obsolete | |
| 303 if (!current_switch_callback_.is_null()) { | |
| 304 base::ResetAndReturn(¤t_switch_callback_).Run( | |
| 305 SWITCH_OUTPUT_DEVICE_RESULT_ERROR_OBSOLETE); | |
| 306 } | 363 } |
| 307 current_switch_callback_ = callback; | |
| 308 current_switch_request_id_++; | |
| 309 } | 364 } |
| 310 | 365 |
| 311 void AudioOutputDevice::OnOutputDeviceSwitched( | 366 void AudioOutputDevice::OnOutputDeviceSwitched( |
| 312 int request_id, | 367 SwitchOutputDeviceResult result, |
| 313 SwitchOutputDeviceResult result) { | 368 const media::AudioParameters& output_params) { |
| 314 DCHECK(task_runner()->BelongsToCurrentThread()); | 369 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 315 DCHECK(request_id <= current_switch_request_id_); | 370 if (result == SWITCH_OUTPUT_DEVICE_RESULT_SUCCESS) { |
| 316 DVLOG(1) << __FUNCTION__ | 371 session_id_ = 0; // Output device is no longer attached to an input device |
| 317 << "(" << request_id << ", " << result << ")"; | 372 device_id_ = current_switch_device_id_; |
|
DaleCurtis
2015/09/09 01:31:57
Clear switch ids?
Guido Urdaneta
2015/09/09 16:22:23
We can clear them, but would there be an advantage
| |
| 318 if (request_id != current_switch_request_id_) { | 373 security_origin_ = current_switch_security_origin_; |
| 319 return; | |
| 320 } | 374 } |
| 375 DCHECK(!current_switch_callback_.is_null()); | |
| 321 base::ResetAndReturn(¤t_switch_callback_).Run(result); | 376 base::ResetAndReturn(¤t_switch_callback_).Run(result); |
| 322 } | 377 } |
| 323 | 378 |
| 324 void AudioOutputDevice::OnIPCClosed() { | 379 void AudioOutputDevice::OnIPCClosed() { |
| 325 DCHECK(task_runner()->BelongsToCurrentThread()); | 380 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 326 state_ = IPC_CLOSED; | 381 state_ = IPC_CLOSED; |
| 327 ipc_.reset(); | 382 ipc_.reset(); |
| 328 } | 383 } |
| 329 | 384 |
| 330 void AudioOutputDevice::WillDestroyCurrentMessageLoop() { | 385 void AudioOutputDevice::WillDestroyCurrentMessageLoop() { |
| 331 LOG(ERROR) << "IO loop going away before the audio device has been stopped"; | 386 LOG(ERROR) << "IO loop going away before the audio device has been stopped"; |
| 332 ShutDownOnIOThread(); | 387 ShutDownOnIOThread(); |
| 333 } | 388 } |
| 334 | 389 |
| 390 void AudioOutputDevice::SetOutputParams( | |
| 391 const media::AudioParameters& output_params) { | |
| 392 DCHECK(task_runner()->BelongsToCurrentThread()); | |
| 393 if (!did_set_output_params_.IsSignaled()) { | |
| 394 did_set_output_params_.Signal(); | |
| 395 output_params_ = output_params; | |
| 396 } | |
| 397 } | |
| 398 | |
| 335 // AudioOutputDevice::AudioThreadCallback | 399 // AudioOutputDevice::AudioThreadCallback |
| 336 | 400 |
| 337 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( | 401 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( |
| 338 const AudioParameters& audio_parameters, | 402 const AudioParameters& audio_parameters, |
| 339 base::SharedMemoryHandle memory, | 403 base::SharedMemoryHandle memory, |
| 340 int memory_length, | 404 int memory_length, |
| 341 AudioRendererSink::RenderCallback* render_callback) | 405 AudioRendererSink::RenderCallback* render_callback) |
| 342 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1), | 406 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1), |
| 343 render_callback_(render_callback), | 407 render_callback_(render_callback), |
| 344 callback_num_(0) {} | 408 callback_num_(0) {} |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 371 TRACE_EVENT_ASYNC_END0("audio", "StartingPlayback", this); | 435 TRACE_EVENT_ASYNC_END0("audio", "StartingPlayback", this); |
| 372 } | 436 } |
| 373 | 437 |
| 374 // Update the audio-delay measurement then ask client to render audio. Since | 438 // Update the audio-delay measurement then ask client to render audio. Since |
| 375 // |output_bus_| is wrapping the shared memory the Render() call is writing | 439 // |output_bus_| is wrapping the shared memory the Render() call is writing |
| 376 // directly into the shared memory. | 440 // directly into the shared memory. |
| 377 render_callback_->Render(output_bus_.get(), audio_delay_milliseconds); | 441 render_callback_->Render(output_bus_.get(), audio_delay_milliseconds); |
| 378 } | 442 } |
| 379 | 443 |
| 380 } // namespace media. | 444 } // namespace media. |
| OLD | NEW |