| 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/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/browser_main_loop.h" | 11 #include "content/browser/browser_main_loop.h" |
| 12 #include "content/browser/renderer_host/media/audio_mirroring_manager.h" |
| 12 #include "content/browser/renderer_host/media/audio_sync_reader.h" | 13 #include "content/browser/renderer_host/media/audio_sync_reader.h" |
| 13 #include "content/common/media/audio_messages.h" | 14 #include "content/common/media/audio_messages.h" |
| 14 #include "content/public/browser/media_observer.h" | 15 #include "content/public/browser/media_observer.h" |
| 15 #include "media/audio/shared_memory_util.h" | 16 #include "media/audio/shared_memory_util.h" |
| 16 #include "media/base/audio_bus.h" | 17 #include "media/base/audio_bus.h" |
| 17 #include "media/base/limits.h" | 18 #include "media/base/limits.h" |
| 18 | 19 |
| 19 using media::AudioBus; | 20 using media::AudioBus; |
| 20 | 21 |
| 21 namespace content { | 22 namespace content { |
| 22 | 23 |
| 23 struct AudioRendererHost::AudioEntry { | 24 struct AudioRendererHost::AudioEntry { |
| 24 AudioEntry(); | 25 AudioEntry(); |
| 25 ~AudioEntry(); | 26 ~AudioEntry(); |
| 26 | 27 |
| 27 // The AudioOutputController that manages the audio stream. | 28 // The AudioOutputController that manages the audio stream. |
| 28 scoped_refptr<media::AudioOutputController> controller; | 29 scoped_refptr<media::AudioOutputController> controller; |
| 29 | 30 |
| 30 // The audio stream ID. | 31 // The audio stream ID. |
| 31 int stream_id; | 32 int stream_id; |
| 32 | 33 |
| 34 // The routing ID of the source render view. |
| 35 int render_view_id; |
| 36 |
| 33 // Shared memory for transmission of the audio data. | 37 // Shared memory for transmission of the audio data. |
| 34 base::SharedMemory shared_memory; | 38 base::SharedMemory shared_memory; |
| 35 | 39 |
| 36 // The synchronous reader to be used by the controller. We have the | 40 // The synchronous reader to be used by the controller. We have the |
| 37 // ownership of the reader. | 41 // ownership of the reader. |
| 38 scoped_ptr<media::AudioOutputController::SyncReader> reader; | 42 scoped_ptr<media::AudioOutputController::SyncReader> reader; |
| 39 | 43 |
| 40 // Set to true after we called Close() for the controller. | 44 // Set to true after we called Close() for the controller. |
| 41 bool pending_close; | 45 bool pending_close; |
| 42 }; | 46 }; |
| 43 | 47 |
| 44 AudioRendererHost::AudioEntry::AudioEntry() | 48 AudioRendererHost::AudioEntry::AudioEntry() |
| 45 : stream_id(0), | 49 : stream_id(0), |
| 50 render_view_id(MSG_ROUTING_NONE), |
| 46 pending_close(false) { | 51 pending_close(false) { |
| 47 } | 52 } |
| 48 | 53 |
| 49 AudioRendererHost::AudioEntry::~AudioEntry() {} | 54 AudioRendererHost::AudioEntry::~AudioEntry() {} |
| 50 | 55 |
| 51 /////////////////////////////////////////////////////////////////////////////// | 56 /////////////////////////////////////////////////////////////////////////////// |
| 52 // AudioRendererHost implementations. | 57 // AudioRendererHost implementations. |
| 53 AudioRendererHost::AudioRendererHost( | 58 AudioRendererHost::AudioRendererHost( |
| 54 media::AudioManager* audio_manager, MediaObserver* media_observer) | 59 int render_process_id, |
| 55 : audio_manager_(audio_manager), | 60 media::AudioManager* audio_manager, |
| 61 AudioMirroringManager* mirroring_manager, |
| 62 MediaObserver* media_observer) |
| 63 : render_process_id_(render_process_id), |
| 64 audio_manager_(audio_manager), |
| 65 mirroring_manager_(mirroring_manager), |
| 56 media_observer_(media_observer) { | 66 media_observer_(media_observer) { |
| 67 DCHECK(audio_manager_); |
| 68 DCHECK(mirroring_manager_); |
| 69 DCHECK(media_observer_); |
| 57 } | 70 } |
| 58 | 71 |
| 59 AudioRendererHost::~AudioRendererHost() { | 72 AudioRendererHost::~AudioRendererHost() { |
| 60 DCHECK(audio_entries_.empty()); | 73 DCHECK(audio_entries_.empty()); |
| 61 } | 74 } |
| 62 | 75 |
| 63 void AudioRendererHost::OnChannelClosing() { | 76 void AudioRendererHost::OnChannelClosing() { |
| 64 BrowserMessageFilter::OnChannelClosing(); | 77 BrowserMessageFilter::OnChannelClosing(); |
| 65 | 78 |
| 66 // Since the IPC channel is gone, close all requested audio streams. | 79 // Since the IPC channel is gone, close all requested audio streams. |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 if (!reader->Init()) { | 271 if (!reader->Init()) { |
| 259 SendErrorMessage(stream_id); | 272 SendErrorMessage(stream_id); |
| 260 return; | 273 return; |
| 261 } | 274 } |
| 262 | 275 |
| 263 // If we have successfully created the SyncReader then assign it to the | 276 // If we have successfully created the SyncReader then assign it to the |
| 264 // entry and construct an AudioOutputController. | 277 // entry and construct an AudioOutputController. |
| 265 entry->reader.reset(reader.release()); | 278 entry->reader.reset(reader.release()); |
| 266 entry->controller = media::AudioOutputController::Create( | 279 entry->controller = media::AudioOutputController::Create( |
| 267 audio_manager_, this, audio_params, entry->reader.get()); | 280 audio_manager_, this, audio_params, entry->reader.get()); |
| 268 | |
| 269 if (!entry->controller) { | 281 if (!entry->controller) { |
| 270 SendErrorMessage(stream_id); | 282 SendErrorMessage(stream_id); |
| 271 return; | 283 return; |
| 272 } | 284 } |
| 273 | 285 |
| 274 // If we have created the controller successfully, create an entry and add it | 286 // If we have created the controller successfully, create an entry and add it |
| 275 // to the map. | 287 // to the map. |
| 276 entry->stream_id = stream_id; | 288 entry->stream_id = stream_id; |
| 277 audio_entries_.insert(std::make_pair(stream_id, entry.release())); | 289 audio_entries_.insert(std::make_pair(stream_id, entry.release())); |
| 278 if (media_observer_) | 290 media_observer_->OnSetAudioStreamStatus(this, stream_id, "created"); |
| 279 media_observer_->OnSetAudioStreamStatus(this, stream_id, "created"); | |
| 280 } | 291 } |
| 281 | 292 |
| 282 void AudioRendererHost::OnAssociateStreamWithProducer(int stream_id, | 293 void AudioRendererHost::OnAssociateStreamWithProducer(int stream_id, |
| 283 int render_view_id) { | 294 int render_view_id) { |
| 284 // TODO(miu): Will use render_view_id in upcoming change. | 295 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 296 |
| 285 DVLOG(1) << "AudioRendererHost@" << this | 297 DVLOG(1) << "AudioRendererHost@" << this |
| 286 << "::OnAssociateStreamWithProducer(stream_id=" << stream_id | 298 << "::OnAssociateStreamWithProducer(stream_id=" << stream_id |
| 287 << ", render_view_id=" << render_view_id << ")"; | 299 << ", render_view_id=" << render_view_id << ")"; |
| 300 |
| 301 AudioEntry* const entry = LookupById(stream_id); |
| 302 if (!entry) { |
| 303 SendErrorMessage(stream_id); |
| 304 return; |
| 305 } |
| 306 |
| 307 if (entry->render_view_id == render_view_id) |
| 308 return; // No change. |
| 309 |
| 310 mirroring_manager_->RemoveDiverter( |
| 311 render_process_id_, entry->render_view_id, entry->controller); |
| 312 entry->render_view_id = render_view_id; |
| 313 mirroring_manager_->AddDiverter( |
| 314 render_process_id_, entry->render_view_id, entry->controller); |
| 288 } | 315 } |
| 289 | 316 |
| 290 void AudioRendererHost::OnPlayStream(int stream_id) { | 317 void AudioRendererHost::OnPlayStream(int stream_id) { |
| 291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 292 | 319 |
| 293 AudioEntry* entry = LookupById(stream_id); | 320 AudioEntry* entry = LookupById(stream_id); |
| 294 if (!entry) { | 321 if (!entry) { |
| 295 SendErrorMessage(stream_id); | 322 SendErrorMessage(stream_id); |
| 296 return; | 323 return; |
| 297 } | 324 } |
| 298 | 325 |
| 299 entry->controller->Play(); | 326 entry->controller->Play(); |
| 300 if (media_observer_) | 327 media_observer_->OnSetAudioStreamPlaying(this, stream_id, true); |
| 301 media_observer_->OnSetAudioStreamPlaying(this, stream_id, true); | |
| 302 } | 328 } |
| 303 | 329 |
| 304 void AudioRendererHost::OnPauseStream(int stream_id) { | 330 void AudioRendererHost::OnPauseStream(int stream_id) { |
| 305 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 306 | 332 |
| 307 AudioEntry* entry = LookupById(stream_id); | 333 AudioEntry* entry = LookupById(stream_id); |
| 308 if (!entry) { | 334 if (!entry) { |
| 309 SendErrorMessage(stream_id); | 335 SendErrorMessage(stream_id); |
| 310 return; | 336 return; |
| 311 } | 337 } |
| 312 | 338 |
| 313 entry->controller->Pause(); | 339 entry->controller->Pause(); |
| 314 if (media_observer_) | 340 media_observer_->OnSetAudioStreamPlaying(this, stream_id, false); |
| 315 media_observer_->OnSetAudioStreamPlaying(this, stream_id, false); | |
| 316 } | 341 } |
| 317 | 342 |
| 318 void AudioRendererHost::OnFlushStream(int stream_id) { | 343 void AudioRendererHost::OnFlushStream(int stream_id) { |
| 319 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 320 | 345 |
| 321 AudioEntry* entry = LookupById(stream_id); | 346 AudioEntry* entry = LookupById(stream_id); |
| 322 if (!entry) { | 347 if (!entry) { |
| 323 SendErrorMessage(stream_id); | 348 SendErrorMessage(stream_id); |
| 324 return; | 349 return; |
| 325 } | 350 } |
| 326 | 351 |
| 327 entry->controller->Flush(); | 352 entry->controller->Flush(); |
| 328 if (media_observer_) | 353 media_observer_->OnSetAudioStreamStatus(this, stream_id, "flushed"); |
| 329 media_observer_->OnSetAudioStreamStatus(this, stream_id, "flushed"); | |
| 330 } | 354 } |
| 331 | 355 |
| 332 void AudioRendererHost::OnCloseStream(int stream_id) { | 356 void AudioRendererHost::OnCloseStream(int stream_id) { |
| 333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 357 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 334 | 358 |
| 335 if (media_observer_) | 359 media_observer_->OnSetAudioStreamStatus(this, stream_id, "closed"); |
| 336 media_observer_->OnSetAudioStreamStatus(this, stream_id, "closed"); | |
| 337 | 360 |
| 338 AudioEntry* entry = LookupById(stream_id); | 361 AudioEntry* entry = LookupById(stream_id); |
| 339 | 362 |
| 340 if (entry) | 363 if (entry) |
| 341 CloseAndDeleteStream(entry); | 364 CloseAndDeleteStream(entry); |
| 342 } | 365 } |
| 343 | 366 |
| 344 void AudioRendererHost::OnSetVolume(int stream_id, double volume) { | 367 void AudioRendererHost::OnSetVolume(int stream_id, double volume) { |
| 345 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 368 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 346 | 369 |
| 347 AudioEntry* entry = LookupById(stream_id); | 370 AudioEntry* entry = LookupById(stream_id); |
| 348 if (!entry) { | 371 if (!entry) { |
| 349 SendErrorMessage(stream_id); | 372 SendErrorMessage(stream_id); |
| 350 return; | 373 return; |
| 351 } | 374 } |
| 352 | 375 |
| 353 // Make sure the volume is valid. | 376 // Make sure the volume is valid. |
| 354 if (volume < 0 || volume > 1.0) | 377 if (volume < 0 || volume > 1.0) |
| 355 return; | 378 return; |
| 356 entry->controller->SetVolume(volume); | 379 entry->controller->SetVolume(volume); |
| 357 if (media_observer_) | 380 media_observer_->OnSetAudioStreamVolume(this, stream_id, volume); |
| 358 media_observer_->OnSetAudioStreamVolume(this, stream_id, volume); | |
| 359 } | 381 } |
| 360 | 382 |
| 361 void AudioRendererHost::SendErrorMessage(int32 stream_id) { | 383 void AudioRendererHost::SendErrorMessage(int32 stream_id) { |
| 362 Send(new AudioMsg_NotifyStreamStateChanged( | 384 Send(new AudioMsg_NotifyStreamStateChanged( |
| 363 stream_id, media::AudioOutputIPCDelegate::kError)); | 385 stream_id, media::AudioOutputIPCDelegate::kError)); |
| 364 } | 386 } |
| 365 | 387 |
| 366 void AudioRendererHost::DeleteEntries() { | 388 void AudioRendererHost::DeleteEntries() { |
| 367 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 389 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 368 | 390 |
| 369 for (AudioEntryMap::iterator i = audio_entries_.begin(); | 391 for (AudioEntryMap::iterator i = audio_entries_.begin(); |
| 370 i != audio_entries_.end(); ++i) { | 392 i != audio_entries_.end(); ++i) { |
| 371 CloseAndDeleteStream(i->second); | 393 CloseAndDeleteStream(i->second); |
| 372 } | 394 } |
| 373 } | 395 } |
| 374 | 396 |
| 375 void AudioRendererHost::CloseAndDeleteStream(AudioEntry* entry) { | 397 void AudioRendererHost::CloseAndDeleteStream(AudioEntry* entry) { |
| 376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 377 | 399 |
| 378 if (!entry->pending_close) { | 400 if (!entry->pending_close) { |
| 401 mirroring_manager_->RemoveDiverter( |
| 402 render_process_id_, entry->render_view_id, entry->controller); |
| 379 entry->controller->Close( | 403 entry->controller->Close( |
| 380 base::Bind(&AudioRendererHost::DeleteEntry, this, entry)); | 404 base::Bind(&AudioRendererHost::DeleteEntry, this, entry)); |
| 381 entry->pending_close = true; | 405 entry->pending_close = true; |
| 382 } | 406 } |
| 383 } | 407 } |
| 384 | 408 |
| 385 void AudioRendererHost::DeleteEntry(AudioEntry* entry) { | 409 void AudioRendererHost::DeleteEntry(AudioEntry* entry) { |
| 386 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 410 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 387 | 411 |
| 388 // Delete the entry when this method goes out of scope. | 412 // Delete the entry when this method goes out of scope. |
| 389 scoped_ptr<AudioEntry> entry_deleter(entry); | 413 scoped_ptr<AudioEntry> entry_deleter(entry); |
| 390 | 414 |
| 391 // Erase the entry identified by |stream_id| from the map. | 415 // Erase the entry identified by |stream_id| from the map. |
| 392 audio_entries_.erase(entry->stream_id); | 416 audio_entries_.erase(entry->stream_id); |
| 393 | 417 |
| 394 // Notify the media observer. | 418 // Notify the media observer. |
| 395 if (media_observer_) | 419 media_observer_->OnDeleteAudioStream(this, entry->stream_id); |
| 396 media_observer_->OnDeleteAudioStream(this, entry->stream_id); | |
| 397 } | 420 } |
| 398 | 421 |
| 399 void AudioRendererHost::DeleteEntryOnError(AudioEntry* entry) { | 422 void AudioRendererHost::DeleteEntryOnError(AudioEntry* entry) { |
| 400 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 401 | 424 |
| 402 // Sends the error message first before we close the stream because | 425 // Sends the error message first before we close the stream because |
| 403 // |entry| is destroyed in DeleteEntry(). | 426 // |entry| is destroyed in DeleteEntry(). |
| 404 SendErrorMessage(entry->stream_id); | 427 SendErrorMessage(entry->stream_id); |
| 405 | 428 |
| 406 if (media_observer_) | 429 media_observer_->OnSetAudioStreamStatus(this, entry->stream_id, "error"); |
| 407 media_observer_->OnSetAudioStreamStatus(this, entry->stream_id, "error"); | |
| 408 CloseAndDeleteStream(entry); | 430 CloseAndDeleteStream(entry); |
| 409 } | 431 } |
| 410 | 432 |
| 411 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) { | 433 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) { |
| 412 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 434 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 413 | 435 |
| 414 AudioEntryMap::iterator i = audio_entries_.find(stream_id); | 436 AudioEntryMap::iterator i = audio_entries_.find(stream_id); |
| 415 if (i != audio_entries_.end() && !i->second->pending_close) | 437 if (i != audio_entries_.end() && !i->second->pending_close) |
| 416 return i->second; | 438 return i->second; |
| 417 return NULL; | 439 return NULL; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 431 return NULL; | 453 return NULL; |
| 432 } | 454 } |
| 433 | 455 |
| 434 media::AudioOutputController* AudioRendererHost::LookupControllerByIdForTesting( | 456 media::AudioOutputController* AudioRendererHost::LookupControllerByIdForTesting( |
| 435 int stream_id) { | 457 int stream_id) { |
| 436 AudioEntry* const entry = LookupById(stream_id); | 458 AudioEntry* const entry = LookupById(stream_id); |
| 437 return entry ? entry->controller : NULL; | 459 return entry ? entry->controller : NULL; |
| 438 } | 460 } |
| 439 | 461 |
| 440 } // namespace content | 462 } // namespace content |
| OLD | NEW |