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 "content/renderer/media/audio_device.h" | 5 #include "content/renderer/media/audio_device.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/threading/thread_restrictions.h" | |
| 10 #include "base/time.h" | 11 #include "base/time.h" |
| 11 #include "content/common/child_process.h" | 12 #include "content/common/child_process.h" |
| 12 #include "content/common/media/audio_messages.h" | 13 #include "content/common/media/audio_messages.h" |
| 13 #include "content/common/view_messages.h" | 14 #include "content/common/view_messages.h" |
| 14 #include "content/renderer/render_thread_impl.h" | 15 #include "content/renderer/render_thread_impl.h" |
| 15 #include "media/audio/audio_output_controller.h" | 16 #include "media/audio/audio_output_controller.h" |
| 16 #include "media/audio/audio_util.h" | 17 #include "media/audio/audio_util.h" |
| 17 | 18 |
| 18 AudioDevice::AudioDevice() | 19 AudioDevice::AudioDevice() |
| 19 : buffer_size_(0), | 20 : buffer_size_(0), |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 236 // Takes care of the case when Stop() is called before OnLowLatencyCreated(). | 237 // Takes care of the case when Stop() is called before OnLowLatencyCreated(). |
| 237 if (!stream_id_) { | 238 if (!stream_id_) { |
| 238 base::SharedMemory::CloseHandle(handle); | 239 base::SharedMemory::CloseHandle(handle); |
| 239 // Close the socket handler. | 240 // Close the socket handler. |
| 240 base::SyncSocket socket(socket_handle); | 241 base::SyncSocket socket(socket_handle); |
| 241 return; | 242 return; |
| 242 } | 243 } |
| 243 | 244 |
| 244 shared_memory_handle_ = handle; | 245 shared_memory_handle_ = handle; |
| 245 memory_length_ = length; | 246 memory_length_ = length; |
| 246 audio_socket_ = new AudioSocket(socket_handle); | 247 audio_socket_.reset(new base::CancelableSyncSocket(socket_handle)); |
| 247 | 248 |
| 248 audio_thread_.reset( | 249 audio_thread_.reset( |
| 249 new base::DelegateSimpleThread(this, "renderer_audio_thread")); | 250 new base::DelegateSimpleThread(this, "renderer_audio_thread")); |
| 250 audio_thread_->Start(); | 251 audio_thread_->Start(); |
| 251 | 252 |
| 252 // We handle the case where Play() and/or Pause() may have been called | 253 // We handle the case where Play() and/or Pause() may have been called |
| 253 // multiple times before OnLowLatencyCreated() gets called. | 254 // multiple times before OnLowLatencyCreated() gets called. |
| 254 is_started_ = true; | 255 is_started_ = true; |
| 255 if (play_on_start_) | 256 if (play_on_start_) |
| 256 PlayOnIOThread(); | 257 PlayOnIOThread(); |
| 257 } | 258 } |
| 258 | 259 |
| 259 void AudioDevice::OnVolume(double volume) { | 260 void AudioDevice::OnVolume(double volume) { |
| 260 NOTIMPLEMENTED(); | 261 NOTIMPLEMENTED(); |
| 261 } | 262 } |
| 262 | 263 |
| 263 void AudioDevice::Send(IPC::Message* message) { | 264 void AudioDevice::Send(IPC::Message* message) { |
| 264 filter_->Send(message); | 265 filter_->Send(message); |
| 265 } | 266 } |
| 266 | 267 |
| 267 // Our audio thread runs here. | 268 // Our audio thread runs here. |
| 268 void AudioDevice::Run() { | 269 void AudioDevice::Run() { |
| 269 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio); | 270 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio); |
| 270 | 271 |
| 271 base::SharedMemory shared_memory(shared_memory_handle_, false); | 272 base::SharedMemory shared_memory(shared_memory_handle_, false); |
| 272 shared_memory.Map(media::TotalSharedMemorySizeInBytes(memory_length_)); | 273 shared_memory.Map(media::TotalSharedMemorySizeInBytes(memory_length_)); |
| 273 scoped_refptr<AudioSocket> audio_socket(audio_socket_); | 274 base::CancelableSyncSocket* audio_socket = audio_socket_.get(); |
|
scherkus (not reviewing)
2012/01/30 19:10:57
nit: do we need this anymore?
tommi (sloooow) - chröme
2012/01/30 21:53:14
yes, this is different than what we had before (sc
| |
| 274 | 275 |
| 275 int pending_data; | |
| 276 const int samples_per_ms = static_cast<int>(sample_rate_) / 1000; | 276 const int samples_per_ms = static_cast<int>(sample_rate_) / 1000; |
| 277 const int bytes_per_ms = channels_ * (bits_per_sample_ / 8) * samples_per_ms; | 277 const int bytes_per_ms = channels_ * (bits_per_sample_ / 8) * samples_per_ms; |
| 278 | 278 |
| 279 while (sizeof(pending_data) == | 279 while (true) { |
| 280 audio_socket->socket()->Receive(&pending_data, sizeof(pending_data))) { | 280 uint32 pending_data = 0; |
| 281 if (pending_data == media::AudioOutputController::kPauseMark) { | 281 size_t bytes_read = audio_socket->Receive(&pending_data, |
| 282 sizeof(pending_data)); | |
| 283 if (bytes_read != sizeof(pending_data)) { | |
| 284 DCHECK_EQ(bytes_read, 0U); | |
| 285 break; | |
| 286 } | |
| 287 | |
| 288 if (pending_data == | |
| 289 static_cast<uint32>(media::AudioOutputController::kPauseMark)) { | |
| 282 memset(shared_memory.memory(), 0, memory_length_); | 290 memset(shared_memory.memory(), 0, memory_length_); |
| 283 media::SetActualDataSizeInBytes(&shared_memory, memory_length_, 0); | 291 media::SetActualDataSizeInBytes(&shared_memory, memory_length_, 0); |
| 284 continue; | 292 continue; |
| 285 } else if (pending_data < 0) { | |
| 286 break; | |
| 287 } | 293 } |
| 288 | 294 |
| 289 // Convert the number of pending bytes in the render buffer | 295 // Convert the number of pending bytes in the render buffer |
| 290 // into milliseconds. | 296 // into milliseconds. |
| 291 audio_delay_milliseconds_ = pending_data / bytes_per_ms; | 297 audio_delay_milliseconds_ = pending_data / bytes_per_ms; |
| 292 size_t num_frames = FireRenderCallback( | 298 size_t num_frames = FireRenderCallback( |
| 293 reinterpret_cast<int16*>(shared_memory.memory())); | 299 reinterpret_cast<int16*>(shared_memory.memory())); |
| 294 | 300 |
| 295 // Let the host know we are done. | 301 // Let the host know we are done. |
| 296 media::SetActualDataSizeInBytes(&shared_memory, | 302 media::SetActualDataSizeInBytes(&shared_memory, |
| 297 memory_length_, | 303 memory_length_, |
| 298 num_frames * channels_ * sizeof(int16)); | 304 num_frames * channels_ * sizeof(int16)); |
| 299 } | 305 } |
| 300 audio_socket->Close(); | |
| 301 } | 306 } |
| 302 | 307 |
| 303 size_t AudioDevice::FireRenderCallback(int16* data) { | 308 size_t AudioDevice::FireRenderCallback(int16* data) { |
| 304 TRACE_EVENT0("audio", "AudioDevice::FireRenderCallback"); | 309 TRACE_EVENT0("audio", "AudioDevice::FireRenderCallback"); |
| 305 | 310 |
| 306 size_t num_frames = 0; | 311 size_t num_frames = 0; |
| 307 if (callback_) { | 312 if (callback_) { |
| 308 // Update the audio-delay measurement then ask client to render audio. | 313 // Update the audio-delay measurement then ask client to render audio. |
| 309 num_frames = callback_->Render(audio_data_, | 314 num_frames = callback_->Render(audio_data_, |
| 310 buffer_size_, | 315 buffer_size_, |
| 311 audio_delay_milliseconds_); | 316 audio_delay_milliseconds_); |
| 312 | 317 |
| 313 // Interleave, scale, and clip to int16. | 318 // Interleave, scale, and clip to int16. |
| 314 // TODO(crogers): avoid converting to integer here, and pass the data | 319 // TODO(crogers): avoid converting to integer here, and pass the data |
| 315 // to the browser process as float, so we don't lose precision for | 320 // to the browser process as float, so we don't lose precision for |
| 316 // audio hardware which has better than 16bit precision. | 321 // audio hardware which has better than 16bit precision. |
| 317 media::InterleaveFloatToInt16(audio_data_, | 322 media::InterleaveFloatToInt16(audio_data_, |
| 318 data, | 323 data, |
| 319 buffer_size_); | 324 buffer_size_); |
| 320 } | 325 } |
| 321 return num_frames; | 326 return num_frames; |
| 322 } | 327 } |
| 323 | 328 |
| 324 void AudioDevice::ShutDownAudioThread() { | 329 void AudioDevice::ShutDownAudioThread() { |
| 325 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); | 330 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); |
| 326 | 331 |
| 327 if (audio_thread_.get()) { | 332 if (audio_thread_.get()) { |
| 328 // Close the socket to terminate the main thread function in the | 333 // Close the socket to terminate the main thread function in the |
| 329 // audio thread. | 334 // audio thread. |
| 330 audio_socket_->Close(); | 335 audio_socket_->Shutdown(); // Stops blocking Receive calls. |
| 331 audio_socket_ = NULL; | 336 // TODO(tommi): We must not do this from the IO thread. Fix. |
|
scherkus (not reviewing)
2012/01/30 19:10:57
is this coming in a follow up CL or should we file
tommi (sloooow) - chröme
2012/01/30 21:53:14
Yes, I'll start working on it tomorrow. I'll file
| |
| 337 base::ThreadRestrictions::ScopedAllowIO allow_wait; | |
| 332 audio_thread_->Join(); | 338 audio_thread_->Join(); |
| 333 audio_thread_.reset(NULL); | 339 audio_thread_.reset(NULL); |
| 340 audio_socket_.reset(); | |
| 334 } | 341 } |
| 335 } | 342 } |
| OLD | NEW |