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/media/capture/audio_mirroring_manager.h"
10 #include "base/bind_helpers.h"
11 #include "base/lazy_instance.h"
17 base::LazyInstance
<AudioMirroringManager
>::Leaky g_audio_mirroring_manager
=
18 LAZY_INSTANCE_INITIALIZER
;
23 AudioMirroringManager
* AudioMirroringManager::GetInstance() {
24 return g_audio_mirroring_manager
.Pointer();
27 AudioMirroringManager::AudioMirroringManager() {
28 // Only *after* construction, check that AudioMirroringManager is being
29 // invoked on the same single thread.
30 thread_checker_
.DetachFromThread();
33 AudioMirroringManager::~AudioMirroringManager() {}
35 void AudioMirroringManager::AddDiverter(
36 int render_process_id
, int render_frame_id
, Diverter
* diverter
) {
37 DCHECK(thread_checker_
.CalledOnValidThread());
40 // DCHECK(diverter not already in routes_)
42 for (StreamRoutes::const_iterator it
= routes_
.begin();
43 it
!= routes_
.end(); ++it
) {
44 DCHECK_NE(diverter
, it
->diverter
);
47 routes_
.push_back(StreamRoutingState(
48 SourceFrameRef(render_process_id
, render_frame_id
),
51 // Query existing destinations to see whether to immediately start diverting
53 std::set
<SourceFrameRef
> candidates
;
54 candidates
.insert(routes_
.back().source_render_frame
);
55 InitiateQueriesToFindNewDestination(NULL
, candidates
);
58 void AudioMirroringManager::RemoveDiverter(Diverter
* diverter
) {
59 DCHECK(thread_checker_
.CalledOnValidThread());
61 // Find and remove the entry from the routing table. If the stream is being
62 // diverted, it is stopped.
63 for (StreamRoutes::iterator it
= routes_
.begin(); it
!= routes_
.end(); ++it
) {
64 if (it
->diverter
== diverter
) {
65 ChangeRoute(&(*it
), NULL
);
73 void AudioMirroringManager::StartMirroring(MirroringDestination
* destination
) {
74 DCHECK(thread_checker_
.CalledOnValidThread());
77 // Insert an entry into the set of active mirroring sessions, if this is a
78 // previously-unknown destination.
79 if (std::find(sessions_
.begin(), sessions_
.end(), destination
) ==
81 sessions_
.push_back(destination
);
84 // Query the MirroringDestination to see which of the audio streams should be
86 std::set
<SourceFrameRef
> candidates
;
87 for (StreamRoutes::const_iterator it
= routes_
.begin(); it
!= routes_
.end();
89 if (!it
->destination
|| it
->destination
== destination
)
90 candidates
.insert(it
->source_render_frame
);
92 if (!candidates
.empty()) {
93 destination
->QueryForMatches(
95 base::Bind(&AudioMirroringManager::UpdateRoutesToDestination
,
96 base::Unretained(this),
102 void AudioMirroringManager::StopMirroring(MirroringDestination
* destination
) {
103 DCHECK(thread_checker_
.CalledOnValidThread());
105 // Stop diverting each audio stream in the mirroring session being stopped.
106 // Each stopped stream becomes a candidate to be diverted to another
108 std::set
<SourceFrameRef
> redivert_candidates
;
109 for (StreamRoutes::iterator it
= routes_
.begin(); it
!= routes_
.end(); ++it
) {
110 if (it
->destination
== destination
) {
111 ChangeRoute(&(*it
), NULL
);
112 redivert_candidates
.insert(it
->source_render_frame
);
115 if (!redivert_candidates
.empty())
116 InitiateQueriesToFindNewDestination(destination
, redivert_candidates
);
118 // Remove the entry from the set of active mirroring sessions.
119 const Destinations::iterator dest_it
=
120 std::find(sessions_
.begin(), sessions_
.end(), destination
);
121 if (dest_it
== sessions_
.end()) {
125 sessions_
.erase(dest_it
);
128 void AudioMirroringManager::InitiateQueriesToFindNewDestination(
129 MirroringDestination
* old_destination
,
130 const std::set
<SourceFrameRef
>& candidates
) {
131 DCHECK(thread_checker_
.CalledOnValidThread());
133 for (Destinations::const_iterator it
= sessions_
.begin();
134 it
!= sessions_
.end(); ++it
) {
135 if (*it
!= old_destination
) {
136 (*it
)->QueryForMatches(
138 base::Bind(&AudioMirroringManager::UpdateRoutesToDestination
,
139 base::Unretained(this),
146 void AudioMirroringManager::UpdateRoutesToDestination(
147 MirroringDestination
* destination
,
149 const std::set
<SourceFrameRef
>& matches
) {
150 DCHECK(thread_checker_
.CalledOnValidThread());
152 if (std::find(sessions_
.begin(), sessions_
.end(), destination
) ==
154 return; // Query result callback invoked after StopMirroring().
157 DVLOG(1) << (add_only
? "Add " : "Replace with ") << matches
.size()
158 << " routes to MirroringDestination@" << destination
;
160 // Start/stop diverting based on |matches|. Any stopped stream becomes a
161 // candidate to be diverted to another destination.
162 std::set
<SourceFrameRef
> redivert_candidates
;
163 for (StreamRoutes::iterator it
= routes_
.begin(); it
!= routes_
.end(); ++it
) {
164 if (matches
.find(it
->source_render_frame
) != matches
.end()) {
165 // Only change the route if the stream is not already being diverted.
166 if (!it
->destination
)
167 ChangeRoute(&(*it
), destination
);
168 } else if (!add_only
) {
169 // Only stop diverting if the stream is currently routed to |destination|.
170 if (it
->destination
== destination
) {
171 ChangeRoute(&(*it
), NULL
);
172 redivert_candidates
.insert(it
->source_render_frame
);
176 if (!redivert_candidates
.empty())
177 InitiateQueriesToFindNewDestination(destination
, redivert_candidates
);
181 void AudioMirroringManager::ChangeRoute(
182 StreamRoutingState
* route
, MirroringDestination
* new_destination
) {
183 if (route
->destination
== new_destination
)
184 return; // No change.
186 if (route
->destination
) {
187 DVLOG(1) << "Stop diverting render_process_id:render_frame_id="
188 << route
->source_render_frame
.first
<< ':'
189 << route
->source_render_frame
.second
190 << " --> MirroringDestination@" << route
->destination
;
191 route
->diverter
->StopDiverting();
192 route
->destination
= NULL
;
195 if (new_destination
) {
196 DVLOG(1) << "Start diverting of render_process_id:render_frame_id="
197 << route
->source_render_frame
.first
<< ':'
198 << route
->source_render_frame
.second
199 << " --> MirroringDestination@" << new_destination
;
200 route
->diverter
->StartDiverting(
201 new_destination
->AddInput(route
->diverter
->GetAudioParameters()));
202 route
->destination
= new_destination
;
206 AudioMirroringManager::StreamRoutingState::StreamRoutingState(
207 const SourceFrameRef
& source_frame
, Diverter
* stream_diverter
)
208 : source_render_frame(source_frame
),
209 diverter(stream_diverter
),
212 AudioMirroringManager::StreamRoutingState::~StreamRoutingState() {}
214 } // namespace content