audio_renderer_host.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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 3// found in the LICENSE file. 4 5#include "content/browser/renderer_host/media/audio_renderer_host.h" 6 7#include "base/bind.h" 8#include "base/metrics/histogram.h" 9#include "base/process.h" 10#include "base/shared_memory.h" 11#include "content/browser/browser_main_loop.h" 12#include "content/browser/media/media_internals.h" 13#include "content/browser/renderer_host/media/audio_mirroring_manager.h" 14#include "content/browser/renderer_host/media/audio_sync_reader.h" 15#include "content/common/media/audio_messages.h" 16#include "content/public/browser/content_browser_client.h" 17#include "content/public/browser/media_observer.h" 18#include "media/audio/shared_memory_util.h" 19#include "media/base/audio_bus.h" 20#include "media/base/limits.h" 21 22// TODO(miu): Re-enable after M27 branch cut. This feature is scheduled for 23// release in M28. 24#define DISABLED_AUDIO_INDICATOR_TRIGGERS_FOR_M27_ONLY 25 26using media::AudioBus; 27 28namespace content { 29 30struct AudioRendererHost::AudioEntry { 31 AudioEntry(); 32 ~AudioEntry(); 33 34 // The AudioOutputController that manages the audio stream. 35 scoped_refptr<media::AudioOutputController> controller; 36 37 // The audio stream ID. 38 int stream_id; 39 40 // The routing ID of the source render view. 41 int render_view_id; 42 43 // Shared memory for transmission of the audio data. 44 base::SharedMemory shared_memory; 45 46 // The synchronous reader to be used by the controller. We have the 47 // ownership of the reader. 48 scoped_ptr<media::AudioOutputController::SyncReader> reader; 49 50 // Set to true after we called Close() for the controller. 51 bool pending_close; 52}; 53 54AudioRendererHost::AudioEntry::AudioEntry() 55 : stream_id(0), 56 render_view_id(MSG_ROUTING_NONE), 57 pending_close(false) { 58} 59 60AudioRendererHost::AudioEntry::~AudioEntry() {} 61 62/////////////////////////////////////////////////////////////////////////////// 63// AudioRendererHost implementations. 64AudioRendererHost::AudioRendererHost( 65 int render_process_id, 66 media::AudioManager* audio_manager, 67 AudioMirroringManager* mirroring_manager, 68 MediaInternals* media_internals) 69 : render_process_id_(render_process_id), 70 audio_manager_(audio_manager), 71 mirroring_manager_(mirroring_manager), 72 media_internals_(media_internals) { 73 DCHECK(audio_manager_); 74} 75 76AudioRendererHost::~AudioRendererHost() { 77 DCHECK(audio_entries_.empty()); 78} 79 80void AudioRendererHost::OnChannelClosing() { 81 BrowserMessageFilter::OnChannelClosing(); 82 83 // Since the IPC channel is gone, close all requested audio streams. 84 DeleteEntries(); 85} 86 87void AudioRendererHost::OnDestruct() const { 88 BrowserThread::DeleteOnIOThread::Destruct(this); 89} 90 91/////////////////////////////////////////////////////////////////////////////// 92// media::AudioOutputController::EventHandler implementations. 93void AudioRendererHost::OnCreated(media::AudioOutputController* controller) { 94 BrowserThread::PostTask( 95 BrowserThread::IO, 96 FROM_HERE, 97 base::Bind( 98 &AudioRendererHost::DoCompleteCreation, 99 this, 100 make_scoped_refptr(controller))); 101} 102 103void AudioRendererHost::OnPlaying(media::AudioOutputController* controller) { 104 BrowserThread::PostTask( 105 BrowserThread::IO, 106 FROM_HERE, 107 base::Bind( 108 &AudioRendererHost::DoSendPlayingMessage, 109 this, 110 make_scoped_refptr(controller))); 111} 112 113void AudioRendererHost::OnPaused(media::AudioOutputController* controller) { 114 BrowserThread::PostTask( 115 BrowserThread::IO, 116 FROM_HERE, 117 base::Bind( 118 &AudioRendererHost::DoSendPausedMessage, 119 this, 120 make_scoped_refptr(controller))); 121} 122 123void AudioRendererHost::OnError(media::AudioOutputController* controller) { 124 BrowserThread::PostTask( 125 BrowserThread::IO, 126 FROM_HERE, 127 base::Bind( 128 &AudioRendererHost::DoHandleError, 129 this, 130 make_scoped_refptr(controller))); 131} 132 133void AudioRendererHost::OnDeviceChange(media::AudioOutputController* controller, 134 int new_buffer_size, 135 int new_sample_rate) { 136 BrowserThread::PostTask( 137 BrowserThread::IO, 138 FROM_HERE, 139 base::Bind(&AudioRendererHost::DoSendDeviceChangeMessage, 140 this, make_scoped_refptr(controller), new_buffer_size, 141 new_sample_rate)); 142} 143 144void AudioRendererHost::DoCompleteCreation( 145 media::AudioOutputController* controller) { 146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 147 148 AudioEntry* entry = LookupByController(controller); 149 if (!entry) 150 return; 151 152 if (!peer_handle()) { 153 NOTREACHED() << "Renderer process handle is invalid."; 154 DeleteEntryOnError(entry); 155 return; 156 } 157 158 // Once the audio stream is created then complete the creation process by 159 // mapping shared memory and sharing with the renderer process. 160 base::SharedMemoryHandle foreign_memory_handle; 161 if (!entry->shared_memory.ShareToProcess(peer_handle(), 162 &foreign_memory_handle)) { 163 // If we failed to map and share the shared memory then close the audio 164 // stream and send an error message. 165 DeleteEntryOnError(entry); 166 return; 167 } 168 169 AudioSyncReader* reader = 170 static_cast<AudioSyncReader*>(entry->reader.get()); 171 172#if defined(OS_WIN) 173 base::SyncSocket::Handle foreign_socket_handle; 174#else 175 base::FileDescriptor foreign_socket_handle; 176#endif 177 178 // If we failed to prepare the sync socket for the renderer then we fail 179 // the construction of audio stream. 180 if (!reader->PrepareForeignSocketHandle(peer_handle(), 181 &foreign_socket_handle)) { 182 DeleteEntryOnError(entry); 183 return; 184 } 185 186 Send(new AudioMsg_NotifyStreamCreated( 187 entry->stream_id, 188 foreign_memory_handle, 189 foreign_socket_handle, 190 media::PacketSizeInBytes(entry->shared_memory.created_size()))); 191} 192 193void AudioRendererHost::DoSendPlayingMessage( 194 media::AudioOutputController* controller) { 195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 196 197 AudioEntry* entry = LookupByController(controller); 198 if (!entry) 199 return; 200 201 Send(new AudioMsg_NotifyStreamStateChanged( 202 entry->stream_id, media::AudioOutputIPCDelegate::kPlaying)); 203} 204 205void AudioRendererHost::DoSendPausedMessage( 206 media::AudioOutputController* controller) { 207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 208 209 AudioEntry* entry = LookupByController(controller); 210 if (!entry) 211 return; 212 213 Send(new AudioMsg_NotifyStreamStateChanged( 214 entry->stream_id, media::AudioOutputIPCDelegate::kPaused)); 215} 216 217void AudioRendererHost::DoSendDeviceChangeMessage( 218 media::AudioOutputController* controller, int new_buffer_size, 219 int new_sample_rate) { 220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 221 222 AudioEntry* entry = LookupByController(controller); 223 if (!entry) 224 return; 225 226 Send(new AudioMsg_NotifyDeviceChanged( 227 entry->stream_id, new_buffer_size, new_sample_rate)); 228} 229 230void AudioRendererHost::DoHandleError( 231 media::AudioOutputController* controller) { 232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 233 234 AudioEntry* entry = LookupByController(controller); 235 if (!entry) 236 return; 237 238 DeleteEntryOnError(entry); 239} 240 241/////////////////////////////////////////////////////////////////////////////// 242// IPC Messages handler 243bool AudioRendererHost::OnMessageReceived(const IPC::Message& message, 244 bool* message_was_ok) { 245 bool handled = true; 246 IPC_BEGIN_MESSAGE_MAP_EX(AudioRendererHost, message, *message_was_ok) 247 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream) 248 IPC_MESSAGE_HANDLER(AudioHostMsg_AssociateStreamWithProducer, 249 OnAssociateStreamWithProducer) 250 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream) 251 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream) 252 IPC_MESSAGE_HANDLER(AudioHostMsg_FlushStream, OnFlushStream) 253 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream) 254 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume) 255 IPC_MESSAGE_UNHANDLED(handled = false) 256 IPC_END_MESSAGE_MAP_EX() 257 258 return handled; 259} 260 261void AudioRendererHost::OnCreateStream( 262 int stream_id, const media::AudioParameters& params) { 263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 264 // media::AudioParameters is validated in the deserializer. 265 int input_channels = params.input_channels(); 266 if (input_channels < 0 || 267 input_channels > media::limits::kMaxChannels || 268 LookupById(stream_id) != NULL) { 269 SendErrorMessage(stream_id); 270 return; 271 } 272 273 media::AudioParameters audio_params(params); 274 275 // Calculate output and input memory size. 276 int output_memory_size = AudioBus::CalculateMemorySize(audio_params); 277 278 int frames = audio_params.frames_per_buffer(); 279 int input_memory_size = 280 AudioBus::CalculateMemorySize(input_channels, frames); 281 282 scoped_ptr<AudioEntry> entry(new AudioEntry()); 283 284 // Create the shared memory and share with the renderer process. 285 // For synchronized I/O (if input_channels > 0) then we allocate 286 // extra memory after the output data for the input data. 287 uint32 io_buffer_size = output_memory_size + input_memory_size; 288 289 uint32 shared_memory_size = 290 media::TotalSharedMemorySizeInBytes(io_buffer_size); 291 if (!entry->shared_memory.CreateAndMapAnonymous(shared_memory_size)) { 292 // If creation of shared memory failed then send an error message. 293 SendErrorMessage(stream_id); 294 return; 295 } 296 297 // Create sync reader and try to initialize it. 298 scoped_ptr<AudioSyncReader> reader( 299 new AudioSyncReader(&entry->shared_memory, params, input_channels)); 300 301 if (!reader->Init()) { 302 SendErrorMessage(stream_id); 303 return; 304 } 305 306 // If we have successfully created the SyncReader then assign it to the 307 // entry and construct an AudioOutputController. 308 entry->reader.reset(reader.release()); 309 entry->controller = media::AudioOutputController::Create( 310 audio_manager_, this, audio_params, entry->reader.get()); 311 312 if (!entry->controller) { 313 SendErrorMessage(stream_id); 314 return; 315 } 316 317 // If we have created the controller successfully, create an entry and add it 318 // to the map. 319 entry->stream_id = stream_id; 320 audio_entries_.insert(std::make_pair(stream_id, entry.release())); 321 if (media_internals_) 322 media_internals_->OnSetAudioStreamStatus(this, stream_id, "created"); 323} 324 325void AudioRendererHost::OnAssociateStreamWithProducer(int stream_id, 326 int render_view_id) { 327 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 328 329 DVLOG(1) << "AudioRendererHost@" << this 330 << "::OnAssociateStreamWithProducer(stream_id=" << stream_id 331 << ", render_view_id=" << render_view_id << ")"; 332 333 AudioEntry* const entry = LookupById(stream_id); 334 if (!entry) { 335 SendErrorMessage(stream_id); 336 return; 337 } 338 339 if (entry->render_view_id == render_view_id) 340 return; 341 342 // TODO(miu): Merge "AssociateWithProducer" message into "CreateStream" 343 // message so AudioRendererHost can assume a simpler "render_view_id is set 344 // once" scheme. http://crbug.com/166779 345 if (mirroring_manager_) { 346 mirroring_manager_->RemoveDiverter( 347 render_process_id_, entry->render_view_id, entry->controller); 348 } 349 entry->render_view_id = render_view_id; 350 if (mirroring_manager_) { 351 mirroring_manager_->AddDiverter( 352 render_process_id_, entry->render_view_id, entry->controller); 353 } 354} 355 356void AudioRendererHost::OnPlayStream(int stream_id) { 357 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 358 359 AudioEntry* entry = LookupById(stream_id); 360 if (!entry) { 361 SendErrorMessage(stream_id); 362 return; 363 } 364 365 entry->controller->Play(); 366 if (media_internals_) 367 media_internals_->OnSetAudioStreamPlaying(this, stream_id, true); 368 369#ifndef DISABLED_AUDIO_INDICATOR_TRIGGERS_FOR_M27_ONLY 370 MediaObserver* media_observer = 371 GetContentClient()->browser()->GetMediaObserver(); 372 if (media_observer) { 373 media_observer->OnAudioStreamPlayingChanged( 374 render_process_id_, entry->render_view_id, stream_id, true); 375 } 376#endif 377} 378 379void AudioRendererHost::OnPauseStream(int stream_id) { 380 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 381 382 AudioEntry* entry = LookupById(stream_id); 383 if (!entry) { 384 SendErrorMessage(stream_id); 385 return; 386 } 387 388 entry->controller->Pause(); 389 if (media_internals_) 390 media_internals_->OnSetAudioStreamPlaying(this, stream_id, false); 391 392#ifndef DISABLED_AUDIO_INDICATOR_TRIGGERS_FOR_M27_ONLY 393 MediaObserver* media_observer = 394 GetContentClient()->browser()->GetMediaObserver(); 395 if (media_observer) { 396 media_observer->OnAudioStreamPlayingChanged( 397 render_process_id_, entry->render_view_id, stream_id, false); 398 } 399#endif 400} 401 402void AudioRendererHost::OnFlushStream(int stream_id) { 403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 404 405 AudioEntry* entry = LookupById(stream_id); 406 if (!entry) { 407 SendErrorMessage(stream_id); 408 return; 409 } 410 411 entry->controller->Flush(); 412 if (media_internals_) 413 media_internals_->OnSetAudioStreamStatus(this, stream_id, "flushed"); 414} 415 416void AudioRendererHost::OnCloseStream(int stream_id) { 417 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 418 419 if (media_internals_) 420 media_internals_->OnSetAudioStreamStatus(this, stream_id, "closed"); 421 422 AudioEntry* entry = LookupById(stream_id); 423 424 if (!entry) 425 return; 426 427 CloseAndDeleteStream(entry); 428} 429 430void AudioRendererHost::OnSetVolume(int stream_id, double volume) { 431 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 432 433 AudioEntry* entry = LookupById(stream_id); 434 if (!entry) { 435 SendErrorMessage(stream_id); 436 return; 437 } 438 439 // Make sure the volume is valid. 440 if (volume < 0 || volume > 1.0) 441 return; 442 entry->controller->SetVolume(volume); 443 if (media_internals_) 444 media_internals_->OnSetAudioStreamVolume(this, stream_id, volume); 445 446#ifndef DISABLED_AUDIO_INDICATOR_TRIGGERS_FOR_M27_ONLY 447 MediaObserver* media_observer = 448 GetContentClient()->browser()->GetMediaObserver(); 449 if (media_observer) { 450 bool playing = volume > 0; 451 media_observer->OnAudioStreamPlayingChanged( 452 render_process_id_, entry->render_view_id, stream_id, playing); 453 } 454#endif 455} 456 457void AudioRendererHost::SendErrorMessage(int32 stream_id) { 458 Send(new AudioMsg_NotifyStreamStateChanged( 459 stream_id, media::AudioOutputIPCDelegate::kError)); 460} 461 462void AudioRendererHost::DeleteEntries() { 463 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 464 465 for (AudioEntryMap::iterator i = audio_entries_.begin(); 466 i != audio_entries_.end(); ++i) { 467 CloseAndDeleteStream(i->second); 468 } 469} 470 471void AudioRendererHost::CloseAndDeleteStream(AudioEntry* entry) { 472 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 473 474#ifndef DISABLED_AUDIO_INDICATOR_TRIGGERS_FOR_M27_ONLY 475 MediaObserver* media_observer = 476 GetContentClient()->browser()->GetMediaObserver(); 477 if (media_observer) { 478 media_observer->OnAudioStreamPlayingChanged( 479 render_process_id_, entry->render_view_id, entry->stream_id, false); 480 } 481#endif 482 if (!entry->pending_close) { 483 if (mirroring_manager_) { 484 mirroring_manager_->RemoveDiverter( 485 render_process_id_, entry->render_view_id, entry->controller); 486 } 487 entry->controller->Close( 488 base::Bind(&AudioRendererHost::DeleteEntry, this, entry)); 489 entry->pending_close = true; 490 } 491} 492 493void AudioRendererHost::DeleteEntry(AudioEntry* entry) { 494 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 495 496 // Delete the entry when this method goes out of scope. 497 scoped_ptr<AudioEntry> entry_deleter(entry); 498 499 // Erase the entry identified by |stream_id| from the map. 500 audio_entries_.erase(entry->stream_id); 501 502 // Notify the media observer. 503 if (media_internals_) 504 media_internals_->OnDeleteAudioStream(this, entry->stream_id); 505} 506 507void AudioRendererHost::DeleteEntryOnError(AudioEntry* entry) { 508 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 509 510 // Sends the error message first before we close the stream because 511 // |entry| is destroyed in DeleteEntry(). 512 SendErrorMessage(entry->stream_id); 513 514 if (media_internals_) 515 media_internals_->OnSetAudioStreamStatus(this, entry->stream_id, "error"); 516 CloseAndDeleteStream(entry); 517} 518 519AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) { 520 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 521 522 AudioEntryMap::iterator i = audio_entries_.find(stream_id); 523 if (i != audio_entries_.end() && !i->second->pending_close) 524 return i->second; 525 return NULL; 526} 527 528AudioRendererHost::AudioEntry* AudioRendererHost::LookupByController( 529 media::AudioOutputController* controller) { 530 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 531 532 // Iterate the map of entries. 533 // TODO(hclam): Implement a faster look up method. 534 for (AudioEntryMap::iterator i = audio_entries_.begin(); 535 i != audio_entries_.end(); ++i) { 536 if (!i->second->pending_close && controller == i->second->controller.get()) 537 return i->second; 538 } 539 return NULL; 540} 541 542media::AudioOutputController* AudioRendererHost::LookupControllerByIdForTesting( 543 int stream_id) { 544 AudioEntry* const entry = LookupById(stream_id); 545 return entry ? entry->controller : NULL; 546} 547 548} // namespace content 549