From 81003890a8285498b9703b5511697cfcbe3b2726 Mon Sep 17 00:00:00 2001 From: Sharad Binjola <31142146+sharadb-amazon@users.noreply.github.com> Date: Fri, 23 Sep 2022 11:59:59 -0700 Subject: [PATCH] Adding Media subscriptions support to Linux tv-casting-app (#22709) --- .../tv-casting-app/linux/CastingUtils.cpp | 62 +++++- examples/tv-casting-app/linux/CastingUtils.h | 7 + .../tv-casting-app/tv-casting-common/BUILD.gn | 4 + .../include/ApplicationLauncher.h | 10 + .../tv-casting-common/include/CastingServer.h | 164 ++++++++++++++- .../tv-casting-common/include/Channel.h | 40 ++++ .../tv-casting-common/include/LevelControl.h | 21 ++ .../tv-casting-common/include/MediaBase.h | 55 ++++++ .../include/MediaCommandBase.h | 32 +-- .../tv-casting-common/include/MediaPlayback.h | 48 +++++ .../include/MediaSubscriptionBase.h | 44 +++++ .../include/TargetNavigator.h | 16 ++ .../tv-casting-common/src/CastingServer.cpp | 187 ++++++++++++++++++ .../tv-casting-common/src/Channel.cpp | 29 +++ 14 files changed, 686 insertions(+), 33 deletions(-) create mode 100644 examples/tv-casting-app/tv-casting-common/include/Channel.h create mode 100644 examples/tv-casting-app/tv-casting-common/include/MediaBase.h create mode 100644 examples/tv-casting-app/tv-casting-common/include/MediaSubscriptionBase.h create mode 100644 examples/tv-casting-app/tv-casting-common/src/Channel.cpp diff --git a/examples/tv-casting-app/linux/CastingUtils.cpp b/examples/tv-casting-app/linux/CastingUtils.cpp index 0e6fc87acf757f..6f5ea539a501d2 100644 --- a/examples/tv-casting-app/linux/CastingUtils.cpp +++ b/examples/tv-casting-app/linux/CastingUtils.cpp @@ -26,6 +26,7 @@ using namespace chip::Dnssd; // TODO: Accept these values over CLI const char * kContentUrl = "https://www.test.com/videoid"; const char * kContentDisplayStr = "Test video"; +int gInitialContextVal = 121212; CHIP_ERROR DiscoverCommissioners() { @@ -114,14 +115,69 @@ void LaunchURLResponseCallback(CHIP_ERROR err) ChipLogProgress(AppServer, "LaunchURLResponseCallback called with %" CHIP_ERROR_FORMAT, err.Format()); } +void OnCurrentStateReadResponseSuccess( + void * context, chip::app::Clusters::MediaPlayback::Attributes::CurrentState::TypeInfo::DecodableArgType responseData) +{ + ChipLogProgress(AppServer, "OnCurrentStateReadResponseSuccess called with responseData: %d", static_cast(responseData)); + switch (responseData) + { + case chip::app::Clusters::MediaPlayback::PlaybackStateEnum::kPlaying: + ChipLogProgress(AppServer, "OnCurrentStateReadResponseSuccess CurrentState: Playing"); + break; + case chip::app::Clusters::MediaPlayback::PlaybackStateEnum::kPaused: + ChipLogProgress(AppServer, "OnCurrentStateReadResponseSuccess CurrentState: Paused"); + break; + case chip::app::Clusters::MediaPlayback::PlaybackStateEnum::kNotPlaying: + ChipLogProgress(AppServer, "OnCurrentStateReadResponseSuccess CurrentState: Not Playing"); + break; + case chip::app::Clusters::MediaPlayback::PlaybackStateEnum::kBuffering: + ChipLogProgress(AppServer, "OnCurrentStateReadResponseSuccess CurrentState: Buffering"); + break; + default: + ChipLogError(AppServer, "OnCurrentStateReadResponseSuccess Invalid CurrentState!"); + break; + } + + if (context != nullptr) + { + ChipLogProgress(AppServer, "OnCurrentStateReadResponseSuccess context value: %d", *(static_cast(context))); + } +} + +void OnCurrentStateReadResponseFailure(void * context, CHIP_ERROR err) +{ + ChipLogProgress(AppServer, "OnCurrentStateReadResponseFailure called with %" CHIP_ERROR_FORMAT, err.Format()); +} + +void OnCurrentStateSubscriptionEstablished(void * context) +{ + ChipLogProgress(AppServer, "OnCurrentStateSubscriptionEstablished called"); + if (context != nullptr) + { + ChipLogProgress(AppServer, "OnCurrentStateSubscriptionEstablished context value: %d", *(static_cast(context))); + } +} + void HandleCommissioningCompleteCallback(CHIP_ERROR err) { ChipLogProgress(AppServer, "HandleCommissioningCompleteCallback called with %" CHIP_ERROR_FORMAT, err.Format()); if (err == CHIP_NO_ERROR) { - ReturnOnFailure( - CastingServer::GetInstance()->ContentLauncherLaunchURL(kContentUrl, kContentDisplayStr, LaunchURLResponseCallback)); - ChipLogProgress(AppServer, "ContentLauncherLaunchURL called successfully"); + // Subscribe to a media attribute + err = CastingServer::GetInstance()->MediaPlayback_SubscribeToCurrentState( + static_cast(&gInitialContextVal), OnCurrentStateReadResponseSuccess, OnCurrentStateReadResponseFailure, 0, 4000, + OnCurrentStateSubscriptionEstablished); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "MediaPlayback_SubscribeToCurrentState call failed!"); + } + + // Send a media command + err = CastingServer::GetInstance()->ContentLauncherLaunchURL(kContentUrl, kContentDisplayStr, LaunchURLResponseCallback); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "ContentLauncherLaunchURL call failed!"); + } } } diff --git a/examples/tv-casting-app/linux/CastingUtils.h b/examples/tv-casting-app/linux/CastingUtils.h index 177bedfdb5506c..172b01896c9675 100644 --- a/examples/tv-casting-app/linux/CastingUtils.h +++ b/examples/tv-casting-app/linux/CastingUtils.h @@ -42,6 +42,13 @@ void HandleCommissioningCompleteCallback(CHIP_ERROR err); void LaunchURLResponseCallback(CHIP_ERROR err); +void OnCurrentStateReadResponseSuccess( + void * context, chip::app::Clusters::MediaPlayback::Attributes::CurrentState::TypeInfo::DecodableArgType responseData); + +void OnCurrentStateReadResponseFailure(void * context, CHIP_ERROR err); + +void OnCurrentStateSubscriptionEstablished(void * context); + #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT void HandleUDCSendExpiration(chip::System::Layer * aSystemLayer, void * context); #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT diff --git a/examples/tv-casting-app/tv-casting-common/BUILD.gn b/examples/tv-casting-app/tv-casting-common/BUILD.gn index b421fada354493..dd3644a2baa039 100644 --- a/examples/tv-casting-app/tv-casting-common/BUILD.gn +++ b/examples/tv-casting-app/tv-casting-common/BUILD.gn @@ -49,16 +49,20 @@ chip_data_model("tv-casting-common") { "commands/common/CHIPCommand.cpp", "include/ApplicationLauncher.h", "include/CastingServer.h", + "include/Channel.h", "include/ContentLauncher.h", "include/KeypadInput.h", "include/LevelControl.h", + "include/MediaBase.h", "include/MediaCommandBase.h", "include/MediaPlayback.h", + "include/MediaSubscriptionBase.h", "include/TargetEndpointInfo.h", "include/TargetNavigator.h", "include/TargetVideoPlayerInfo.h", "src/ApplicationLauncher.cpp", "src/CastingServer.cpp", + "src/Channel.cpp", "src/ContentLauncher.cpp", "src/KeypadInput.cpp", "src/LevelControl.cpp", diff --git a/examples/tv-casting-app/tv-casting-common/include/ApplicationLauncher.h b/examples/tv-casting-app/tv-casting-common/include/ApplicationLauncher.h index d3365be9f00f9c..3444955958b6d2 100644 --- a/examples/tv-casting-app/tv-casting-common/include/ApplicationLauncher.h +++ b/examples/tv-casting-app/tv-casting-common/include/ApplicationLauncher.h @@ -17,10 +17,12 @@ */ #include "MediaCommandBase.h" +#include "MediaSubscriptionBase.h" #include #include +// COMMAND CLASSES class LaunchAppCommand : public MediaCommandBase @@ -51,3 +53,11 @@ class HideAppCommand : public MediaCommandBase responseCallback); }; + +// SUBSCRIBER CLASSES +class CurrentAppSubscriber + : public MediaSubscriptionBase +{ +public: + CurrentAppSubscriber() : MediaSubscriptionBase(chip::app::Clusters::ApplicationLauncher::Id) {} +}; diff --git a/examples/tv-casting-app/tv-casting-common/include/CastingServer.h b/examples/tv-casting-app/tv-casting-common/include/CastingServer.h index b29f82e0cba118..b91a0e0b077183 100644 --- a/examples/tv-casting-app/tv-casting-common/include/CastingServer.h +++ b/examples/tv-casting-app/tv-casting-common/include/CastingServer.h @@ -19,6 +19,7 @@ #pragma once #include "ApplicationLauncher.h" +#include "Channel.h" #include "ContentLauncher.h" #include "KeypadInput.h" #include "LevelControl.h" @@ -27,13 +28,15 @@ #include "TargetNavigator.h" #include "TargetVideoPlayerInfo.h" +#include #include #include #include +#include #include constexpr chip::System::Clock::Seconds16 kCommissioningWindowTimeout = chip::System::Clock::Seconds16(3 * 60); -constexpr chip::EndpointId kTvEndpoint = 1; +constexpr chip::EndpointId kTvEndpoint = 4; /** * @brief Represents a TV Casting server that can get the casting app commissioned @@ -73,6 +76,9 @@ class CastingServer chip::FabricIndex CurrentFabricIndex() { return mTargetVideoPlayerInfo.GetFabricIndex(); } void SetDefaultFabricIndex(); + /** + * @brief Content Launcher cluster + */ CHIP_ERROR ContentLauncher_LaunchURL( const char * contentUrl, const char * contentDisplayStr, chip::Optional brandingInformation, @@ -80,10 +86,43 @@ class CastingServer CHIP_ERROR ContentLauncher_LaunchContent(chip::app::Clusters::ContentLauncher::Structs::ContentSearch::Type search, bool autoPlay, chip::Optional data, std::function responseCallback); + + /** + * @brief Level Control cluster + */ CHIP_ERROR LevelControl_Step(chip::app::Clusters::LevelControl::StepMode stepMode, uint8_t stepSize, uint16_t transitionTime, uint8_t optionMask, uint8_t optionOverride, std::function responseCallback); CHIP_ERROR LevelControl_MoveToLevel(uint8_t level, uint16_t transitionTime, uint8_t optionMask, uint8_t optionOverride, std::function responseCallback); + + CHIP_ERROR + LevelControl_SubscribeToCurrentLevel( + void * context, + chip::Controller::ReadResponseSuccessCallback< + chip::app::Clusters::LevelControl::Attributes::CurrentLevel::TypeInfo::DecodableArgType> + successFn, + chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); + CHIP_ERROR + LevelControl_SubscribeToMinLevel(void * context, + chip::Controller::ReadResponseSuccessCallback< + chip::app::Clusters::LevelControl::Attributes::MinLevel::TypeInfo::DecodableArgType> + successFn, + chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, + uint16_t maxInterval, + chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); + CHIP_ERROR + LevelControl_SubscribeToMaxLevel(void * context, + chip::Controller::ReadResponseSuccessCallback< + chip::app::Clusters::LevelControl::Attributes::MaxLevel::TypeInfo::DecodableArgType> + successFn, + chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, + uint16_t maxInterval, + chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); + + /** + * @brief Media Playback cluster + */ CHIP_ERROR MediaPlayback_Play(std::function responseCallback); CHIP_ERROR MediaPlayback_Pause(std::function responseCallback); CHIP_ERROR MediaPlayback_StopPlayback(std::function responseCallback); @@ -91,17 +130,116 @@ class CastingServer CHIP_ERROR MediaPlayback_Seek(uint64_t position, std::function responseCallback); CHIP_ERROR MediaPlayback_SkipForward(uint64_t deltaPositionMilliseconds, std::function responseCallback); CHIP_ERROR MediaPlayback_SkipBackward(uint64_t deltaPositionMilliseconds, std::function responseCallback); + + CHIP_ERROR MediaPlayback_SubscribeToCurrentState( + void * context, + chip::Controller::ReadResponseSuccessCallback< + chip::app::Clusters::MediaPlayback::Attributes::CurrentState::TypeInfo::DecodableArgType> + successFn, + chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); + CHIP_ERROR + MediaPlayback_SubscribeToStartTime(void * context, + chip::Controller::ReadResponseSuccessCallback< + chip::app::Clusters::MediaPlayback::Attributes::StartTime::TypeInfo::DecodableArgType> + successFn, + chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, + uint16_t maxInterval, + chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); + CHIP_ERROR + MediaPlayback_SubscribeToDuration(void * context, + chip::Controller::ReadResponseSuccessCallback< + chip::app::Clusters::MediaPlayback::Attributes::Duration::TypeInfo::DecodableArgType> + successFn, + chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, + uint16_t maxInterval, + chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); + CHIP_ERROR MediaPlayback_SubscribeToSampledPosition( + void * context, + chip::Controller::ReadResponseSuccessCallback< + chip::app::Clusters::MediaPlayback::Attributes::SampledPosition::TypeInfo::DecodableArgType> + successFn, + chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); + CHIP_ERROR MediaPlayback_SubscribeToPlaybackSpeed( + void * context, + chip::Controller::ReadResponseSuccessCallback< + chip::app::Clusters::MediaPlayback::Attributes::PlaybackSpeed::TypeInfo::DecodableArgType> + successFn, + chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); + CHIP_ERROR MediaPlayback_SubscribeToSeekRangeEnd( + void * context, + chip::Controller::ReadResponseSuccessCallback< + chip::app::Clusters::MediaPlayback::Attributes::SeekRangeEnd::TypeInfo::DecodableArgType> + successFn, + chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); + CHIP_ERROR MediaPlayback_SubscribeToSeekRangeStart( + void * context, + chip::Controller::ReadResponseSuccessCallback< + chip::app::Clusters::MediaPlayback::Attributes::SeekRangeStart::TypeInfo::DecodableArgType> + successFn, + chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); + + /** + * @brief Application Launcher cluster + */ CHIP_ERROR ApplicationLauncher_LaunchApp(chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application, chip::Optional data, std::function responseCallback); CHIP_ERROR ApplicationLauncher_StopApp(chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application, std::function responseCallback); CHIP_ERROR ApplicationLauncher_HideApp(chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application, std::function responseCallback); + + CHIP_ERROR + ApplicationLauncher_SubscribeToCurrentApp( + void * context, + chip::Controller::ReadResponseSuccessCallback< + chip::app::Clusters::ApplicationLauncher::Attributes::CurrentApp::TypeInfo::DecodableArgType> + successFn, + chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); + + /** + * @brief Target Navigator cluster + */ CHIP_ERROR TargetNavigator_NavigateTarget(const uint8_t target, const chip::Optional data, std::function responseCallback); + + CHIP_ERROR TargetNavigator_SubscribeToTargetList( + void * context, + chip::Controller::ReadResponseSuccessCallback< + chip::app::Clusters::TargetNavigator::Attributes::TargetList::TypeInfo::DecodableArgType> + successFn, + chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); + CHIP_ERROR TargetNavigator_SubscribeToCurrentTarget( + void * context, + chip::Controller::ReadResponseSuccessCallback< + chip::app::Clusters::TargetNavigator::Attributes::CurrentTarget::TypeInfo::DecodableArgType> + successFn, + chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); + + /** + * @brief Keypad Input cluster + */ CHIP_ERROR KeypadInput_SendKey(const chip::app::Clusters::KeypadInput::CecKeyCode keyCode, std::function responseCallback); + /** + * @brief Channel cluster + */ + CHIP_ERROR Channel_ChangeChannelCommand(const chip::CharSpan & match, std::function responseCallback); + CHIP_ERROR Channel_SubscribeToLineup( + void * context, + chip::Controller::ReadResponseSuccessCallback + successFn, + chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); + private: CHIP_ERROR InitBindingHandlers(); static void DeviceEventCallback(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); @@ -127,6 +265,10 @@ class CastingServer StepCommand mStepCommand; MoveToLevelCommand mMoveToLevelCommand; + CurrentLevelSubscriber mCurrentLevelSubscriber; + MinLevelSubscriber mMinLevelSubscriber; + MaxLevelSubscriber mMaxLevelSubscriber; + /** * @brief Media Playback cluster */ @@ -138,6 +280,14 @@ class CastingServer SkipForwardCommand mSkipForwardCommand; SkipBackwardCommand mSkipBackwardCommand; + CurrentStateSubscriber mCurrentStateSubscriber; + StartTimeSubscriber mStartTimeSubscriber; + DurationSubscriber mDurationSubscriber; + SampledPositionSubscriber mSampledPositionSubscriber; + PlaybackSpeedSubscriber mPlaybackSpeedSubscriber; + SeekRangeEndSubscriber mSeekRangeEndSubscriber; + SeekRangeStartSubscriber mSeekRangeStartSubscriber; + /** * @brief Application Launcher cluster */ @@ -145,13 +295,25 @@ class CastingServer StopAppCommand mStopAppCommand; HideAppCommand mHideAppCommand; + CurrentAppSubscriber mCurrentAppSubscriber; + /** * @brief Target Navigator cluster */ NavigateTargetCommand mNavigateTargetCommand; + TargetListSubscriber mTargetListSubscriber; + CurrentTargetSubscriber mCurrentTargetSubscriber; + /** * @brief Keypad Input cluster */ SendKeyCommand mSendKeyCommand; + + /** + * @brief Channel cluster + */ + ChangeChannelCommand mChangeChannelCommand; + + LineupSubscriber mLineupSubscriber; }; diff --git a/examples/tv-casting-app/tv-casting-common/include/Channel.h b/examples/tv-casting-app/tv-casting-common/include/Channel.h new file mode 100644 index 00000000000000..1a0a18ec196ad8 --- /dev/null +++ b/examples/tv-casting-app/tv-casting-common/include/Channel.h @@ -0,0 +1,40 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MediaCommandBase.h" +#include "MediaSubscriptionBase.h" + +#include +#include + +// COMMAND CLASSES +class ChangeChannelCommand : public MediaCommandBase +{ +public: + ChangeChannelCommand() : MediaCommandBase(chip::app::Clusters::Channel::Id) {} + + CHIP_ERROR Invoke(const chip::CharSpan & match, std::function responseCallback); +}; + +// SUBSCRIBER CLASSES +class LineupSubscriber : public MediaSubscriptionBase +{ +public: + LineupSubscriber() : MediaSubscriptionBase(chip::app::Clusters::Channel::Id) {} +}; diff --git a/examples/tv-casting-app/tv-casting-common/include/LevelControl.h b/examples/tv-casting-app/tv-casting-common/include/LevelControl.h index d431e3bb289597..a1fd1724b9de41 100644 --- a/examples/tv-casting-app/tv-casting-common/include/LevelControl.h +++ b/examples/tv-casting-app/tv-casting-common/include/LevelControl.h @@ -17,10 +17,12 @@ */ #include "MediaCommandBase.h" +#include "MediaSubscriptionBase.h" #include #include +// COMMAND CLASSES class StepCommand : public MediaCommandBase { @@ -41,3 +43,22 @@ class MoveToLevelCommand CHIP_ERROR Invoke(uint8_t level, chip::app::DataModel::Nullable transitionTime, uint8_t optionMask, uint8_t optionOverride, std::function responseCallback); }; + +// SUBSCRIBER CLASSES +class CurrentLevelSubscriber : public MediaSubscriptionBase +{ +public: + CurrentLevelSubscriber() : MediaSubscriptionBase(chip::app::Clusters::LevelControl::Id) {} +}; + +class MinLevelSubscriber : public MediaSubscriptionBase +{ +public: + MinLevelSubscriber() : MediaSubscriptionBase(chip::app::Clusters::LevelControl::Id) {} +}; + +class MaxLevelSubscriber : public MediaSubscriptionBase +{ +public: + MaxLevelSubscriber() : MediaSubscriptionBase(chip::app::Clusters::LevelControl::Id) {} +}; diff --git a/examples/tv-casting-app/tv-casting-common/include/MediaBase.h b/examples/tv-casting-app/tv-casting-common/include/MediaBase.h new file mode 100644 index 00000000000000..36861611e714cd --- /dev/null +++ b/examples/tv-casting-app/tv-casting-common/include/MediaBase.h @@ -0,0 +1,55 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include "TargetVideoPlayerInfo.h" + +#include + +class MediaBase +{ +public: + MediaBase(chip::ClusterId clusterId) { mClusterId = clusterId; } + + CHIP_ERROR SetTarget(TargetVideoPlayerInfo & targetVideoPlayerInfo, chip::EndpointId tvEndpoint) + { + auto deviceProxy = targetVideoPlayerInfo.GetOperationalDeviceProxy(); + if (deviceProxy == nullptr) + { + ChipLogError(AppServer, "Failed in getting an instance of OperationalDeviceProxy"); + return CHIP_ERROR_PEER_NODE_NOT_FOUND; + } + mTargetVideoPlayerInfo = &targetVideoPlayerInfo; + mTvEndpoint = tvEndpoint; + return CHIP_NO_ERROR; + } + + class MediaClusterBase : public chip::Controller::ClusterBase + { + public: + MediaClusterBase(chip::Messaging::ExchangeManager & exchangeManager, const chip::SessionHandle & session, + chip::ClusterId cluster, chip::EndpointId endpoint) : + ClusterBase(exchangeManager, session, cluster, endpoint) + {} + }; + +protected: + chip::ClusterId mClusterId; + TargetVideoPlayerInfo * mTargetVideoPlayerInfo = nullptr; + chip::EndpointId mTvEndpoint; +}; diff --git a/examples/tv-casting-app/tv-casting-common/include/MediaCommandBase.h b/examples/tv-casting-app/tv-casting-common/include/MediaCommandBase.h index a125f18d139f92..1b9c3d28929d3c 100644 --- a/examples/tv-casting-app/tv-casting-common/include/MediaCommandBase.h +++ b/examples/tv-casting-app/tv-casting-common/include/MediaCommandBase.h @@ -17,29 +17,15 @@ */ #pragma once -#include "TargetVideoPlayerInfo.h" +#include "MediaBase.h" -#include #include template -class MediaCommandBase +class MediaCommandBase : public MediaBase { public: - MediaCommandBase(chip::ClusterId clusterId) { mClusterId = clusterId; } - - CHIP_ERROR SetTarget(TargetVideoPlayerInfo & targetVideoPlayerInfo, chip::EndpointId tvEndpoint) - { - auto deviceProxy = targetVideoPlayerInfo.GetOperationalDeviceProxy(); - if (deviceProxy == nullptr) - { - ChipLogError(AppServer, "Failed in getting an instance of OperationalDeviceProxy"); - return CHIP_ERROR_PEER_NODE_NOT_FOUND; - } - mTargetVideoPlayerInfo = &targetVideoPlayerInfo; - mTvEndpoint = tvEndpoint; - return CHIP_NO_ERROR; - } + MediaCommandBase(chip::ClusterId clusterId) : MediaBase(clusterId) {} CHIP_ERROR Invoke(RequestType request, std::function responseCallback) { @@ -50,15 +36,6 @@ class MediaCommandBase sResponseCallback = responseCallback; - class MediaClusterBase : public chip::Controller::ClusterBase - { - public: - MediaClusterBase(chip::Messaging::ExchangeManager & exchangeManager, const chip::SessionHandle & session, - chip::ClusterId cluster, chip::EndpointId endpoint) : - ClusterBase(exchangeManager, session, cluster, endpoint) - {} - }; - MediaClusterBase cluster(*deviceProxy->GetExchangeManager(), deviceProxy->GetSecureSession().Value(), mClusterId, mTvEndpoint); return cluster.InvokeCommand(request, nullptr, OnSuccess, OnFailure); @@ -69,9 +46,6 @@ class MediaCommandBase static void OnFailure(void * context, CHIP_ERROR error) { sResponseCallback(error); } protected: - chip::ClusterId mClusterId; - TargetVideoPlayerInfo * mTargetVideoPlayerInfo = nullptr; - chip::EndpointId mTvEndpoint; static std::function sResponseCallback; }; diff --git a/examples/tv-casting-app/tv-casting-common/include/MediaPlayback.h b/examples/tv-casting-app/tv-casting-common/include/MediaPlayback.h index ca551bd5f832f5..c4d540fb353464 100644 --- a/examples/tv-casting-app/tv-casting-common/include/MediaPlayback.h +++ b/examples/tv-casting-app/tv-casting-common/include/MediaPlayback.h @@ -17,10 +17,12 @@ */ #include "MediaCommandBase.h" +#include "MediaSubscriptionBase.h" #include #include +// COMMAND CLASSES class PlayCommand : public MediaCommandBase { @@ -83,3 +85,49 @@ class SkipBackwardCommand : public MediaCommandBase responseCallback); }; + +// SUBSCRIBER CLASSES +class CurrentStateSubscriber : public MediaSubscriptionBase +{ +public: + CurrentStateSubscriber() : MediaSubscriptionBase(chip::app::Clusters::MediaPlayback::Id) {} +}; + +class StartTimeSubscriber : public MediaSubscriptionBase +{ +public: + StartTimeSubscriber() : MediaSubscriptionBase(chip::app::Clusters::MediaPlayback::Id) {} +}; + +class DurationSubscriber : public MediaSubscriptionBase +{ +public: + DurationSubscriber() : MediaSubscriptionBase(chip::app::Clusters::MediaPlayback::Id) {} +}; + +class SampledPositionSubscriber + : public MediaSubscriptionBase +{ +public: + SampledPositionSubscriber() : MediaSubscriptionBase(chip::app::Clusters::MediaPlayback::Id) {} +}; + +class PlaybackSpeedSubscriber + : public MediaSubscriptionBase +{ +public: + PlaybackSpeedSubscriber() : MediaSubscriptionBase(chip::app::Clusters::MediaPlayback::Id) {} +}; + +class SeekRangeEndSubscriber : public MediaSubscriptionBase +{ +public: + SeekRangeEndSubscriber() : MediaSubscriptionBase(chip::app::Clusters::MediaPlayback::Id) {} +}; + +class SeekRangeStartSubscriber + : public MediaSubscriptionBase +{ +public: + SeekRangeStartSubscriber() : MediaSubscriptionBase(chip::app::Clusters::MediaPlayback::Id) {} +}; diff --git a/examples/tv-casting-app/tv-casting-common/include/MediaSubscriptionBase.h b/examples/tv-casting-app/tv-casting-common/include/MediaSubscriptionBase.h new file mode 100644 index 00000000000000..e2a065ef13cdc4 --- /dev/null +++ b/examples/tv-casting-app/tv-casting-common/include/MediaSubscriptionBase.h @@ -0,0 +1,44 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include "MediaBase.h" + +template +class MediaSubscriptionBase : public MediaBase +{ +public: + MediaSubscriptionBase(chip::ClusterId clusterId) : MediaBase(clusterId) {} + + CHIP_ERROR SubscribeAttribute(void * context, + chip::Controller::ReadResponseSuccessCallback successFn, + chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, + uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) + { + VerifyOrDieWithMsg(mTargetVideoPlayerInfo != nullptr, AppServer, "Target unknown"); + + auto deviceProxy = mTargetVideoPlayerInfo->GetOperationalDeviceProxy(); + ReturnErrorCodeIf(deviceProxy == nullptr || !deviceProxy->ConnectionReady(), CHIP_ERROR_PEER_NODE_NOT_FOUND); + + MediaClusterBase cluster(*deviceProxy->GetExchangeManager(), deviceProxy->GetSecureSession().Value(), mClusterId, + mTvEndpoint); + + return cluster.template SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, + onSubscriptionEstablished); + } +}; diff --git a/examples/tv-casting-app/tv-casting-common/include/TargetNavigator.h b/examples/tv-casting-app/tv-casting-common/include/TargetNavigator.h index 731dfb78169a3e..b42d1685b183af 100644 --- a/examples/tv-casting-app/tv-casting-common/include/TargetNavigator.h +++ b/examples/tv-casting-app/tv-casting-common/include/TargetNavigator.h @@ -17,10 +17,12 @@ */ #include "MediaCommandBase.h" +#include "MediaSubscriptionBase.h" #include #include +// COMMAND CLASSES class NavigateTargetCommand : public MediaCommandBase @@ -31,3 +33,17 @@ class NavigateTargetCommand CHIP_ERROR Invoke(const uint8_t target, const chip::Optional data, std::function responseCallback); }; + +// SUBSCRIBER CLASSES +class TargetListSubscriber : public MediaSubscriptionBase +{ +public: + TargetListSubscriber() : MediaSubscriptionBase(chip::app::Clusters::TargetNavigator::Id) {} +}; + +class CurrentTargetSubscriber + : public MediaSubscriptionBase +{ +public: + CurrentTargetSubscriber() : MediaSubscriptionBase(chip::app::Clusters::TargetNavigator::Id) {} +}; diff --git a/examples/tv-casting-app/tv-casting-common/src/CastingServer.cpp b/examples/tv-casting-app/tv-casting-common/src/CastingServer.cpp index 67c5f2f9132bc5..1acc685f117cac 100644 --- a/examples/tv-casting-app/tv-casting-common/src/CastingServer.cpp +++ b/examples/tv-casting-app/tv-casting-common/src/CastingServer.cpp @@ -282,6 +282,9 @@ void CastingServer::SetDefaultFabricIndex() ChipLogError(AppServer, " -- No initialized fabrics with video players"); } +/** + * @brief Content Launcher cluster + */ CHIP_ERROR CastingServer::ContentLauncher_LaunchURL( const char * contentUrl, const char * contentDisplayStr, chip::Optional brandingInformation, @@ -299,6 +302,9 @@ CHIP_ERROR CastingServer::ContentLauncher_LaunchContent(chip::app::Clusters::Con return mLaunchContentCommand.Invoke(search, autoPlay, data, responseCallback); } +/** + * @brief Level Control cluster + */ CHIP_ERROR CastingServer::LevelControl_Step(chip::app::Clusters::LevelControl::StepMode stepMode, uint8_t stepSize, uint16_t transitionTime, uint8_t optionMask, uint8_t optionOverride, std::function responseCallback) @@ -322,6 +328,42 @@ CHIP_ERROR CastingServer::LevelControl_MoveToLevel(uint8_t level, uint16_t trans return mMoveToLevelCommand.Invoke(level, nullableTransitionTime, optionMask, optionOverride, responseCallback); } +CHIP_ERROR CastingServer::LevelControl_SubscribeToCurrentLevel( + void * context, + ReadResponseSuccessCallback successFn, + ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + SubscriptionEstablishedCallback onSubscriptionEstablished) +{ + ReturnErrorOnFailure(mCurrentLevelSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + return mCurrentLevelSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, + onSubscriptionEstablished); +} + +CHIP_ERROR CastingServer::LevelControl_SubscribeToMinLevel( + void * context, + ReadResponseSuccessCallback successFn, + ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + SubscriptionEstablishedCallback onSubscriptionEstablished) +{ + ReturnErrorOnFailure(mMinLevelSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + return mMinLevelSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, + onSubscriptionEstablished); +} + +CHIP_ERROR CastingServer::LevelControl_SubscribeToMaxLevel( + void * context, + ReadResponseSuccessCallback successFn, + ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + SubscriptionEstablishedCallback onSubscriptionEstablished) +{ + ReturnErrorOnFailure(mMaxLevelSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + return mMaxLevelSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, + onSubscriptionEstablished); +} + +/** + * @brief Media Playback cluster + */ CHIP_ERROR CastingServer::MediaPlayback_Play(std::function responseCallback) { ReturnErrorOnFailure(mPlayCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); @@ -366,6 +408,89 @@ CHIP_ERROR CastingServer::MediaPlayback_SkipBackward(uint64_t deltaPositionMilli return mSkipBackwardCommand.Invoke(deltaPositionMilliseconds, responseCallback); } +CHIP_ERROR CastingServer::MediaPlayback_SubscribeToCurrentState( + void * context, + ReadResponseSuccessCallback successFn, + ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + SubscriptionEstablishedCallback onSubscriptionEstablished) +{ + ReturnErrorOnFailure(mCurrentStateSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + return mCurrentStateSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, + onSubscriptionEstablished); +} + +CHIP_ERROR CastingServer::MediaPlayback_SubscribeToStartTime( + void * context, + ReadResponseSuccessCallback successFn, + ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + SubscriptionEstablishedCallback onSubscriptionEstablished) +{ + ReturnErrorOnFailure(mStartTimeSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + return mStartTimeSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, + onSubscriptionEstablished); +} + +CHIP_ERROR CastingServer::MediaPlayback_SubscribeToDuration( + void * context, + ReadResponseSuccessCallback successFn, + ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + SubscriptionEstablishedCallback onSubscriptionEstablished) +{ + ReturnErrorOnFailure(mDurationSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + return mDurationSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, + onSubscriptionEstablished); +} + +CHIP_ERROR CastingServer::MediaPlayback_SubscribeToSampledPosition( + void * context, + ReadResponseSuccessCallback + successFn, + ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + SubscriptionEstablishedCallback onSubscriptionEstablished) +{ + ReturnErrorOnFailure(mSampledPositionSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + return mSampledPositionSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, + onSubscriptionEstablished); +} + +CHIP_ERROR CastingServer::MediaPlayback_SubscribeToPlaybackSpeed( + void * context, + ReadResponseSuccessCallback + successFn, + ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + SubscriptionEstablishedCallback onSubscriptionEstablished) +{ + ReturnErrorOnFailure(mPlaybackSpeedSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + return mPlaybackSpeedSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, + onSubscriptionEstablished); +} + +CHIP_ERROR CastingServer::MediaPlayback_SubscribeToSeekRangeEnd( + void * context, + ReadResponseSuccessCallback successFn, + ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + SubscriptionEstablishedCallback onSubscriptionEstablished) +{ + ReturnErrorOnFailure(mSeekRangeEndSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + return mSeekRangeEndSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, + onSubscriptionEstablished); +} + +CHIP_ERROR CastingServer::MediaPlayback_SubscribeToSeekRangeStart( + void * context, + ReadResponseSuccessCallback + successFn, + ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + SubscriptionEstablishedCallback onSubscriptionEstablished) +{ + ReturnErrorOnFailure(mSeekRangeStartSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + return mSeekRangeStartSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, + onSubscriptionEstablished); +} + +/** + * @brief Application Launcher cluster + */ CHIP_ERROR CastingServer::ApplicationLauncher_LaunchApp(chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application, chip::Optional data, std::function responseCallback) @@ -390,6 +515,21 @@ CastingServer::ApplicationLauncher_HideApp(chip::app::Clusters::ApplicationLaunc return mHideAppCommand.Invoke(application, responseCallback); } +CHIP_ERROR CastingServer::ApplicationLauncher_SubscribeToCurrentApp( + void * context, + ReadResponseSuccessCallback + successFn, + ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + SubscriptionEstablishedCallback onSubscriptionEstablished) +{ + ReturnErrorOnFailure(mCurrentAppSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + return mCurrentAppSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, + onSubscriptionEstablished); +} + +/** + * @brief Target Navigator cluster + */ CHIP_ERROR CastingServer::TargetNavigator_NavigateTarget(const uint8_t target, const chip::Optional data, std::function responseCallback) { @@ -397,9 +537,56 @@ CHIP_ERROR CastingServer::TargetNavigator_NavigateTarget(const uint8_t target, c return mNavigateTargetCommand.Invoke(target, data, responseCallback); } +CHIP_ERROR CastingServer::TargetNavigator_SubscribeToTargetList( + void * context, + ReadResponseSuccessCallback successFn, + ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + SubscriptionEstablishedCallback onSubscriptionEstablished) +{ + ReturnErrorOnFailure(mTargetListSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + return mTargetListSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, + onSubscriptionEstablished); +} + +CHIP_ERROR CastingServer::TargetNavigator_SubscribeToCurrentTarget( + void * context, + ReadResponseSuccessCallback + successFn, + ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + SubscriptionEstablishedCallback onSubscriptionEstablished) +{ + ReturnErrorOnFailure(mCurrentTargetSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + return mCurrentTargetSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, + onSubscriptionEstablished); +} + +/** + * @brief Keypad Input cluster + */ CHIP_ERROR CastingServer::KeypadInput_SendKey(const chip::app::Clusters::KeypadInput::CecKeyCode keyCode, std::function responseCallback) { ReturnErrorOnFailure(mSendKeyCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); return mSendKeyCommand.Invoke(keyCode, responseCallback); } + +/** + * @brief Channel cluster + */ +CHIP_ERROR CastingServer::Channel_ChangeChannelCommand(const chip::CharSpan & match, + std::function responseCallback) +{ + ReturnErrorOnFailure(mChangeChannelCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + return mChangeChannelCommand.Invoke(match, responseCallback); +} + +CHIP_ERROR CastingServer::Channel_SubscribeToLineup( + void * context, + chip::Controller::ReadResponseSuccessCallback + successFn, + chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, + chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) +{ + ReturnErrorOnFailure(mLineupSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + return mLineupSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); +} diff --git a/examples/tv-casting-app/tv-casting-common/src/Channel.cpp b/examples/tv-casting-app/tv-casting-common/src/Channel.cpp new file mode 100644 index 00000000000000..2f11367cb2d232 --- /dev/null +++ b/examples/tv-casting-app/tv-casting-common/src/Channel.cpp @@ -0,0 +1,29 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Channel.h" + +using namespace chip; +using namespace chip::app::Clusters; + +CHIP_ERROR ChangeChannelCommand::Invoke(const CharSpan & match, std::function responseCallback) +{ + Channel::Commands::ChangeChannel::Type request; + request.match = match; + return MediaCommandBase::Invoke(request, responseCallback); +}