1 // Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include "libcef/browser/media_router/media_sink_impl.h"
6
7 #include "libcef/browser/thread_util.h"
8
9 #include "base/strings/string_number_conversions.h"
10 #include "chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h"
11 #include "chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h"
12 #include "chrome/browser/media/router/providers/cast/dual_media_sink_service.h"
13 #include "components/media_router/common/discovery/media_sink_internal.h"
14 #include "components/media_router/common/discovery/media_sink_service_base.h"
15
16 namespace {
17
18 using SinkServiceVector = std::vector<media_router::MediaSinkServiceBase*>;
19
GetSinkServices()20 SinkServiceVector GetSinkServices() {
21 CEF_REQUIRE_UIT();
22 auto sink_service = media_router::DualMediaSinkService::GetInstance();
23 return {sink_service->GetCastMediaSinkServiceImpl(),
24 sink_service->GetDialMediaSinkServiceImpl()};
25 }
26
GetSinkInternalAndContinue(SinkServiceVector services,const media_router::MediaSink::Id & sink_id,CefRefPtr<CefMediaSinkDeviceInfoCallback> callback)27 void GetSinkInternalAndContinue(
28 SinkServiceVector services,
29 const media_router::MediaSink::Id& sink_id,
30 CefRefPtr<CefMediaSinkDeviceInfoCallback> callback) {
31 CEF_REQUIRE_IOT();
32
33 CefMediaSinkDeviceInfo device_info;
34 const media_router::MediaSinkInternal* sink_internal = nullptr;
35
36 for (auto service : services) {
37 sink_internal = service->GetSinkById(sink_id);
38 if (sink_internal)
39 break;
40 }
41
42 if (sink_internal) {
43 if (sink_internal->is_cast_sink()) {
44 const auto& cast_data = sink_internal->cast_data();
45 CefString(&device_info.ip_address) =
46 cast_data.ip_endpoint.ToStringWithoutPort();
47 device_info.port = cast_data.ip_endpoint.port();
48 CefString(&device_info.model_name) = cast_data.model_name;
49 } else if (sink_internal->is_dial_sink()) {
50 const auto& dial_data = sink_internal->dial_data();
51 CefString(&device_info.ip_address) = dial_data.ip_address.ToString();
52 if (dial_data.app_url.is_valid() && dial_data.app_url.has_port()) {
53 base::StringToInt(dial_data.app_url.port_piece(), &device_info.port);
54 }
55 CefString(&device_info.model_name) = dial_data.model_name;
56 }
57 }
58
59 // Execute the callback on the UI thread.
60 CEF_POST_TASK(
61 CEF_UIT,
62 base::BindOnce(&CefMediaSinkDeviceInfoCallback::OnMediaSinkDeviceInfo,
63 callback, device_info));
64 }
65
GetDeviceInfo(const media_router::MediaSink::Id & sink_id,CefRefPtr<CefMediaSinkDeviceInfoCallback> callback)66 void GetDeviceInfo(const media_router::MediaSink::Id& sink_id,
67 CefRefPtr<CefMediaSinkDeviceInfoCallback> callback) {
68 auto next_step = base::BindOnce(
69 [](const media_router::MediaSink::Id& sink_id,
70 CefRefPtr<CefMediaSinkDeviceInfoCallback> callback) {
71 CEF_POST_TASK(CEF_IOT,
72 base::BindOnce(GetSinkInternalAndContinue,
73 GetSinkServices(), sink_id, callback));
74 },
75 sink_id, callback);
76
77 if (CEF_CURRENTLY_ON(CEF_UIT)) {
78 std::move(next_step).Run();
79 } else {
80 CEF_POST_TASK(CEF_UIT, std::move(next_step));
81 }
82 }
83
84 } // namespace
85
CefMediaSinkImpl(const media_router::MediaSink & sink)86 CefMediaSinkImpl::CefMediaSinkImpl(const media_router::MediaSink& sink)
87 : sink_(sink) {}
88
CefMediaSinkImpl(const media_router::MediaSink::Id & sink_id,const std::string & sink_name,media_router::mojom::MediaRouteProviderId provider_id)89 CefMediaSinkImpl::CefMediaSinkImpl(
90 const media_router::MediaSink::Id& sink_id,
91 const std::string& sink_name,
92 media_router::mojom::MediaRouteProviderId provider_id)
93 : sink_(sink_id,
94 sink_name,
95 media_router::SinkIconType::GENERIC,
96 provider_id) {}
97
GetId()98 CefString CefMediaSinkImpl::GetId() {
99 return sink_.id();
100 }
101
GetName()102 CefString CefMediaSinkImpl::GetName() {
103 return sink_.name();
104 }
105
GetDescription()106 CefString CefMediaSinkImpl::GetDescription() {
107 return sink_.description().value_or("");
108 }
109
GetIconType()110 CefMediaSink::IconType CefMediaSinkImpl::GetIconType() {
111 // Verify that our enum matches Chromium's values.
112 static_assert(static_cast<int>(CEF_MSIT_TOTAL_COUNT) ==
113 static_cast<int>(media_router::SinkIconType::TOTAL_COUNT),
114 "enum mismatch");
115
116 return static_cast<CefMediaSink::IconType>(sink_.icon_type());
117 }
118
GetDeviceInfo(CefRefPtr<CefMediaSinkDeviceInfoCallback> callback)119 void CefMediaSinkImpl::GetDeviceInfo(
120 CefRefPtr<CefMediaSinkDeviceInfoCallback> callback) {
121 ::GetDeviceInfo(sink_.id(), callback);
122 }
123
IsCastSink()124 bool CefMediaSinkImpl::IsCastSink() {
125 return sink_.provider_id() == media_router::mojom::MediaRouteProviderId::CAST;
126 }
127
IsDialSink()128 bool CefMediaSinkImpl::IsDialSink() {
129 return sink_.provider_id() == media_router::mojom::MediaRouteProviderId::DIAL;
130 }
131
IsCompatibleWith(CefRefPtr<CefMediaSource> source)132 bool CefMediaSinkImpl::IsCompatibleWith(CefRefPtr<CefMediaSource> source) {
133 if (source) {
134 if (IsCastSink())
135 return source->IsCastSource();
136 if (IsDialSink())
137 return source->IsDialSource();
138 }
139 return false;
140 }
141