Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / media / capture / audio_mirroring_manager.cc
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.
4
5 #include "content/browser/media/capture/audio_mirroring_manager.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/lazy_instance.h"
12
13 namespace content {
14
15 namespace {
16
17 base::LazyInstance<AudioMirroringManager>::Leaky g_audio_mirroring_manager =
18     LAZY_INSTANCE_INITIALIZER;
19
20 }  // namespace
21
22 // static
23 AudioMirroringManager* AudioMirroringManager::GetInstance() {
24   return g_audio_mirroring_manager.Pointer();
25 }
26
27 AudioMirroringManager::AudioMirroringManager() {
28   // Only *after* construction, check that AudioMirroringManager is being
29   // invoked on the same single thread.
30   thread_checker_.DetachFromThread();
31 }
32
33 AudioMirroringManager::~AudioMirroringManager() {}
34
35 void AudioMirroringManager::AddDiverter(
36     int render_process_id, int render_frame_id, Diverter* diverter) {
37   DCHECK(thread_checker_.CalledOnValidThread());
38   DCHECK(diverter);
39
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);
45   }
46 #endif
47   routes_.push_back(StreamRoutingState(
48       SourceFrameRef(render_process_id, render_frame_id),
49       diverter));
50
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);
56 }
57
58 void AudioMirroringManager::RemoveDiverter(Diverter* diverter) {
59   DCHECK(thread_checker_.CalledOnValidThread());
60
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;
68     }
69   }
70   NOTREACHED();
71 }
72
73 void AudioMirroringManager::StartMirroring(MirroringDestination* destination) {
74   DCHECK(thread_checker_.CalledOnValidThread());
75   DCHECK(destination);
76
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);
82   }
83
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);
91   }
92   if (!candidates.empty()) {
93     destination->QueryForMatches(
94         candidates,
95         base::Bind(&AudioMirroringManager::UpdateRoutesToDestination,
96                    base::Unretained(this),
97                    destination,
98                    false));
99   }
100 }
101
102 void AudioMirroringManager::StopMirroring(MirroringDestination* destination) {
103   DCHECK(thread_checker_.CalledOnValidThread());
104
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);
113     }
114   }
115   if (!redivert_candidates.empty())
116     InitiateQueriesToFindNewDestination(destination, redivert_candidates);
117
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;
124   }
125   sessions_.erase(dest_it);
126 }
127
128 void AudioMirroringManager::InitiateQueriesToFindNewDestination(
129     MirroringDestination* old_destination,
130     const std::set<SourceFrameRef>& candidates) {
131   DCHECK(thread_checker_.CalledOnValidThread());
132
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));
142     }
143   }
144 }
145
146 void AudioMirroringManager::UpdateRoutesToDestination(
147     MirroringDestination* destination,
148     bool add_only,
149     const std::set<SourceFrameRef>& matches) {
150   DCHECK(thread_checker_.CalledOnValidThread());
151
152   if (std::find(sessions_.begin(), sessions_.end(), destination) ==
153           sessions_.end()) {
154     return;  // Query result callback invoked after StopMirroring().
155   }
156
157   DVLOG(1) << (add_only ? "Add " : "Replace with ") << matches.size()
158            << " routes to MirroringDestination@" << destination;
159
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);
173       }
174     }
175   }
176   if (!redivert_candidates.empty())
177     InitiateQueriesToFindNewDestination(destination, redivert_candidates);
178 }
179
180 // static
181 void AudioMirroringManager::ChangeRoute(
182     StreamRoutingState* route, MirroringDestination* new_destination) {
183   if (route->destination == new_destination)
184     return;  // No change.
185
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;
193   }
194
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;
203   }
204 }
205
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) {}
211
212 AudioMirroringManager::StreamRoutingState::~StreamRoutingState() {}
213
214 }  // namespace content