/* * * 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 "CastingServer.h" #include "ConversionUtils.h" #include "app/clusters/bindings/BindingManager.h" #include using namespace chip; using namespace chip::Controller; using namespace chip::Credentials; using namespace chip::app::Clusters::ContentLauncher::Commands; CastingServer * CastingServer::castingServer_ = nullptr; CastingServer::CastingServer() {} CastingServer * CastingServer::GetInstance() { if (castingServer_ == nullptr) { castingServer_ = new CastingServer(); } return castingServer_; } CHIP_ERROR CastingServer::PreInit(AppParams * appParams) { #if CHIP_ENABLE_ROTATING_DEVICE_ID return SetRotatingDeviceIdUniqueId(appParams != nullptr ? appParams->GetRotatingDeviceIdUniqueId() : chip::NullOptional); #else return CHIP_ERROR_NOT_IMPLEMENTED; #endif // CHIP_ENABLE_ROTATING_DEVICE_ID } CHIP_ERROR CastingServer::Init(AppParams * AppParams) { if (mInited) { return CHIP_NO_ERROR; } // Set CastingServer as AppDelegate InitAppDelegation(); // Initialize binding handlers ReturnErrorOnFailure(InitBindingHandlers()); // Set FabricDelegate chip::Server::GetInstance().GetFabricTable().AddFabricDelegate(&mPersistenceManager); // Add callback to send Content casting commands after commissioning completes ReturnErrorOnFailure(DeviceLayer::PlatformMgrImpl().AddEventHandler(DeviceEventCallback, 0)); #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT Server::GetInstance().GetUserDirectedCommissioningClient()->SetCommissionerDeclarationHandler(this); #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT mInited = true; return CHIP_NO_ERROR; } void CastingServer::InitAppDelegation() { chip::Server::Server::GetInstance().GetCommissioningWindowManager().SetAppDelegate(this); } CHIP_ERROR CastingServer::SetRotatingDeviceIdUniqueId(chip::Optional rotatingDeviceIdUniqueIdOptional) { #if CHIP_ENABLE_ROTATING_DEVICE_ID // if this class's client provided a RotatingDeviceIdUniqueId, use that if (rotatingDeviceIdUniqueIdOptional.HasValue()) { ChipLogProgress(AppServer, "Setting rotatingDeviceIdUniqueId received from client app"); return chip::DeviceLayer::ConfigurationMgr().SetRotatingDeviceIdUniqueId(rotatingDeviceIdUniqueIdOptional.Value()); } #ifdef CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID else { // otherwise, generate and set a random uniqueId for generating rotatingId ChipLogProgress(AppServer, "Setting random rotatingDeviceIdUniqueId"); uint8_t rotatingDeviceIdUniqueId[chip::DeviceLayer::ConfigurationManager::kRotatingDeviceIDUniqueIDLength]; for (size_t i = 0; i < sizeof(rotatingDeviceIdUniqueId); i++) { rotatingDeviceIdUniqueId[i] = chip::Crypto::GetRandU8(); } return chip::DeviceLayer::ConfigurationMgr().SetRotatingDeviceIdUniqueId(ByteSpan(rotatingDeviceIdUniqueId)); } #endif // CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID #endif // CHIP_ENABLE_ROTATING_DEVICE_ID return CHIP_NO_ERROR; } CHIP_ERROR CastingServer::InitBindingHandlers() { auto & server = chip::Server::GetInstance(); chip::BindingManager::GetInstance().Init( { &server.GetFabricTable(), server.GetCASESessionManager(), &server.GetPersistentStorage() }); return CHIP_NO_ERROR; } CHIP_ERROR CastingServer::TargetVideoPlayerInfoInit(NodeId nodeId, FabricIndex fabricIndex, std::function onConnectionSuccess, std::function onConnectionFailure, std::function onNewOrUpdatedEndpoint) { Init(); mOnConnectionSuccessClientCallback = onConnectionSuccess; mOnConnectionFailureClientCallback = onConnectionFailure; mOnNewOrUpdatedEndpoint = onNewOrUpdatedEndpoint; return mActiveTargetVideoPlayerInfo.Initialize(nodeId, fabricIndex, mOnConnectionSuccessClientCallback, mOnConnectionFailureClientCallback); } CHIP_ERROR CastingServer::DiscoverCommissioners(DeviceDiscoveryDelegate * deviceDiscoveryDelegate) { TargetVideoPlayerInfo * connectableVideoPlayerList = ReadCachedTargetVideoPlayerInfos(); if (connectableVideoPlayerList == nullptr || !connectableVideoPlayerList[0].IsInitialized()) { ChipLogProgress(AppServer, "No cached video players found during discovery"); } mCommissionableNodeController.RegisterDeviceDiscoveryDelegate(deviceDiscoveryDelegate); // Send discover commissioners request return mCommissionableNodeController.DiscoverCommissioners( Dnssd::DiscoveryFilter(Dnssd::DiscoveryFilterType::kDeviceType, static_cast(35))); } CHIP_ERROR CastingServer::OpenBasicCommissioningWindow(CommissioningCallbacks commissioningCallbacks, std::function onConnectionSuccess, std::function onConnectionFailure, std::function onNewOrUpdatedEndpoint) { mCommissioningCallbacks = commissioningCallbacks; mOnConnectionSuccessClientCallback = onConnectionSuccess; mOnConnectionFailureClientCallback = onConnectionFailure; mOnNewOrUpdatedEndpoint = onNewOrUpdatedEndpoint; return Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow(kCommissioningWindowTimeout); } void CastingServer::OnCommissioningSessionStarted() { ChipLogProgress(AppServer, "CastingServer::OnCommissioningSessionStarted"); if (mCommissioningCallbacks.sessionEstablished) { mCommissioningCallbacks.sessionEstablished(); } } void CastingServer::OnCommissioningSessionEstablishmentError(CHIP_ERROR err) { ChipLogProgress(AppServer, "CastingServer::OnCommissioningSessionEstablishmentError"); if (mCommissioningCallbacks.sessionEstablishmentError) { mCommissioningCallbacks.sessionEstablishmentError(err); } } void CastingServer::OnCommissioningSessionStopped() { ChipLogProgress(AppServer, "CastingServer::OnCommissioningSessionStopped"); if (mCommissioningCallbacks.sessionEstablishmentStopped) { mCommissioningCallbacks.sessionEstablishmentStopped(); } } void CastingServer::OnCommissioningSessionEstablishmentStarted() { ChipLogProgress(AppServer, "CastingServer::OnCommissioningSessionEstablishmentStarted"); if (mCommissioningCallbacks.sessionEstablishmentStarted) { mCommissioningCallbacks.sessionEstablishmentStarted(); } } #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT void CastingServer::OnCommissionerDeclarationMessage(const chip::Transport::PeerAddress & source, chip::Protocols::UserDirectedCommissioning::CommissionerDeclaration cd) { ChipLogProgress(AppServer, "CastingServer::OnCommissionerDeclarationMessage"); // TODO: call a mCommissioningCallbacks } CHIP_ERROR CastingServer::SendUserDirectedCommissioningRequest(chip::Transport::PeerAddress commissioner) { // TODO: expose options to the higher layer Protocols::UserDirectedCommissioning::IdentificationDeclaration id; if (mUdcCommissionerPasscodeEnabled) { id.SetCommissionerPasscode(true); if (mUdcCommissionerPasscodeReady) { id.SetCommissionerPasscodeReady(true); id.SetInstanceName(mUdcCommissionerPasscodeInstanceName); mUdcCommissionerPasscodeReady = false; } else { CHIP_ERROR err = app::DnssdServer::Instance().GetCommissionableInstanceName( mUdcCommissionerPasscodeInstanceName, sizeof(mUdcCommissionerPasscodeInstanceName)); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "Failed to get mdns instance name error: %" CHIP_ERROR_FORMAT, err.Format()); } else { id.SetInstanceName(mUdcCommissionerPasscodeInstanceName); } } } return Server::GetInstance().SendUserDirectedCommissioningRequest(commissioner, id); } chip::Inet::IPAddress * CastingServer::getIpAddressForUDCRequest(chip::Inet::IPAddress ipAddresses[], const size_t numIPs) { size_t ipIndexToUse = 0; for (size_t i = 0; i < numIPs; i++) { if (ipAddresses[i].IsIPv4()) { ipIndexToUse = i; ChipLogProgress(AppServer, "Found IPv4 address at index: %lu - prioritizing use of IPv4", static_cast(ipIndexToUse)); break; } if (i == (numIPs - 1)) { ChipLogProgress(AppServer, "Could not find an IPv4 address, defaulting to the first address in IP list"); } } return &ipAddresses[ipIndexToUse]; } CHIP_ERROR CastingServer::SendUserDirectedCommissioningRequest(Dnssd::CommissionNodeData * selectedCommissioner) { mUdcInProgress = true; // Send User Directed commissioning request chip::Inet::IPAddress * ipAddressToUse = getIpAddressForUDCRequest(selectedCommissioner->ipAddress, selectedCommissioner->numIPs); ReturnErrorOnFailure(SendUserDirectedCommissioningRequest( chip::Transport::PeerAddress::UDP(*ipAddressToUse, selectedCommissioner->port, selectedCommissioner->interfaceId))); mTargetVideoPlayerVendorId = selectedCommissioner->vendorId; mTargetVideoPlayerProductId = selectedCommissioner->productId; mTargetVideoPlayerDeviceType = selectedCommissioner->deviceType; mTargetVideoPlayerNumIPs = selectedCommissioner->numIPs; for (size_t i = 0; i < mTargetVideoPlayerNumIPs && i < chip::Dnssd::CommonResolutionData::kMaxIPAddresses; i++) { mTargetVideoPlayerIpAddress[i] = selectedCommissioner->ipAddress[i]; } chip::Platform::CopyString(mTargetVideoPlayerDeviceName, chip::Dnssd::kMaxDeviceNameLen + 1, selectedCommissioner->deviceName); chip::Platform::CopyString(mTargetVideoPlayerHostName, chip::Dnssd::kHostNameMaxLength + 1, selectedCommissioner->hostName); chip::Platform::CopyString(mTargetVideoPlayerInstanceName, chip::Dnssd::Commission::kInstanceNameMaxLength + 1, selectedCommissioner->instanceName); mTargetVideoPlayerPort = selectedCommissioner->port; return CHIP_NO_ERROR; } #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT const Dnssd::CommissionNodeData * CastingServer::GetDiscoveredCommissioner(int index, chip::Optional & outAssociatedConnectableVideoPlayer) { const Dnssd::CommissionNodeData * discoveredNodeData = mCommissionableNodeController.GetDiscoveredCommissioner(index); if (discoveredNodeData != nullptr) { for (size_t i = 0; i < kMaxCachedVideoPlayers && mCachedTargetVideoPlayerInfo[i].IsInitialized(); i++) { if (mCachedTargetVideoPlayerInfo[i].IsSameAs(discoveredNodeData)) { outAssociatedConnectableVideoPlayer = MakeOptional(&mCachedTargetVideoPlayerInfo[i]); } } } return discoveredNodeData; } void CastingServer::ReadServerClustersForNode(NodeId nodeId) { ChipLogProgress(NotSpecified, "ReadServerClustersForNode nodeId=0x" ChipLogFormatX64, ChipLogValueX64(nodeId)); CHIP_ERROR err = Init(); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "Init error: %" CHIP_ERROR_FORMAT, err.Format()); } for (const auto & binding : BindingTable::GetInstance()) { ChipLogProgress(NotSpecified, "Binding type=%d fab=%d nodeId=0x" ChipLogFormatX64 " groupId=%d local endpoint=%d remote endpoint=%d cluster=" ChipLogFormatMEI, binding.type, binding.fabricIndex, ChipLogValueX64(binding.nodeId), binding.groupId, binding.local, binding.remote, ChipLogValueMEI(binding.clusterId.value_or(0))); if (binding.type == MATTER_UNICAST_BINDING && nodeId == binding.nodeId) { if (!mActiveTargetVideoPlayerInfo.HasEndpoint(binding.remote)) { ReadServerClusters(binding.remote); } else { TargetEndpointInfo * endpointInfo = mActiveTargetVideoPlayerInfo.GetEndpoint(binding.remote); if (endpointInfo != nullptr && endpointInfo->IsInitialized()) { endpointInfo->PrintInfo(); } } } } } void CastingServer::ReadServerClusters(EndpointId endpointId) { const OperationalDeviceProxy * deviceProxy = mActiveTargetVideoPlayerInfo.GetOperationalDeviceProxy(); if (deviceProxy == nullptr) { ChipLogError(AppServer, "Failed in getting an instance of DeviceProxy"); return; } // GetOperationalDeviceProxy only passes us a deviceProxy if we can get a SessionHandle. chip::Controller::ClusterBase cluster(*deviceProxy->GetExchangeManager(), deviceProxy->GetSecureSession().Value(), endpointId); TargetEndpointInfo * endpointInfo = mActiveTargetVideoPlayerInfo.GetOrAddEndpoint(endpointId); if (cluster.ReadAttribute( endpointInfo, CastingServer::OnDescriptorReadSuccessResponse, CastingServer::OnDescriptorReadFailureResponse) != CHIP_NO_ERROR) { ChipLogError(Controller, "Could not read Descriptor cluster ServerList"); } ChipLogProgress(Controller, "Sent descriptor read for remote endpoint=%d", endpointId); } CHIP_ERROR CastingServer::SendWakeOnLan(TargetVideoPlayerInfo & targetVideoPlayerInfo) { return SendWakeOnLanPacket(targetVideoPlayerInfo.GetMACAddress()); } CHIP_ERROR CastingServer::ReadMACAddress(TargetEndpointInfo * endpoint) { CHIP_ERROR err = CHIP_NO_ERROR; if (endpoint != nullptr && endpoint->HasCluster(chip::app::Clusters::WakeOnLan::Id)) { // Read MAC address ChipLogProgress(AppServer, "Endpoint supports WoL. Reading Active VideoPlayer's MACAddress"); mMACAddressReader.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId()); err = mMACAddressReader.ReadAttribute( &mActiveTargetVideoPlayerInfo, [](void * context, const chip::app::Clusters::WakeOnLan::Attributes::MACAddress::TypeInfo::DecodableArgType response) { ChipLogProgress(AppServer, "Read MACAddress successfully"); TargetVideoPlayerInfo * videoPlayerInfo = static_cast(context); if (response.data() != nullptr && response.size() > 0) { videoPlayerInfo->SetMACAddress(response); ChipLogProgress(AppServer, "Updating cache of VideoPlayers with MACAddress: %.*s", static_cast(response.size()), response.data()); CHIP_ERROR error = CastingServer::GetInstance()->mPersistenceManager.AddVideoPlayer(videoPlayerInfo); if (error != CHIP_NO_ERROR) { ChipLogError(AppServer, "AddVideoPlayer(ToCache) error: %" CHIP_ERROR_FORMAT, error.Format()); } } }, [](void * context, CHIP_ERROR error) { ChipLogError(AppServer, "Failed to read MACAddress"); }); } else { err = CHIP_ERROR_INVALID_ARGUMENT; } return err; } void CastingServer::OnDescriptorReadSuccessResponse(void * context, const app::DataModel::DecodableList & responseList) { TargetEndpointInfo * endpointInfo = static_cast(context); ChipLogProgress(AppServer, "Descriptor: Default Success Response endpoint=%d", endpointInfo->GetEndpointId()); auto iter = responseList.begin(); while (iter.Next()) { auto & clusterId = iter.GetValue(); endpointInfo->AddCluster(clusterId); } // Always print the target info after handling descriptor read response // Even when we get nothing back for any reasons CastingServer::GetInstance()->mActiveTargetVideoPlayerInfo.PrintInfo(); CHIP_ERROR err = CastingServer::GetInstance()->mPersistenceManager.AddVideoPlayer( &CastingServer::GetInstance()->mActiveTargetVideoPlayerInfo); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "AddVideoPlayer(ToCache) error: %" CHIP_ERROR_FORMAT, err.Format()); } // Read WoL:MACAddress (if available from this endpoint) CastingServer::GetInstance()->ReadMACAddress(endpointInfo); if (CastingServer::GetInstance()->mOnNewOrUpdatedEndpoint) { CastingServer::GetInstance()->mOnNewOrUpdatedEndpoint(endpointInfo); } } void CastingServer::OnDescriptorReadFailureResponse(void * context, CHIP_ERROR error) { TargetEndpointInfo * endpointInfo = static_cast(context); ChipLogError(AppServer, "Descriptor: Default Failure Response: %" CHIP_ERROR_FORMAT, error.Format()); CHIP_ERROR err = CastingServer::GetInstance()->mPersistenceManager.AddVideoPlayer( &CastingServer::GetInstance()->mActiveTargetVideoPlayerInfo); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "AddVideoPlayer(ToCache) error: %" CHIP_ERROR_FORMAT, err.Format()); } if (CastingServer::GetInstance()->mOnNewOrUpdatedEndpoint) { CastingServer::GetInstance()->mOnNewOrUpdatedEndpoint(endpointInfo); } } TargetVideoPlayerInfo * CastingServer::ReadCachedTargetVideoPlayerInfos() { CHIP_ERROR err = mPersistenceManager.ReadAllVideoPlayers(mCachedTargetVideoPlayerInfo); if (err != CHIP_NO_ERROR) { ChipLogProgress(AppServer, "ReadAllVideoPlayers error: %" CHIP_ERROR_FORMAT, err.Format()); return nullptr; } return mCachedTargetVideoPlayerInfo; } void CastingServer::LogCachedVideoPlayers() { ChipLogProgress(AppServer, "CastingServer:LogCachedVideoPlayers dumping any/all cached video players."); for (size_t i = 0; i < kMaxCachedVideoPlayers && mCachedTargetVideoPlayerInfo[i].IsInitialized(); i++) { mCachedTargetVideoPlayerInfo[i].PrintInfo(); } } CHIP_ERROR CastingServer::VerifyOrEstablishConnection(TargetVideoPlayerInfo & targetVideoPlayerInfo, std::function onConnectionSuccess, std::function onConnectionFailure, std::function onNewOrUpdatedEndpoint) { LogCachedVideoPlayers(); if (!targetVideoPlayerInfo.IsInitialized()) { return CHIP_ERROR_INVALID_ARGUMENT; } mOnConnectionSuccessClientCallback = onConnectionSuccess; mOnConnectionFailureClientCallback = onConnectionFailure; mOnNewOrUpdatedEndpoint = onNewOrUpdatedEndpoint; chip::OperationalDeviceProxy * prevDeviceProxy = CastingServer::GetInstance()->mActiveTargetVideoPlayerInfo.GetOperationalDeviceProxy(); if (prevDeviceProxy != nullptr) { ChipLogProgress(AppServer, "CastingServer::VerifyOrEstablishConnection Disconnecting previous deviceProxy"); prevDeviceProxy->Disconnect(); } CastingServer::GetInstance()->mActiveTargetVideoPlayerInfo = targetVideoPlayerInfo; uint32_t delay = 0; if (targetVideoPlayerInfo.IsAsleep()) { ChipLogProgress(AppServer, "CastingServer::VerifyOrEstablishConnection(): Sending WoL to sleeping VideoPlayer and waiting"); ReturnErrorOnFailure(CastingServer::GetInstance()->SendWakeOnLan(targetVideoPlayerInfo)); #ifdef CHIP_DEVICE_CONFIG_STR_WAKE_UP_DELAY_SEC delay = CHIP_DEVICE_CONFIG_STR_WAKE_UP_DELAY_SEC * 1000; #endif } // cancel preexisting timer for VerifyOrEstablishConnectionTask, if any, and schedule the task chip::DeviceLayer::SystemLayer().CancelTimer(VerifyOrEstablishConnectionTask, nullptr); return chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Milliseconds32(delay), VerifyOrEstablishConnectionTask, nullptr); } void CastingServer::VerifyOrEstablishConnectionTask(chip::System::Layer * aSystemLayer, void * context) { ChipLogProgress(AppServer, "CastingServer::VerifyOrEstablishConnectionTask called"); CastingServer::GetInstance()->mActiveTargetVideoPlayerInfo.PrintInfo(); CHIP_ERROR err = CastingServer::GetInstance()->mActiveTargetVideoPlayerInfo.FindOrEstablishCASESession( [](TargetVideoPlayerInfo * videoPlayer) { ChipLogProgress(AppServer, "CastingServer::OnConnectionSuccess lambda called"); CastingServer::GetInstance()->mActiveTargetVideoPlayerInfo = *videoPlayer; CastingServer::GetInstance()->ReadMACAddress( videoPlayer->GetEndpoint(1)); // Read MACAddress from cached VideoPlayer endpoint (1) which supports WoL CastingServer::GetInstance()->mOnConnectionSuccessClientCallback(videoPlayer); }, [](CHIP_ERROR error) { ChipLogProgress(AppServer, "Deleting VideoPlayer from cache after connection failure: %" CHIP_ERROR_FORMAT, error.Format()); CastingServer::GetInstance()->mPersistenceManager.DeleteVideoPlayer( &CastingServer::GetInstance()->mActiveTargetVideoPlayerInfo); CastingServer::GetInstance()->mOnConnectionFailureClientCallback(error); }); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "CastingServer::VerifyOrEstablishConnectionTask FindOrEstablishCASESession failed with %" CHIP_ERROR_FORMAT, err.Format()); CastingServer::GetInstance()->mOnConnectionFailureClientCallback(err); } } CHIP_ERROR CastingServer::PurgeCache() { return mPersistenceManager.PurgeVideoPlayerCache(); } CHIP_ERROR CastingServer::AddVideoPlayer(TargetVideoPlayerInfo * targetVideoPlayerInfo) { return CastingServer::GetInstance()->mPersistenceManager.AddVideoPlayer(targetVideoPlayerInfo); } [[deprecated("Use ContentLauncher_LaunchURL(..) instead")]] CHIP_ERROR CastingServer::ContentLauncherLaunchURL(TargetEndpointInfo * endpoint, const char * contentUrl, const char * contentDisplayStr, std::function launchURLResponseCallback) { return ContentLauncher_LaunchURL(endpoint, contentUrl, contentDisplayStr, MakeOptional(chip::app::Clusters::ContentLauncher::Structs::BrandingInformationStruct::Type()), launchURLResponseCallback); } void CastingServer::DeviceEventCallback(const DeviceLayer::ChipDeviceEvent * event, intptr_t arg) { bool runPostCommissioning = false; chip::NodeId targetPeerNodeId = 0; chip::FabricIndex targetFabricIndex = 0; if (event->Type == DeviceLayer::DeviceEventType::kBindingsChangedViaCluster) { ChipLogProgress(AppServer, "CastingServer::DeviceEventCallback kBindingsChangedViaCluster received"); if (CastingServer::GetInstance()->GetActiveTargetVideoPlayer()->IsInitialized() && CastingServer::GetInstance()->GetActiveTargetVideoPlayer()->GetOperationalDeviceProxy() != nullptr) { ChipLogProgress(AppServer, "CastingServer::DeviceEventCallback already connected to video player, reading server clusters"); CastingServer::GetInstance()->ReadServerClustersForNode( CastingServer::GetInstance()->GetActiveTargetVideoPlayer()->GetNodeId()); } else if (CastingServer::GetInstance()->mUdcInProgress) { ChipLogProgress(AppServer, "CastingServer::DeviceEventCallback UDC is in progress while handling kBindingsChangedViaCluster with " "fabricIndex: %d", event->BindingsChanged.fabricIndex); CastingServer::GetInstance()->mUdcInProgress = false; // find targetPeerNodeId from binding table by matching the binding's fabricIndex with the accessing fabricIndex // received in BindingsChanged event for (const auto & binding : BindingTable::GetInstance()) { ChipLogProgress( AppServer, "CastingServer::DeviceEventCallback Read cached binding type=%d fabrixIndex=%d nodeId=0x" ChipLogFormatX64 " groupId=%d local endpoint=%d remote endpoint=%d cluster=" ChipLogFormatMEI, binding.type, binding.fabricIndex, ChipLogValueX64(binding.nodeId), binding.groupId, binding.local, binding.remote, ChipLogValueMEI(binding.clusterId.value_or(0))); if (binding.type == MATTER_UNICAST_BINDING && event->BindingsChanged.fabricIndex == binding.fabricIndex) { ChipLogProgress( NotSpecified, "CastingServer::DeviceEventCallback Matched accessingFabricIndex with nodeId=0x" ChipLogFormatX64, ChipLogValueX64(binding.nodeId)); targetPeerNodeId = binding.nodeId; targetFabricIndex = binding.fabricIndex; runPostCommissioning = true; break; } } if (targetPeerNodeId == 0 && runPostCommissioning == false) { ChipLogError(AppServer, "CastingServer::DeviceEventCallback accessingFabricIndex: %d did not match bindings", event->BindingsChanged.fabricIndex); if (CastingServer::GetInstance()->mCommissioningCallbacks.commissioningComplete) { CastingServer::GetInstance()->mCommissioningCallbacks.commissioningComplete(CHIP_ERROR_INCORRECT_STATE); } return; } } } else if (event->Type == DeviceLayer::DeviceEventType::kCommissioningComplete) { ChipLogProgress(AppServer, "CastingServer::DeviceEventCallback kCommissioningComplete received"); CastingServer::GetInstance()->mUdcInProgress = false; targetPeerNodeId = event->CommissioningComplete.nodeId; targetFabricIndex = event->CommissioningComplete.fabricIndex; runPostCommissioning = true; } if (runPostCommissioning) { ChipLogProgress(AppServer, "CastingServer::DeviceEventCallback will connect with nodeId=0x" ChipLogFormatX64 " fabricIndex=%d", ChipLogValueX64(targetPeerNodeId), targetFabricIndex); CHIP_ERROR err = CastingServer::GetInstance()->GetActiveTargetVideoPlayer()->Initialize( targetPeerNodeId, targetFabricIndex, CastingServer::GetInstance()->mOnConnectionSuccessClientCallback, CastingServer::GetInstance()->mOnConnectionFailureClientCallback, CastingServer::GetInstance()->mTargetVideoPlayerVendorId, CastingServer::GetInstance()->mTargetVideoPlayerProductId, CastingServer::GetInstance()->mTargetVideoPlayerDeviceType, CastingServer::GetInstance()->mTargetVideoPlayerDeviceName, CastingServer::GetInstance()->mTargetVideoPlayerHostName, CastingServer::GetInstance()->mTargetVideoPlayerNumIPs, CastingServer::GetInstance()->mTargetVideoPlayerIpAddress, CastingServer::GetInstance()->mTargetVideoPlayerPort, CastingServer::GetInstance()->mTargetVideoPlayerInstanceName, System::SystemClock().GetMonotonicMilliseconds64()); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "Failed to initialize target video player"); } else { // add discovery timestamp chip::System::Clock::Timestamp currentUnixTimeMS = chip::System::Clock::kZero; chip::System::SystemClock().GetClock_RealTimeMS(currentUnixTimeMS); ChipLogProgress(AppServer, "Updating discovery timestamp for VideoPlayer to %lu", static_cast(currentUnixTimeMS.count())); CastingServer::GetInstance()->mActiveTargetVideoPlayerInfo.SetLastDiscovered(currentUnixTimeMS); } err = CastingServer::GetInstance()->mPersistenceManager.AddVideoPlayer( &CastingServer::GetInstance()->mActiveTargetVideoPlayerInfo); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "AddVideoPlayer(ToCache) error: %" CHIP_ERROR_FORMAT, err.Format()); } if (CastingServer::GetInstance()->mCommissioningCallbacks.commissioningComplete) { CastingServer::GetInstance()->mCommissioningCallbacks.commissioningComplete(err); } } } // given a fabric index, try to determine the video-player nodeId by searching the binding table NodeId CastingServer::GetVideoPlayerNodeForFabricIndex(FabricIndex fabricIndex) { CHIP_ERROR err = Init(); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "GetVideoPlayerNodeForFabricIndex Init error: %" CHIP_ERROR_FORMAT, err.Format()); } for (const auto & binding : BindingTable::GetInstance()) { ChipLogProgress(NotSpecified, "Binding type=%d fab=%d nodeId=0x" ChipLogFormatX64 " groupId=%d local endpoint=%d remote endpoint=%d cluster=" ChipLogFormatMEI, binding.type, binding.fabricIndex, ChipLogValueX64(binding.nodeId), binding.groupId, binding.local, binding.remote, ChipLogValueMEI(binding.clusterId.value_or(0))); if (binding.type == MATTER_UNICAST_BINDING && fabricIndex == binding.fabricIndex) { ChipLogProgress(NotSpecified, "GetVideoPlayerNodeForFabricIndex nodeId=0x" ChipLogFormatX64, ChipLogValueX64(binding.nodeId)); return binding.nodeId; } } ChipLogProgress(NotSpecified, "GetVideoPlayerNodeForFabricIndex no bindings found for fabricIndex=%d", fabricIndex); return kUndefinedNodeId; } // given a nodeId, try to determine the video-player fabric index by searching the binding table FabricIndex CastingServer::GetVideoPlayerFabricIndexForNode(NodeId nodeId) { CHIP_ERROR err = Init(); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "GetVideoPlayerFabricIndexForNode Init error: %" CHIP_ERROR_FORMAT, err.Format()); } for (const auto & binding : BindingTable::GetInstance()) { ChipLogProgress(NotSpecified, "Binding type=%d fab=%d nodeId=0x" ChipLogFormatX64 " groupId=%d local endpoint=%d remote endpoint=%d cluster=" ChipLogFormatMEI, binding.type, binding.fabricIndex, ChipLogValueX64(binding.nodeId), binding.groupId, binding.local, binding.remote, ChipLogValueMEI(binding.clusterId.value_or(0))); if (binding.type == MATTER_UNICAST_BINDING && nodeId == binding.nodeId) { ChipLogProgress(NotSpecified, "GetVideoPlayerFabricIndexForNode fabricIndex=%d nodeId=0x" ChipLogFormatX64, binding.fabricIndex, ChipLogValueX64(binding.nodeId)); return binding.fabricIndex; } } ChipLogProgress(NotSpecified, "GetVideoPlayerFabricIndexForNode no bindings found for nodeId=0x" ChipLogFormatX64, ChipLogValueX64(nodeId)); return kUndefinedFabricIndex; } void CastingServer::SetDefaultFabricIndex(std::function onConnectionSuccess, std::function onConnectionFailure, std::function onNewOrUpdatedEndpoint) { Init(); // set fabric to be the first in the list for (const auto & fb : chip::Server::GetInstance().GetFabricTable()) { FabricIndex fabricIndex = fb.GetFabricIndex(); ChipLogError(AppServer, "Next Fabric index=%d", fabricIndex); if (!fb.IsInitialized()) { ChipLogError(AppServer, " -- Not initialized"); continue; } [[maybe_unused]] NodeId myNodeId = fb.GetNodeId(); ChipLogProgress(NotSpecified, "---- Current Fabric nodeId=0x" ChipLogFormatX64 " fabricId=0x" ChipLogFormatX64 " fabricIndex=%d", ChipLogValueX64(myNodeId), ChipLogValueX64(fb.GetFabricId()), fabricIndex); NodeId videoPlayerNodeId = GetVideoPlayerNodeForFabricIndex(fabricIndex); if (videoPlayerNodeId == kUndefinedNodeId) { // could not determine video player nodeid for this fabric continue; } mOnConnectionSuccessClientCallback = onConnectionSuccess; mOnConnectionFailureClientCallback = onConnectionFailure; mOnNewOrUpdatedEndpoint = onNewOrUpdatedEndpoint; mActiveTargetVideoPlayerInfo.Initialize(videoPlayerNodeId, fabricIndex, mOnConnectionSuccessClientCallback, mOnConnectionFailureClientCallback); return; } ChipLogError(AppServer, " -- No initialized fabrics with video players"); } void CastingServer::ShutdownAllSubscriptions() { ChipLogProgress(AppServer, "Shutting down ALL Subscriptions"); app::InteractionModelEngine::GetInstance()->ShutdownAllSubscriptions(); } void CastingServer::Disconnect() { TargetVideoPlayerInfo * currentVideoPlayer = GetActiveTargetVideoPlayer(); if (currentVideoPlayer != nullptr && currentVideoPlayer->IsInitialized()) { chip::OperationalDeviceProxy * operationalDeviceProxy = currentVideoPlayer->GetOperationalDeviceProxy(); if (operationalDeviceProxy != nullptr) { ChipLogProgress(AppServer, "Disconnecting from VideoPlayer with nodeId=0x" ChipLogFormatX64 " fabricIndex=%d", ChipLogValueX64(currentVideoPlayer->GetNodeId()), currentVideoPlayer->GetFabricIndex()); operationalDeviceProxy->Disconnect(); } } } /** * @brief Content Launcher cluster */ CHIP_ERROR CastingServer::ContentLauncher_LaunchURL( TargetEndpointInfo * endpoint, const char * contentUrl, const char * contentDisplayStr, chip::Optional brandingInformation, std::function responseCallback) { ReturnErrorOnFailure(mLaunchURLCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mLaunchURLCommand.Invoke(contentUrl, contentDisplayStr, brandingInformation, responseCallback); } CHIP_ERROR CastingServer::ContentLauncher_LaunchContent( TargetEndpointInfo * endpoint, chip::app::Clusters::ContentLauncher::Structs::ContentSearchStruct::Type search, bool autoPlay, chip::Optional data, std::function responseCallback) { ReturnErrorOnFailure(mLaunchContentCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mLaunchContentCommand.Invoke(search, autoPlay, data, responseCallback); } CHIP_ERROR CastingServer::ContentLauncher_SubscribeToAcceptHeader( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ContentLauncher::Attributes::AcceptHeader::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mAcceptHeaderSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mAcceptHeaderSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ContentLauncher_SubscribeToSupportedStreamingProtocols( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ContentLauncher::Attributes::SupportedStreamingProtocols::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mSupportedStreamingProtocolsSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mSupportedStreamingProtocolsSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } /** * @brief Level Control cluster */ CHIP_ERROR CastingServer::LevelControl_Step(TargetEndpointInfo * endpoint, chip::app::Clusters::LevelControl::StepModeEnum stepMode, uint8_t stepSize, uint16_t transitionTime, uint8_t optionMask, uint8_t optionOverride, std::function responseCallback) { ReturnErrorOnFailure(mStepCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); app::DataModel::Nullable nullableTransitionTime; nullableTransitionTime.SetNonNull(transitionTime); return mStepCommand.Invoke(stepMode, stepSize, nullableTransitionTime, optionMask, optionOverride, responseCallback); } CHIP_ERROR CastingServer::LevelControl_MoveToLevel(TargetEndpointInfo * endpoint, uint8_t level, uint16_t transitionTime, uint8_t optionMask, uint8_t optionOverride, std::function responseCallback) { ReturnErrorOnFailure(mMoveToLevelCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); app::DataModel::Nullable nullableTransitionTime; nullableTransitionTime.SetNonNull(transitionTime); return mMoveToLevelCommand.Invoke(level, nullableTransitionTime, optionMask, optionOverride, responseCallback); } CHIP_ERROR CastingServer::LevelControl_SubscribeToCurrentLevel( TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mCurrentLevelSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mCurrentLevelSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::LevelControl_SubscribeToMinLevel( TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mMinLevelSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mMinLevelSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::LevelControl_SubscribeToMaxLevel( TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mMaxLevelSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mMaxLevelSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } /** * @brief OnOff cluster */ CHIP_ERROR CastingServer::OnOff_On(TargetEndpointInfo * endpoint, std::function responseCallback) { ReturnErrorOnFailure(mOnCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mOnCommand.Invoke(responseCallback); } CHIP_ERROR CastingServer::OnOff_Off(TargetEndpointInfo * endpoint, std::function responseCallback) { ReturnErrorOnFailure(mOffCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mOffCommand.Invoke(responseCallback); } CHIP_ERROR CastingServer::OnOff_Toggle(TargetEndpointInfo * endpoint, std::function responseCallback) { ReturnErrorOnFailure(mToggleCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mToggleCommand.Invoke(responseCallback); } /** * @brief Messages cluster */ CHIP_ERROR CastingServer::Messages_PresentMessagesRequest(TargetEndpointInfo * endpoint, const char * messageText, std::function responseCallback) { ReturnErrorOnFailure(mPresentMessagesRequestCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mPresentMessagesRequestCommand.Invoke(messageText, responseCallback); } /** * @brief Media Playback cluster */ CHIP_ERROR CastingServer::MediaPlayback_Play(TargetEndpointInfo * endpoint, std::function responseCallback) { ReturnErrorOnFailure(mPlayCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mPlayCommand.Invoke(responseCallback); } CHIP_ERROR CastingServer::MediaPlayback_Pause(TargetEndpointInfo * endpoint, std::function responseCallback) { ReturnErrorOnFailure(mPauseCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mPauseCommand.Invoke(responseCallback); } CHIP_ERROR CastingServer::MediaPlayback_StopPlayback(TargetEndpointInfo * endpoint, std::function responseCallback) { ReturnErrorOnFailure(mStopPlaybackCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mStopPlaybackCommand.Invoke(responseCallback); } CHIP_ERROR CastingServer::MediaPlayback_Next(TargetEndpointInfo * endpoint, std::function responseCallback) { ReturnErrorOnFailure(mNextCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mNextCommand.Invoke(responseCallback); } CHIP_ERROR CastingServer::MediaPlayback_Previous(TargetEndpointInfo * endpoint, std::function responseCallback) { ReturnErrorOnFailure(mPreviousCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mPreviousCommand.Invoke(responseCallback); } CHIP_ERROR CastingServer::MediaPlayback_Rewind(TargetEndpointInfo * endpoint, std::function responseCallback) { ReturnErrorOnFailure(mRewindCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mRewindCommand.Invoke(responseCallback); } CHIP_ERROR CastingServer::MediaPlayback_FastForward(TargetEndpointInfo * endpoint, std::function responseCallback) { ReturnErrorOnFailure(mFastForwardCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mFastForwardCommand.Invoke(responseCallback); } CHIP_ERROR CastingServer::MediaPlayback_StartOver(TargetEndpointInfo * endpoint, std::function responseCallback) { ReturnErrorOnFailure(mStartOverCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mStartOverCommand.Invoke(responseCallback); } CHIP_ERROR CastingServer::MediaPlayback_Seek(TargetEndpointInfo * endpoint, uint64_t position, std::function responseCallback) { ReturnErrorOnFailure(mSeekCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mSeekCommand.Invoke(position, responseCallback); } CHIP_ERROR CastingServer::MediaPlayback_SkipForward(TargetEndpointInfo * endpoint, uint64_t deltaPositionMilliseconds, std::function responseCallback) { ReturnErrorOnFailure(mSkipForwardCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mSkipForwardCommand.Invoke(deltaPositionMilliseconds, responseCallback); } CHIP_ERROR CastingServer::MediaPlayback_SkipBackward(TargetEndpointInfo * endpoint, uint64_t deltaPositionMilliseconds, std::function responseCallback) { ReturnErrorOnFailure(mSkipBackwardCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mSkipBackwardCommand.Invoke(deltaPositionMilliseconds, responseCallback); } CHIP_ERROR CastingServer::MediaPlayback_SubscribeToCurrentState( TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mCurrentStateSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mCurrentStateSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::MediaPlayback_SubscribeToStartTime( TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mStartTimeSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mStartTimeSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::MediaPlayback_SubscribeToDuration( TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mDurationSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mDurationSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::MediaPlayback_SubscribeToSampledPosition( TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mSampledPositionSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mSampledPositionSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::MediaPlayback_SubscribeToPlaybackSpeed( TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mPlaybackSpeedSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mPlaybackSpeedSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::MediaPlayback_SubscribeToSeekRangeEnd( TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mSeekRangeEndSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mSeekRangeEndSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::MediaPlayback_SubscribeToSeekRangeStart( TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mSeekRangeStartSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mSeekRangeStartSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } /** * @brief Application Launcher cluster */ CHIP_ERROR CastingServer::ApplicationLauncher_LaunchApp(TargetEndpointInfo * endpoint, chip::app::Clusters::ApplicationLauncher::Structs::ApplicationStruct::Type application, chip::Optional data, std::function responseCallback) { ReturnErrorOnFailure(mLaunchAppCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mLaunchAppCommand.Invoke(application, data, responseCallback); } CHIP_ERROR CastingServer::ApplicationLauncher_StopApp(TargetEndpointInfo * endpoint, chip::app::Clusters::ApplicationLauncher::Structs::ApplicationStruct::Type application, std::function responseCallback) { ReturnErrorOnFailure(mStopAppCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mStopAppCommand.Invoke(application, responseCallback); } CHIP_ERROR CastingServer::ApplicationLauncher_HideApp(TargetEndpointInfo * endpoint, chip::app::Clusters::ApplicationLauncher::Structs::ApplicationStruct::Type application, std::function responseCallback) { ReturnErrorOnFailure(mHideAppCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mHideAppCommand.Invoke(application, responseCallback); } CHIP_ERROR CastingServer::ApplicationLauncher_SubscribeToCurrentApp( TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mCurrentAppSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mCurrentAppSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } /** * @brief Target Navigator cluster */ CHIP_ERROR CastingServer::TargetNavigator_NavigateTarget(TargetEndpointInfo * endpoint, const uint8_t target, const chip::Optional data, std::function responseCallback) { ReturnErrorOnFailure(mNavigateTargetCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mNavigateTargetCommand.Invoke(target, data, responseCallback); } CHIP_ERROR CastingServer::TargetNavigator_SubscribeToTargetList( TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mTargetListSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mTargetListSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::TargetNavigator_SubscribeToCurrentTarget( TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mCurrentTargetSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mCurrentTargetSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } /** * @brief Keypad Input cluster */ CHIP_ERROR CastingServer::KeypadInput_SendKey(TargetEndpointInfo * endpoint, const chip::app::Clusters::KeypadInput::CECKeyCodeEnum keyCode, std::function responseCallback) { ReturnErrorOnFailure(mSendKeyCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mSendKeyCommand.Invoke(keyCode, responseCallback); } /** * @brief Application Basic cluster */ CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToVendorName( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::VendorName::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mVendorNameSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mVendorNameSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToVendorID( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::VendorID::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mVendorIDSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mVendorIDSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToApplicationName( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::ApplicationName::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mApplicationNameSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mApplicationNameSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToProductID( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::ProductID::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mProductIDSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mProductIDSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToApplication( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::Application::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mApplicationSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mApplicationSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToStatus( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::Status::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mStatusSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mStatusSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToApplicationVersion( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::ApplicationVersion::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mApplicationVersionSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mApplicationVersionSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToAllowedVendorList( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::AllowedVendorList::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mAllowedVendorListSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mAllowedVendorListSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ApplicationBasic_ReadVendorName( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::VendorName::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn) { ReturnErrorOnFailure(mVendorNameReader.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mVendorNameReader.ReadAttribute(context, successFn, failureFn); } CHIP_ERROR CastingServer::ApplicationBasic_ReadVendorID( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::VendorID::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn) { ReturnErrorOnFailure(mVendorIDReader.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mVendorIDReader.ReadAttribute(context, successFn, failureFn); } CHIP_ERROR CastingServer::ApplicationBasic_ReadApplicationName( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::ApplicationName::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn) { ReturnErrorOnFailure(mApplicationNameReader.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mApplicationNameReader.ReadAttribute(context, successFn, failureFn); } CHIP_ERROR CastingServer::ApplicationBasic_ReadProductID( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::ProductID::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn) { ReturnErrorOnFailure(mProductIDReader.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mProductIDReader.ReadAttribute(context, successFn, failureFn); } CHIP_ERROR CastingServer::ApplicationBasic_ReadApplication( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::Application::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn) { ReturnErrorOnFailure(mApplicationReader.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mApplicationReader.ReadAttribute(context, successFn, failureFn); } CHIP_ERROR CastingServer::ApplicationBasic_ReadStatus( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::Status::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn) { ReturnErrorOnFailure(mStatusReader.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mStatusReader.ReadAttribute(context, successFn, failureFn); } CHIP_ERROR CastingServer::ApplicationBasic_ReadApplicationVersion( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::ApplicationVersion::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn) { ReturnErrorOnFailure(mApplicationVersionReader.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mApplicationVersionReader.ReadAttribute(context, successFn, failureFn); } CHIP_ERROR CastingServer::ApplicationBasic_ReadAllowedVendorList( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::AllowedVendorList::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn) { ReturnErrorOnFailure(mAllowedVendorListReader.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mAllowedVendorListReader.ReadAttribute(context, successFn, failureFn); } /* * @brief Channel cluster */ CHIP_ERROR CastingServer::Channel_ChangeChannelCommand(TargetEndpointInfo * endpoint, const chip::CharSpan & match, std::function responseCallback) { ReturnErrorOnFailure(mChangeChannelCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mChangeChannelCommand.Invoke(match, responseCallback); } CHIP_ERROR CastingServer::Channel_SubscribeToLineup( TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { ReturnErrorOnFailure(mLineupSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mLineupSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); }