1 // Copyright (c) 2013 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.
5 #include "content/browser/renderer_host/media/audio_mirroring_manager.h"
7 #include "content/public/browser/browser_thread.h"
13 // Debug utility to make sure methods of AudioMirroringManager are not invoked
14 // more than once in a single call stack. In release builds, this compiles to
15 // nothing and gets completely optimized out.
16 class ReentrancyGuard
{
23 DCHECK(!inside_a_method_
);
24 inside_a_method_
= true;
27 inside_a_method_
= false;
30 static bool inside_a_method_
; // Safe to be static, since AMM is a singleton.
35 bool ReentrancyGuard::inside_a_method_
= false;
40 AudioMirroringManager::AudioMirroringManager() {}
42 AudioMirroringManager::~AudioMirroringManager() {
43 DCHECK(diverters_
.empty());
44 DCHECK(sessions_
.empty());
47 void AudioMirroringManager::AddDiverter(
48 int render_process_id
, int render_view_id
, Diverter
* diverter
) {
49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
50 ReentrancyGuard guard
;
53 // DCHECK(diverter not already in diverters_ under any key)
55 for (DiverterMap::const_iterator it
= diverters_
.begin();
56 it
!= diverters_
.end(); ++it
) {
57 DCHECK_NE(diverter
, it
->second
);
61 // Add the diverter to the set of active diverters.
62 const Target
target(render_process_id
, render_view_id
);
63 diverters_
.insert(std::make_pair(target
, diverter
));
65 // If a mirroring session is active, start diverting the audio stream
67 SessionMap::iterator session_it
= sessions_
.find(target
);
68 if (session_it
!= sessions_
.end()) {
69 diverter
->StartDiverting(
70 session_it
->second
->AddInput(diverter
->GetAudioParameters()));
74 void AudioMirroringManager::RemoveDiverter(
75 int render_process_id
, int render_view_id
, Diverter
* diverter
) {
76 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
77 ReentrancyGuard guard
;
79 // Stop diverting the audio stream if a mirroring session is active.
80 const Target
target(render_process_id
, render_view_id
);
81 SessionMap::iterator session_it
= sessions_
.find(target
);
82 if (session_it
!= sessions_
.end())
83 diverter
->StopDiverting();
85 // Remove the diverter from the set of active diverters.
86 for (DiverterMap::iterator it
= diverters_
.lower_bound(target
);
87 it
!= diverters_
.end() && it
->first
== target
; ++it
) {
88 if (it
->second
== diverter
) {
95 void AudioMirroringManager::StartMirroring(
96 int render_process_id
, int render_view_id
,
97 MirroringDestination
* destination
) {
98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
99 ReentrancyGuard guard
;
102 // Insert an entry into the set of active mirroring sessions. If a mirroring
103 // session is already active for |render_process_id| + |render_view_id|,
104 // replace the entry.
105 const Target
target(render_process_id
, render_view_id
);
106 SessionMap::iterator session_it
= sessions_
.find(target
);
107 MirroringDestination
* old_destination
;
108 if (session_it
== sessions_
.end()) {
109 old_destination
= NULL
;
110 sessions_
.insert(std::make_pair(target
, destination
));
112 DVLOG(1) << "Start mirroring render_process_id:render_view_id="
113 << render_process_id
<< ':' << render_view_id
114 << " --> MirroringDestination@" << destination
;
116 old_destination
= session_it
->second
;
117 session_it
->second
= destination
;
119 DVLOG(1) << "Switch mirroring of render_process_id:render_view_id="
120 << render_process_id
<< ':' << render_view_id
121 << " MirroringDestination@" << old_destination
122 << " --> MirroringDestination@" << destination
;
125 // Divert audio streams coming from |target| to |destination|. If streams
126 // were already diverted to the |old_destination|, remove them.
127 for (DiverterMap::iterator it
= diverters_
.lower_bound(target
);
128 it
!= diverters_
.end() && it
->first
== target
; ++it
) {
129 Diverter
* const diverter
= it
->second
;
131 diverter
->StopDiverting();
132 diverter
->StartDiverting(
133 destination
->AddInput(diverter
->GetAudioParameters()));
137 void AudioMirroringManager::StopMirroring(
138 int render_process_id
, int render_view_id
,
139 MirroringDestination
* destination
) {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
141 ReentrancyGuard guard
;
143 // Stop mirroring if there is an active session *and* the destination
145 const Target
target(render_process_id
, render_view_id
);
146 SessionMap::iterator session_it
= sessions_
.find(target
);
147 if (session_it
== sessions_
.end() || destination
!= session_it
->second
)
150 DVLOG(1) << "Stop mirroring render_process_id:render_view_id="
151 << render_process_id
<< ':' << render_view_id
152 << " --> MirroringDestination@" << destination
;
154 // Stop diverting each audio stream in the mirroring session being stopped.
155 for (DiverterMap::iterator it
= diverters_
.lower_bound(target
);
156 it
!= diverters_
.end() && it
->first
== target
; ++it
) {
157 it
->second
->StopDiverting();
160 // Remove the entry from the set of active mirroring sessions.
161 sessions_
.erase(session_it
);
164 } // namespace content