diff options
Diffstat (limited to 'chromium/content/browser/media/capture/audio_mirroring_manager.cc')
-rw-r--r-- | chromium/content/browser/media/capture/audio_mirroring_manager.cc | 164 |
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 |