| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/browser/renderer_host/media/audio_renderer_host.h" | 5 #include "content/browser/renderer_host/media/audio_renderer_host.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
| 9 #include "base/process.h" | 9 #include "base/process.h" |
| 10 #include "base/shared_memory.h" | 10 #include "base/shared_memory.h" |
| 11 #include "content/browser/renderer_host/media/audio_common.h" | 11 #include "content/browser/renderer_host/media/audio_common.h" |
| 12 #include "content/browser/renderer_host/media/audio_sync_reader.h" | 12 #include "content/browser/renderer_host/media/audio_sync_reader.h" |
| 13 #include "content/browser/renderer_host/media/media_observer.h" | 13 #include "content/browser/renderer_host/media/media_observer.h" |
| 14 #include "content/browser/resource_context.h" | 14 #include "content/browser/resource_context.h" |
| 15 #include "content/common/media/audio_messages.h" | 15 #include "content/common/media/audio_messages.h" |
| 16 #include "media/audio/audio_util.h" | 16 #include "media/audio/audio_util.h" |
| 17 #include "ipc/ipc_logging.h" | 17 #include "ipc/ipc_logging.h" |
| 18 | 18 |
| 19 using content::BrowserMessageFilter; | 19 using content::BrowserMessageFilter; |
| 20 using content::BrowserThread; | 20 using content::BrowserThread; |
| 21 | 21 |
| 22 AudioRendererHost::AudioEntry::AudioEntry() | 22 AudioRendererHost::AudioEntry::AudioEntry() |
| 23 : stream_id(0), | 23 : stream_id(0), |
| 24 pending_buffer_request(false), | |
| 25 pending_close(false) { | 24 pending_close(false) { |
| 26 } | 25 } |
| 27 | 26 |
| 28 AudioRendererHost::AudioEntry::~AudioEntry() {} | 27 AudioRendererHost::AudioEntry::~AudioEntry() {} |
| 29 | 28 |
| 30 /////////////////////////////////////////////////////////////////////////////// | 29 /////////////////////////////////////////////////////////////////////////////// |
| 31 // AudioRendererHost implementations. | 30 // AudioRendererHost implementations. |
| 32 AudioRendererHost::AudioRendererHost( | 31 AudioRendererHost::AudioRendererHost( |
| 33 const content::ResourceContext* resource_context) | 32 const content::ResourceContext* resource_context) |
| 34 : resource_context_(resource_context), | 33 : resource_context_(resource_context), |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 | 83 |
| 85 void AudioRendererHost::OnError(media::AudioOutputController* controller, | 84 void AudioRendererHost::OnError(media::AudioOutputController* controller, |
| 86 int error_code) { | 85 int error_code) { |
| 87 BrowserThread::PostTask( | 86 BrowserThread::PostTask( |
| 88 BrowserThread::IO, | 87 BrowserThread::IO, |
| 89 FROM_HERE, | 88 FROM_HERE, |
| 90 base::Bind(&AudioRendererHost::DoHandleError, | 89 base::Bind(&AudioRendererHost::DoHandleError, |
| 91 this, make_scoped_refptr(controller), error_code)); | 90 this, make_scoped_refptr(controller), error_code)); |
| 92 } | 91 } |
| 93 | 92 |
| 94 void AudioRendererHost::OnMoreData(media::AudioOutputController* controller, | |
| 95 AudioBuffersState buffers_state) { | |
| 96 BrowserThread::PostTask( | |
| 97 BrowserThread::IO, | |
| 98 FROM_HERE, | |
| 99 base::Bind(&AudioRendererHost::DoRequestMoreData, | |
| 100 this, make_scoped_refptr(controller), | |
| 101 buffers_state)); | |
| 102 } | |
| 103 | |
| 104 void AudioRendererHost::DoCompleteCreation( | 93 void AudioRendererHost::DoCompleteCreation( |
| 105 media::AudioOutputController* controller) { | 94 media::AudioOutputController* controller) { |
| 106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 107 | 96 |
| 108 AudioEntry* entry = LookupByController(controller); | 97 AudioEntry* entry = LookupByController(controller); |
| 109 if (!entry) | 98 if (!entry) |
| 110 return; | 99 return; |
| 111 | 100 |
| 112 if (!peer_handle()) { | 101 if (!peer_handle()) { |
| 113 NOTREACHED() << "Renderer process handle is invalid."; | 102 NOTREACHED() << "Renderer process handle is invalid."; |
| 114 DeleteEntryOnError(entry); | 103 DeleteEntryOnError(entry); |
| 115 return; | 104 return; |
| 116 } | 105 } |
| 117 | 106 |
| 118 // Once the audio stream is created then complete the creation process by | 107 // Once the audio stream is created then complete the creation process by |
| 119 // mapping shared memory and sharing with the renderer process. | 108 // mapping shared memory and sharing with the renderer process. |
| 120 base::SharedMemoryHandle foreign_memory_handle; | 109 base::SharedMemoryHandle foreign_memory_handle; |
| 121 if (!entry->shared_memory.ShareToProcess(peer_handle(), | 110 if (!entry->shared_memory.ShareToProcess(peer_handle(), |
| 122 &foreign_memory_handle)) { | 111 &foreign_memory_handle)) { |
| 123 // If we failed to map and share the shared memory then close the audio | 112 // If we failed to map and share the shared memory then close the audio |
| 124 // stream and send an error message. | 113 // stream and send an error message. |
| 125 DeleteEntryOnError(entry); | 114 DeleteEntryOnError(entry); |
| 126 return; | 115 return; |
| 127 } | 116 } |
| 128 | 117 |
| 129 if (entry->controller->LowLatencyMode()) { | 118 AudioSyncReader* reader = |
| 130 AudioSyncReader* reader = | 119 static_cast<AudioSyncReader*>(entry->reader.get()); |
| 131 static_cast<AudioSyncReader*>(entry->reader.get()); | |
| 132 | 120 |
| 133 #if defined(OS_WIN) | 121 #if defined(OS_WIN) |
| 134 base::SyncSocket::Handle foreign_socket_handle; | 122 base::SyncSocket::Handle foreign_socket_handle; |
| 135 #else | 123 #else |
| 136 base::FileDescriptor foreign_socket_handle; | 124 base::FileDescriptor foreign_socket_handle; |
| 137 #endif | 125 #endif |
| 138 | 126 |
| 139 // If we failed to prepare the sync socket for the renderer then we fail | 127 // If we failed to prepare the sync socket for the renderer then we fail |
| 140 // the construction of audio stream. | 128 // the construction of audio stream. |
| 141 if (!reader->PrepareForeignSocketHandle(peer_handle(), | 129 if (!reader->PrepareForeignSocketHandle(peer_handle(), |
| 142 &foreign_socket_handle)) { | 130 &foreign_socket_handle)) { |
| 143 DeleteEntryOnError(entry); | 131 DeleteEntryOnError(entry); |
| 144 return; | |
| 145 } | |
| 146 | |
| 147 Send(new AudioMsg_NotifyLowLatencyStreamCreated( | |
| 148 entry->stream_id, | |
| 149 foreign_memory_handle, | |
| 150 foreign_socket_handle, | |
| 151 media::PacketSizeSizeInBytes(entry->shared_memory.created_size()))); | |
| 152 return; | 132 return; |
| 153 } | 133 } |
| 154 | 134 |
| 155 // The normal audio stream has created, send a message to the renderer | |
| 156 // process. | |
| 157 Send(new AudioMsg_NotifyStreamCreated( | 135 Send(new AudioMsg_NotifyStreamCreated( |
| 158 entry->stream_id, foreign_memory_handle, | 136 entry->stream_id, |
| 159 entry->shared_memory.created_size())); | 137 foreign_memory_handle, |
| 138 foreign_socket_handle, |
| 139 media::PacketSizeSizeInBytes(entry->shared_memory.created_size()))); |
| 160 } | 140 } |
| 161 | 141 |
| 162 void AudioRendererHost::DoSendPlayingMessage( | 142 void AudioRendererHost::DoSendPlayingMessage( |
| 163 media::AudioOutputController* controller) { | 143 media::AudioOutputController* controller) { |
| 164 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 165 | 145 |
| 166 AudioEntry* entry = LookupByController(controller); | 146 AudioEntry* entry = LookupByController(controller); |
| 167 if (!entry) | 147 if (!entry) |
| 168 return; | 148 return; |
| 169 | 149 |
| 170 Send(new AudioMsg_NotifyStreamStateChanged( | 150 Send(new AudioMsg_NotifyStreamStateChanged( |
| 171 entry->stream_id, kAudioStreamPlaying)); | 151 entry->stream_id, kAudioStreamPlaying)); |
| 172 } | 152 } |
| 173 | 153 |
| 174 void AudioRendererHost::DoSendPausedMessage( | 154 void AudioRendererHost::DoSendPausedMessage( |
| 175 media::AudioOutputController* controller) { | 155 media::AudioOutputController* controller) { |
| 176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 177 | 157 |
| 178 AudioEntry* entry = LookupByController(controller); | 158 AudioEntry* entry = LookupByController(controller); |
| 179 if (!entry) | 159 if (!entry) |
| 180 return; | 160 return; |
| 181 | 161 |
| 182 Send(new AudioMsg_NotifyStreamStateChanged( | 162 Send(new AudioMsg_NotifyStreamStateChanged( |
| 183 entry->stream_id, kAudioStreamPaused)); | 163 entry->stream_id, kAudioStreamPaused)); |
| 184 } | 164 } |
| 185 | 165 |
| 186 void AudioRendererHost::DoRequestMoreData( | |
| 187 media::AudioOutputController* controller, | |
| 188 AudioBuffersState buffers_state) { | |
| 189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 190 | |
| 191 // If we already have a pending request then return. | |
| 192 AudioEntry* entry = LookupByController(controller); | |
| 193 if (!entry || entry->pending_buffer_request) | |
| 194 return; | |
| 195 | |
| 196 DCHECK(!entry->controller->LowLatencyMode()); | |
| 197 entry->pending_buffer_request = true; | |
| 198 Send(new AudioMsg_RequestPacket( | |
| 199 entry->stream_id, buffers_state)); | |
| 200 } | |
| 201 | |
| 202 void AudioRendererHost::DoHandleError(media::AudioOutputController* controller, | 166 void AudioRendererHost::DoHandleError(media::AudioOutputController* controller, |
| 203 int error_code) { | 167 int error_code) { |
| 204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 205 | 169 |
| 206 AudioEntry* entry = LookupByController(controller); | 170 AudioEntry* entry = LookupByController(controller); |
| 207 if (!entry) | 171 if (!entry) |
| 208 return; | 172 return; |
| 209 | 173 |
| 210 DeleteEntryOnError(entry); | 174 DeleteEntryOnError(entry); |
| 211 } | 175 } |
| 212 | 176 |
| 213 /////////////////////////////////////////////////////////////////////////////// | 177 /////////////////////////////////////////////////////////////////////////////// |
| 214 // IPC Messages handler | 178 // IPC Messages handler |
| 215 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message, | 179 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message, |
| 216 bool* message_was_ok) { | 180 bool* message_was_ok) { |
| 217 bool handled = true; | 181 bool handled = true; |
| 218 IPC_BEGIN_MESSAGE_MAP_EX(AudioRendererHost, message, *message_was_ok) | 182 IPC_BEGIN_MESSAGE_MAP_EX(AudioRendererHost, message, *message_was_ok) |
| 219 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream) | 183 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream) |
| 220 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream) | 184 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream) |
| 221 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream) | 185 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream) |
| 222 IPC_MESSAGE_HANDLER(AudioHostMsg_FlushStream, OnFlushStream) | 186 IPC_MESSAGE_HANDLER(AudioHostMsg_FlushStream, OnFlushStream) |
| 223 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream) | 187 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream) |
| 224 IPC_MESSAGE_HANDLER(AudioHostMsg_NotifyPacketReady, OnNotifyPacketReady) | |
| 225 IPC_MESSAGE_HANDLER(AudioHostMsg_GetVolume, OnGetVolume) | |
| 226 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume) | 188 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume) |
| 227 IPC_MESSAGE_UNHANDLED(handled = false) | 189 IPC_MESSAGE_UNHANDLED(handled = false) |
| 228 IPC_END_MESSAGE_MAP_EX() | 190 IPC_END_MESSAGE_MAP_EX() |
| 229 | 191 |
| 230 return handled; | 192 return handled; |
| 231 } | 193 } |
| 232 | 194 |
| 233 void AudioRendererHost::OnCreateStream( | 195 void AudioRendererHost::OnCreateStream( |
| 234 int stream_id, const AudioParameters& params, bool low_latency) { | 196 int stream_id, const AudioParameters& params) { |
| 235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 236 DCHECK(LookupById(stream_id) == NULL); | 198 DCHECK(LookupById(stream_id) == NULL); |
| 237 | 199 |
| 238 AudioParameters audio_params(params); | 200 AudioParameters audio_params(params); |
| 239 | 201 |
| 240 // Select the hardware packet size if not specified. | 202 // Select the hardware packet size if not specified. |
| 241 if (!audio_params.samples_per_packet) { | 203 if (!audio_params.samples_per_packet) { |
| 242 audio_params.samples_per_packet = SelectSamplesPerPacket(audio_params); | 204 audio_params.samples_per_packet = SelectSamplesPerPacket(audio_params); |
| 243 } | 205 } |
| 244 uint32 packet_size = audio_params.GetPacketSize(); | 206 uint32 packet_size = audio_params.GetPacketSize(); |
| 245 | 207 |
| 246 scoped_ptr<AudioEntry> entry(new AudioEntry()); | 208 scoped_ptr<AudioEntry> entry(new AudioEntry()); |
| 209 |
| 247 // Create the shared memory and share with the renderer process. | 210 // Create the shared memory and share with the renderer process. |
| 248 uint32 shared_memory_size = packet_size; | 211 uint32 shared_memory_size = |
| 249 if (low_latency) { | 212 media::TotalSharedMemorySizeInBytes(packet_size); |
| 250 shared_memory_size = | |
| 251 media::TotalSharedMemorySizeInBytes(shared_memory_size); | |
| 252 } | |
| 253 if (!entry->shared_memory.CreateAndMapAnonymous(shared_memory_size)) { | 213 if (!entry->shared_memory.CreateAndMapAnonymous(shared_memory_size)) { |
| 254 // If creation of shared memory failed then send an error message. | 214 // If creation of shared memory failed then send an error message. |
| 255 SendErrorMessage(stream_id); | 215 SendErrorMessage(stream_id); |
| 256 return; | 216 return; |
| 257 } | 217 } |
| 258 | 218 |
| 259 if (low_latency) { | 219 // Create sync reader and try to initialize it. |
| 260 // If this is the low latency mode, we need to construct a SyncReader first. | 220 scoped_ptr<AudioSyncReader> reader( |
| 261 scoped_ptr<AudioSyncReader> reader( | 221 new AudioSyncReader(&entry->shared_memory)); |
| 262 new AudioSyncReader(&entry->shared_memory)); | |
| 263 | 222 |
| 264 // Then try to initialize the sync reader. | 223 if (!reader->Init()) { |
| 265 if (!reader->Init()) { | 224 SendErrorMessage(stream_id); |
| 266 SendErrorMessage(stream_id); | 225 return; |
| 267 return; | 226 } |
| 268 } | |
| 269 | 227 |
| 270 // If we have successfully created the SyncReader then assign it to the | 228 // If we have successfully created the SyncReader then assign it to the |
| 271 // entry and construct an AudioOutputController. | 229 // entry and construct an AudioOutputController. |
| 272 entry->reader.reset(reader.release()); | 230 entry->reader.reset(reader.release()); |
| 273 entry->controller = | 231 entry->controller = media::AudioOutputController::Create( |
| 274 media::AudioOutputController::CreateLowLatency( | 232 resource_context_->audio_manager(), this, audio_params, |
| 275 resource_context_->audio_manager(), this, audio_params, | 233 entry->reader.get()); |
| 276 entry->reader.get()); | |
| 277 } else { | |
| 278 // The choice of buffer capacity is based on experiment. | |
| 279 entry->controller = | |
| 280 media::AudioOutputController::Create( | |
| 281 resource_context_->audio_manager(), this, audio_params, | |
| 282 3 * packet_size); | |
| 283 } | |
| 284 | 234 |
| 285 if (!entry->controller) { | 235 if (!entry->controller) { |
| 286 SendErrorMessage(stream_id); | 236 SendErrorMessage(stream_id); |
| 287 return; | 237 return; |
| 288 } | 238 } |
| 289 | 239 |
| 290 // If we have created the controller successfully create a entry and add it | 240 // If we have created the controller successfully, create an entry and add it |
| 291 // to the map. | 241 // to the map. |
| 292 entry->stream_id = stream_id; | 242 entry->stream_id = stream_id; |
| 293 audio_entries_.insert(std::make_pair(stream_id, entry.release())); | 243 audio_entries_.insert(std::make_pair(stream_id, entry.release())); |
| 294 media_observer()->OnSetAudioStreamStatus(this, stream_id, "created"); | 244 media_observer()->OnSetAudioStreamStatus(this, stream_id, "created"); |
| 295 } | 245 } |
| 296 | 246 |
| 297 void AudioRendererHost::OnPlayStream(int stream_id) { | 247 void AudioRendererHost::OnPlayStream(int stream_id) { |
| 298 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 299 | 249 |
| 300 AudioEntry* entry = LookupById(stream_id); | 250 AudioEntry* entry = LookupById(stream_id); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 return; | 303 return; |
| 354 } | 304 } |
| 355 | 305 |
| 356 // Make sure the volume is valid. | 306 // Make sure the volume is valid. |
| 357 if (volume < 0 || volume > 1.0) | 307 if (volume < 0 || volume > 1.0) |
| 358 return; | 308 return; |
| 359 entry->controller->SetVolume(volume); | 309 entry->controller->SetVolume(volume); |
| 360 media_observer()->OnSetAudioStreamVolume(this, stream_id, volume); | 310 media_observer()->OnSetAudioStreamVolume(this, stream_id, volume); |
| 361 } | 311 } |
| 362 | 312 |
| 363 void AudioRendererHost::OnGetVolume(int stream_id) { | |
| 364 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 365 NOTREACHED() << "This message shouldn't be received"; | |
| 366 } | |
| 367 | |
| 368 void AudioRendererHost::OnNotifyPacketReady(int stream_id, uint32 packet_size) { | |
| 369 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 370 | |
| 371 AudioEntry* entry = LookupById(stream_id); | |
| 372 if (!entry) { | |
| 373 SendErrorMessage(stream_id); | |
| 374 return; | |
| 375 } | |
| 376 | |
| 377 DCHECK(!entry->controller->LowLatencyMode()); | |
| 378 CHECK(packet_size <= entry->shared_memory.created_size()); | |
| 379 | |
| 380 if (!entry->pending_buffer_request) { | |
| 381 NOTREACHED() << "Buffer received but no such pending request"; | |
| 382 } | |
| 383 entry->pending_buffer_request = false; | |
| 384 | |
| 385 // Enqueue the data to media::AudioOutputController. | |
| 386 entry->controller->EnqueueData( | |
| 387 reinterpret_cast<uint8*>(entry->shared_memory.memory()), | |
| 388 packet_size); | |
| 389 } | |
| 390 | |
| 391 void AudioRendererHost::SendErrorMessage(int32 stream_id) { | 313 void AudioRendererHost::SendErrorMessage(int32 stream_id) { |
| 392 Send(new AudioMsg_NotifyStreamStateChanged(stream_id, kAudioStreamError)); | 314 Send(new AudioMsg_NotifyStreamStateChanged(stream_id, kAudioStreamError)); |
| 393 } | 315 } |
| 394 | 316 |
| 395 void AudioRendererHost::DeleteEntries() { | 317 void AudioRendererHost::DeleteEntries() { |
| 396 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 397 | 319 |
| 398 for (AudioEntryMap::iterator i = audio_entries_.begin(); | 320 for (AudioEntryMap::iterator i = audio_entries_.begin(); |
| 399 i != audio_entries_.end(); ++i) { | 321 i != audio_entries_.end(); ++i) { |
| 400 CloseAndDeleteStream(i->second); | 322 CloseAndDeleteStream(i->second); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 465 } | 387 } |
| 466 return NULL; | 388 return NULL; |
| 467 } | 389 } |
| 468 | 390 |
| 469 MediaObserver* AudioRendererHost::media_observer() { | 391 MediaObserver* AudioRendererHost::media_observer() { |
| 470 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 471 if (!media_observer_) | 393 if (!media_observer_) |
| 472 media_observer_ = resource_context_->media_observer(); | 394 media_observer_ = resource_context_->media_observer(); |
| 473 return media_observer_; | 395 return media_observer_; |
| 474 } | 396 } |
| OLD | NEW |