diff --git a/examples/tv-casting-app/APIs.md b/examples/tv-casting-app/APIs.md index 404c6d896bd118..5888972ad97e42 100644 --- a/examples/tv-casting-app/APIs.md +++ b/examples/tv-casting-app/APIs.md @@ -489,12 +489,16 @@ On Linux, the Casting Client can connect to a `CastingPlayer` by successfully calling `VerifyOrEstablishConnection` on it. ```c - +// VendorId of the Endpoint on the CastingPlayer that the CastingApp desires to interact with after connection const uint16_t kDesiredEndpointVendorId = 65521; void ConnectionHandler(CHIP_ERROR err, matter::casting::core::CastingPlayer * castingPlayer) { - ChipLogProgress(AppServer, "ConnectionHandler called with %" CHIP_ERROR_FORMAT, err.Format()); + if(err == CHIP_NO_ERROR) + { + ChipLogProgress(AppServer, "ConnectionHandler: Successfully connected to CastingPlayer(ID: %s)", castingPlayer->GetId()); + ... + } } ... @@ -509,10 +513,195 @@ targetCastingPlayer->VerifyOrEstablishConnection(ConnectionHandler, ### Select an Endpoint on the Casting Player +_{Complete Endpoint selection examples: [Linux](linux/simple-app-helper.cpp)}_ + +On a successful connection with a `CastingPlayer`, a Casting Client may select +one of the Endpoints to interact with based on its attributes (e.g. Vendor ID, +Product ID, list of supported Clusters, etc). + +On Linux, for example, it may select an Endpoint with a particular VendorID. + +```c +// VendorId of the Endpoint on the CastingPlayer that the CastingApp desires to interact with after connection +const uint16_t kDesiredEndpointVendorId = 65521; + +std::vector> endpoints = castingPlayer->GetEndpoints(); +// Find the desired Endpoint and auto-trigger some Matter Casting demo interactions +auto it = std::find_if(endpoints.begin(), endpoints.end(), + [](const matter::casting::memory::Strong & endpoint) { + return endpoint->GetVendorId() == 65521; + }); +if (it != endpoints.end()) +{ + // The desired endpoint is endpoints[index] + unsigned index = (unsigned int) std::distance(endpoints.begin(), it); + ... +} +``` + ## Interacting with a Casting Endpoint +Once the Casting Client has selected an `Endpoint`, it is ready to +[issue commands](#issuing-commands) to it, [read](#read-operations) current +playback state, and [subscribe](#subscriptions) to playback events. + +Refer to the following platform specific files for a list of clusters, command +and attributes supported by the Matter TV Casting library: + +1. Linux: + [tv-casting-common/clusters/Clusters.h](tv-casting-common/clusters/Clusters.h) + +Refer to the following platform specific files for the IDs and request / +response types to use with these APIs: + +1. Linux: + [/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h](/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h) + ### Issuing Commands +_{Complete Command invocation examples: [Linux](linux/simple-app-helper.cpp)}_ + +The Casting Client can get a reference to a `endpoint` on a `CastingPlayer`, +check if it supports the required cluster/command, and send commands to it. It +can then handle any command response / error the `CastingPlayer` sends back. + +On Linux, for example, given an `endpoint`, it can send a `LaunchURL` command +(part of the Content Launcher cluster) by calling the `Invoke` API on a +`Command` of type +`matter::casting::core::Command` + +```c +void InvokeContentLauncherLaunchURL(matter::casting::memory::Strong endpoint) +{ + // get contentLauncherCluster from the endpoint + matter::casting::memory::Strong contentLauncherCluster = + endpoint->GetCluster(); + VerifyOrReturn(contentLauncherCluster != nullptr); + + // get the launchURLCommand from the contentLauncherCluster + matter::casting::core::Command * launchURLCommand = + static_cast *>( + contentLauncherCluster->GetCommand(chip::app::Clusters::ContentLauncher::Commands::LaunchURL::Id)); + VerifyOrReturn(launchURLCommand != nullptr, ChipLogError(AppServer, "LaunchURL command not found on ContentLauncherCluster")); + + // create the LaunchURL request + chip::app::Clusters::ContentLauncher::Commands::LaunchURL::Type request; + request.contentURL = chip::CharSpan::fromCharString(kContentURL); + request.displayString = chip::Optional(chip::CharSpan::fromCharString(kContentDisplayStr)); + request.brandingInformation = + chip::MakeOptional(chip::app::Clusters::ContentLauncher::Structs::BrandingInformationStruct::Type()); + + // call Invoke on launchURLCommand while passing in success/failure callbacks + launchURLCommand->Invoke( + request, nullptr, + [](void * context, const chip::app::Clusters::ContentLauncher::Commands::LaunchURL::Type::ResponseType & response) { + ChipLogProgress(AppServer, "LaunchURL Success with response.data: %.*s", static_cast(response.data.Value().size()), + response.data.Value().data()); + }, + [](void * context, CHIP_ERROR error) { + ChipLogError(AppServer, "LaunchURL Failure with err %" CHIP_ERROR_FORMAT, error.Format()); + }, + chip::MakeOptional(kTimedInvokeCommandTimeoutMs)); // time out after kTimedInvokeCommandTimeoutMs +} +``` + ### Read Operations +_{Complete Attribute Read examples: [Linux](linux/simple-app-helper.cpp)}_ + +The `CastingClient` may read an Attribute from the `Endpoint` on the +`CastingPlayer`. It should ensure that the desired cluster / attribute are +available for reading on the endpoint before trying to read it. + +On Linux, for example, given an `endpoint`, it can read the `VendorID` (part of +the Application Basic cluster) by calling the `Read` API on an `Attribute` of +type +`matter::casting::core::Attribute` + +```c +void ReadApplicationBasicVendorID(matter::casting::memory::Strong endpoint) +{ + // get applicationBasicCluster from the endpoint + matter::casting::memory::Strong applicationBasicCluster = + endpoint->GetCluster(); + VerifyOrReturn(applicationBasicCluster != nullptr); + + // get the vendorIDAttribute from the applicationBasicCluster + matter::casting::core::Attribute * vendorIDAttribute = + static_cast *>( + applicationBasicCluster->GetAttribute(chip::app::Clusters::ApplicationBasic::Attributes::VendorID::Id)); + VerifyOrReturn(vendorIDAttribute != nullptr, + ChipLogError(AppServer, "VendorID attribute not found on ApplicationBasicCluster")); + + // call Read on vendorIDAttribute while passing in success/failure callbacks + vendorIDAttribute->Read( + nullptr, + [](void * context, + chip::Optional before, + chip::app::Clusters::ApplicationBasic::Attributes::VendorID::TypeInfo::DecodableArgType after) { + if (before.HasValue()) + { + ChipLogProgress(AppServer, "Read VendorID value: %d [Before reading value: %d]", after, before.Value()); + } + else + { + ChipLogProgress(AppServer, "Read VendorID value: %d", after); + } + }, + [](void * context, CHIP_ERROR error) { + ChipLogError(AppServer, "VendorID Read failure with err %" CHIP_ERROR_FORMAT, error.Format()); + }); +} +``` + ### Subscriptions + +_{Complete Attribute subscription examples: +[Linux](linux/simple-app-helper.cpp)}_ + +A Casting Client may subscribe to an attribute on an `Endpoint` of the +`CastingPlayer` to get data reports when the attributes change. + +On Linux, for example, given an `endpoint`, it can subscribe to the +`CurrentState` (part of the Media Playback Basic cluster) by calling the +`Subscribe` API on an `Attribute` of type +`matter::casting::core::Attribute` + +```c +void SubscribeToMediaPlaybackCurrentState(matter::casting::memory::Strong endpoint) +{ + // get mediaPlaybackCluster from the endpoint + matter::casting::memory::Strong mediaPlaybackCluster = + endpoint->GetCluster(); + VerifyOrReturn(mediaPlaybackCluster != nullptr); + + // get the currentStateAttribute from the mediaPlaybackCluster + matter::casting::core::Attribute * + currentStateAttribute = + static_cast *>( + mediaPlaybackCluster->GetAttribute(chip::app::Clusters::MediaPlayback::Attributes::CurrentState::Id)); + VerifyOrReturn(currentStateAttribute != nullptr, + ChipLogError(AppServer, "CurrentState attribute not found on MediaPlaybackCluster")); + + // call Subscribe on currentStateAttribute while passing in success/failure callbacks + currentStateAttribute->Subscribe( + nullptr, + [](void * context, + chip::Optional before, + chip::app::Clusters::MediaPlayback::Attributes::CurrentState::TypeInfo::DecodableArgType after) { + if (before.HasValue()) + { + ChipLogProgress(AppServer, "Read CurrentState value: %d [Before reading value: %d]", static_cast(after), + static_cast(before.Value())); + } + else + { + ChipLogProgress(AppServer, "Read CurrentState value: %d", static_cast(after)); + } + }, + [](void * context, CHIP_ERROR error) { + ChipLogError(AppServer, "CurrentState Read failure with err %" CHIP_ERROR_FORMAT, error.Format()); + }, + kMinIntervalFloorSeconds, kMaxIntervalCeilingSeconds); +} +``` diff --git a/examples/tv-casting-app/linux/simple-app-helper.cpp b/examples/tv-casting-app/linux/simple-app-helper.cpp index fe248c2a66d2a8..f0e7c2068883ea 100644 --- a/examples/tv-casting-app/linux/simple-app-helper.cpp +++ b/examples/tv-casting-app/linux/simple-app-helper.cpp @@ -16,7 +16,7 @@ */ #include "simple-app-helper.h" -#include "clusters/ContentLauncherCluster.h" +#include "clusters/Clusters.h" #include "app/clusters/bindings/BindingManager.h" #include @@ -61,9 +61,143 @@ void DiscoveryDelegateImpl::HandleOnUpdated(matter::casting::memory::StrongGetId()); } +void InvokeContentLauncherLaunchURL(matter::casting::memory::Strong endpoint) +{ + // get contentLauncherCluster from the endpoint + matter::casting::memory::Strong contentLauncherCluster = + endpoint->GetCluster(); + VerifyOrReturn(contentLauncherCluster != nullptr); + + // get the launchURLCommand from the contentLauncherCluster + matter::casting::core::Command * launchURLCommand = + static_cast *>( + contentLauncherCluster->GetCommand(chip::app::Clusters::ContentLauncher::Commands::LaunchURL::Id)); + VerifyOrReturn(launchURLCommand != nullptr, ChipLogError(AppServer, "LaunchURL command not found on ContentLauncherCluster")); + + // create the LaunchURL request + chip::app::Clusters::ContentLauncher::Commands::LaunchURL::Type request; + request.contentURL = chip::CharSpan::fromCharString(kContentURL); + request.displayString = chip::Optional(chip::CharSpan::fromCharString(kContentDisplayStr)); + request.brandingInformation = + chip::MakeOptional(chip::app::Clusters::ContentLauncher::Structs::BrandingInformationStruct::Type()); + + // call Invoke on launchURLCommand while passing in success/failure callbacks + launchURLCommand->Invoke( + request, nullptr, + [](void * context, const chip::app::Clusters::ContentLauncher::Commands::LaunchURL::Type::ResponseType & response) { + ChipLogProgress(AppServer, "LaunchURL Success with response.data: %.*s", static_cast(response.data.Value().size()), + response.data.Value().data()); + }, + [](void * context, CHIP_ERROR error) { + ChipLogError(AppServer, "LaunchURL Failure with err %" CHIP_ERROR_FORMAT, error.Format()); + }, + chip::MakeOptional(kTimedInvokeCommandTimeoutMs)); // time out after kTimedInvokeCommandTimeoutMs +} + +void ReadApplicationBasicVendorID(matter::casting::memory::Strong endpoint) +{ + // get applicationBasicCluster from the endpoint + matter::casting::memory::Strong applicationBasicCluster = + endpoint->GetCluster(); + VerifyOrReturn(applicationBasicCluster != nullptr); + + // get the vendorIDAttribute from the applicationBasicCluster + matter::casting::core::Attribute * vendorIDAttribute = + static_cast *>( + applicationBasicCluster->GetAttribute(chip::app::Clusters::ApplicationBasic::Attributes::VendorID::Id)); + VerifyOrReturn(vendorIDAttribute != nullptr, + ChipLogError(AppServer, "VendorID attribute not found on ApplicationBasicCluster")); + + // call Read on vendorIDAttribute while passing in success/failure callbacks + vendorIDAttribute->Read( + nullptr, + [](void * context, + chip::Optional before, + chip::app::Clusters::ApplicationBasic::Attributes::VendorID::TypeInfo::DecodableArgType after) { + if (before.HasValue()) + { + ChipLogProgress(AppServer, "Read VendorID value: %d [Before reading value: %d]", after, before.Value()); + } + else + { + ChipLogProgress(AppServer, "Read VendorID value: %d", after); + } + }, + [](void * context, CHIP_ERROR error) { + ChipLogError(AppServer, "VendorID Read failure with err %" CHIP_ERROR_FORMAT, error.Format()); + }); +} + +void SubscribeToMediaPlaybackCurrentState(matter::casting::memory::Strong endpoint) +{ + // get mediaPlaybackCluster from the endpoint + matter::casting::memory::Strong mediaPlaybackCluster = + endpoint->GetCluster(); + VerifyOrReturn(mediaPlaybackCluster != nullptr); + + // get the currentStateAttribute from the applicationBasicCluster + matter::casting::core::Attribute * + currentStateAttribute = + static_cast *>( + mediaPlaybackCluster->GetAttribute(chip::app::Clusters::MediaPlayback::Attributes::CurrentState::Id)); + VerifyOrReturn(currentStateAttribute != nullptr, + ChipLogError(AppServer, "CurrentState attribute not found on MediaPlaybackCluster")); + + // call Subscribe on currentStateAttribute while passing in success/failure callbacks + currentStateAttribute->Subscribe( + nullptr, + [](void * context, + chip::Optional before, + chip::app::Clusters::MediaPlayback::Attributes::CurrentState::TypeInfo::DecodableArgType after) { + if (before.HasValue()) + { + ChipLogProgress(AppServer, "Read CurrentState value: %d [Before reading value: %d]", static_cast(after), + static_cast(before.Value())); + } + else + { + ChipLogProgress(AppServer, "Read CurrentState value: %d", static_cast(after)); + } + }, + [](void * context, CHIP_ERROR error) { + ChipLogError(AppServer, "CurrentState Read failure with err %" CHIP_ERROR_FORMAT, error.Format()); + }, + kMinIntervalFloorSeconds, kMaxIntervalCeilingSeconds); +} + void ConnectionHandler(CHIP_ERROR err, matter::casting::core::CastingPlayer * castingPlayer) { - ChipLogProgress(AppServer, "ConnectionHandler called with %" CHIP_ERROR_FORMAT, err.Format()); + VerifyOrReturn(err == CHIP_NO_ERROR, + ChipLogProgress(AppServer, + "ConnectionHandler: Failed to connect to CastingPlayer(ID: %s) with err %" CHIP_ERROR_FORMAT, + castingPlayer->GetId(), err.Format())); + + ChipLogProgress(AppServer, "ConnectionHandler: Successfully connected to CastingPlayer(ID: %s)", castingPlayer->GetId()); + + std::vector> endpoints = castingPlayer->GetEndpoints(); + // Find the desired Endpoint and auto-trigger some Matter Casting demo interactions + auto it = std::find_if(endpoints.begin(), endpoints.end(), + [](const matter::casting::memory::Strong & endpoint) { + return endpoint->GetVendorId() == 65521; + }); + if (it != endpoints.end()) + { + // The desired endpoint is endpoints[index] + unsigned index = (unsigned int) std::distance(endpoints.begin(), it); + + // demonstrate invoking a command + InvokeContentLauncherLaunchURL(endpoints[index]); + + // demonstrate reading an attribute + ReadApplicationBasicVendorID(endpoints[index]); + + // demonstrate subscribing to an attribute + SubscribeToMediaPlaybackCurrentState(endpoints[index]); + } + else + { + ChipLogError(AppServer, "Desired Endpoint not found on the CastingPlayer(ID: %s)", castingPlayer->GetId()); + } } #if defined(ENABLE_CHIP_SHELL) diff --git a/examples/tv-casting-app/linux/simple-app-helper.h b/examples/tv-casting-app/linux/simple-app-helper.h index 9b114337d2fff1..b1dbbe60cf04b3 100644 --- a/examples/tv-casting-app/linux/simple-app-helper.h +++ b/examples/tv-casting-app/linux/simple-app-helper.h @@ -30,6 +30,15 @@ */ const uint64_t kTargetPlayerDeviceType = 35; +/** + * @brief Test values used for demo command and attribute read/subscribe calls + */ +const char kContentURL[] = "https://www.test.com/videoid"; +const char kContentDisplayStr[] = "Test video"; +const unsigned short kTimedInvokeCommandTimeoutMs = 5 * 1000; +const uint16_t kMinIntervalFloorSeconds = 0; +const uint16_t kMaxIntervalCeilingSeconds = 1; + /** * @brief Singleton that reacts to CastingPlayer discovery results */ diff --git a/examples/tv-casting-app/tv-casting-common/BUILD.gn b/examples/tv-casting-app/tv-casting-common/BUILD.gn index 697ae980e40c54..ae85e14f1030b2 100644 --- a/examples/tv-casting-app/tv-casting-common/BUILD.gn +++ b/examples/tv-casting-app/tv-casting-common/BUILD.gn @@ -93,17 +93,16 @@ chip_data_model("tv-casting-common") { # Add simplified casting API files here sources += [ - "clusters/ContentLauncherCluster.h", - "clusters/MediaPlaybackCluster.h", - "clusters/TargetNavigatorCluster.h", + "clusters/Clusters.h", "core/Attribute.h", + "core/BaseCluster.h", "core/CastingApp.cpp", "core/CastingApp.h", "core/CastingPlayer.cpp", "core/CastingPlayer.h", "core/CastingPlayerDiscovery.cpp", "core/CastingPlayerDiscovery.h", - "core/Cluster.h", + "core/Command.h", "core/Endpoint.h", "core/Types.h", "support/AppParameters.h", diff --git a/examples/tv-casting-app/tv-casting-common/clusters/Clusters.h b/examples/tv-casting-app/tv-casting-common/clusters/Clusters.h new file mode 100644 index 00000000000000..2da2f61e4825aa --- /dev/null +++ b/examples/tv-casting-app/tv-casting-common/clusters/Clusters.h @@ -0,0 +1,355 @@ +/* + * + * Copyright (c) 2023 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 "core/Attribute.h" +#include "core/Command.h" +#include "core/Endpoint.h" + +#include + +/** + * @brief This file contains classes representing all the Matter clusters supported by the Matter TV Casting library + */ +namespace matter { +namespace casting { +namespace clusters { +namespace application_basic { +class ApplicationBasicCluster : public core::BaseCluster +{ +public: + ApplicationBasicCluster(memory::Weak endpoint) : core::BaseCluster(endpoint) {} + + void SetUp() + { + ChipLogProgress(AppServer, "Setting up ApplicationBasicCluster on EndpointId: %d", GetEndpoint().lock()->GetId()); + + RegisterAttribute( + chip::app::Clusters::ApplicationBasic::Attributes::VendorName::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::ApplicationBasic::Attributes::VendorID::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::ApplicationBasic::Attributes::ApplicationName::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::ApplicationBasic::Attributes::ProductID::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::ApplicationBasic::Attributes::Application::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute(chip::app::Clusters::ApplicationBasic::Attributes::Status::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::ApplicationBasic::Attributes::ApplicationVersion::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::ApplicationBasic::Attributes::AllowedVendorList::Id, + new core::Attribute(GetEndpoint())); + } +}; +}; // namespace application_basic + +namespace application_launcher { +class ApplicationLauncherCluster : public core::BaseCluster +{ +public: + ApplicationLauncherCluster(memory::Weak endpoint) : core::BaseCluster(endpoint) {} + + void SetUp() + { + ChipLogProgress(AppServer, "Setting up ApplicationLauncherCluster on EndpointId: %d", GetEndpoint().lock()->GetId()); + + RegisterCommand(chip::app::Clusters::ApplicationLauncher::Commands::LaunchApp::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::ApplicationLauncher::Commands::StopApp::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::ApplicationLauncher::Commands::HideApp::Id, + new core::Command(GetEndpoint())); + + RegisterAttribute( + chip::app::Clusters::ApplicationLauncher::Attributes::CatalogList::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::ApplicationLauncher::Attributes::CurrentApp::Id, + new core::Attribute(GetEndpoint())); + } +}; +}; // namespace application_launcher + +namespace content_launcher { +class ContentLauncherCluster : public core::BaseCluster +{ +public: + ContentLauncherCluster(memory::Weak endpoint) : core::BaseCluster(endpoint) {} + + void SetUp() + { + ChipLogProgress(AppServer, "Setting up ContentLauncherCluster on EndpointId: %d", GetEndpoint().lock()->GetId()); + + RegisterCommand(chip::app::Clusters::ContentLauncher::Commands::LaunchURL::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::ContentLauncher::Commands::LaunchContent::Id, + new core::Command(GetEndpoint())); + + RegisterAttribute( + chip::app::Clusters::ContentLauncher::Attributes::SupportedStreamingProtocols::Id, + new core::Attribute( + GetEndpoint())); + } +}; +}; // namespace content_launcher + +namespace keypad_input { +class KeypadInputCluster : public core::BaseCluster +{ +public: + KeypadInputCluster(memory::Weak endpoint) : core::BaseCluster(endpoint) {} + + void SetUp() + { + ChipLogProgress(AppServer, "Setting up KeypadInputCluster on EndpointId: %d", GetEndpoint().lock()->GetId()); + RegisterCommand(chip::app::Clusters::KeypadInput::Commands::SendKey::Id, + new core::Command(GetEndpoint())); + } +}; +}; // namespace keypad_input + +namespace level_control { +class LevelControlCluster : public core::BaseCluster +{ +public: + LevelControlCluster(memory::Weak endpoint) : core::BaseCluster(endpoint) {} + + void SetUp() + { + ChipLogProgress(AppServer, "Setting up LevelControlCluster on EndpointId: %d", GetEndpoint().lock()->GetId()); + RegisterCommand(chip::app::Clusters::LevelControl::Commands::MoveToLevel::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::LevelControl::Commands::Move::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::LevelControl::Commands::Step::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::LevelControl::Commands::Stop::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::LevelControl::Commands::MoveToLevelWithOnOff::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::LevelControl::Commands::MoveWithOnOff::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::LevelControl::Commands::StepWithOnOff::Id, + new core::Command(GetEndpoint())); + RegisterCommand( + chip::app::Clusters::LevelControl::Commands::MoveToClosestFrequency::Id, + new core::Command(GetEndpoint())); + + RegisterAttribute( + chip::app::Clusters::LevelControl::Attributes::CurrentLevel::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::LevelControl::Attributes::RemainingTime::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute(chip::app::Clusters::LevelControl::Attributes::MinLevel::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute(chip::app::Clusters::LevelControl::Attributes::MaxLevel::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::LevelControl::Attributes::CurrentFrequency::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::LevelControl::Attributes::MinFrequency::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::LevelControl::Attributes::MaxFrequency::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute(chip::app::Clusters::LevelControl::Attributes::Options::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::LevelControl::Attributes::OnOffTransitionTime::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute(chip::app::Clusters::LevelControl::Attributes::OnLevel::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::LevelControl::Attributes::OnTransitionTime::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::LevelControl::Attributes::DefaultMoveRate::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::LevelControl::Attributes::StartUpCurrentLevel::Id, + new core::Attribute(GetEndpoint())); + } +}; +}; // namespace level_control + +namespace media_playback { +class MediaPlaybackCluster : public core::BaseCluster +{ +public: + MediaPlaybackCluster(memory::Weak endpoint) : core::BaseCluster(endpoint) {} + + void SetUp() + { + ChipLogProgress(AppServer, "Setting up MediaPlaybackCluster on EndpointId: %d", GetEndpoint().lock()->GetId()); + RegisterCommand(chip::app::Clusters::MediaPlayback::Commands::Play::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::MediaPlayback::Commands::Pause::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::MediaPlayback::Commands::Stop::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::MediaPlayback::Commands::StartOver::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::MediaPlayback::Commands::Previous::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::MediaPlayback::Commands::Next::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::MediaPlayback::Commands::Rewind::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::MediaPlayback::Commands::FastForward::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::MediaPlayback::Commands::SkipForward::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::MediaPlayback::Commands::SkipBackward::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::MediaPlayback::Commands::PlaybackResponse::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::MediaPlayback::Commands::Seek::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::MediaPlayback::Commands::ActivateAudioTrack::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::MediaPlayback::Commands::ActivateTextTrack::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::MediaPlayback::Commands::DeactivateTextTrack::Id, + new core::Command(GetEndpoint())); + + RegisterAttribute( + chip::app::Clusters::MediaPlayback::Attributes::CurrentState::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute(chip::app::Clusters::MediaPlayback::Attributes::StartTime::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute(chip::app::Clusters::MediaPlayback::Attributes::Duration::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::MediaPlayback::Attributes::SampledPosition::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::MediaPlayback::Attributes::PlaybackSpeed::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::MediaPlayback::Attributes::SeekRangeEnd::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::MediaPlayback::Attributes::SeekRangeStart::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::MediaPlayback::Attributes::ActiveAudioTrack::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::MediaPlayback::Attributes::AvailableAudioTracks::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::MediaPlayback::Attributes::ActiveTextTrack::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::MediaPlayback::Attributes::AvailableTextTracks::Id, + new core::Attribute(GetEndpoint())); + } +}; +}; // namespace media_playback + +namespace on_off { +class OnOffCluster : public core::BaseCluster +{ +public: + OnOffCluster(memory::Weak endpoint) : core::BaseCluster(endpoint) {} + + void SetUp() + { + ChipLogProgress(AppServer, "Setting up OnOffCluster on EndpointId: %d", GetEndpoint().lock()->GetId()); + + RegisterCommand(chip::app::Clusters::OnOff::Commands::Off::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::OnOff::Commands::On::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::OnOff::Commands::Toggle::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::OnOff::Commands::OffWithEffect::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::OnOff::Commands::OnWithRecallGlobalScene::Id, + new core::Command(GetEndpoint())); + RegisterCommand(chip::app::Clusters::OnOff::Commands::OnWithTimedOff::Id, + new core::Command(GetEndpoint())); + + RegisterAttribute(chip::app::Clusters::OnOff::Attributes::OnOff::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute(chip::app::Clusters::OnOff::Attributes::GlobalSceneControl::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute(chip::app::Clusters::OnOff::Attributes::OnTime::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute(chip::app::Clusters::OnOff::Attributes::OffWaitTime::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute(chip::app::Clusters::OnOff::Attributes::StartUpOnOff::Id, + new core::Attribute(GetEndpoint())); + } +}; +}; // namespace on_off + +namespace target_navigator { +class TargetNavigatorCluster : public core::BaseCluster +{ +public: + TargetNavigatorCluster(memory::Weak endpoint) : core::BaseCluster(endpoint) {} + + void SetUp() + { + ChipLogProgress(AppServer, "Setting up TargetNavigatorCluster on EndpointId: %d", GetEndpoint().lock()->GetId()); + RegisterCommand(chip::app::Clusters::TargetNavigator::Commands::NavigateTarget::Id, + new core::Command(GetEndpoint())); + + RegisterAttribute( + chip::app::Clusters::TargetNavigator::Attributes::TargetList::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::TargetNavigator::Attributes::CurrentTarget::Id, + new core::Attribute(GetEndpoint())); + } +}; +}; // namespace target_navigator + +namespace wake_on_lan { +class WakeOnLanCluster : public core::BaseCluster +{ +public: + WakeOnLanCluster(memory::Weak endpoint) : core::BaseCluster(endpoint) {} + + void SetUp() + { + ChipLogProgress(AppServer, "Setting up WakeOnLanCluster on EndpointId: %d", GetEndpoint().lock()->GetId()); + RegisterAttribute(chip::app::Clusters::WakeOnLan::Attributes::MACAddress::Id, + new core::Attribute(GetEndpoint())); + RegisterAttribute( + chip::app::Clusters::WakeOnLan::Attributes::LinkLocalAddress::Id, + new core::Attribute(GetEndpoint())); + } +}; +}; // namespace wake_on_lan + +}; // namespace clusters +}; // namespace casting +}; // namespace matter diff --git a/examples/tv-casting-app/tv-casting-common/clusters/ContentLauncherCluster.h b/examples/tv-casting-app/tv-casting-common/clusters/ContentLauncherCluster.h deleted file mode 100644 index a8d5ad847a003b..00000000000000 --- a/examples/tv-casting-app/tv-casting-common/clusters/ContentLauncherCluster.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * - * Copyright (c) 2023 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 "core/Endpoint.h" -#include "core/Types.h" - -#include "lib/support/logging/CHIPLogging.h" - -namespace matter { -namespace casting { -namespace clusters { - -class ContentLauncherCluster : public core::BaseCluster -{ -private: -protected: -public: - ContentLauncherCluster(memory::Weak endpoint) : core::BaseCluster(endpoint) {} - - // TODO: - // LaunchURL(const char * contentUrl, const char * contentDisplayStr, - // chip::Optional brandingInformation); -}; - -}; // namespace clusters -}; // namespace casting -}; // namespace matter diff --git a/examples/tv-casting-app/tv-casting-common/clusters/MediaPlaybackCluster.h b/examples/tv-casting-app/tv-casting-common/clusters/MediaPlaybackCluster.h deleted file mode 100644 index 8fe196597f001e..00000000000000 --- a/examples/tv-casting-app/tv-casting-common/clusters/MediaPlaybackCluster.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Copyright (c) 2023 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 "core/Endpoint.h" -#include "core/Types.h" - -#include "lib/support/logging/CHIPLogging.h" - -namespace matter { -namespace casting { -namespace clusters { - -class MediaPlaybackCluster : public core::BaseCluster -{ -private: -protected: -public: - MediaPlaybackCluster(memory::Weak endpoint) : core::BaseCluster(endpoint) {} - - // TODO: add commands -}; - -}; // namespace clusters -}; // namespace casting -}; // namespace matter diff --git a/examples/tv-casting-app/tv-casting-common/clusters/TargetNavigatorCluster.h b/examples/tv-casting-app/tv-casting-common/clusters/TargetNavigatorCluster.h deleted file mode 100644 index 0f03e9296d73ca..00000000000000 --- a/examples/tv-casting-app/tv-casting-common/clusters/TargetNavigatorCluster.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Copyright (c) 2023 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 "core/Endpoint.h" -#include "core/Types.h" - -#include "lib/support/logging/CHIPLogging.h" - -namespace matter { -namespace casting { -namespace clusters { - -class TargetNavigatorCluster : public core::BaseCluster -{ -private: -protected: -public: - TargetNavigatorCluster(memory::Weak endpoint) : core::BaseCluster(endpoint) {} - - // TODO: add commands -}; - -}; // namespace clusters -}; // namespace casting -}; // namespace matter diff --git a/examples/tv-casting-app/tv-casting-common/core/Attribute.h b/examples/tv-casting-app/tv-casting-common/core/Attribute.h index 5c8716967bab86..08296135afa070 100644 --- a/examples/tv-casting-app/tv-casting-common/core/Attribute.h +++ b/examples/tv-casting-app/tv-casting-common/core/Attribute.h @@ -18,41 +18,41 @@ #pragma once -#include "Cluster.h" -#include "Types.h" +#include "core/BaseCluster.h" +#include "core/Endpoint.h" #include "lib/support/logging/CHIPLogging.h" - namespace matter { namespace casting { namespace core { -enum ReadAttributeError -{ - READ_ATTRIBUTE_NO_ERROR -}; - -enum WriteAttributeError -{ - WRITE_ATTRIBUTE_NO_ERROR -}; - -template -using ReadAttributeCallback = std::function before, ValueType after, ReadAttributeError)>; - -using WriteAttributeCallback = std::function; +template +using ReadResponseSuccessCallbackFn = + std::function before, TypeInfoDecodableType after)>; +using ReadResponseFailureCallbackFn = std::function; +using WriteResponseSuccessCallbackFn = std::function; +using WriteResponseFailureCallbackFn = std::function; -class BaseCluster; +template +struct ReadAttributeContext; +template +struct WriteAttributeContext; +template +struct SubscribeAttributeContext; -template +template class Attribute { private: - memory::Weak cluster; - ValueType value; + bool hasValue = false; + typename TypeInfo::DecodableType value; + +protected: + memory::Weak GetEndpoint() const { return mEndpoint.lock(); } + memory::Weak mEndpoint; public: - Attribute(memory::Weak cluster) { this->cluster = cluster; } + Attribute(memory::Weak endpoint) { this->mEndpoint = endpoint; } ~Attribute() {} @@ -60,15 +60,349 @@ class Attribute Attribute(Attribute & other) = delete; void operator=(const Attribute &) = delete; -protected: - memory::Strong GetCluster() const { return cluster.lock(); } + chip::Optional GetValue() + { + return hasValue ? chip::MakeOptional(value) : chip::NullOptional; + } -public: - ValueType GetValue(); - void Read(ReadAttributeCallback onRead); - void Write(ValueType value, WriteAttributeCallback onWrite); - bool SubscribeAttribute(AttributeId attributeId, ReadAttributeCallback callback); - bool UnsubscribeAttribute(AttributeId attributeId, ReadAttributeCallback callback); + /** + * @brief Reads the value of the Attribute that belongs to the associated Endpoint and corresponding Cluster + * + * @param context + * @param successCb Called when the Attribute is read successfully, with the value of the attribute after reading, as well as + * before (if the Attribute had been previously read) + * @param failureCb Called when there is a failure in reading the Attribute + */ + void Read(void * context, ReadResponseSuccessCallbackFn successCb, + ReadResponseFailureCallbackFn failureCb) + { + memory::Strong endpoint = this->GetEndpoint().lock(); + if (endpoint) + { + ReadAttributeContext * attributeContext = + new ReadAttributeContext(this, endpoint, context, successCb, failureCb); + + endpoint->GetCastingPlayer()->FindOrEstablishSession( + attributeContext, + // FindOrEstablishSession success handler + [](void * _context, chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle) { + ReadAttributeContext * _attributeContext = + static_cast *>(_context); + ChipLogProgress(AppServer, "::Read() Found or established session"); + + // Read attribute + MediaClusterBase mediaClusterBase(exchangeMgr, sessionHandle, _attributeContext->mEndpoint->GetId()); + CHIP_ERROR err = mediaClusterBase.template ReadAttribute( + _attributeContext, + // Read success handler + [](void * __context, typename TypeInfo::DecodableType response) { + ReadAttributeContext * __attributeContext = + static_cast *>(__context); + ChipLogProgress(AppServer, "::Read() success"); + Attribute * __attr = static_cast *>(__attributeContext->mAttribute); + __attr->value = response; + if (__attr->hasValue) + { + __attributeContext->mSuccessCb(__attributeContext->mClientContext, + chip::MakeOptional(__attr->value), response); + } + else + { + __attr->hasValue = true; + __attributeContext->mSuccessCb(__attributeContext->mClientContext, chip::NullOptional, response); + } + delete __attributeContext; + }, + // Read failure handler + [](void * __context, CHIP_ERROR error) { + ReadAttributeContext * __attributeContext = + static_cast *>(__context); + ChipLogError(AppServer, + "::Read() failure response on EndpointId: %d with error: " + "%" CHIP_ERROR_FORMAT, + __attributeContext->mEndpoint->GetId(), error.Format()); + __attributeContext->mFailureCb(__attributeContext->mClientContext, error); + delete __attributeContext; + }); + + // error in reading the attribute + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, + "::Read() failure in reading attribute on EndpointId: %d with error: " + "%" CHIP_ERROR_FORMAT, + _attributeContext->mEndpoint->GetId(), err.Format()); + _attributeContext->mFailureCb(_attributeContext->mClientContext, err); + delete _attributeContext; + } + }, + // FindOrEstablishSession failure handler + [](void * _context, const chip::ScopedNodeId & peerId, CHIP_ERROR error) { + ReadAttributeContext * _attributeContext = + static_cast *>(_context); + ChipLogError(AppServer, + "::Read() failure in retrieving session info for peerId.nodeId: " + "0x" ChipLogFormatX64 ", peer.fabricIndex: %d with error: %" CHIP_ERROR_FORMAT, + ChipLogValueX64(peerId.GetNodeId()), peerId.GetFabricIndex(), error.Format()); + _attributeContext->mFailureCb(_attributeContext->mClientContext, error); + delete _attributeContext; + }); + } + else + { + ChipLogError(AppServer, "::Read() failure in retrieving Endpoint"); + failureCb(context, CHIP_ERROR_INCORRECT_STATE); + } + } + + /** + * @brief Writes the value of the Attribute to an associated Endpoint and corresponding Cluster + * + * @param requestData value of the Attribute to be written + * @param context + * @param successCb Called when the Attribute is written successfully + * @param failureCb Called when there is a failure in writing the Attribute + * @param aTimedWriteTimeoutMs write timeout + */ + void Write(const typename TypeInfo::Type & requestData, void * context, WriteResponseSuccessCallbackFn successCb, + WriteResponseFailureCallbackFn failureCb, const chip::Optional & aTimedWriteTimeoutMs) + { + memory::Strong endpoint = this->GetEndpoint().lock(); + if (endpoint) + { + WriteAttributeContext * attributeContext = new WriteAttributeContext( + this, endpoint, requestData, context, successCb, failureCb, aTimedWriteTimeoutMs); + + endpoint->GetCastingPlayer()->FindOrEstablishSession( + attributeContext, + // FindOrEstablishSession success handler + [](void * _context, chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle) { + WriteAttributeContext * _attributeContext = + static_cast *>(_context); + ChipLogProgress(AppServer, "::Write() Found or established session"); + + // Write attribute + MediaClusterBase mediaClusterBase(exchangeMgr, sessionHandle, _attributeContext->mEndpoint->GetId()); + CHIP_ERROR err = mediaClusterBase.template WriteAttribute( + _attributeContext->mRequestData, _attributeContext, + // Write success handler + [](void * __context) { + WriteAttributeContext * __attributeContext = + static_cast *>(__context); + ChipLogProgress(AppServer, "::Write() success"); + __attributeContext->mSuccessCb(__attributeContext->mClientContext); + delete __attributeContext; + }, + // Write failure handler + [](void * __context, CHIP_ERROR error) { + WriteAttributeContext * __attributeContext = + static_cast *>(__context); + ChipLogError(AppServer, + "::Write() failure response on EndpointId: %d with error: " + "%" CHIP_ERROR_FORMAT, + __attributeContext->mEndpoint->GetId(), error.Format()); + __attributeContext->mFailureCb(__attributeContext->mClientContext, error); + delete __attributeContext; + }, + _attributeContext->mTimedWriteTimeoutMs); + + // error in writing to the attribute + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, + "::Write() failure in reading attribute on EndpointId: %d with error: " + "%" CHIP_ERROR_FORMAT, + _attributeContext->mEndpoint->GetId(), err.Format()); + _attributeContext->mFailureCb(_attributeContext->mClientContext, err); + delete _attributeContext; + } + }, + // FindOrEstablishSession failure handler + [](void * _context, const chip::ScopedNodeId & peerId, CHIP_ERROR error) { + WriteAttributeContext * _attributeContext = + static_cast *>(_context); + ChipLogError(AppServer, + "::Write() failure in retrieving session info for peerId.nodeId: " + "0x" ChipLogFormatX64 ", peer.fabricIndex: %d with error: %" CHIP_ERROR_FORMAT, + ChipLogValueX64(peerId.GetNodeId()), peerId.GetFabricIndex(), error.Format()); + _attributeContext->mFailureCb(_attributeContext->mClientContext, error); + delete _attributeContext; + }); + } + else + { + ChipLogError(AppServer, "::Write() failure in retrieving Endpoint"); + failureCb(context, CHIP_ERROR_INCORRECT_STATE); + } + } + + /** + * @brief Subscribes to the value of the Attribute that belongs to the associated Endpoint and corresponding Cluster + * + * @param context + * @param successCb Called when the Attribute is read successfully, with the value of the attribute after reading, as well as + * before (if the Attribute had been previously read) + * @param failureCb Called when there is a failure in reading the Attribute + * @param minIntervalFloorSeconds + * @param maxIntervalCeilingSeconds + */ + void Subscribe(void * context, ReadResponseSuccessCallbackFn successCb, + ReadResponseFailureCallbackFn failureCb, uint16_t minIntervalFloorSeconds, uint16_t maxIntervalCeilingSeconds) + { + memory::Strong endpoint = this->GetEndpoint().lock(); + if (endpoint) + { + SubscribeAttributeContext * attributeContext = + new SubscribeAttributeContext(this, endpoint, context, successCb, failureCb, + minIntervalFloorSeconds, maxIntervalCeilingSeconds); + + endpoint->GetCastingPlayer()->FindOrEstablishSession( + attributeContext, + // FindOrEstablishSession success handler + [](void * _context, chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle) { + SubscribeAttributeContext * _attributeContext = + static_cast *>(_context); + ChipLogProgress(AppServer, "::Subscribe() Found or established session"); + + // Subscribe to attribute + MediaClusterBase mediaClusterBase(exchangeMgr, sessionHandle, _attributeContext->mEndpoint->GetId()); + CHIP_ERROR err = mediaClusterBase.template SubscribeAttribute( + _attributeContext, + // Subscription success handler + [](void * __context, typename TypeInfo::DecodableType response) { + SubscribeAttributeContext * __attributeContext = + static_cast *>(__context); + ChipLogProgress(AppServer, "::Subscribe() success"); + Attribute * __attr = static_cast *>(__attributeContext->mAttribute); + __attr->value = response; + if (__attr->hasValue) + { + __attributeContext->mSuccessCb(__attributeContext->mClientContext, + chip::MakeOptional(__attr->value), response); + } + else + { + __attr->hasValue = true; + __attributeContext->mSuccessCb(__attributeContext->mClientContext, chip::NullOptional, response); + } + delete __attributeContext; + }, + // Subscription failure handler + [](void * __context, CHIP_ERROR error) { + SubscribeAttributeContext * __attributeContext = + static_cast *>(__context); + ChipLogError(AppServer, + "::Subscribe() failure response on EndpointId: %d with error: " + "%" CHIP_ERROR_FORMAT, + __attributeContext->mEndpoint->GetId(), error.Format()); + __attributeContext->mFailureCb(__attributeContext->mClientContext, error); + delete __attributeContext; + }, + _attributeContext->mMinIntervalFloorSeconds, _attributeContext->mMaxIntervalCeilingSeconds, + nullptr /* SubscriptionEstablishedCallback */, nullptr /* ResubscriptionAttemptCallback */, + true /* aIsFabricFiltered */, true /* aKeepPreviousSubscriptions */); + + // error in subscribing to the attribute + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, + "::Subscribe() failure in reading attribute on EndpointId: %d with error: " + "%" CHIP_ERROR_FORMAT, + _attributeContext->mEndpoint->GetId(), err.Format()); + _attributeContext->mFailureCb(_attributeContext->mClientContext, err); + delete _attributeContext; + } + }, + // FindOrEstablishSession failure handler + [](void * _context, const chip::ScopedNodeId & peerId, CHIP_ERROR error) { + SubscribeAttributeContext * _attributeContext = + static_cast *>(_context); + ChipLogError(AppServer, + "::Subscribe() failure in retrieving session info for peerId.nodeId: " + "0x" ChipLogFormatX64 ", peer.fabricIndex: %d with error: %" CHIP_ERROR_FORMAT, + ChipLogValueX64(peerId.GetNodeId()), peerId.GetFabricIndex(), error.Format()); + _attributeContext->mFailureCb(_attributeContext->mClientContext, error); + delete _attributeContext; + }); + } + else + { + ChipLogError(AppServer, "::Subscribe() failure in retrieving Endpoint"); + failureCb(context, CHIP_ERROR_INCORRECT_STATE); + } + } +}; + +/** + * @brief Context object used by the Attribute class during the Read API's execution + */ +template +struct ReadAttributeContext +{ + ReadAttributeContext(void * attribute, memory::Strong endpoint, void * clientContext, + ReadResponseSuccessCallbackFn successCb, ReadResponseFailureCallbackFn failureCb) : + mEndpoint(endpoint), + mClientContext(clientContext), mSuccessCb(successCb), mFailureCb(failureCb) + { + mAttribute = attribute; + } + + void * mAttribute; + memory::Strong mEndpoint; + void * mClientContext; + ReadResponseSuccessCallbackFn mSuccessCb; + ReadResponseFailureCallbackFn mFailureCb; +}; + +/** + * @brief Context object used by the Attribute class during the Write API's execution + */ +template +struct WriteAttributeContext +{ + WriteAttributeContext(memory::Strong endpoint, const TypeInfoType & requestData, void * clientContext, + WriteResponseSuccessCallbackFn successCb, WriteResponseFailureCallbackFn failureCb, + const chip::Optional & timedWriteTimeoutMs) : + mEndpoint(endpoint), + mClientContext(clientContext), mSuccessCb(successCb), mFailureCb(failureCb) + { + mRequestData = requestData; + mTimedWriteTimeoutMs = timedWriteTimeoutMs; + } + + memory::Strong mEndpoint; + TypeInfoType mRequestData; + void * mClientContext; + WriteResponseSuccessCallbackFn mSuccessCb; + WriteResponseFailureCallbackFn mFailureCb; + chip::Optional & mTimedWriteTimeoutMs; +}; + +/** + * @brief Context object used by the Attribute class during the Subscribe API's execution + */ +template +struct SubscribeAttributeContext +{ + SubscribeAttributeContext(void * attribute, memory::Strong endpoint, void * clientContext, + ReadResponseSuccessCallbackFn successCb, + ReadResponseFailureCallbackFn failureCb, uint16_t minIntervalFloorSeconds, + uint16_t maxIntervalCeilingSeconds) : + mEndpoint(endpoint), + mClientContext(clientContext), mSuccessCb(successCb), mFailureCb(failureCb) + { + mAttribute = attribute; + mMinIntervalFloorSeconds = minIntervalFloorSeconds; + mMaxIntervalCeilingSeconds = maxIntervalCeilingSeconds; + } + + void * mAttribute; + memory::Strong mEndpoint; + void * mClientContext; + ReadResponseSuccessCallbackFn mSuccessCb; + ReadResponseFailureCallbackFn mFailureCb; + uint16_t mMinIntervalFloorSeconds; + uint16_t mMaxIntervalCeilingSeconds; }; }; // namespace core diff --git a/examples/tv-casting-app/tv-casting-common/core/BaseCluster.h b/examples/tv-casting-app/tv-casting-common/core/BaseCluster.h new file mode 100644 index 00000000000000..e98f690cee0087 --- /dev/null +++ b/examples/tv-casting-app/tv-casting-common/core/BaseCluster.h @@ -0,0 +1,100 @@ +/* + * + * Copyright (c) 2023 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 "Endpoint.h" +#include "Types.h" + +#include + +#include +#include +#include +#include + +namespace matter { +namespace casting { +namespace core { + +template +class Attribute; +class Endpoint; + +// Base cluster class +class BaseCluster +{ +public: + BaseCluster(memory::Weak endpoint) { this->mEndpoint = endpoint; } + + virtual ~BaseCluster() {} + + BaseCluster() = delete; + BaseCluster(BaseCluster & other) = delete; + void operator=(const BaseCluster &) = delete; + + memory::Weak GetEndpoint() const { return mEndpoint.lock(); } + + /** + * @brief Registers Commands and Attributes to this cluster + */ + virtual void SetUp() {} + + /** + * @return Pointer to the Attribute registered in this cluster, corresponding to attributeId + */ + void * GetAttribute(const chip::AttributeId attributeId) { return mAttributes[attributeId]; } + + /** + * @return Pointer to the Command registered in this cluster, corresponding to commandId + */ + void * GetCommand(const chip::CommandId commandId) { return mCommands[commandId]; } + +protected: + /** + * @brief Registers the attribute (expected to be of type Attribute *) against the attributeId in this cluster + */ + void RegisterAttribute(const chip::AttributeId attributeId, void * attribute) { mAttributes[attributeId] = attribute; } + + /** + * @brief Registers the command (expected to be of type Command *) against the commandId in this cluster + */ + void RegisterCommand(const chip::CommandId commandId, void * command) { mCommands[commandId] = command; } + + memory::Weak mEndpoint; + +private: + std::map mCommands; + std::map mAttributes; +}; + +/** + * @brief MediaClusterBase is used to invoke controller/CHIPCluster.h#ReadAttribute() API calls + */ +class MediaClusterBase : public chip::Controller::ClusterBase +{ +public: + MediaClusterBase(chip::Messaging::ExchangeManager & exchangeManager, const chip::SessionHandle & session, + chip::EndpointId endpoint) : + ClusterBase(exchangeManager, session, endpoint) + {} +}; + +}; // namespace core +}; // namespace casting +}; // namespace matter diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingApp.cpp b/examples/tv-casting-app/tv-casting-common/core/CastingApp.cpp index cf1d8b935b144d..0493c98794295e 100644 --- a/examples/tv-casting-app/tv-casting-common/core/CastingApp.cpp +++ b/examples/tv-casting-app/tv-casting-common/core/CastingApp.cpp @@ -20,6 +20,7 @@ #include "support/ChipDeviceEventHandler.h" +#include #include #include #include @@ -137,6 +138,15 @@ CHIP_ERROR CastingApp::Stop() return CHIP_ERROR_NOT_IMPLEMENTED; } +CHIP_ERROR CastingApp::ShutdownAllSubscriptions() +{ + VerifyOrReturnError(mState == CASTING_APP_RUNNING, CHIP_ERROR_INCORRECT_STATE); + + chip::app::InteractionModelEngine::GetInstance()->ShutdownAllSubscriptions(); + + return CHIP_NO_ERROR; +} + }; // namespace core }; // namespace casting }; // namespace matter diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingApp.h b/examples/tv-casting-app/tv-casting-common/core/CastingApp.h index 84bff301dfb1cf..3ac2c34b104e8b 100644 --- a/examples/tv-casting-app/tv-casting-common/core/CastingApp.h +++ b/examples/tv-casting-app/tv-casting-common/core/CastingApp.h @@ -72,6 +72,11 @@ class CastingApp */ bool isRunning() { return mState == CASTING_APP_RUNNING; } + /** + * @brief Tears down all active subscriptions. + */ + CHIP_ERROR ShutdownAllSubscriptions(); + private: CastingApp(); static CastingApp * _castingApp; diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp index 7aaf5744f2ae6a..f2fa4057855d91 100644 --- a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp +++ b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp @@ -287,7 +287,7 @@ ConnectionContext::ConnectionContext(void * clientContext, core::CastingPlayer * ChipLogError(AppServer, "Invalid ConnectionContext received in DeviceConnection success callback")); connectionContext->mTargetCastingPlayer->mConnectionState = core::CASTING_PLAYER_CONNECTED; - connectionContext->mOnDeviceConnectedFn(context, exchangeMgr, sessionHandle); + connectionContext->mOnDeviceConnectedFn(connectionContext->mClientContext, exchangeMgr, sessionHandle); delete connectionContext; }, this); diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h index 60aba39b94c254..424981eb8df0a0 100644 --- a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h +++ b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h @@ -130,6 +130,23 @@ class CastingPlayer : public std::enable_shared_from_this unsigned long long int commissioningWindowTimeoutSec = kCommissioningWindowTimeoutSec, EndpointFilter desiredEndpointFilter = EndpointFilter()); + /** + * @brief Find an existing session for this CastingPlayer, or trigger a new session + * request. + * + * The caller can optionally provide `onDeviceConnected` and `onDeviceConnectionFailure` callback + * objects. If provided, these will be used to inform the caller about + * successful or failed connection establishment. + * + * If the connection is already established, the `onDeviceConnected` callback + * will be immediately called, before FindOrEstablishSession returns. + * + * The `onDeviceConnectionFailure` callback may be called before the FindOrEstablishSession + * call returns, for error cases that are detected synchronously. + */ + void FindOrEstablishSession(void * clientContext, chip::OnDeviceConnected onDeviceConnected, + chip::OnDeviceConnectionFailure onDeviceConnectionFailure); + /** * @brief Register an endpoint on this CastingPlayer. If the provided endpoint was already registered, its information will be * updated in the registry. @@ -191,23 +208,6 @@ class CastingPlayer : public std::enable_shared_from_this chip::Inet::IPAddress * GetIpAddressForUDCRequest(); #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT - /** - * @brief Find an existing session for this CastingPlayer, or trigger a new session - * request. - * - * The caller can optionally provide `onDeviceConnected` and `onDeviceConnectionFailure` callback - * objects. If provided, these will be used to inform the caller about - * successful or failed connection establishment. - * - * If the connection is already established, the `onDeviceConnected` callback - * will be immediately called, before FindOrEstablishSession returns. - * - * The `onDeviceConnectionFailure` callback may be called before the FindOrEstablishSession - * call returns, for error cases that are detected synchronously. - */ - void FindOrEstablishSession(void * clientContext, chip::OnDeviceConnected onDeviceConnected, - chip::OnDeviceConnectionFailure onDeviceConnectionFailure); - /** * @brief Checks if the cachedCastingPlayer contains an Endpoint that matches the description of the desiredEndpointFilter * diff --git a/examples/tv-casting-app/tv-casting-common/core/Cluster.h b/examples/tv-casting-app/tv-casting-common/core/Cluster.h deleted file mode 100644 index 678e55caf4237d..00000000000000 --- a/examples/tv-casting-app/tv-casting-common/core/Cluster.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * Copyright (c) 2023 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 "Endpoint.h" -#include "Types.h" - -#include "lib/support/logging/CHIPLogging.h" - -namespace matter { -namespace casting { -namespace core { - -class Endpoint; - -// Base cluster class -class BaseCluster -{ -private: -protected: - memory::Weak mEndpoint; - -public: - BaseCluster(memory::Weak endpoint) { this->mEndpoint = endpoint; } - - virtual ~BaseCluster() {} - - BaseCluster() = delete; - BaseCluster(BaseCluster & other) = delete; - void operator=(const BaseCluster &) = delete; - -protected: - memory::Weak GetEndpoint() const { return mEndpoint.lock(); } -}; - -}; // namespace core -}; // namespace casting -}; // namespace matter diff --git a/examples/tv-casting-app/tv-casting-common/core/Command.h b/examples/tv-casting-app/tv-casting-common/core/Command.h new file mode 100644 index 00000000000000..3075053b98493a --- /dev/null +++ b/examples/tv-casting-app/tv-casting-common/core/Command.h @@ -0,0 +1,152 @@ +/* + * + * Copyright (c) 2023 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 "core/BaseCluster.h" +#include "core/Endpoint.h" + +#include "lib/support/logging/CHIPLogging.h" + +namespace matter { +namespace casting { +namespace core { +template +using CommandSuccessCallbackType = std::function; +using CommandFailureCallbackType = std::function; + +template +struct CommandContext; + +template +class Command +{ +public: + Command(memory::Weak endpoint) { this->mEndpoint = endpoint; } + + /** + * @brief Invokes this command on the associated Endpoint and corresponding Cluster + * + * @param request request data corresponding to this command invocation + * @param context + * @param successCb Called on command execution success, with responseData + * @param failureCb Called on command execution failure + * @param timedInvokeTimeoutMs command timeout + */ + void Invoke(RequestType request, void * context, CommandSuccessCallbackType successCb, + CommandFailureCallbackType failureCb, const chip::Optional & timedInvokeTimeoutMs) + { + memory::Strong endpoint = this->GetEndpoint().lock(); + if (endpoint) + { + CommandContext * commandContext = + new CommandContext(endpoint, request, context, successCb, failureCb, timedInvokeTimeoutMs); + + endpoint->GetCastingPlayer()->FindOrEstablishSession( + commandContext, + // FindOrEstablishSession success handler + [](void * _context, chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle) { + CommandContext * _commandContext = static_cast *>(_context); + ChipLogProgress(AppServer, "::Invoke() Found or established session"); + + // Invoke command + MediaClusterBase cluster(exchangeMgr, sessionHandle, _commandContext->mEndpoint->GetId()); + CHIP_ERROR err = cluster.template InvokeCommand( + _commandContext->mRequest, _commandContext, + // Command success handler + [](void * __context, const typename RequestType::ResponseType & response) { + CommandContext * __commandContext = static_cast *>(__context); + ChipLogProgress(AppServer, "::Invoke() response success"); + __commandContext->mSuccessCb(__commandContext->mClientContext, response); + delete __commandContext; + }, + // Command failure handler + [](void * __context, CHIP_ERROR error) { + CommandContext * __commandContext = static_cast *>(__context); + ChipLogError(AppServer, + "::Invoke() failure response on EndpointId: %d with error: " + "%" CHIP_ERROR_FORMAT, + __commandContext->mEndpoint->GetId(), error.Format()); + __commandContext->mFailureCb(__commandContext->mClientContext, error); + delete __commandContext; + }, + _commandContext->mTimedInvokeTimeoutMs); + + // error in invoking the command + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, + "::Invoke() failure in invoking command on EndpointId: %d with error: " + "%" CHIP_ERROR_FORMAT, + _commandContext->mEndpoint->GetId(), err.Format()); + _commandContext->mFailureCb(_commandContext->mClientContext, err); + delete _commandContext; + } + }, + // FindOrEstablishSession failure handler + [](void * _context, const chip::ScopedNodeId & peerId, CHIP_ERROR error) { + CommandContext * _commandContext = static_cast *>(_context); + ChipLogError(AppServer, + "::Invoke() failure in retrieving session info for peerId.nodeId: " + "0x" ChipLogFormatX64 ", peer.fabricIndex: %d with error: %" CHIP_ERROR_FORMAT, + ChipLogValueX64(peerId.GetNodeId()), peerId.GetFabricIndex(), error.Format()); + _commandContext->mFailureCb(_commandContext->mClientContext, error); + delete _commandContext; + }); + } + else + { + ChipLogError(AppServer, "::Invoke() failure in retrieving Endpoint"); + failureCb(context, CHIP_ERROR_INCORRECT_STATE); + } + } + +protected: + memory::Weak GetEndpoint() const { return mEndpoint.lock(); } + memory::Weak mEndpoint; +}; + +/** + * @brief Context object used by the Command class during the Invoke API's execution + */ +template +struct CommandContext +{ + CommandContext(memory::Strong endpoint, RequestType request, void * context, + CommandSuccessCallbackType successCb, CommandFailureCallbackType failureCb, + const chip::Optional & timedInvokeTimeoutMs) : + mSuccessCb(successCb), + mFailureCb(failureCb) + { + mEndpoint = endpoint; + mRequest = request; + mClientContext = context; + mTimedInvokeTimeoutMs = timedInvokeTimeoutMs; + } + + memory::Strong mEndpoint; + RequestType mRequest; + void * mClientContext; + CommandSuccessCallbackType mSuccessCb; + CommandFailureCallbackType mFailureCb; + chip::Optional mTimedInvokeTimeoutMs; +}; + +}; // namespace core +}; // namespace casting +}; // namespace matter diff --git a/examples/tv-casting-app/tv-casting-common/core/Endpoint.h b/examples/tv-casting-app/tv-casting-common/core/Endpoint.h index a481882b6de80e..c8389ba63fa2e0 100644 --- a/examples/tv-casting-app/tv-casting-common/core/Endpoint.h +++ b/examples/tv-casting-app/tv-casting-common/core/Endpoint.h @@ -18,8 +18,8 @@ #pragma once +#include "BaseCluster.h" #include "CastingPlayer.h" -#include "Cluster.h" #include "Types.h" #include "lib/support/logging/CHIPLogging.h" @@ -59,9 +59,6 @@ class Endpoint : public std::enable_shared_from_this EndpointAttributes mAttributes; std::map> mClusters; -protected: - CastingPlayer * GetCastingPlayer() const { return mCastingPlayer; } - public: Endpoint(CastingPlayer * castingPlayer, const EndpointAttributes & attributes) { @@ -75,6 +72,8 @@ class Endpoint : public std::enable_shared_from_this Endpoint(Endpoint & other) = delete; void operator=(const Endpoint &) = delete; + CastingPlayer * GetCastingPlayer() const { return mCastingPlayer; } + /** * @brief Compares based on the Id */ @@ -121,7 +120,8 @@ class Endpoint : public std::enable_shared_from_this void RegisterCluster(const chip::ClusterId clusterId) { static_assert(std::is_base_of::value, "T must be derived from BaseCluster"); - auto cluster = std::make_shared(shared_from_this()); + auto cluster = std::make_shared(shared_from_this()); + cluster->SetUp(); mClusters[clusterId] = std::static_pointer_cast(cluster); } diff --git a/examples/tv-casting-app/tv-casting-common/support/EndpointListLoader.cpp b/examples/tv-casting-app/tv-casting-common/support/EndpointListLoader.cpp index 396a3229c23e2a..d78e5790a0ceb0 100644 --- a/examples/tv-casting-app/tv-casting-common/support/EndpointListLoader.cpp +++ b/examples/tv-casting-app/tv-casting-common/support/EndpointListLoader.cpp @@ -18,14 +18,14 @@ #include "EndpointListLoader.h" -#include "clusters/ContentLauncherCluster.h" -#include "clusters/MediaPlaybackCluster.h" -#include "clusters/TargetNavigatorCluster.h" +#include "clusters/Clusters.h" +#include "core/BaseCluster.h" #include "core/CastingPlayer.h" #include "core/Types.h" #include "support/CastingStore.h" #include "app/clusters/bindings/BindingManager.h" +#include namespace matter { namespace casting { @@ -125,16 +125,40 @@ void EndpointListLoader::Complete() { switch (clusterId) { + case chip::app::Clusters::ApplicationBasic::Id: + endpoint->RegisterCluster(clusterId); + break; + + case chip::app::Clusters::ApplicationLauncher::Id: + endpoint->RegisterCluster(clusterId); + break; + case chip::app::Clusters::ContentLauncher::Id: - endpoint->RegisterCluster(clusterId); + endpoint->RegisterCluster(clusterId); + break; + + case chip::app::Clusters::KeypadInput::Id: + endpoint->RegisterCluster(clusterId); + break; + + case chip::app::Clusters::LevelControl::Id: + endpoint->RegisterCluster(clusterId); + break; + + case chip::app::Clusters::OnOff::Id: + endpoint->RegisterCluster(clusterId); break; case chip::app::Clusters::MediaPlayback::Id: - endpoint->RegisterCluster(clusterId); + endpoint->RegisterCluster(clusterId); break; case chip::app::Clusters::TargetNavigator::Id: - endpoint->RegisterCluster(clusterId); + endpoint->RegisterCluster(clusterId); + break; + + case chip::app::Clusters::WakeOnLan::Id: + endpoint->RegisterCluster(clusterId); break; default: @@ -166,7 +190,7 @@ void EndpointListLoader::Complete() CHIP_ERROR EndpointListLoader::ReadVendorId(EndpointAttributes * endpointAttributes) { - MediaClusterBase cluster(*mExchangeMgr, *mSessionHandle, endpointAttributes->mId); + core::MediaClusterBase cluster(*mExchangeMgr, *mSessionHandle, endpointAttributes->mId); return cluster.template ReadAttribute( endpointAttributes, @@ -186,7 +210,7 @@ CHIP_ERROR EndpointListLoader::ReadVendorId(EndpointAttributes * endpointAttribu CHIP_ERROR EndpointListLoader::ReadProductId(EndpointAttributes * endpointAttributes) { - MediaClusterBase cluster(*mExchangeMgr, *mSessionHandle, endpointAttributes->mId); + core::MediaClusterBase cluster(*mExchangeMgr, *mSessionHandle, endpointAttributes->mId); return cluster.template ReadAttribute( endpointAttributes, @@ -207,7 +231,7 @@ CHIP_ERROR EndpointListLoader::ReadProductId(EndpointAttributes * endpointAttrib CHIP_ERROR EndpointListLoader::ReadDeviceTypeList(EndpointAttributes * endpointAttributes) { - MediaClusterBase cluster(*mExchangeMgr, *mSessionHandle, endpointAttributes->mId); + core::MediaClusterBase cluster(*mExchangeMgr, *mSessionHandle, endpointAttributes->mId); return cluster.template ReadAttribute( endpointAttributes, @@ -233,7 +257,7 @@ CHIP_ERROR EndpointListLoader::ReadDeviceTypeList(EndpointAttributes * endpointA CHIP_ERROR EndpointListLoader::ReadServerList(std::vector * endpointServerList, chip::EndpointId endpointId) { - MediaClusterBase cluster(*mExchangeMgr, *mSessionHandle, endpointId); + core::MediaClusterBase cluster(*mExchangeMgr, *mSessionHandle, endpointId); return cluster.template ReadAttribute( endpointServerList, diff --git a/examples/tv-casting-app/tv-casting-common/support/EndpointListLoader.h b/examples/tv-casting-app/tv-casting-common/support/EndpointListLoader.h index 4905e281e94fd6..f9582a645d8ac7 100644 --- a/examples/tv-casting-app/tv-casting-common/support/EndpointListLoader.h +++ b/examples/tv-casting-app/tv-casting-common/support/EndpointListLoader.h @@ -21,14 +21,17 @@ #include "core/Endpoint.h" #include "core/Types.h" -#include #include #include namespace matter { namespace casting { -namespace support { +namespace core { +class EndpointAttributes; +}; + +namespace support { /** * @brief EndpointListLoader builds Endpoints corresponding to the CastingPlayer::GetTargetCastingPlayer by reading Bindings and * fetching Endpoint attributes (like VendorID, ProductID, DeviceTypeList, ServerList, etc). It then loads all of these Endpoints @@ -102,18 +105,6 @@ enum DesiredAttributes kTotalDesiredAttributes }; -/** - * @brief MediaClusterBase is used by the EndpointListLoader to invoke controller/CHIPCluster.h#ReadAttribute() API calls - */ -class MediaClusterBase : public chip::Controller::ClusterBase -{ -public: - MediaClusterBase(chip::Messaging::ExchangeManager & exchangeManager, const chip::SessionHandle & session, - chip::EndpointId endpoint) : - ClusterBase(exchangeManager, session, endpoint) - {} -}; - }; // namespace support }; // namespace casting }; // namespace matter