From e8573173dd9b13c35630f9c42a2f08cc7ce9c8ee Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Tue, 14 Jul 2020 16:43:57 -0400 Subject: [PATCH] Expose MediaSink device ip/port and model name (see issue #2900) --- cef_paths.gypi | 6 +- include/capi/cef_media_router_capi.h | 29 +++- include/cef_api_hash.h | 8 +- include/cef_media_router.h | 24 +++ include/internal/cef_types.h | 9 ++ include/internal/cef_types_wrappers.h | 26 +++ .../browser/media_router/media_sink_impl.cc | 83 ++++++++++ libcef/browser/media_router/media_sink_impl.h | 2 + libcef_dll/cpptoc/media_sink_cpptoc.cc | 24 ++- .../media_sink_device_info_callback_cpptoc.cc | 78 +++++++++ .../media_sink_device_info_callback_cpptoc.h | 38 +++++ libcef_dll/ctocpp/media_sink_ctocpp.cc | 24 ++- libcef_dll/ctocpp/media_sink_ctocpp.h | 4 +- .../media_sink_device_info_callback_ctocpp.cc | 60 +++++++ .../media_sink_device_info_callback_ctocpp.h | 42 +++++ libcef_dll/wrapper_types.h | 3 +- tests/cefclient/browser/media_router_test.cc | 148 +++++++++++++++--- tests/cefclient/resources/media_router.html | 5 +- 18 files changed, 578 insertions(+), 35 deletions(-) create mode 100644 libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.cc create mode 100644 libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.h create mode 100644 libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.cc create mode 100644 libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.h diff --git a/cef_paths.gypi b/cef_paths.gypi index c15b2bb9e..a972dea7a 100644 --- a/cef_paths.gypi +++ b/cef_paths.gypi @@ -8,7 +8,7 @@ # by hand. See the translator.README.txt file in the tools directory for # more information. # -# $hash=30eed8c81da55c640eb6a491283d1c00fb59d635$ +# $hash=72268a78a76d7d91b8ad47f6b6e9f6d9cb04d9cf$ # { @@ -330,6 +330,8 @@ 'libcef_dll/cpptoc/media_router_cpptoc.h', 'libcef_dll/cpptoc/media_sink_cpptoc.cc', 'libcef_dll/cpptoc/media_sink_cpptoc.h', + 'libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.cc', + 'libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.h', 'libcef_dll/cpptoc/media_source_cpptoc.cc', 'libcef_dll/cpptoc/media_source_cpptoc.h', 'libcef_dll/cpptoc/views/menu_button_cpptoc.cc', @@ -638,6 +640,8 @@ 'libcef_dll/ctocpp/media_router_ctocpp.h', 'libcef_dll/ctocpp/media_sink_ctocpp.cc', 'libcef_dll/ctocpp/media_sink_ctocpp.h', + 'libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.cc', + 'libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.h', 'libcef_dll/ctocpp/media_source_ctocpp.cc', 'libcef_dll/ctocpp/media_source_ctocpp.h', 'libcef_dll/ctocpp/views/menu_button_ctocpp.cc', diff --git a/include/capi/cef_media_router_capi.h b/include/capi/cef_media_router_capi.h index dfb78cd70..3b22668e6 100644 --- a/include/capi/cef_media_router_capi.h +++ b/include/capi/cef_media_router_capi.h @@ -33,7 +33,7 @@ // by hand. See the translator.README.txt file in the tools directory for // more information. // -// $hash=a259fab661bc913498ae4f46f8dee1c1e592823d$ +// $hash=4f4a0d76efaf87055ebf5e784f5d1b69fafdabc2$ // #ifndef CEF_INCLUDE_CAPI_CEF_MEDIA_ROUTER_CAPI_H_ @@ -50,6 +50,7 @@ extern "C" { struct _cef_media_observer_t; struct _cef_media_route_create_callback_t; struct _cef_media_route_t; +struct _cef_media_sink_device_info_callback_t; struct _cef_media_sink_t; struct _cef_media_source_t; @@ -265,6 +266,13 @@ typedef struct _cef_media_sink_t { cef_media_sink_icon_type_t(CEF_CALLBACK* get_icon_type)( struct _cef_media_sink_t* self); + /// + // Asynchronously retrieves device info. + /// + void(CEF_CALLBACK* get_device_info)( + struct _cef_media_sink_t* self, + struct _cef_media_sink_device_info_callback_t* callback); + /// // Returns true (1) if this sink accepts content via Cast. /// @@ -282,6 +290,25 @@ typedef struct _cef_media_sink_t { struct _cef_media_source_t* source); } cef_media_sink_t; +/// +// Callback structure for cef_media_sink_t::GetDeviceInfo. The functions of this +// structure will be called on the browser process UI thread. +/// +typedef struct _cef_media_sink_device_info_callback_t { + /// + // Base structure. + /// + cef_base_ref_counted_t base; + + /// + // Method that will be executed asyncronously once device information has been + // retrieved. + /// + void(CEF_CALLBACK* on_media_sink_device_info)( + struct _cef_media_sink_device_info_callback_t* self, + const struct _cef_media_sink_device_info_t* device_info); +} cef_media_sink_device_info_callback_t; + /// // Represents a source from which media can be routed. Instances of this object // are retrieved via cef_media_router_t::GetSource. The functions of this diff --git a/include/cef_api_hash.h b/include/cef_api_hash.h index fcdbe9d34..5e29e9d2f 100644 --- a/include/cef_api_hash.h +++ b/include/cef_api_hash.h @@ -42,13 +42,13 @@ // way that may cause binary incompatibility with other builds. The universal // hash value will change if any platform is affected whereas the platform hash // values will change only if that particular platform is affected. -#define CEF_API_HASH_UNIVERSAL "fb680f6c23c5fb612f22894422b058c8f8833703" +#define CEF_API_HASH_UNIVERSAL "20d95f0b54da45b2ced365aa92c784e348862bd3" #if defined(OS_WIN) -#define CEF_API_HASH_PLATFORM "b174bf9f140ac8cdfcc8db9185723d8236768496" +#define CEF_API_HASH_PLATFORM "fbe8ca0acbdc4b4050d5e44cbde930177be44edf" #elif defined(OS_MACOSX) -#define CEF_API_HASH_PLATFORM "a93343f0e769bade840574e1547bd16546afcc9d" +#define CEF_API_HASH_PLATFORM "68ba2cd3b110e52ef2d6b07412155b845b105177" #elif defined(OS_LINUX) -#define CEF_API_HASH_PLATFORM "92fb849966e00682c42bcf22fa36a689a16c9d9f" +#define CEF_API_HASH_PLATFORM "40e1cf30d708463e32bf65f9d033f98f22a321e8" #endif #ifdef __cplusplus diff --git a/include/cef_media_router.h b/include/cef_media_router.h index 40ca8fafe..a406884ec 100644 --- a/include/cef_media_router.h +++ b/include/cef_media_router.h @@ -46,6 +46,7 @@ class CefMediaObserver; class CefMediaRoute; class CefMediaRouteCreateCallback; class CefMediaSink; +class CefMediaSinkDeviceInfoCallback; class CefMediaSource; /// @@ -247,6 +248,13 @@ class CefMediaSink : public virtual CefBaseRefCounted { /*--cef(default_retval=CEF_MSIT_GENERIC)--*/ virtual IconType GetIconType() = 0; + /// + // Asynchronously retrieves device info. + /// + /*--cef()--*/ + virtual void GetDeviceInfo( + CefRefPtr callback) = 0; + /// // Returns true if this sink accepts content via Cast. /// @@ -266,6 +274,22 @@ class CefMediaSink : public virtual CefBaseRefCounted { virtual bool IsCompatibleWith(CefRefPtr source) = 0; }; +/// +// Callback interface for CefMediaSink::GetDeviceInfo. The methods of this +// class will be called on the browser process UI thread. +/// +/*--cef(source=client)--*/ +class CefMediaSinkDeviceInfoCallback : public virtual CefBaseRefCounted { + public: + /// + // Method that will be executed asyncronously once device information has been + // retrieved. + /// + /*--cef()--*/ + virtual void OnMediaSinkDeviceInfo( + const CefMediaSinkDeviceInfo& device_info) = 0; +}; + /// // Represents a source from which media can be routed. Instances of this object // are retrieved via CefMediaRouter::GetSource. The methods of this class may be diff --git a/include/internal/cef_types.h b/include/internal/cef_types.h index 5a8348809..622623d9a 100644 --- a/include/internal/cef_types.h +++ b/include/internal/cef_types.h @@ -3187,6 +3187,15 @@ typedef enum { CEF_MSIT_TOTAL_COUNT, // The total number of values. } cef_media_sink_icon_type_t; +/// +// Device information for a MediaSink object. +/// +typedef struct _cef_media_sink_device_info_t { + cef_string_t ip_address; + int port; + cef_string_t model_name; +} cef_media_sink_device_info_t; + /// // Represents commands available to TextField. /// diff --git a/include/internal/cef_types_wrappers.h b/include/internal/cef_types_wrappers.h index 2d9695db6..08310cffb 100644 --- a/include/internal/cef_types_wrappers.h +++ b/include/internal/cef_types_wrappers.h @@ -980,4 +980,30 @@ struct CefAudioParametersTraits { /// typedef CefStructBase CefAudioParameters; +struct CefMediaSinkDeviceInfoTraits { + typedef cef_media_sink_device_info_t struct_type; + + static inline void init(struct_type* s) {} + + static inline void clear(struct_type* s) { + cef_string_clear(&s->ip_address); + cef_string_clear(&s->model_name); + } + + static inline void set(const struct_type* src, + struct_type* target, + bool copy) { + cef_string_set(src->ip_address.str, src->ip_address.length, + &target->ip_address, copy); + target->port = src->port; + cef_string_set(src->model_name.str, src->model_name.length, + &target->model_name, copy); + } +}; + +/// +// Class representing MediaSink device info. +/// +typedef CefStructBase CefMediaSinkDeviceInfo; + #endif // CEF_INCLUDE_INTERNAL_CEF_TYPES_WRAPPERS_H_ diff --git a/libcef/browser/media_router/media_sink_impl.cc b/libcef/browser/media_router/media_sink_impl.cc index 48a2f8fd4..ee284276c 100644 --- a/libcef/browser/media_router/media_sink_impl.cc +++ b/libcef/browser/media_router/media_sink_impl.cc @@ -4,6 +4,84 @@ #include "libcef/browser/media_router/media_sink_impl.h" +#include "libcef/browser/thread_util.h" + +#include "base/strings/string_number_conversions.h" +#include "chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h" +#include "chrome/browser/media/router/providers/cast/dual_media_sink_service.h" +#include "chrome/common/media_router/discovery/media_sink_internal.h" +#include "chrome/common/media_router/discovery/media_sink_service_base.h" + +namespace { + +using SinkServiceVector = std::vector; + +SinkServiceVector GetSinkServices() { + CEF_REQUIRE_UIT(); + auto sink_service = media_router::DualMediaSinkService::GetInstance(); + return {sink_service->GetCastMediaSinkServiceImpl(), + sink_service->GetDialMediaSinkServiceImpl()}; +} + +void GetSinkInternalAndContinue( + SinkServiceVector services, + const media_router::MediaSink::Id& sink_id, + CefRefPtr callback) { + CEF_REQUIRE_IOT(); + + CefMediaSinkDeviceInfo device_info; + const media_router::MediaSinkInternal* sink_internal = nullptr; + + for (auto service : services) { + sink_internal = service->GetSinkById(sink_id); + if (sink_internal) + break; + } + + if (sink_internal) { + if (sink_internal->is_cast_sink()) { + const auto& cast_data = sink_internal->cast_data(); + CefString(&device_info.ip_address) = + cast_data.ip_endpoint.ToStringWithoutPort(); + device_info.port = cast_data.ip_endpoint.port(); + CefString(&device_info.model_name) = cast_data.model_name; + } else if (sink_internal->is_dial_sink()) { + const auto& dial_data = sink_internal->dial_data(); + CefString(&device_info.ip_address) = dial_data.ip_address.ToString(); + if (dial_data.app_url.is_valid() && dial_data.app_url.has_port()) { + base::StringToInt(dial_data.app_url.port_piece(), &device_info.port); + } + CefString(&device_info.model_name) = dial_data.model_name; + } + } + + // Execute the callback on the UI thread. + CEF_POST_TASK( + CEF_UIT, + base::BindOnce(&CefMediaSinkDeviceInfoCallback::OnMediaSinkDeviceInfo, + callback, device_info)); +} + +void GetDeviceInfo(const media_router::MediaSink::Id& sink_id, + CefRefPtr callback) { + auto next_step = base::BindOnce( + [](const media_router::MediaSink::Id& sink_id, + CefRefPtr callback) { + CEF_POST_TASK(CEF_IOT, + base::BindOnce(GetSinkInternalAndContinue, + GetSinkServices(), sink_id, callback)); + }, + sink_id, callback); + + if (CEF_CURRENTLY_ON(CEF_UIT)) { + std::move(next_step).Run(); + } else { + CEF_POST_TASK(CEF_UIT, std::move(next_step)); + } +} + +} // namespace + CefMediaSinkImpl::CefMediaSinkImpl(const media_router::MediaSink& sink) : sink_(sink) {} @@ -32,6 +110,11 @@ CefMediaSink::IconType CefMediaSinkImpl::GetIconType() { return static_cast(sink_.icon_type()); } +void CefMediaSinkImpl::GetDeviceInfo( + CefRefPtr callback) { + ::GetDeviceInfo(sink_.id(), callback); +} + bool CefMediaSinkImpl::IsCastSink() { return sink_.provider_id() == media_router::CAST; } diff --git a/libcef/browser/media_router/media_sink_impl.h b/libcef/browser/media_router/media_sink_impl.h index aa05f3e99..cc91b84b0 100644 --- a/libcef/browser/media_router/media_sink_impl.h +++ b/libcef/browser/media_router/media_sink_impl.h @@ -22,6 +22,8 @@ class CefMediaSinkImpl : public CefMediaSink { CefString GetName() override; CefString GetDescription() override; IconType GetIconType() override; + void GetDeviceInfo( + CefRefPtr callback) override; bool IsCastSink() override; bool IsDialSink() override; bool IsCompatibleWith(CefRefPtr source) override; diff --git a/libcef_dll/cpptoc/media_sink_cpptoc.cc b/libcef_dll/cpptoc/media_sink_cpptoc.cc index fb4453296..fb03f1d8c 100644 --- a/libcef_dll/cpptoc/media_sink_cpptoc.cc +++ b/libcef_dll/cpptoc/media_sink_cpptoc.cc @@ -9,11 +9,12 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=53dca3d842bb3d2f8a329a38759eb623620439a2$ +// $hash=67d4596d3230067ea7dfe3c8150e3cf87ac526a5$ // #include "libcef_dll/cpptoc/media_sink_cpptoc.h" #include "libcef_dll/cpptoc/media_source_cpptoc.h" +#include "libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.h" #include "libcef_dll/shutdown_checker.h" namespace { @@ -89,6 +90,26 @@ media_sink_get_icon_type(struct _cef_media_sink_t* self) { return _retval; } +void CEF_CALLBACK media_sink_get_device_info( + struct _cef_media_sink_t* self, + struct _cef_media_sink_device_info_callback_t* callback) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: callback; type: refptr_diff + DCHECK(callback); + if (!callback) + return; + + // Execute + CefMediaSinkCppToC::Get(self)->GetDeviceInfo( + CefMediaSinkDeviceInfoCallbackCToCpp::Wrap(callback)); +} + int CEF_CALLBACK media_sink_is_cast_sink(struct _cef_media_sink_t* self) { shutdown_checker::AssertNotShutdown(); @@ -153,6 +174,7 @@ CefMediaSinkCppToC::CefMediaSinkCppToC() { GetStruct()->get_name = media_sink_get_name; GetStruct()->get_description = media_sink_get_description; GetStruct()->get_icon_type = media_sink_get_icon_type; + GetStruct()->get_device_info = media_sink_get_device_info; GetStruct()->is_cast_sink = media_sink_is_cast_sink; GetStruct()->is_dial_sink = media_sink_is_dial_sink; GetStruct()->is_compatible_with = media_sink_is_compatible_with; diff --git a/libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.cc b/libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.cc new file mode 100644 index 000000000..33ca0b788 --- /dev/null +++ b/libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.cc @@ -0,0 +1,78 @@ +// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=c22023ad9e7d7d80d72729dbebdf03f0b60f4dc9$ +// + +#include "libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.h" +#include "libcef_dll/shutdown_checker.h" + +namespace { + +// MEMBER FUNCTIONS - Body may be edited by hand. + +void CEF_CALLBACK media_sink_device_info_callback_on_media_sink_device_info( + struct _cef_media_sink_device_info_callback_t* self, + const struct _cef_media_sink_device_info_t* device_info) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: device_info; type: struct_byref_const + DCHECK(device_info); + if (!device_info) + return; + + // Translate param: device_info; type: struct_byref_const + CefMediaSinkDeviceInfo device_infoObj; + if (device_info) + device_infoObj.Set(*device_info, false); + + // Execute + CefMediaSinkDeviceInfoCallbackCppToC::Get(self)->OnMediaSinkDeviceInfo( + device_infoObj); +} + +} // namespace + +// CONSTRUCTOR - Do not edit by hand. + +CefMediaSinkDeviceInfoCallbackCppToC::CefMediaSinkDeviceInfoCallbackCppToC() { + GetStruct()->on_media_sink_device_info = + media_sink_device_info_callback_on_media_sink_device_info; +} + +// DESTRUCTOR - Do not edit by hand. + +CefMediaSinkDeviceInfoCallbackCppToC::~CefMediaSinkDeviceInfoCallbackCppToC() { + shutdown_checker::AssertNotShutdown(); +} + +template <> +CefRefPtr +CefCppToCRefCounted:: + UnwrapDerived(CefWrapperType type, + cef_media_sink_device_info_callback_t* s) { + NOTREACHED() << "Unexpected class type: " << type; + return nullptr; +} + +template <> +CefWrapperType + CefCppToCRefCounted::kWrapperType = + WT_MEDIA_SINK_DEVICE_INFO_CALLBACK; diff --git a/libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.h b/libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.h new file mode 100644 index 000000000..87c5d5c5b --- /dev/null +++ b/libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.h @@ -0,0 +1,38 @@ +// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=5313c2346d5db18dca956f2dac98b73e049a4995$ +// + +#ifndef CEF_LIBCEF_DLL_CPPTOC_MEDIA_SINK_DEVICE_INFO_CALLBACK_CPPTOC_H_ +#define CEF_LIBCEF_DLL_CPPTOC_MEDIA_SINK_DEVICE_INFO_CALLBACK_CPPTOC_H_ +#pragma once + +#if !defined(WRAPPING_CEF_SHARED) +#error This file can be included wrapper-side only +#endif + +#include "include/capi/cef_media_router_capi.h" +#include "include/cef_media_router.h" +#include "libcef_dll/cpptoc/cpptoc_ref_counted.h" + +// Wrap a C++ class with a C structure. +// This class may be instantiated and accessed wrapper-side only. +class CefMediaSinkDeviceInfoCallbackCppToC + : public CefCppToCRefCounted { + public: + CefMediaSinkDeviceInfoCallbackCppToC(); + virtual ~CefMediaSinkDeviceInfoCallbackCppToC(); +}; + +#endif // CEF_LIBCEF_DLL_CPPTOC_MEDIA_SINK_DEVICE_INFO_CALLBACK_CPPTOC_H_ diff --git a/libcef_dll/ctocpp/media_sink_ctocpp.cc b/libcef_dll/ctocpp/media_sink_ctocpp.cc index bf420d548..69a31aa79 100644 --- a/libcef_dll/ctocpp/media_sink_ctocpp.cc +++ b/libcef_dll/ctocpp/media_sink_ctocpp.cc @@ -9,10 +9,11 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=6ffdd140e2cb688f1d7db2eb1e2356a62ac08e5e$ +// $hash=8f3906cf08a292e81bf59629cf073c93cf388725$ // #include "libcef_dll/ctocpp/media_sink_ctocpp.h" +#include "libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.h" #include "libcef_dll/ctocpp/media_source_ctocpp.h" #include "libcef_dll/shutdown_checker.h" @@ -89,6 +90,27 @@ CefMediaSink::IconType CefMediaSinkCToCpp::GetIconType() { return _retval; } +NO_SANITIZE("cfi-icall") +void CefMediaSinkCToCpp::GetDeviceInfo( + CefRefPtr callback) { + shutdown_checker::AssertNotShutdown(); + + cef_media_sink_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, get_device_info)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: callback; type: refptr_diff + DCHECK(callback.get()); + if (!callback.get()) + return; + + // Execute + _struct->get_device_info( + _struct, CefMediaSinkDeviceInfoCallbackCppToC::Wrap(callback)); +} + NO_SANITIZE("cfi-icall") bool CefMediaSinkCToCpp::IsCastSink() { shutdown_checker::AssertNotShutdown(); diff --git a/libcef_dll/ctocpp/media_sink_ctocpp.h b/libcef_dll/ctocpp/media_sink_ctocpp.h index 811f2976b..af1dd920b 100644 --- a/libcef_dll/ctocpp/media_sink_ctocpp.h +++ b/libcef_dll/ctocpp/media_sink_ctocpp.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=9d3af9897a857a63abec8327f84f5d809be603da$ +// $hash=d5ab2dbf52c45129296b1ee156ead2f1e3182db8$ // #ifndef CEF_LIBCEF_DLL_CTOCPP_MEDIA_SINK_CTOCPP_H_ @@ -38,6 +38,8 @@ class CefMediaSinkCToCpp : public CefCToCppRefCounted callback) OVERRIDE; bool IsCastSink() OVERRIDE; bool IsDialSink() OVERRIDE; bool IsCompatibleWith(CefRefPtr source) OVERRIDE; diff --git a/libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.cc b/libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.cc new file mode 100644 index 000000000..fdd582270 --- /dev/null +++ b/libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.cc @@ -0,0 +1,60 @@ +// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=c56362ea79609562dacc4bf8303f2bd920ddeada$ +// + +#include "libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.h" +#include "libcef_dll/shutdown_checker.h" + +// VIRTUAL METHODS - Body may be edited by hand. + +NO_SANITIZE("cfi-icall") +void CefMediaSinkDeviceInfoCallbackCToCpp::OnMediaSinkDeviceInfo( + const CefMediaSinkDeviceInfo& device_info) { + shutdown_checker::AssertNotShutdown(); + + cef_media_sink_device_info_callback_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, on_media_sink_device_info)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + _struct->on_media_sink_device_info(_struct, &device_info); +} + +// CONSTRUCTOR - Do not edit by hand. + +CefMediaSinkDeviceInfoCallbackCToCpp::CefMediaSinkDeviceInfoCallbackCToCpp() {} + +// DESTRUCTOR - Do not edit by hand. + +CefMediaSinkDeviceInfoCallbackCToCpp::~CefMediaSinkDeviceInfoCallbackCToCpp() { + shutdown_checker::AssertNotShutdown(); +} + +template <> +cef_media_sink_device_info_callback_t* +CefCToCppRefCounted:: + UnwrapDerived(CefWrapperType type, CefMediaSinkDeviceInfoCallback* c) { + NOTREACHED() << "Unexpected class type: " << type; + return nullptr; +} + +template <> +CefWrapperType + CefCToCppRefCounted::kWrapperType = + WT_MEDIA_SINK_DEVICE_INFO_CALLBACK; diff --git a/libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.h b/libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.h new file mode 100644 index 000000000..c5cfef8c2 --- /dev/null +++ b/libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.h @@ -0,0 +1,42 @@ +// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=e48d0b8482168d355e04460ea6ea5b7662dbe4fd$ +// + +#ifndef CEF_LIBCEF_DLL_CTOCPP_MEDIA_SINK_DEVICE_INFO_CALLBACK_CTOCPP_H_ +#define CEF_LIBCEF_DLL_CTOCPP_MEDIA_SINK_DEVICE_INFO_CALLBACK_CTOCPP_H_ +#pragma once + +#if !defined(BUILDING_CEF_SHARED) +#error This file can be included DLL-side only +#endif + +#include "include/capi/cef_media_router_capi.h" +#include "include/cef_media_router.h" +#include "libcef_dll/ctocpp/ctocpp_ref_counted.h" + +// Wrap a C structure with a C++ class. +// This class may be instantiated and accessed DLL-side only. +class CefMediaSinkDeviceInfoCallbackCToCpp + : public CefCToCppRefCounted { + public: + CefMediaSinkDeviceInfoCallbackCToCpp(); + virtual ~CefMediaSinkDeviceInfoCallbackCToCpp(); + + // CefMediaSinkDeviceInfoCallback methods. + void OnMediaSinkDeviceInfo( + const CefMediaSinkDeviceInfo& device_info) override; +}; + +#endif // CEF_LIBCEF_DLL_CTOCPP_MEDIA_SINK_DEVICE_INFO_CALLBACK_CTOCPP_H_ diff --git a/libcef_dll/wrapper_types.h b/libcef_dll/wrapper_types.h index 68cb7882b..980b90d44 100644 --- a/libcef_dll/wrapper_types.h +++ b/libcef_dll/wrapper_types.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=20268db646dcf8aa6d54b2342dbc70a6e624e202$ +// $hash=6e7cec57ce98a10f0b0668d47c9935639963c215$ // #ifndef CEF_LIBCEF_DLL_WRAPPER_TYPES_H_ @@ -80,6 +80,7 @@ enum CefWrapperType { WT_MEDIA_ROUTE_CREATE_CALLBACK, WT_MEDIA_ROUTER, WT_MEDIA_SINK, + WT_MEDIA_SINK_DEVICE_INFO_CALLBACK, WT_MEDIA_SOURCE, WT_MENU_BUTTON, WT_MENU_BUTTON_DELEGATE, diff --git a/tests/cefclient/browser/media_router_test.cc b/tests/cefclient/browser/media_router_test.cc index 271ec7f20..ddc1354c6 100644 --- a/tests/cefclient/browser/media_router_test.cc +++ b/tests/cefclient/browser/media_router_test.cc @@ -93,7 +93,12 @@ class MediaObserver : public CefMediaObserver { MediaObserver(CefRefPtr media_router, CefRefPtr subscription_callback) : media_router_(media_router), - subscription_callback_(subscription_callback) {} + subscription_callback_(subscription_callback), + next_sink_query_id_(0), + pending_sink_query_id_(-1), + pending_sink_callbacks_(0U) {} + + ~MediaObserver() OVERRIDE { ClearSinkInfoMap(); } bool CreateRoute(const std::string& source_urn, const std::string& sink_id, @@ -141,35 +146,62 @@ class MediaObserver : public CefMediaObserver { } protected: + class DeviceInfoCallback : public CefMediaSinkDeviceInfoCallback { + public: + // Callback to be executed when the device info is available. + typedef base::Callback + CallbackType; + + DeviceInfoCallback(const std::string& sink_id, const CallbackType& callback) + : sink_id_(sink_id), callback_(callback) {} + + void OnMediaSinkDeviceInfo( + const CefMediaSinkDeviceInfo& device_info) OVERRIDE { + CEF_REQUIRE_UI_THREAD(); + callback_.Run(sink_id_, device_info); + callback_.Reset(); + } + + private: + const std::string sink_id_; + CallbackType callback_; + + IMPLEMENT_REFCOUNTING(DeviceInfoCallback); + DISALLOW_COPY_AND_ASSIGN(DeviceInfoCallback); + }; + // CefMediaObserver methods: void OnSinks(const MediaSinkVector& sinks) OVERRIDE { CEF_REQUIRE_UI_THREAD(); - sink_map_.clear(); + ClearSinkInfoMap(); - CefRefPtr payload = CefDictionaryValue::Create(); - CefRefPtr sinks_list = CefListValue::Create(); - sinks_list->SetSize(sinks.size()); + // Reset pending sink state. + pending_sink_callbacks_ = sinks.size(); + pending_sink_query_id_ = ++next_sink_query_id_; + + if (sinks.empty()) { + // No sinks, send the response immediately. + SendSinksResponse(); + return; + } + + DeviceInfoCallback::CallbackType callback = base::Bind( + &MediaObserver::OnSinkDeviceInfo, this, pending_sink_query_id_); MediaSinkVector::const_iterator it = sinks.begin(); for (size_t idx = 0; it != sinks.end(); ++it, ++idx) { CefRefPtr sink = *it; const std::string& sink_id = sink->GetId(); - sink_map_.insert(std::make_pair(sink_id, sink)); + SinkInfo* info = new SinkInfo; + info->sink = sink; + sink_info_map_.insert(std::make_pair(sink_id, info)); - CefRefPtr sink_dict = CefDictionaryValue::Create(); - sink_dict->SetString("id", sink_id); - sink_dict->SetString("name", sink->GetName()); - sink_dict->SetString("desc", sink->GetDescription()); - sink_dict->SetInt("icon", sink->GetIconType()); - sink_dict->SetString( - "type", sink->IsCastSink() ? "cast" - : sink->IsDialSink() ? "dial" : "unknown"); - sinks_list->SetDictionary(idx, sink_dict); + // Request the device info asynchronously. Send the response once all + // callbacks have executed. + sink->GetDeviceInfo(new DeviceInfoCallback(sink_id, callback)); } - - payload->SetList("sinks_list", sinks_list); - SendResponse("onSinks", payload); } void OnRoutes(const MediaRouteVector& routes) OVERRIDE { @@ -230,12 +262,39 @@ class MediaObserver : public CefMediaObserver { } CefRefPtr GetSink(const std::string& sink_id) { - SinkMap::const_iterator it = sink_map_.find(sink_id); - if (it != sink_map_.end()) - return it->second; + SinkInfoMap::const_iterator it = sink_info_map_.find(sink_id); + if (it != sink_info_map_.end()) + return it->second->sink; return NULL; } + void ClearSinkInfoMap() { + SinkInfoMap::const_iterator it = sink_info_map_.begin(); + for (; it != sink_info_map_.end(); ++it) { + delete it->second; + } + sink_info_map_.clear(); + } + + void OnSinkDeviceInfo(int sink_query_id, + const std::string& sink_id, + const CefMediaSinkDeviceInfo& device_info) { + // Discard callbacks that arrive after a new call to OnSinks(). + if (sink_query_id != pending_sink_query_id_) + return; + + SinkInfoMap::const_iterator it = sink_info_map_.find(sink_id); + if (it != sink_info_map_.end()) { + it->second->device_info = device_info; + } + + // Send the response once we've received all expected callbacks. + DCHECK_GT(pending_sink_callbacks_, 0U); + if (--pending_sink_callbacks_ == 0U) { + SendSinksResponse(); + } + } + CefRefPtr GetRoute(const std::string& route_id) { RouteMap::const_iterator it = route_map_.find(route_id); if (it != route_map_.end()) @@ -251,12 +310,55 @@ class MediaObserver : public CefMediaObserver { SendSuccess(subscription_callback_, result); } + void SendSinksResponse() { + CefRefPtr payload = CefDictionaryValue::Create(); + CefRefPtr sinks_list = CefListValue::Create(); + sinks_list->SetSize(sink_info_map_.size()); + + SinkInfoMap::const_iterator it = sink_info_map_.begin(); + for (size_t idx = 0; it != sink_info_map_.end(); ++it, ++idx) { + const SinkInfo* info = it->second; + + CefRefPtr sink_dict = CefDictionaryValue::Create(); + sink_dict->SetString("id", it->first); + sink_dict->SetString("name", info->sink->GetName()); + sink_dict->SetString("desc", info->sink->GetDescription()); + sink_dict->SetInt("icon", info->sink->GetIconType()); + sink_dict->SetString("ip_address", + CefString(&info->device_info.ip_address)); + sink_dict->SetInt("port", info->device_info.port); + sink_dict->SetString("model_name", + CefString(&info->device_info.model_name)); + sink_dict->SetString("type", + info->sink->IsCastSink() + ? "cast" + : info->sink->IsDialSink() ? "dial" : "unknown"); + sinks_list->SetDictionary(idx, sink_dict); + } + + payload->SetList("sinks_list", sinks_list); + SendResponse("onSinks", payload); + } + CefRefPtr media_router_; CefRefPtr subscription_callback_; - typedef std::map> SinkMap; - SinkMap sink_map_; + struct SinkInfo { + CefRefPtr sink; + CefMediaSinkDeviceInfo device_info; + }; + typedef std::map SinkInfoMap; + // Used to uniquely identify a call to OnSinks(), for the purpose of + // associating OnMediaSinkDeviceInfo() callbacks. + int next_sink_query_id_; + + // State from the most recent call to OnSinks(). + SinkInfoMap sink_info_map_; + int pending_sink_query_id_; + size_t pending_sink_callbacks_; + + // State from the most recent call to OnRoutes(). typedef std::map> RouteMap; RouteMap route_map_; diff --git a/tests/cefclient/resources/media_router.html b/tests/cefclient/resources/media_router.html index 3860082dc..54f8b745e 100644 --- a/tests/cefclient/resources/media_router.html +++ b/tests/cefclient/resources/media_router.html @@ -42,7 +42,7 @@ input, select, textarea, button { } .route_controls .control { - width: 400px; + width: 500px; } .messages { @@ -276,7 +276,8 @@ function updateSinks(sinks) { if (oldValues.includes(sink.id)) continue; var opt = document.createElement('option'); - opt.innerHTML = sink.name + ' (' + sink.type + ', ' + getIconTypeLabel(sink.icon) + ')'; + opt.innerHTML = sink.name + ' (' + sink.model_name + ', ' + sink.type + ', ' + + getIconTypeLabel(sink.icon) + ', ' + sink.ip_address + ':' + sink.port + ')'; opt.value = sink.id; sinksSelect.appendChild(opt); }