Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / media / capture / audio_mirroring_manager.cc
bloba75eb3c6476f8c0d80c64fbea0085362b05d866d
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"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/lazy_instance.h"
13 namespace content {
15 namespace {
17 base::LazyInstance<AudioMirroringManager>::Leaky g_audio_mirroring_manager =
18 LAZY_INSTANCE_INITIALIZER;
20 } // namespace
22 // static
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());
38 DCHECK(diverter);
40 // DCHECK(diverter not already in routes_)
41 #ifndef NDEBUG
42 for (StreamRoutes::const_iterator it = routes_.begin();
43 it != routes_.end(); ++it) {
44 DCHECK_NE(diverter, it->diverter);
46 #endif
47 routes_.push_back(StreamRoutingState(
48 SourceFrameRef(render_process_id, render_frame_id),
49 diverter));
51 // Query existing destinations to see whether to immediately start diverting
52 // the stream.
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);
66 routes_.erase(it);
67 return;
70 NOTREACHED();
73 void AudioMirroringManager::StartMirroring(MirroringDestination* destination) {
74 DCHECK(thread_checker_.CalledOnValidThread());
75 DCHECK(destination);
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) ==
80 sessions_.end()) {
81 sessions_.push_back(destination);
84 // Query the MirroringDestination to see which of the audio streams should be
85 // diverted.
86 std::set<SourceFrameRef> candidates;
87 for (StreamRoutes::const_iterator it = routes_.begin(); it != routes_.end();
88 ++it) {
89 if (!it->destination || it->destination == destination)
90 candidates.insert(it->source_render_frame);
92 if (!candidates.empty()) {
93 destination->QueryForMatches(
94 candidates,
95 base::Bind(&AudioMirroringManager::UpdateRoutesToDestination,
96 base::Unretained(this),
97 destination,
98 false));
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
107 // destination.
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()) {
122 NOTREACHED();
123 return;
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(
137 candidates,
138 base::Bind(&AudioMirroringManager::UpdateRoutesToDestination,
139 base::Unretained(this),
140 *it,
141 true));
146 void AudioMirroringManager::UpdateRoutesToDestination(
147 MirroringDestination* destination,
148 bool add_only,
149 const std::set<SourceFrameRef>& matches) {
150 DCHECK(thread_checker_.CalledOnValidThread());
152 if (std::find(sessions_.begin(), sessions_.end(), destination) ==
153 sessions_.end()) {
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);
180 // static
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),
210 destination(NULL) {}
212 AudioMirroringManager::StreamRoutingState::~StreamRoutingState() {}
214 } // namespace content