1 // Copyright 2015 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 "chrome/browser/ui/webui/media_router/query_result_manager.h"
7 #include "base/containers/hash_tables.h"
8 #include "base/stl_util.h"
9 #include "chrome/browser/media/router/media_router.h"
10 #include "chrome/browser/media/router/media_sinks_observer.h"
12 namespace media_router
{
14 // MediaSinkObserver that propagates results back to |result_manager|.
15 // An instance of this class is associated with each registered MediaCastMode.
16 class QueryResultManager::CastModeMediaSinksObserver
17 : public MediaSinksObserver
{
19 CastModeMediaSinksObserver(MediaCastMode cast_mode
,
20 const MediaSource
& source
,
22 QueryResultManager
* result_manager
)
23 : MediaSinksObserver(router
, source
),
24 cast_mode_(cast_mode
),
25 result_manager_(result_manager
) {
26 DCHECK(result_manager
);
29 ~CastModeMediaSinksObserver() override
{}
32 void OnSinksReceived(const std::vector
<MediaSink
>& result
) override
{
33 latest_sink_ids_
.clear();
34 for (const MediaSink
& sink
: result
) {
35 latest_sink_ids_
.push_back(sink
.id());
37 result_manager_
->UpdateWithSinksQueryResult(cast_mode_
, result
);
38 result_manager_
->NotifyOnResultsUpdated();
41 // Returns the most recent sink IDs that were passed to |OnSinksReceived|.
42 void GetLatestSinkIds(std::vector
<MediaSink::Id
>* sink_ids
) const {
44 *sink_ids
= latest_sink_ids_
;
47 MediaCastMode
cast_mode() const { return cast_mode_
; }
50 MediaCastMode cast_mode_
;
51 std::vector
<MediaSink::Id
> latest_sink_ids_
;
52 QueryResultManager
* result_manager_
;
55 QueryResultManager::QueryResultManager(MediaRouter
* router
) : router_(router
) {
59 QueryResultManager::~QueryResultManager() {
60 DCHECK(thread_checker_
.CalledOnValidThread());
63 void QueryResultManager::AddObserver(Observer
* observer
) {
64 DCHECK(thread_checker_
.CalledOnValidThread());
66 observers_
.AddObserver(observer
);
69 void QueryResultManager::RemoveObserver(Observer
* observer
) {
70 DCHECK(thread_checker_
.CalledOnValidThread());
72 observers_
.RemoveObserver(observer
);
75 void QueryResultManager::StartSinksQuery(MediaCastMode cast_mode
,
76 const MediaSource
& source
) {
77 DCHECK(thread_checker_
.CalledOnValidThread());
79 LOG(WARNING
) << "StartSinksQuery called with empty source for "
84 SetSourceForCastMode(cast_mode
, source
);
85 RemoveObserverForCastMode(cast_mode
);
86 UpdateWithSinksQueryResult(cast_mode
, std::vector
<MediaSink
>());
88 linked_ptr
<CastModeMediaSinksObserver
> observer(
89 new CastModeMediaSinksObserver(cast_mode
, source
, router_
, this));
90 auto result
= sinks_observers_
.insert(std::make_pair(cast_mode
, observer
));
91 DCHECK(result
.second
);
92 NotifyOnResultsUpdated();
95 void QueryResultManager::StopSinksQuery(MediaCastMode cast_mode
) {
96 DCHECK(thread_checker_
.CalledOnValidThread());
97 RemoveObserverForCastMode(cast_mode
);
98 SetSourceForCastMode(cast_mode
, MediaSource());
99 UpdateWithSinksQueryResult(cast_mode
, std::vector
<MediaSink
>());
100 NotifyOnResultsUpdated();
103 void QueryResultManager::SetSourceForCastMode(
104 MediaCastMode cast_mode
, const MediaSource
& source
) {
105 DCHECK(thread_checker_
.CalledOnValidThread());
106 cast_mode_sources_
[cast_mode
] = source
;
109 void QueryResultManager::RemoveObserverForCastMode(MediaCastMode cast_mode
) {
110 auto observers_it
= sinks_observers_
.find(cast_mode
);
111 if (observers_it
!= sinks_observers_
.end())
112 sinks_observers_
.erase(observers_it
);
115 bool QueryResultManager::IsValid(const MediaSinkWithCastModes
& entry
) const {
116 return !entry
.cast_modes
.empty();
119 void QueryResultManager::UpdateWithSinksQueryResult(
120 MediaCastMode cast_mode
,
121 const std::vector
<MediaSink
>& result
) {
122 base::hash_set
<MediaSink::Id
> result_sink_ids
;
123 for (const MediaSink
& sink
: result
)
124 result_sink_ids
.insert(sink
.id());
126 // (1) Iterate through current sink set, remove cast mode from those that
127 // do not appear in latest result.
128 for (auto it
= all_sinks_
.begin(); it
!= all_sinks_
.end(); /*no-op*/) {
129 if (!ContainsKey(result_sink_ids
, it
->first
)) {
130 it
->second
.cast_modes
.erase(cast_mode
);
132 if (!IsValid(it
->second
)) {
133 all_sinks_
.erase(it
++);
139 // (2) Add / update sinks with latest result.
140 for (const MediaSink
& sink
: result
) {
142 all_sinks_
.insert(std::make_pair(sink
.id(),
143 MediaSinkWithCastModes(sink
)));
145 result
.first
->second
.sink
= sink
;
146 result
.first
->second
.cast_modes
.insert(cast_mode
);
150 void QueryResultManager::GetSupportedCastModes(CastModeSet
* cast_modes
) const {
153 for (const auto& observer_pair
: sinks_observers_
) {
154 cast_modes
->insert(observer_pair
.first
);
158 MediaSource
QueryResultManager::GetSourceForCastMode(
159 MediaCastMode cast_mode
) const {
160 DCHECK(thread_checker_
.CalledOnValidThread());
161 auto source_it
= cast_mode_sources_
.find(cast_mode
);
162 return source_it
== cast_mode_sources_
.end() ?
163 MediaSource() : source_it
->second
;
166 void QueryResultManager::NotifyOnResultsUpdated() {
167 std::vector
<MediaSinkWithCastModes
> sinks
;
168 for (const auto& sink_pair
: all_sinks_
) {
169 sinks
.push_back(sink_pair
.second
);
171 FOR_EACH_OBSERVER(QueryResultManager::Observer
, observers_
,
172 OnResultsUpdated(sinks
));
175 } // namespace media_router