summaryrefslogtreecommitdiffstats
path: root/chromium/content/browser/media/capture/audio_mirroring_manager.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/browser/media/capture/audio_mirroring_manager.cc')
-rw-r--r--chromium/content/browser/media/capture/audio_mirroring_manager.cc164
1 files changed, 164 insertions, 0 deletions
diff --git a/chromium/content/browser/media/capture/audio_mirroring_manager.cc b/chromium/content/browser/media/capture/audio_mirroring_manager.cc
new file mode 100644
index 00000000000..b8051fa73d0
--- /dev/null
+++ b/chromium/content/browser/media/capture/audio_mirroring_manager.cc
@@ -0,0 +1,164 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/capture/audio_mirroring_manager.h"
+
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+
+namespace {
+
+// Debug utility to make sure methods of AudioMirroringManager are not invoked
+// more than once in a single call stack. In release builds, this compiles to
+// nothing and gets completely optimized out.
+class ReentrancyGuard {
+ public:
+#ifdef NDEBUG
+ ReentrancyGuard() {}
+ ~ReentrancyGuard() {}
+#else
+ ReentrancyGuard() {
+ DCHECK(!inside_a_method_);
+ inside_a_method_ = true;
+ }
+ ~ReentrancyGuard() {
+ inside_a_method_ = false;
+ }
+
+ static bool inside_a_method_; // Safe to be static, since AMM is a singleton.
+#endif
+};
+
+#ifndef NDEBUG
+bool ReentrancyGuard::inside_a_method_ = false;
+#endif
+
+} // namespace
+
+AudioMirroringManager::AudioMirroringManager() {}
+
+AudioMirroringManager::~AudioMirroringManager() {
+ DCHECK(diverters_.empty());
+ DCHECK(sessions_.empty());
+}
+
+void AudioMirroringManager::AddDiverter(
+ int render_process_id, int render_view_id, Diverter* diverter) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ ReentrancyGuard guard;
+ DCHECK(diverter);
+
+ // DCHECK(diverter not already in diverters_ under any key)
+#ifndef NDEBUG
+ for (DiverterMap::const_iterator it = diverters_.begin();
+ it != diverters_.end(); ++it) {
+ DCHECK_NE(diverter, it->second);
+ }
+#endif
+
+ // Add the diverter to the set of active diverters.
+ const Target target(render_process_id, render_view_id);
+ diverters_.insert(std::make_pair(target, diverter));
+
+ // If a mirroring session is active, start diverting the audio stream
+ // immediately.
+ SessionMap::iterator session_it = sessions_.find(target);
+ if (session_it != sessions_.end()) {
+ diverter->StartDiverting(
+ session_it->second->AddInput(diverter->GetAudioParameters()));
+ }
+}
+
+void AudioMirroringManager::RemoveDiverter(
+ int render_process_id, int render_view_id, Diverter* diverter) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ ReentrancyGuard guard;
+
+ // Stop diverting the audio stream if a mirroring session is active.
+ const Target target(render_process_id, render_view_id);
+ SessionMap::iterator session_it = sessions_.find(target);
+ if (session_it != sessions_.end())
+ diverter->StopDiverting();
+
+ // Remove the diverter from the set of active diverters.
+ for (DiverterMap::iterator it = diverters_.lower_bound(target);
+ it != diverters_.end() && it->first == target; ++it) {
+ if (it->second == diverter) {
+ diverters_.erase(it);
+ break;
+ }
+ }
+}
+
+void AudioMirroringManager::StartMirroring(
+ int render_process_id, int render_view_id,
+ MirroringDestination* destination) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ ReentrancyGuard guard;
+ DCHECK(destination);
+
+ // Insert an entry into the set of active mirroring sessions. If a mirroring
+ // session is already active for |render_process_id| + |render_view_id|,
+ // replace the entry.
+ const Target target(render_process_id, render_view_id);
+ SessionMap::iterator session_it = sessions_.find(target);
+ MirroringDestination* old_destination;
+ if (session_it == sessions_.end()) {
+ old_destination = NULL;
+ sessions_.insert(std::make_pair(target, destination));
+
+ DVLOG(1) << "Start mirroring render_process_id:render_view_id="
+ << render_process_id << ':' << render_view_id
+ << " --> MirroringDestination@" << destination;
+ } else {
+ old_destination = session_it->second;
+ session_it->second = destination;
+
+ DVLOG(1) << "Switch mirroring of render_process_id:render_view_id="
+ << render_process_id << ':' << render_view_id
+ << " MirroringDestination@" << old_destination
+ << " --> MirroringDestination@" << destination;
+ }
+
+ // Divert audio streams coming from |target| to |destination|. If streams
+ // were already diverted to the |old_destination|, remove them.
+ for (DiverterMap::iterator it = diverters_.lower_bound(target);
+ it != diverters_.end() && it->first == target; ++it) {
+ Diverter* const diverter = it->second;
+ if (old_destination)
+ diverter->StopDiverting();
+ diverter->StartDiverting(
+ destination->AddInput(diverter->GetAudioParameters()));
+ }
+}
+
+void AudioMirroringManager::StopMirroring(
+ int render_process_id, int render_view_id,
+ MirroringDestination* destination) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ ReentrancyGuard guard;
+
+ // Stop mirroring if there is an active session *and* the destination
+ // matches.
+ const Target target(render_process_id, render_view_id);
+ SessionMap::iterator session_it = sessions_.find(target);
+ if (session_it == sessions_.end() || destination != session_it->second)
+ return;
+
+ DVLOG(1) << "Stop mirroring render_process_id:render_view_id="
+ << render_process_id << ':' << render_view_id
+ << " --> MirroringDestination@" << destination;
+
+ // Stop diverting each audio stream in the mirroring session being stopped.
+ for (DiverterMap::iterator it = diverters_.lower_bound(target);
+ it != diverters_.end() && it->first == target; ++it) {
+ it->second->StopDiverting();
+ }
+
+ // Remove the entry from the set of active mirroring sessions.
+ sessions_.erase(session_it);
+}
+
+} // namespace content