Index: content/browser/renderer_host/media/audio_renderer_host.cc |
diff --git a/content/browser/renderer_host/media/audio_renderer_host.cc b/content/browser/renderer_host/media/audio_renderer_host.cc |
index 98e931b295c9007e5e6bd6365320647bbfca16bc..dc62df35673747023c68dae70246adfcff879dd0 100644 |
--- a/content/browser/renderer_host/media/audio_renderer_host.cc |
+++ b/content/browser/renderer_host/media/audio_renderer_host.cc |
@@ -5,13 +5,10 @@ |
#include "content/browser/renderer_host/media/audio_renderer_host.h" |
#include <stdint.h> |
-#include <utility> |
#include "base/bind.h" |
#include "base/bind_helpers.h" |
#include "base/lazy_instance.h" |
-#include "base/memory/ptr_util.h" |
-#include "base/memory/shared_memory.h" |
#include "base/metrics/histogram_macros.h" |
#include "content/browser/bad_message.h" |
#include "content/browser/browser_main_loop.h" |
@@ -21,7 +18,6 @@ |
#include "content/browser/renderer_host/media/audio_input_device_manager.h" |
#include "content/browser/renderer_host/media/audio_sync_reader.h" |
#include "content/browser/renderer_host/media/media_stream_manager.h" |
-#include "content/browser/renderer_host/media/media_stream_ui_proxy.h" |
#include "content/common/media/audio_messages.h" |
#include "content/public/browser/content_browser_client.h" |
#include "content/public/browser/media_device_id.h" |
@@ -75,117 +71,19 @@ void ValidateRenderFrameId(int render_process_id, |
} // namespace |
-class AudioRendererHost::AudioEntry |
- : public media::AudioOutputController::EventHandler { |
- public: |
- ~AudioEntry() override; |
- |
- // Returns nullptr on failure. |
- static std::unique_ptr<AudioRendererHost::AudioEntry> Create( |
- AudioRendererHost* host, |
- int stream_id, |
- int render_frame_id, |
- const media::AudioParameters& params, |
- const std::string& output_device_id); |
- |
- int stream_id() const { |
- return stream_id_; |
- } |
- |
- int render_frame_id() const { return render_frame_id_; } |
- |
- media::AudioOutputController* controller() const { return controller_.get(); } |
- |
- AudioSyncReader* reader() const { return reader_.get(); } |
- |
- // Used by ARH to track the number of active streams for UMA stats. |
- bool playing() const { return playing_; } |
- void set_playing(bool playing) { playing_ = playing; } |
- |
- private: |
- AudioEntry(AudioRendererHost* host, |
- int stream_id, |
- int render_frame_id, |
- const media::AudioParameters& params, |
- const std::string& output_device_id, |
- std::unique_ptr<AudioSyncReader> reader); |
- |
- // media::AudioOutputController::EventHandler implementation. |
- void OnCreated() override; |
- void OnPlaying() override; |
- void OnPaused() override; |
- void OnError() override; |
- |
- AudioRendererHost* const host_; |
- const int stream_id_; |
- |
- // The routing ID of the source RenderFrame. |
- const int render_frame_id_; |
- |
- // The synchronous reader to be used by |controller_|. |
- const std::unique_ptr<AudioSyncReader> reader_; |
- |
- // The AudioOutputController that manages the audio stream. |
- const scoped_refptr<media::AudioOutputController> controller_; |
- |
- bool playing_; |
- |
- DISALLOW_COPY_AND_ASSIGN(AudioEntry); |
-}; |
- |
-AudioRendererHost::AudioEntry::AudioEntry( |
- AudioRendererHost* host, |
- int stream_id, |
- int render_frame_id, |
- const media::AudioParameters& params, |
- const std::string& output_device_id, |
- std::unique_ptr<AudioSyncReader> reader) |
- : host_(host), |
- stream_id_(stream_id), |
- render_frame_id_(render_frame_id), |
- reader_(std::move(reader)), |
- controller_(media::AudioOutputController::Create(host->audio_manager_, |
- this, |
- params, |
- output_device_id, |
- reader_.get())), |
- playing_(false) { |
- DCHECK(controller_); |
-} |
- |
-AudioRendererHost::AudioEntry::~AudioEntry() {} |
- |
-// static |
-std::unique_ptr<AudioRendererHost::AudioEntry> |
-AudioRendererHost::AudioEntry::Create(AudioRendererHost* host, |
- int stream_id, |
- int render_frame_id, |
- const media::AudioParameters& params, |
- const std::string& output_device_id) { |
- std::unique_ptr<AudioSyncReader> reader(AudioSyncReader::Create(params)); |
- if (!reader) { |
- return nullptr; |
- } |
- return base::WrapUnique(new AudioEntry(host, stream_id, render_frame_id, |
- params, output_device_id, |
- std::move(reader))); |
-} |
- |
/////////////////////////////////////////////////////////////////////////////// |
// AudioRendererHost implementations. |
AudioRendererHost::AudioRendererHost(int render_process_id, |
media::AudioManager* audio_manager, |
AudioMirroringManager* mirroring_manager, |
- MediaInternals* media_internals, |
MediaStreamManager* media_stream_manager, |
const std::string& salt) |
: BrowserMessageFilter(AudioMsgStart), |
render_process_id_(render_process_id), |
audio_manager_(audio_manager), |
mirroring_manager_(mirroring_manager), |
- audio_log_(media_internals->CreateAudioLog( |
- media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), |
+ media_stream_manager_(media_stream_manager), |
num_playing_streams_(0), |
salt_(salt), |
validate_render_frame_id_function_(&ValidateRenderFrameId), |
@@ -199,7 +97,7 @@ AudioRendererHost::AudioRendererHost(int render_process_id, |
AudioRendererHost::~AudioRendererHost() { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- CHECK(audio_entries_.empty()); |
+ DCHECK(delegates_.empty()); |
// If we had any streams, report UMA stats for the maximum number of |
// simultaneous streams for this render process and for the whole browser |
@@ -226,10 +124,10 @@ void AudioRendererHost::GetOutputControllers( |
void AudioRendererHost::OnChannelClosing() { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
// Since the IPC sender is gone, close all requested audio streams. |
- while (!audio_entries_.empty()) { |
- // Note: OnCloseStream() removes the entries from audio_entries_. |
- OnCloseStream(audio_entries_.begin()->first); |
- } |
+ // The audio streams tracker isn't automatically decremented since the |
+ // removal isn't done through OnCloseStream. |
+ g_audio_streams_tracker.Get().DecreaseStreamCount(delegates_.size()); |
+ delegates_.clear(); |
// Remove any authorizations for streams that were not yet created |
authorizations_.clear(); |
@@ -239,53 +137,23 @@ void AudioRendererHost::OnDestruct() const { |
BrowserThread::DeleteOnIOThread::Destruct(this); |
} |
-void AudioRendererHost::AudioEntry::OnCreated() { |
- BrowserThread::PostTask( |
- BrowserThread::IO, |
- FROM_HERE, |
- base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_)); |
-} |
- |
-void AudioRendererHost::AudioEntry::OnPlaying() { |
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
- base::Bind(&AudioRendererHost::StreamStateChanged, |
- host_, stream_id_, true)); |
-} |
- |
-void AudioRendererHost::AudioEntry::OnPaused() { |
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
- base::Bind(&AudioRendererHost::StreamStateChanged, |
- host_, stream_id_, false)); |
-} |
- |
-void AudioRendererHost::AudioEntry::OnError() { |
- BrowserThread::PostTask( |
- BrowserThread::IO, |
- FROM_HERE, |
- base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_)); |
-} |
- |
-void AudioRendererHost::DoCompleteCreation(int stream_id) { |
+void AudioRendererHost::OnStreamCreated( |
+ int stream_id, |
+ base::SharedMemory* shared_memory, |
+ base::CancelableSyncSocket* foreign_socket) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
if (!PeerHandle()) { |
DLOG(WARNING) << "Renderer process handle is invalid."; |
- ReportErrorAndClose(stream_id); |
+ OnStreamError(stream_id); |
return; |
} |
- AudioEntry* const entry = LookupById(stream_id); |
- if (!entry) { |
- ReportErrorAndClose(stream_id); |
+ if (!LookupById(stream_id)) { |
+ OnStreamError(stream_id); |
return; |
} |
- // Now construction is done and we are ready to send the shared memory and the |
- // sync socket to the renderer. |
- base::SharedMemory* shared_memory = entry->reader()->shared_memory(); |
- base::CancelableSyncSocket* foreign_socket = |
- entry->reader()->foreign_socket(); |
- |
base::SharedMemoryHandle foreign_memory_handle; |
base::SyncSocket::TransitDescriptor socket_descriptor; |
size_t shared_memory_size = shared_memory->requested_size(); |
@@ -294,7 +162,7 @@ void AudioRendererHost::DoCompleteCreation(int stream_id) { |
foreign_socket->PrepareTransitDescriptor(PeerHandle(), |
&socket_descriptor))) { |
// Something went wrong in preparing the IPC handles. |
- ReportErrorAndClose(entry->stream_id()); |
+ OnStreamError(stream_id); |
return; |
} |
@@ -303,35 +171,22 @@ void AudioRendererHost::DoCompleteCreation(int stream_id) { |
base::checked_cast<uint32_t>(shared_memory_size))); |
} |
-void AudioRendererHost::DidValidateRenderFrame(int stream_id, bool is_valid) { |
+void AudioRendererHost::OnStreamError(int stream_id) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- if (!is_valid) { |
- DLOG(WARNING) << "Render frame for stream (id=" << stream_id |
- << ") no longer exists."; |
- ReportErrorAndClose(stream_id); |
- } |
+ SendErrorMessage(stream_id); |
+ OnCloseStream(stream_id); |
} |
-void AudioRendererHost::StreamStateChanged(int stream_id, bool is_playing) { |
+void AudioRendererHost::DidValidateRenderFrame(int stream_id, bool is_valid) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- AudioEntry* const entry = LookupById(stream_id); |
- if (!entry) |
+ if (is_valid) |
return; |
- if (is_playing) { |
- AudioStreamMonitor::StartMonitoringStream( |
- render_process_id_, |
- entry->render_frame_id(), |
- entry->stream_id(), |
- base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip, |
- entry->controller())); |
- } else { |
- AudioStreamMonitor::StopMonitoringStream( |
- render_process_id_, entry->render_frame_id(), entry->stream_id()); |
- } |
- UpdateNumPlayingStreams(entry, is_playing); |
+ DLOG(WARNING) << "Render frame for stream (id=" << stream_id |
+ << ") no longer exists."; |
+ OnStreamError(stream_id); |
} |
RenderProcessHost::AudioOutputControllerList |
@@ -339,11 +194,8 @@ AudioRendererHost::DoGetOutputControllers() const { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
RenderProcessHost::AudioOutputControllerList controllers; |
- for (AudioEntryMap::const_iterator it = audio_entries_.begin(); |
- it != audio_entries_.end(); |
- ++it) { |
- controllers.push_back(it->second->controller()); |
- } |
+ for (const auto& delegate : delegates_) |
+ controllers.push_back(delegate->controller()); |
return controllers; |
} |
@@ -379,6 +231,7 @@ void AudioRendererHost::OnRequestDeviceAuthorization( |
<< ", render_frame_id=" << render_frame_id |
<< ", session_id=" << session_id << ", device_id=" << device_id |
<< ", security_origin=" << security_origin << ")"; |
+ |
if (LookupById(stream_id) || IsAuthorizationStarted(stream_id)) |
return; |
@@ -453,8 +306,9 @@ void AudioRendererHost::OnCreateStream(int stream_id, |
} |
// Fail early if either of two sanity-checks fail: |
- // 1. There should not yet exist an AudioEntry for the given |stream_id| |
- // since the renderer may not create two streams with the same ID. |
+ // 1. There should not yet exist an AudioOutputDelegate for the given |
+ // |stream_id| since the renderer may not create two streams with the |
+ // same ID. |
// 2. An out-of-range render frame ID was provided. Renderers must *always* |
// specify a valid render frame ID for each audio output they create, as |
// several browser-level features depend on this (e.g., OOM manager, UI |
@@ -481,64 +335,54 @@ void AudioRendererHost::OnCreateStream(int stream_id, |
base::Bind(&AudioRendererHost::DidValidateRenderFrame, this, |
stream_id))); |
- std::unique_ptr<AudioEntry> entry = AudioEntry::Create( |
- this, stream_id, render_frame_id, params, device_unique_id); |
- if (!entry) { |
- SendErrorMessage(stream_id); |
- return; |
- } |
- |
MediaObserver* const media_observer = |
GetContentClient()->browser()->GetMediaObserver(); |
- if (media_observer) |
- media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id); |
- if (mirroring_manager_) { |
- mirroring_manager_->AddDiverter( |
- render_process_id_, entry->render_frame_id(), entry->controller()); |
- } |
- audio_entries_.insert(std::make_pair(stream_id, entry.release())); |
- g_audio_streams_tracker.Get().IncreaseStreamCount(); |
+ MediaInternals* const media_internals = MediaInternals::GetInstance(); |
+ std::unique_ptr<media::AudioLog> audio_log = media_internals->CreateAudioLog( |
+ media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER); |
+ media_internals->SetWebContentsTitleForAudioLogEntry( |
+ stream_id, render_process_id_, render_frame_id, audio_log.get()); |
+ delegates_.push_back(AudioOutputDelegate::Create( |
+ this, audio_manager_, std::move(audio_log), mirroring_manager_, |
+ media_observer, stream_id, render_frame_id, render_process_id_, params, |
+ device_unique_id)); |
- audio_log_->OnCreated(stream_id, params, device_unique_id); |
- MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry( |
- stream_id, render_process_id_, render_frame_id, audio_log_.get()); |
+ g_audio_streams_tracker.Get().IncreaseStreamCount(); |
- if (audio_entries_.size() > max_simultaneous_streams_) |
- max_simultaneous_streams_ = audio_entries_.size(); |
+ if (delegates_.size() > max_simultaneous_streams_) |
+ max_simultaneous_streams_ = delegates_.size(); |
} |
void AudioRendererHost::OnPlayStream(int stream_id) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- AudioEntry* entry = LookupById(stream_id); |
- if (!entry) { |
+ AudioOutputDelegate* delegate = LookupById(stream_id); |
+ if (!delegate) { |
SendErrorMessage(stream_id); |
return; |
} |
- entry->controller()->Play(); |
- audio_log_->OnStarted(stream_id); |
+ delegate->OnPlayStream(); |
} |
void AudioRendererHost::OnPauseStream(int stream_id) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- AudioEntry* entry = LookupById(stream_id); |
- if (!entry) { |
+ AudioOutputDelegate* delegate = LookupById(stream_id); |
+ if (!delegate) { |
SendErrorMessage(stream_id); |
return; |
} |
- entry->controller()->Pause(); |
- audio_log_->OnStopped(stream_id); |
+ delegate->OnPauseStream(); |
} |
void AudioRendererHost::OnSetVolume(int stream_id, double volume) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- AudioEntry* entry = LookupById(stream_id); |
- if (!entry) { |
+ AudioOutputDelegate* delegate = LookupById(stream_id); |
+ if (!delegate) { |
SendErrorMessage(stream_id); |
return; |
} |
@@ -546,8 +390,7 @@ void AudioRendererHost::OnSetVolume(int stream_id, double volume) { |
// Make sure the volume is valid. |
if (volume < 0 || volume > 1.0) |
return; |
- entry->controller()->SetVolume(volume); |
- audio_log_->OnSetVolume(stream_id, volume); |
+ delegate->OnSetVolume(volume); |
} |
void AudioRendererHost::SendErrorMessage(int stream_id) { |
@@ -558,71 +401,44 @@ void AudioRendererHost::OnCloseStream(int stream_id) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
authorizations_.erase(stream_id); |
+ auto i = LookupIteratorById(stream_id); |
+ |
// Prevent oustanding callbacks from attempting to close/delete the same |
- // AudioEntry twice. |
- AudioEntryMap::iterator i = audio_entries_.find(stream_id); |
- if (i == audio_entries_.end()) |
+ // AudioOutputDelegate twice. |
+ if (i == delegates_.end()) |
return; |
- std::unique_ptr<AudioEntry> entry(i->second); |
- audio_entries_.erase(i); |
- g_audio_streams_tracker.Get().DecreaseStreamCount(); |
- |
- media::AudioOutputController* const controller = entry->controller(); |
- controller->Close( |
- base::Bind(&AudioRendererHost::DeleteEntry, this, base::Passed(&entry))); |
- audio_log_->OnClosed(stream_id); |
-} |
-void AudioRendererHost::DeleteEntry(std::unique_ptr<AudioEntry> entry) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ std::swap(*i, delegates_.back()); |
+ delegates_.pop_back(); |
- // De-register the controller from the AudioMirroringManager now that the |
- // controller has closed the AudioOutputStream and shut itself down. This |
- // ensures that calling RemoveDiverter() here won't trigger the controller to |
- // re-start the default AudioOutputStream and cause a brief audio blip to come |
- // out the user's speakers. http://crbug.com/474432 |
- if (mirroring_manager_) |
- mirroring_manager_->RemoveDiverter(entry->controller()); |
- |
- AudioStreamMonitor::StopMonitoringStream( |
- render_process_id_, entry->render_frame_id(), entry->stream_id()); |
- UpdateNumPlayingStreams(entry.get(), false); |
+ g_audio_streams_tracker.Get().DecreaseStreamCount(); |
} |
-void AudioRendererHost::ReportErrorAndClose(int stream_id) { |
+AudioRendererHost::AudioOutputDelegateList::iterator |
+AudioRendererHost::LookupIteratorById(int stream_id) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- // Make sure this isn't a stray callback executing after the stream has been |
- // closed, so error notifications aren't sent after clients believe the stream |
- // is closed. |
- if (!LookupById(stream_id)) |
- return; |
- |
- SendErrorMessage(stream_id); |
- |
- audio_log_->OnError(stream_id); |
- OnCloseStream(stream_id); |
+ return std::find_if(delegates_.begin(), delegates_.end(), |
+ [stream_id](const AudioOutputDelegate::UniquePtr& d) { |
+ return d->stream_id() == stream_id; |
+ }); |
} |
-AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) { |
+AudioOutputDelegate* AudioRendererHost::LookupById(int stream_id) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- AudioEntryMap::const_iterator i = audio_entries_.find(stream_id); |
- return i != audio_entries_.end() ? i->second : NULL; |
+ auto i = LookupIteratorById(stream_id); |
+ return i != delegates_.end() ? i->get() : nullptr; |
} |
-void AudioRendererHost::UpdateNumPlayingStreams(AudioEntry* entry, |
- bool is_playing) { |
+void AudioRendererHost::OnStreamStateChanged(bool is_playing) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- if (entry->playing() == is_playing) |
- return; |
- |
if (is_playing) { |
- entry->set_playing(true); |
base::AtomicRefCountInc(&num_playing_streams_); |
// Inform the RenderProcessHost when audio starts playing for the first |
- // time. |
+ // time. The nonatomic increment-and-read is ok since this is the only |
+ // thread that |num_plaing_streams_| may be updated on. |
if (base::AtomicRefCountIsOne(&num_playing_streams_)) { |
BrowserThread::PostTask( |
BrowserThread::UI, FROM_HERE, |
@@ -630,7 +446,6 @@ void AudioRendererHost::UpdateNumPlayingStreams(AudioEntry* entry, |
render_process_id_)); |
} |
} else { |
- entry->set_playing(false); |
// Inform the RenderProcessHost when there is no more audio playing. |
if (!base::AtomicRefCountDec(&num_playing_streams_)) { |
BrowserThread::PostTask( |