| 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 <stddef.h> | 7 #include <stddef.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| 11 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
| 12 #include "base/macros.h" | 12 #include "base/macros.h" |
| 13 #include "base/threading/thread_restrictions.h" | 13 #include "base/threading/thread_restrictions.h" |
| 14 #include "base/time/time.h" | 14 #include "base/time/time.h" |
| 15 #include "base/trace_event/trace_event.h" | 15 #include "base/trace_event/trace_event.h" |
| 16 #include "build/build_config.h" | 16 #include "build/build_config.h" |
| 17 #include "media/audio/audio_output_controller.h" | 17 #include "media/audio/audio_output_controller.h" |
| 18 #include "media/base/limits.h" | 18 #include "media/base/limits.h" |
| 19 | 19 |
| 20 #include "base/debug/stack_trace.h" |
| 21 |
| 20 namespace media { | 22 namespace media { |
| 21 | 23 |
| 22 // Takes care of invoking the render callback on the audio thread. | 24 // Takes care of invoking the render callback on the audio thread. |
| 23 // An instance of this class is created for each capture stream in | 25 // An instance of this class is created for each capture stream in |
| 24 // OnStreamCreated(). | 26 // OnStreamCreated(). |
| 25 class AudioOutputDevice::AudioThreadCallback | 27 class AudioOutputDevice::AudioThreadCallback |
| 26 : public AudioDeviceThread::Callback { | 28 : public AudioDeviceThread::Callback { |
| 27 public: | 29 public: |
| 28 AudioThreadCallback(const AudioParameters& audio_parameters, | 30 AudioThreadCallback(const AudioParameters& audio_parameters, |
| 29 base::SharedMemoryHandle memory, | 31 base::SharedMemoryHandle memory, |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 static_assert(IDLE < AUTHORIZING, "invalid enum value assignment 1"); | 72 static_assert(IDLE < AUTHORIZING, "invalid enum value assignment 1"); |
| 71 static_assert(AUTHORIZING < AUTHORIZED, "invalid enum value assignment 2"); | 73 static_assert(AUTHORIZING < AUTHORIZED, "invalid enum value assignment 2"); |
| 72 static_assert(AUTHORIZED < CREATING_STREAM, | 74 static_assert(AUTHORIZED < CREATING_STREAM, |
| 73 "invalid enum value assignment 3"); | 75 "invalid enum value assignment 3"); |
| 74 static_assert(CREATING_STREAM < PAUSED, "invalid enum value assignment 4"); | 76 static_assert(CREATING_STREAM < PAUSED, "invalid enum value assignment 4"); |
| 75 static_assert(PAUSED < PLAYING, "invalid enum value assignment 5"); | 77 static_assert(PAUSED < PLAYING, "invalid enum value assignment 5"); |
| 76 } | 78 } |
| 77 | 79 |
| 78 void AudioOutputDevice::Initialize(const AudioParameters& params, | 80 void AudioOutputDevice::Initialize(const AudioParameters& params, |
| 79 RenderCallback* callback) { | 81 RenderCallback* callback) { |
| 80 DCHECK(!callback_) << "Calling Initialize() twice?"; | |
| 81 DCHECK(params.IsValid()); | 82 DCHECK(params.IsValid()); |
| 82 audio_parameters_ = params; | 83 task_runner()->PostTask( |
| 83 callback_ = callback; | 84 FROM_HERE, |
| 85 base::Bind(&AudioOutputDevice::InitializeOnIOThread, |
| 86 this, params, callback)); |
| 84 } | 87 } |
| 85 | 88 |
| 86 AudioOutputDevice::~AudioOutputDevice() { | 89 AudioOutputDevice::~AudioOutputDevice() { |
| 87 // The current design requires that the user calls Stop() before deleting | 90 // The current design requires that the user calls Stop() before deleting |
| 88 // this class. | 91 // this class. Since this object is reference counted, we're the only one |
| 89 DCHECK(audio_thread_.IsStopped()); | 92 // accessing data when we destruct. |
| 93 DCHECK(state_ == IDLE || state_ == IPC_CLOSED); |
| 94 audio_thread_.Stop(base::MessageLoop::current()); |
| 90 } | 95 } |
| 91 | 96 |
| 92 void AudioOutputDevice::RequestDeviceAuthorization() { | 97 void AudioOutputDevice::RequestDeviceAuthorization() { |
| 93 task_runner()->PostTask( | 98 task_runner()->PostTask( |
| 94 FROM_HERE, | 99 FROM_HERE, |
| 95 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread, | 100 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread, |
| 96 this)); | 101 this)); |
| 97 } | 102 } |
| 98 | 103 |
| 99 void AudioOutputDevice::Start() { | 104 void AudioOutputDevice::Start() { |
| 100 DCHECK(callback_) << "Initialize hasn't been called"; | |
| 101 task_runner()->PostTask(FROM_HERE, | 105 task_runner()->PostTask(FROM_HERE, |
| 102 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, | 106 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this)); |
| 103 audio_parameters_)); | |
| 104 } | 107 } |
| 105 | 108 |
| 106 void AudioOutputDevice::Stop() { | 109 void AudioOutputDevice::Stop() { |
| 107 { | 110 { |
| 108 base::AutoLock auto_lock(audio_thread_lock_); | 111 base::AutoLock auto_lock(audio_thread_lock_); |
| 109 audio_thread_.Stop(base::MessageLoop::current()); | 112 audio_thread_.StopRun(); |
| 110 stopping_hack_ = true; | 113 stopping_hack_ = true; |
| 111 } | 114 } |
| 112 | 115 |
| 113 task_runner()->PostTask(FROM_HERE, | 116 task_runner()->PostTask(FROM_HERE, |
| 114 base::Bind(&AudioOutputDevice::ShutDownOnIOThread, this)); | 117 base::Bind(&AudioOutputDevice::StopOnIOThread, this)); |
| 115 } | 118 } |
| 116 | 119 |
| 117 void AudioOutputDevice::Play() { | 120 void AudioOutputDevice::Play() { |
| 118 task_runner()->PostTask(FROM_HERE, | 121 task_runner()->PostTask(FROM_HERE, |
| 119 base::Bind(&AudioOutputDevice::PlayOnIOThread, this)); | 122 base::Bind(&AudioOutputDevice::PlayOnIOThread, this)); |
| 120 } | 123 } |
| 121 | 124 |
| 122 void AudioOutputDevice::Pause() { | 125 void AudioOutputDevice::Pause() { |
| 123 task_runner()->PostTask(FROM_HERE, | 126 task_runner()->PostTask(FROM_HERE, |
| 124 base::Bind(&AudioOutputDevice::PauseOnIOThread, this)); | 127 base::Bind(&AudioOutputDevice::PauseOnIOThread, this)); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 153 return output_params_; | 156 return output_params_; |
| 154 } | 157 } |
| 155 | 158 |
| 156 OutputDeviceStatus AudioOutputDevice::GetDeviceStatus() { | 159 OutputDeviceStatus AudioOutputDevice::GetDeviceStatus() { |
| 157 CHECK(!task_runner()->BelongsToCurrentThread()); | 160 CHECK(!task_runner()->BelongsToCurrentThread()); |
| 158 did_receive_auth_.Wait(); | 161 did_receive_auth_.Wait(); |
| 159 return device_status_; | 162 return device_status_; |
| 160 } | 163 } |
| 161 | 164 |
| 162 void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() { | 165 void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() { |
| 166 printf("****** AudioOutputDevice::RequestDeviceAuthorizationOnIOThread this =
%p, state_ = %d\n", |
| 167 this, state_); |
| 163 DCHECK(task_runner()->BelongsToCurrentThread()); | 168 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 164 DCHECK_EQ(state_, IDLE); | 169 DCHECK_EQ(state_, IDLE); |
| 165 state_ = AUTHORIZING; | 170 state_ = AUTHORIZING; |
| 171 |
| 172 // TODO(grunell): Store authorization so that we don't have to authorize |
| 173 // again when re-starting. This involves mostly changes on the browser side: |
| 174 // associate authorization by a new id (currently the stream id), don't forget |
| 175 // authorization away after start or stop. Here we would have to explicitly |
| 176 // make the browser side forget authorization in the dtor with a new |
| 177 // AudioOutputIPC function. |
| 166 ipc_->RequestDeviceAuthorization(this, session_id_, device_id_, | 178 ipc_->RequestDeviceAuthorization(this, session_id_, device_id_, |
| 167 security_origin_); | 179 security_origin_); |
| 168 } | 180 } |
| 169 | 181 |
| 170 void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) { | 182 void AudioOutputDevice::InitializeOnIOThread(const AudioParameters& params, |
| 183 RenderCallback* callback) { |
| 171 DCHECK(task_runner()->BelongsToCurrentThread()); | 184 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 185 DCHECK(!callback_); |
| 186 audio_parameters_ = params; |
| 187 callback_ = callback; |
| 188 } |
| 189 |
| 190 void AudioOutputDevice::CreateStreamOnIOThread() { |
| 191 printf("****** AudioOutputDevice::CreateStreamOnIOThread this = %p, state_ = %
d\n", |
| 192 this, state_); |
| 193 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 194 DCHECK(callback_ || state_ == IPC_CLOSED); |
| 195 |
| 172 switch (state_) { | 196 switch (state_) { |
| 173 case IPC_CLOSED: | 197 case IPC_CLOSED: |
| 174 if (callback_) | 198 if (callback_) |
| 175 callback_->OnRenderError(); | 199 callback_->OnRenderError(); |
| 176 break; | 200 break; |
| 177 | 201 |
| 178 case IDLE: | 202 case IDLE: |
| 179 if (did_receive_auth_.IsSignaled() && device_id_.empty() && | 203 if (did_receive_auth_.IsSignaled() && device_id_.empty() && |
| 180 security_origin_.unique()) { | 204 security_origin_.unique()) { |
| 181 state_ = CREATING_STREAM; | 205 state_ = CREATING_STREAM; |
| 182 ipc_->CreateStream(this, params); | 206 ipc_->CreateStream(this, audio_parameters_); |
| 183 } else { | 207 } else { |
| 184 RequestDeviceAuthorizationOnIOThread(); | 208 RequestDeviceAuthorizationOnIOThread(); |
| 185 start_on_authorized_ = true; | 209 start_on_authorized_ = true; |
| 186 } | 210 } |
| 187 break; | 211 break; |
| 188 | 212 |
| 189 case AUTHORIZING: | 213 case AUTHORIZING: |
| 190 start_on_authorized_ = true; | 214 start_on_authorized_ = true; |
| 191 break; | 215 break; |
| 192 | 216 |
| 193 case AUTHORIZED: | 217 case AUTHORIZED: |
| 194 state_ = CREATING_STREAM; | 218 state_ = CREATING_STREAM; |
| 195 ipc_->CreateStream(this, params); | 219 ipc_->CreateStream(this, audio_parameters_); |
| 196 start_on_authorized_ = false; | 220 start_on_authorized_ = false; |
| 197 break; | 221 break; |
| 198 | 222 |
| 199 case CREATING_STREAM: | 223 case CREATING_STREAM: |
| 200 case PAUSED: | 224 case PAUSED: |
| 201 case PLAYING: | 225 case PLAYING: |
| 202 NOTREACHED(); | 226 NOTREACHED(); |
| 203 break; | 227 break; |
| 204 } | 228 } |
| 205 } | 229 } |
| 206 | 230 |
| 207 void AudioOutputDevice::PlayOnIOThread() { | 231 void AudioOutputDevice::PlayOnIOThread() { |
| 232 printf("****** AudioOutputDevice::PlayOnIOThread this = %p, state_ = %d\n", |
| 233 this, state_); |
| 208 DCHECK(task_runner()->BelongsToCurrentThread()); | 234 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 209 if (state_ == PAUSED) { | 235 if (state_ == PAUSED) { |
| 210 TRACE_EVENT_ASYNC_BEGIN0( | 236 TRACE_EVENT_ASYNC_BEGIN0( |
| 211 "audio", "StartingPlayback", audio_callback_.get()); | 237 "audio", "StartingPlayback", audio_callback_.get()); |
| 212 ipc_->PlayStream(); | 238 ipc_->PlayStream(); |
| 213 state_ = PLAYING; | 239 state_ = PLAYING; |
| 214 play_on_start_ = false; | 240 play_on_start_ = false; |
| 215 } else { | 241 } else { |
| 216 play_on_start_ = true; | 242 play_on_start_ = true; |
| 217 } | 243 } |
| 218 } | 244 } |
| 219 | 245 |
| 220 void AudioOutputDevice::PauseOnIOThread() { | 246 void AudioOutputDevice::PauseOnIOThread() { |
| 247 printf("****** AudioOutputDevice::PauseOnIOThread this = %p, state_ = %d\n", |
| 248 this, state_); |
| 221 DCHECK(task_runner()->BelongsToCurrentThread()); | 249 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 222 if (state_ == PLAYING) { | 250 if (state_ == PLAYING) { |
| 223 TRACE_EVENT_ASYNC_END0( | 251 TRACE_EVENT_ASYNC_END0( |
| 224 "audio", "StartingPlayback", audio_callback_.get()); | 252 "audio", "StartingPlayback", audio_callback_.get()); |
| 225 ipc_->PauseStream(); | 253 ipc_->PauseStream(); |
| 226 state_ = PAUSED; | 254 state_ = PAUSED; |
| 227 } | 255 } |
| 228 play_on_start_ = false; | 256 play_on_start_ = false; |
| 229 } | 257 } |
| 230 | 258 |
| 231 void AudioOutputDevice::ShutDownOnIOThread() { | 259 void AudioOutputDevice::StopOnIOThread() { |
| 260 printf("****** AudioOutputDevice::StopOnIOThread this = %p, state_ = %d\n", |
| 261 this, state_); |
| 232 DCHECK(task_runner()->BelongsToCurrentThread()); | 262 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 233 | 263 |
| 234 // Close the stream, if we haven't already. | 264 // Close the stream, if we haven't already. |
| 235 if (state_ >= AUTHORIZING) { | 265 if (state_ >= AUTHORIZING) { |
| 236 ipc_->CloseStream(); | 266 ipc_->CloseStream(); |
| 237 state_ = IDLE; | 267 state_ = IDLE; |
| 238 } | 268 } |
| 239 start_on_authorized_ = false; | 269 start_on_authorized_ = false; |
| 240 | 270 |
| 241 // We can run into an issue where ShutDownOnIOThread is called right after | 271 // We can run into an issue where StopOnIOThread is called right after |
| 242 // OnStreamCreated is called in cases where Start/Stop are called before we | 272 // OnStreamCreated is called in cases where Start/Stop are called before we |
| 243 // get the OnStreamCreated callback. To handle that corner case, we call | 273 // get the OnStreamCreated callback. To handle that corner case, we call |
| 244 // Stop(). In most cases, the thread will already be stopped. | 274 // Stop(). In most cases, the thread will already be stopped. |
| 245 // | |
| 246 // Another situation is when the IO thread goes away before Stop() is called | |
| 247 // in which case, we cannot use the message loop to close the thread handle | |
| 248 // and can't rely on the main thread existing either. | |
| 249 base::AutoLock auto_lock_(audio_thread_lock_); | 275 base::AutoLock auto_lock_(audio_thread_lock_); |
| 250 base::ThreadRestrictions::ScopedAllowIO allow_io; | 276 audio_thread_.StopRun(); |
| 251 audio_thread_.Stop(NULL); | |
| 252 audio_callback_.reset(); | 277 audio_callback_.reset(); |
| 253 stopping_hack_ = false; | 278 stopping_hack_ = false; |
| 279 callback_ = nullptr; |
| 254 } | 280 } |
| 255 | 281 |
| 256 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { | 282 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { |
| 257 DCHECK(task_runner()->BelongsToCurrentThread()); | 283 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 258 if (state_ >= CREATING_STREAM) | 284 if (state_ >= CREATING_STREAM) |
| 259 ipc_->SetVolume(volume); | 285 ipc_->SetVolume(volume); |
| 260 } | 286 } |
| 261 | 287 |
| 262 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) { | 288 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) { |
| 289 printf("****** AudioOutputDevice::OnStateChanged this = %p, state_ = %d, state
= %d\n", |
| 290 this, state_, state); |
| 263 DCHECK(task_runner()->BelongsToCurrentThread()); | 291 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 264 | 292 |
| 265 // Do nothing if the stream has been closed. | 293 // Do nothing if the stream has been closed. |
| 266 if (state_ < CREATING_STREAM) | 294 if (state_ < CREATING_STREAM) |
| 267 return; | 295 return; |
| 268 | 296 |
| 269 // TODO(miu): Clean-up inconsistent and incomplete handling here. | 297 // TODO(miu): Clean-up inconsistent and incomplete handling here. |
| 270 // http://crbug.com/180640 | 298 // http://crbug.com/180640 |
| 271 switch (state) { | 299 switch (state) { |
| 272 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING: | 300 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING: |
| 273 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED: | 301 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED: |
| 274 break; | 302 break; |
| 275 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR: | 303 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR: |
| 276 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)"; | 304 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)"; |
| 277 // Don't dereference the callback object if the audio thread | 305 // The callback object is cleared in Stop(). |
| 278 // is stopped or stopping. That could mean that the callback | 306 if (callback_) |
| 279 // object has been deleted. | |
| 280 // TODO(tommi): Add an explicit contract for clearing the callback | |
| 281 // object. Possibly require calling Initialize again or provide | |
| 282 // a callback object via Start() and clear it in Stop(). | |
| 283 if (!audio_thread_.IsStopped()) | |
| 284 callback_->OnRenderError(); | 307 callback_->OnRenderError(); |
| 285 break; | 308 break; |
| 286 default: | 309 default: |
| 287 NOTREACHED(); | 310 NOTREACHED(); |
| 288 break; | 311 break; |
| 289 } | 312 } |
| 290 } | 313 } |
| 291 | 314 |
| 292 void AudioOutputDevice::OnDeviceAuthorized( | 315 void AudioOutputDevice::OnDeviceAuthorized( |
| 293 OutputDeviceStatus device_status, | 316 OutputDeviceStatus device_status, |
| 294 const media::AudioParameters& output_params) { | 317 const media::AudioParameters& output_params) { |
| 318 printf("****** AudioOutputDevice::OnDeviceAuthorized this = %p, state_ = %d, d
evice_status = %d\n", |
| 319 this, state_, device_status); |
| 295 DCHECK(task_runner()->BelongsToCurrentThread()); | 320 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 296 DCHECK_EQ(state_, AUTHORIZING); | 321 DCHECK_EQ(state_, AUTHORIZING); |
| 297 | 322 |
| 298 // It may happen that a second authorization is received as a result to a | 323 // It may happen that a second authorization is received as a result to a |
| 299 // call to Start() after Stop(). If the status for the second authorization | 324 // call to Start() after Stop(). If the status for the second authorization |
| 300 // differs from the first, it will not be reflected in |device_status_| | 325 // differs from the first, it will not be reflected in |device_status_| |
| 301 // to avoid a race. | 326 // to avoid a race. |
| 302 // This scenario is unlikely. If it occurs, the new value will be | 327 // This scenario is unlikely. If it occurs, the new value will be |
| 303 // different from OUTPUT_DEVICE_STATUS_OK, so the AudioOutputDevice | 328 // different from OUTPUT_DEVICE_STATUS_OK, so the AudioOutputDevice |
| 304 // will enter the IPC_CLOSED state anyway, which is the safe thing to do. | 329 // will enter the IPC_CLOSED state anyway, which is the safe thing to do. |
| 305 // This is preferable to holding a lock. | 330 // This is preferable to holding a lock. |
| 306 if (!did_receive_auth_.IsSignaled()) | 331 if (!did_receive_auth_.IsSignaled()) |
| 307 device_status_ = device_status; | 332 device_status_ = device_status; |
| 308 | 333 |
| 309 if (device_status == OUTPUT_DEVICE_STATUS_OK) { | 334 if (device_status == OUTPUT_DEVICE_STATUS_OK) { |
| 310 state_ = AUTHORIZED; | 335 state_ = AUTHORIZED; |
| 311 if (!did_receive_auth_.IsSignaled()) { | 336 if (!did_receive_auth_.IsSignaled()) { |
| 312 output_params_ = output_params; | 337 output_params_ = output_params; |
| 313 did_receive_auth_.Signal(); | 338 did_receive_auth_.Signal(); |
| 314 } | 339 } |
| 315 if (start_on_authorized_) | 340 if (start_on_authorized_) |
| 316 CreateStreamOnIOThread(audio_parameters_); | 341 CreateStreamOnIOThread(); |
| 317 } else { | 342 } else { |
| 318 // Closing IPC forces a Signal(), so no clients are locked waiting | 343 // Closing IPC forces a Signal(), so no clients are locked waiting |
| 319 // indefinitely after this method returns. | 344 // indefinitely after this method returns. |
| 320 ipc_->CloseStream(); | 345 ipc_->CloseStream(); |
| 321 OnIPCClosed(); | 346 OnIPCClosed(); |
| 322 if (callback_) | 347 if (callback_) |
| 323 callback_->OnRenderError(); | 348 callback_->OnRenderError(); |
| 324 } | 349 } |
| 325 } | 350 } |
| 326 | 351 |
| 327 void AudioOutputDevice::OnStreamCreated( | 352 void AudioOutputDevice::OnStreamCreated( |
| 328 base::SharedMemoryHandle handle, | 353 base::SharedMemoryHandle handle, |
| 329 base::SyncSocket::Handle socket_handle, | 354 base::SyncSocket::Handle socket_handle, |
| 330 int length) { | 355 int length) { |
| 356 printf("****** AudioOutputDevice::OnStreamCreated this = %p, state_ = %d\n", |
| 357 this, state_); |
| 331 DCHECK(task_runner()->BelongsToCurrentThread()); | 358 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 332 DCHECK(base::SharedMemory::IsHandleValid(handle)); | 359 DCHECK(base::SharedMemory::IsHandleValid(handle)); |
| 333 #if defined(OS_WIN) | 360 #if defined(OS_WIN) |
| 334 DCHECK(socket_handle); | 361 DCHECK(socket_handle); |
| 335 #else | 362 #else |
| 336 DCHECK_GE(socket_handle, 0); | 363 DCHECK_GE(socket_handle, 0); |
| 337 #endif | 364 #endif |
| 338 DCHECK_GT(length, 0); | 365 DCHECK_GT(length, 0); |
| 339 | 366 |
| 340 if (state_ != CREATING_STREAM) | 367 if (state_ != CREATING_STREAM) |
| 341 return; | 368 return; |
| 342 | 369 |
| 343 // We can receive OnStreamCreated() on the IO thread after the client has | 370 // We can receive OnStreamCreated() on the IO thread after the client has |
| 344 // called Stop() but before ShutDownOnIOThread() is processed. In such a | 371 // called Stop() but before StopOnIOThread() is processed. In such a |
| 345 // situation |callback_| might point to freed memory. Instead of starting | 372 // situation |callback_| might point to freed memory. Instead of starting |
| 346 // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called. | 373 // |audio_thread_| do nothing and wait for StopOnIOThread() to get called. |
| 347 // | 374 // |
| 348 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact | 375 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact |
| 349 // that |callback_| (which should own and outlive this object!) can point to | 376 // that |callback_| (which should own and outlive this object!) can point to |
| 350 // freed memory is a mess. AudioRendererSink should be non-refcounted so that | 377 // freed memory is a mess. AudioRendererSink should be non-refcounted so that |
| 351 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and | 378 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and |
| 352 // delete as they see fit. AudioOutputDevice should internally use WeakPtr | 379 // delete as they see fit. AudioOutputDevice should internally use WeakPtr |
| 353 // to handle teardown and thread hopping. See http://crbug.com/151051 for | 380 // to handle teardown and thread hopping. See http://crbug.com/151051 for |
| 354 // details. | 381 // details. |
| 355 { | 382 { |
| 356 base::AutoLock auto_lock(audio_thread_lock_); | 383 base::AutoLock auto_lock(audio_thread_lock_); |
| 357 if (stopping_hack_) | 384 if (stopping_hack_) |
| 358 return; | 385 return; |
| 359 | 386 |
| 360 DCHECK(audio_thread_.IsStopped()); | |
| 361 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( | 387 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( |
| 362 audio_parameters_, handle, length, callback_)); | 388 audio_parameters_, handle, length, callback_)); |
| 363 audio_thread_.Start(audio_callback_.get(), socket_handle, | 389 |
| 364 "AudioOutputDevice", true); | 390 // If the audio thread hasn't been started before, start it. |
| 391 if (audio_thread_.IsStopped()) { |
| 392 printf("****** Starting audio thread.\n"); |
| 393 audio_thread_.Start("AudioOutputDevice", true); |
| 394 } |
| 395 audio_thread_.StartRun(audio_callback_.get(), socket_handle); |
| 396 |
| 365 state_ = PAUSED; | 397 state_ = PAUSED; |
| 366 | 398 |
| 367 // We handle the case where Play() and/or Pause() may have been called | 399 // We handle the case where Play() and/or Pause() may have been called |
| 368 // multiple times before OnStreamCreated() gets called. | 400 // multiple times before OnStreamCreated() gets called. |
| 369 if (play_on_start_) | 401 if (play_on_start_) |
| 370 PlayOnIOThread(); | 402 PlayOnIOThread(); |
| 371 } | 403 } |
| 372 } | 404 } |
| 373 | 405 |
| 374 void AudioOutputDevice::OnIPCClosed() { | 406 void AudioOutputDevice::OnIPCClosed() { |
| 407 printf("****** AudioOutputDevice::OnIPCClosed this = %p, state_ = %d\n", |
| 408 this, state_); |
| 375 DCHECK(task_runner()->BelongsToCurrentThread()); | 409 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 376 state_ = IPC_CLOSED; | 410 state_ = IPC_CLOSED; |
| 377 ipc_.reset(); | 411 ipc_.reset(); |
| 378 | 412 |
| 379 // Signal to unblock any blocked threads waiting for parameters | 413 // Signal to unblock any blocked threads waiting for parameters |
| 380 did_receive_auth_.Signal(); | 414 did_receive_auth_.Signal(); |
| 381 } | 415 } |
| 382 | 416 |
| 383 void AudioOutputDevice::WillDestroyCurrentMessageLoop() { | 417 void AudioOutputDevice::WillDestroyCurrentMessageLoop() { |
| 384 LOG(ERROR) << "IO loop going away before the audio device has been stopped"; | 418 LOG(ERROR) << "IO loop going away before the audio device has been stopped"; |
| 385 ShutDownOnIOThread(); | 419 StopOnIOThread(); |
| 386 } | 420 } |
| 387 | 421 |
| 388 // AudioOutputDevice::AudioThreadCallback | 422 // AudioOutputDevice::AudioThreadCallback |
| 389 | 423 |
| 390 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( | 424 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( |
| 391 const AudioParameters& audio_parameters, | 425 const AudioParameters& audio_parameters, |
| 392 base::SharedMemoryHandle memory, | 426 base::SharedMemoryHandle memory, |
| 393 int memory_length, | 427 int memory_length, |
| 394 AudioRendererSink::RenderCallback* render_callback) | 428 AudioRendererSink::RenderCallback* render_callback) |
| 395 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1), | 429 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1), |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 435 | 469 |
| 436 // Update the audio-delay measurement, inform about the number of skipped | 470 // Update the audio-delay measurement, inform about the number of skipped |
| 437 // frames, and ask client to render audio. Since |output_bus_| is wrapping | 471 // frames, and ask client to render audio. Since |output_bus_| is wrapping |
| 438 // the shared memory the Render() call is writing directly into the shared | 472 // the shared memory the Render() call is writing directly into the shared |
| 439 // memory. | 473 // memory. |
| 440 render_callback_->Render(output_bus_.get(), audio_delay_milliseconds, | 474 render_callback_->Render(output_bus_.get(), audio_delay_milliseconds, |
| 441 frames_skipped); | 475 frames_skipped); |
| 442 } | 476 } |
| 443 | 477 |
| 444 } // namespace media | 478 } // namespace media |
| OLD | NEW |