From 40fee02e572a8bef027c20a70c04be0f3f63d5e4 Mon Sep 17 00:00:00 2001 From: Sayon Deep Date: Wed, 26 Feb 2025 16:13:44 +0530 Subject: [PATCH 01/22] initial implementation of pushav server --- src/app/chip_data_model.gni | 1 + .../push-av-stream-transport-server.cpp | 369 ++++++++++++++++++ .../push-av-stream-transport-server.h | 290 ++++++++++++++ src/app/common/templates/config-data.yaml | 1 + src/app/zap_cluster_list.json | 4 +- .../app-common/zap-generated/callback.h | 53 +++ 6 files changed, 717 insertions(+), 1 deletion(-) create mode 100644 src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp create mode 100644 src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni index ccdf551fc9e267..846827c7663b49 100644 --- a/src/app/chip_data_model.gni +++ b/src/app/chip_data_model.gni @@ -468,6 +468,7 @@ template("chip_data_model") { "${_app_root}/clusters/${cluster}/closure-control-cluster-objects.h", ] } else if (cluster == "camera-av-stream-management-server") { + } else if (cluster == "push-av-stream-transport-server") { sources += [ "${_app_root}/clusters/${cluster}/${cluster}.cpp", "${_app_root}/clusters/${cluster}/${cluster}.h", diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp new file mode 100644 index 00000000000000..f8d58ec89f5111 --- /dev/null +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp @@ -0,0 +1,369 @@ +/** + * + * Copyright (c) 2025 Project CHIP Authors + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_PUSH_TRANSPORT_CONNECTION_ID 65535 + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::PushAvStreamTransport; +using namespace chip::app::Clusters::PushAvStreamTransport::Structs; +using namespace chip::app::Clusters::PushAvStreamTransport::Attributes; +using namespace Protocols::InteractionModel; + +namespace chip { +namespace app { +namespace Clusters { +namespace PushAvStreamTransport { + +PushAvStreamTransportServer::PushAvStreamTransportServer(EndpointId aEndpointId, PushAvStreamTransportDelegate & aDelegate, + const BitFlags aFeature, + PersistentStorageDelegate & aPersistentStorage) : + CommandHandlerInterface(MakeOptional(aEndpointId), CameraAvStreamManagement::Id), + AttributeAccessInterface(MakeOptional(aEndpointId), CameraAvStreamManagement::Id), mDelegate(aDelegate), + mEndpointId(aEndpointId), mFeature(aFeature) +{ + mDelegate.SetPushAvStreamTransportServer(this); +} + +PushAvStreamTransportServer::~PushAvStreamTransportServer() +{ + // Explicitly set the PushAvStreamTransportServer pointer in the Delegate to null. + + mDelegate.SetPushAvStreamTransportServer(nullptr); + + // Unregister command handler and attribute access interfaces + CommandHandlerInterfaceRegistry::Instance().UnregisterCommandHandler(this); + AttributeAccessInterfaceRegistry::Instance().Unregister(this); +} + +CHIP_ERROR PushAvStreamTransportServer::Init() +{ + LoadPersistentAttributes(); + + VerifyOrReturnError(AttributeAccessInterfaceRegistry::Instance().Register(this), CHIP_ERROR_INTERNAL); + ReturnErrorOnFailure(CommandHandlerInterfaceRegistry::Instance().RegisterCommandHandler(this)); + return CHIP_NO_ERROR; +} + +bool PushAvStreamTransportServer::HasFeature(Feature feature) const +{ + return mFeature.Has(feature); +} + +CHIP_ERROR PushAvStreamTransportServer::ReadAndEncodeCurrentConnections(const AttributeValueEncoder::ListEncodeHelper & encoder) +{ + for (const auto & currentConnections : mCurrentConnections) + { + ReturnErrorOnFailure(encoder.Encode(currentConnections)); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR PushAvStreamTransportServer::AddStreamTransportConnection(const uint16_t transportConnectionId) +{ + mCurrentConnections.push_back(transportConnectionId); + auto path = ConcreteAttributePath(mEndpointId, PushAvStreamTransport::Id, Attributes::CurrentConnections::Id); + mDelegate.OnAttributeChanged(Attributes::CurrentConnections::Id); + MatterReportingAttributeChangeCallback(path); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR PushAvStreamTransportServer::RemoveStreamTransportConnection(const uint16_t transportConnectionId) +{ + mCurrentConnections.erase(std::remove_if(mCurrentConnections.begin(), mCurrentConnections.end(), + [&](const uint16_t connectionID) { return connectionID == transportConnectionId; }), + mCurrentConnections.end()); + auto path = ConcreteAttributePath(mEndpointId, PushAvStreamTransport::Id, Attributes::CurrentConnections::Id); + mDelegate.OnAttributeChanged(Attributes::CurrentConnections::Id); + MatterReportingAttributeChangeCallback(path); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR PushAvStreamTransportServer::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) +{ + VerifyOrDie(aPath.mClusterId == PushAvStreamTransport::Id); + ChipLogError(Zcl, "Push AV Stream Transport: Reading"); + + switch (aPath.mAttributeId) + { + case FeatureMap::Id: + ReturnErrorOnFailure(aEncoder.Encode(mFeature)); + break; + + case SupportedContainerFormats::Id: + ReturnErrorOnFailure(aEncoder.Encode(mSupportedContainerFormats)); + break; + + case SupportedIngestMethods::Id: + ReturnErrorOnFailure(aEncoder.Encode(mSupportedIngestMethods)); + break; + + case CurrentConnections::Id: + ReturnErrorOnFailure(aEncoder.EncodeList( + [this](const auto & encoder) -> CHIP_ERROR { return this->ReadAndEncodeCurrentConnections(encoder); })); + break; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR PushAvStreamTransportServer::Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) +{ + VerifyOrDie(aPath.mClusterId == PushAvStreamTransport::Id); + + return CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute); +} + +void PushAvStreamTransportServer::LoadPersistentAttributes() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + // Load currentConnections + mDelegate.LoadCurrentConnections(mCurrentConnections); + + // Signal delegate that all persistent configuration attributes have been loaded. + mDelegate.PersistentAttributesLoadedCallback(); +} + +// CommandHandlerInterface +void PushAvStreamTransportServer::InvokeCommand(HandlerContext & handlerContext) +{ + ChipLogDetail(Zcl, "PushAV: InvokeCommand"); + switch (handlerContext.mRequestPath.mCommandId) + { + case Commands::AllocatePushTransport::Id: + ChipLogDetail(Zcl, "PushAVStreamTransport: Allocating Push Transport"); + + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandleAllocatePushTransport(ctx, commandData); }); + + break; + + case Commands::DeallocatePushTransport::Id: + ChipLogDetail(Zcl, "PushAVStreamTransport: Deallocating Push Transport"); + + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandleDeallocatePushTransport(ctx, commandData); }); + + break; + + case Commands::ModifyPushTransport::Id: + ChipLogDetail(Zcl, "PushAVStreamTransport: Modifying Push Transport"); + + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandleModifyPushTransport(ctx, commandData); }); + + break; + + case Commands::SetTransportStatus::Id: + ChipLogDetail(Zcl, "PushAVStreamTransport: Setting Push Transport Status"); + + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandleSetTransportStatus(ctx, commandData); }); + + break; + + case Commands::ManuallyTriggerTransport::Id: + ChipLogDetail(Zcl, "PushAVStreamTransport: Manually Triggered Push Transport"); + + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandleManuallyTriggerTransport(ctx, commandData); }); + + break; + + case Commands::FindTransport::Id: + ChipLogDetail(Zcl, "PushAVStreamTransport: Finding Push Transport"); + + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandleFindTransport(ctx, commandData); }); + + break; + } +} + +bool PushAvStreamTransportServer::FindStreamTransportConnection(const uint16_t connectionID) +{ + for (auto & id : mCurrentConnections) + { + if (id == connectionID) + return true; + } + return false; +} + +uint16_t PushAvStreamTransportServer::GenerateConnectionID() +{ + static uint16_t assignedConnectionID = 0; + uint16_t nextConnectionID; + + if (assignedConnectionID == MAX_PUSH_TRANSPORT_CONNECTION_ID) + nextConnectionID = 0; + else + nextConnectionID = assignedConnectionID + 1; + + while (FindStreamTransportConnection(nextConnectionID) != false) + { + if (nextConnectionID == MAX_PUSH_TRANSPORT_CONNECTION_ID) + nextConnectionID = 0; + else + nextConnectionID = nextConnectionID + 1; + } + return nextConnectionID; +} + +void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & ctx, + const Commands::AllocatePushTransport::DecodableType & commandData) +{ + Status status = Status::Success; + Commands::AllocatePushTransportResponse::Type response; + auto & transportOptions = commandData.transportOptions; + + uint16_t connectionID = GenerateConnectionID(); + TransportStatusEnum outTranportStatus = TransportStatusEnum::kUnknownEnumValue; + + // call the delegate + status = mDelegate.AllocatePushTransport(connectionID, transportOptions, outTranportStatus); + + if (status == Status::Success) + { + response.connectionID = connectionID; + response.transportOptions = transportOptions; + response.transportStatus = outTranportStatus; + + // add connection to CurrentConnections + AddStreamTransportConnection(connectionID); + + ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); + } + else + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); + } +} + +void PushAvStreamTransportServer::HandleDeallocatePushTransport( + HandlerContext & ctx, const Commands::DeallocatePushTransport::DecodableType & commandData) +{ + Status status = Status::Success; + uint16_t connectionID = commandData.connectionID; + + // Call the delegate + status = mDelegate.DeallocatePushTransport(connectionID); + + if (status == Status::Success) + // Remove connection form CurrentConnections + RemoveStreamTransportConnection(connectionID); + + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void PushAvStreamTransportServer::HandleModifyPushTransport(HandlerContext & ctx, + const Commands::ModifyPushTransport::DecodableType & commandData) +{ + Status status = Status::Success; + uint16_t connectionID = commandData.connectionID; + auto & outTransportOptions = commandData.transportOptions; + + // Call the delegate + status = mDelegate.ModifyPushTransport(connectionID, outTransportOptions); + + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void PushAvStreamTransportServer::HandleSetTransportStatus(HandlerContext & ctx, + const Commands::SetTransportStatus::DecodableType & commandData) +{ + Status status = Status::Success; + uint16_t connectionID = commandData.connectionID; + auto & transportOptions = commandData.transportOptions; + + // Call the delegate + status = mDelegate.SetTransportStatus(connectionID, transportOptions); + + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void PushAvStreamTransportServer::HandleManuallyTriggerTransport( + HandlerContext & ctx, const Commands::ManuallyTriggerTransport::DecodableType & commandData) +{ + Status status = Status::Success; + uint16_t connectionID = commandData.connectionID; + auto & activationReason = commandData.activationReason; + auto & timeControl = commandData.timeControl; + + // Call the delegate + status = mDelegate.ManuallyTriggerTransport(connectionID, activationReason, timeControl); + + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void PushAvStreamTransportServer::HandleFindTransport(HandlerContext & ctx, + const Commands::FindTransport::DecodableType & commandData) +{ + Status status = Status::Success; + Commands::FindTransportResponse::Type response; + + Optional> connectionID = commandData.connectionID; + + DataModel::List outStreamConfigurations; + + // Call the delegate + status = mDelegate.FindTransport(connectionID, outStreamConfigurations); + if (status == Status::Success) + { + response.streamConfigurations = outStreamConfigurations; + + ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); + } + else + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); + } +} + +} // namespace PushAvStreamTransport +} // namespace Clusters +} // namespace app +} // namespace chip + +/** @brief Push AV Stream Transport Cluster Server Init + * + * Server Init + * + */ +void MatterPushAvStreamTransportPluginServerInitCallback() {} diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h new file mode 100644 index 00000000000000..fe4f60944bbf53 --- /dev/null +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h @@ -0,0 +1,290 @@ +/* + * + * 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 +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace PushAvStreamTransport { + +using MetadataOptionsStruct = Structs::MetadataOptionsStruct::Type; +using CMAFContainerOptionsStruct = Structs::CMAFContainerOptionsStruct::Type; +using ContainerOptionsStruct = Structs::ContainerOptionsStruct::Type; +using TransportZoneOptionsStruct = Structs::TransportZoneOptionsStruct::Type; +using TransportTriggerOptionsStruct = Structs::TransportTriggerOptionsStruct::Type; +using TransportMotionTriggerTimeControlStruct = Structs::TransportMotionTriggerTimeControlStruct::Type; +using TransportOptionsStruct = Structs::TransportOptionsStruct::Type; +using TransportConfigurationStruct = Structs::TransportConfigurationStruct::Type; + +class PushAvStreamTransportServer; + +/** @brief + * Defines interfaces for implementing application-specific logic for various aspects of the PushAvStreamTransport Cluster. + * Specifically, it defines interfaces for the command handling and loading of the allocated streams. + */ +class PushAvStreamTransportDelegate +{ +public: + PushAvStreamTransportDelegate() = default; + + virtual ~PushAvStreamTransportDelegate() = default; + + /** + * @brief Handle Command Delegate for stream transport allocation with the provided transport configuration option. + * + * @param connectionID[in] Indicates the connectionID to allocate. + * + * @param transportOptions[in] represent the configuration options of the transport to be allocated + * + * @param outTransportStatus[out] represent the status of the transport allocation + * + * @return Success if the allocation is successful and a PushTransportConnectionID was + * produced; otherwise, the command SHALL be rejected with an appropriate + * error. + */ + virtual Protocols::InteractionModel::Status AllocatePushTransport(uint16_t & connectionID, + const TransportOptionsStruct & transportOptions, + TransportStatusEnum & outTransportStatus) = 0; + /** + * @brief Handle Command Delegate for Stream transport deallocation for the + * provided connectionID. + * + * @param connectionID[in] Indicates the connectionID to deallocate. + * + * @return Success if the transport deallocation is successful; otherwise, the command SHALL be rejected with an appropriate + * error. + * + */ + virtual Protocols::InteractionModel::Status DeallocatePushTransport(const uint16_t & connectionID) = 0; + /** + * @brief Handle Command Delegate for Stream transport modification. + * + * @param connectionID [in] Indicates the connectionID of the stream transport to modify. + * + * @param outTransportOptions [out] represents the Trigger Options to modify. + * + * @return Success if the stream transport modification is successful; otherwise, the command SHALL be rejected with an + * appropriate error. + */ + virtual Protocols::InteractionModel::Status ModifyPushTransport(const uint16_t & connectionID, + const TransportOptionsStruct & outTransportOptions) = 0; + + /** + * @brief Handle Command Delegate for Stream transport modification. + * + * @param connectionID [in] Indicates the connectionID of the stream transport to set status for. + * + * @param transportStatus [in] represent the new transport status to apply. + * + * @return Success if the stream transport status is successfully set; otherwise, the command SHALL be rejected with an + * appropriate error. + */ + virtual Protocols::InteractionModel::Status SetTransportStatus(const uint16_t & connectionID, + TransportStatusEnum transportStatus) = 0; + + /** + * @brief Handle Command Delegate to request the Node to manually start the specified push transport. + * + * @param connectionID [in] Indicates the connectionID of the stream transport to set trigger for. + * + * @param activationReason [in] Provide information as to why the transport was started or stopped. + * + * @param timeControl [in] Configuration to control the life cycle of a triggered transport. + * + * @return Success if the stream transport trigger is successful; otherwise, the command SHALL be rejected with an +appropriate + * error. + */ + virtual Protocols::InteractionModel::Status + ManuallyTriggerTransport(const uint16_t & connectionID, TriggerActivationReasonEnum activationReason, + const TransportMotionTriggerTimeControlStruct & timeControl) = 0; + + /** + * @brief Handle Command Delegate to get the Stream Options Configuration for the specified push transport. + * + * @param connectionID [in] Indicates the allocated connectionID to get the Stream Options Configuration of. + * + * @param outtransportConfigurations [out] Single item list of mapped transport configuration or list if connectionID is + * NULL. + * + * @return Success if the transport is already allocated; otherwise, the command SHALL be rejected with an appropriate + * error. + * + */ + virtual Protocols::InteractionModel::Status + FindTransport(const Optional> & connectionID, + DataModel::List & outtransportConfigurations) = 0; + + /** + * @brief Delegate callback for notifying change in an attribute. + * + */ + virtual void OnAttributeChanged(AttributeId attributeId) = 0; + + /** + * Delegate functions to load the allocated transport connections. + * The delegate application is responsible for creating and persisting these connections ( based on the Allocation commands ). + * These Load APIs would be used to load the pre-allocated transport connections context information into the cluster server + * list, at initialization. Once loaded, the cluster server would be serving Reads on these attributes. The list is updatable + * via the Add/Remove functions for the respective transport connections. + */ + virtual Protocols::InteractionModel::Status LoadCurrentConnections(std::vector & currentConnections) = 0; + + /** + * @brief Callback into the delegate once persistent attributes managed by + * the Cluster have been loaded from Storage. + */ + virtual Protocols::InteractionModel::Status PersistentAttributesLoadedCallback() = 0; + +private: + friend class PushAvStreamTransportServer; + + PushAvStreamTransportServer * mPushAvStreamTransportServer = nullptr; + + /** + * This method is used by the SDK to set the PushAvStreamTransportServer pointer member in the delegate. + * This is done in the constructor during the instantiation of the PushAvStreamTransportServer object. + * + * @param aPushAvStreamTransportServer A pointer to the PushAvStreamTransportServer object related to this delegate object. + */ + void SetPushAvStreamTransportServer(PushAvStreamTransportServer * aPushAvStreamTransportServer) + { + mPushAvStreamTransportServer = aPushAvStreamTransportServer; + } + +protected: + PushAvStreamTransportServer * GetPushAvStreamTransportServer() const { return mPushAvStreamTransportServer; } +}; + +class PushAvStreamTransportServer : private AttributeAccessInterface, private CommandHandlerInterface +{ +public: + /** + * Creates a Push AV Stream Transport server instance. The Init() function needs to be called for this instance to be registered + * and called by the interaction model at the appropriate times. + * @param aEndpointId The endpoint on which this cluster exists. This must match the zap configuration. + * @param aDelegate A reference to the delegate to be used by this server. + * Note: the caller must ensure that the delegate lives throughout the instance's lifetime. + */ + PushAvStreamTransportServer(EndpointId endpointId, PushAvStreamTransportDelegate & delegate, const BitFlags aFeature, + PersistentStorageDelegate & aPersistentStorage); + + ~PushAvStreamTransportServer() override; + + /** + * @brief Initialise the Push AV Stream Transport server instance. + * This function must be called after defining an PushAvStreamTransportServer class object. + * @return Returns an error if the given endpoint and cluster ID have not been enabled in zap or if the + * CommandHandler or AttributeHandler registration fails, else returns CHIP_NO_ERROR. + * This method also checks if the feature setting is valid, if invalid it will return CHIP_ERROR_INVALID_ARGUMENT. + */ + CHIP_ERROR Init(); + + bool HasFeature(Feature feature) const; + + // Attribute Getters + BitMask GetSupportedContainerFormats() const { return mSupportedContainerFormats; } + BitMask GetSupportedIngestMethods() const { return mSupportedIngestMethods; } + + // Helper functions + bool FindStreamTransportConnection(const uint16_t connectionID); + uint16_t GenerateConnectionID(); + + // Add/Remove Management functions for transport + CHIP_ERROR AddStreamTransportConnection(const uint16_t transportConnectionId); + + CHIP_ERROR RemoveStreamTransportConnection(const uint16_t transportConnectionId); + +private: + PushAvStreamTransportDelegate & mDelegate; + EndpointId mEndpointId; + const BitFlags mFeature; + + // Attributes + BitMask mSupportedContainerFormats; + BitMask mSupportedIngestMethods; + // lists + std::vector mCurrentConnections; + + // Utility function to set and persist attributes + template + CHIP_ERROR SetAttributeIfDifferent(T & currentValue, const T & newValue, AttributeId attributeId, bool shouldPersist = true) + { + if (currentValue != newValue) + { + currentValue = newValue; + auto path = ConcreteAttributePath(mEndpointId, PushAvStreamTransport::Id, attributeId); + if (shouldPersist) + { + ReturnErrorOnFailure(GetSafeAttributePersistenceProvider()->WriteScalarValue(path, currentValue)); + } + mDelegate.OnAttributeChanged(attributeId); + MatterReportingAttributeChangeCallback(path); + } + return CHIP_NO_ERROR; + } + + /** + * IM-level implementation of read + * @return appropriately mapped CHIP_ERROR if applicable + */ + CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; + + /** + * IM-level implementation of write + * @return appropriately mapped CHIP_ERROR if applicable + */ + CHIP_ERROR Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) override; + + /** + * Helper function that loads all the persistent attributes from the KVS. + */ + void LoadPersistentAttributes(); + + // Helpers to read list items via delegate APIs + CHIP_ERROR ReadAndEncodeCurrentConnections(const AttributeValueEncoder::ListEncodeHelper & encoder); + + /** + * @brief Inherited from CommandHandlerInterface + */ + void InvokeCommand(HandlerContext & ctx) override; + + void HandleAllocatePushTransport(HandlerContext & ctx, const Commands::AllocatePushTransport::DecodableType & req); + + void HandleDeallocatePushTransport(HandlerContext & ctx, const Commands::DeallocatePushTransport::DecodableType & req); + + void HandleModifyPushTransport(HandlerContext & ctx, const Commands::ModifyPushTransport::DecodableType & req); + + void HandleSetTransportStatus(HandlerContext & ctx, const Commands::SetTransportStatus::DecodableType & req); + + void HandleManuallyTriggerTransport(HandlerContext & ctx, const Commands::ManuallyTriggerTransport::DecodableType & req); + + void HandleFindTransport(HandlerContext & ctx, const Commands::FindTransport::DecodableType & req); +}; + +} // namespace PushAvStreamTransport +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/src/app/common/templates/config-data.yaml b/src/app/common/templates/config-data.yaml index 15f02f4a8802e6..f6e057f1040961 100644 --- a/src/app/common/templates/config-data.yaml +++ b/src/app/common/templates/config-data.yaml @@ -38,6 +38,7 @@ CommandHandlerInterfaceOnlyClusters: - Microwave Oven Control - Chime - Camera AV Stream Management + - Push AV Stream Transport - Commissioner Control - Commodity Price - Energy EVSE diff --git a/src/app/zap_cluster_list.json b/src/app/zap_cluster_list.json index 6b5d08a8531f64..bb7d635adac998 100644 --- a/src/app/zap_cluster_list.json +++ b/src/app/zap_cluster_list.json @@ -252,7 +252,9 @@ "NITROGEN_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER": [ "concentration-measurement-server" ], - "PUSH_AV_STREAM_TRANSPORT_CLUSTER": [], + "PUSH_AV_STREAM_TRANSPORT_CLUSTER": [ + "push-av-stream-transport-server" + ], "SAMPLE_MEI_CLUSTER": ["sample-mei-server"], "OCCUPANCY_SENSING_CLUSTER": ["occupancy-sensor-server"], "ON_OFF_CLUSTER": ["on-off-server"], diff --git a/zzz_generated/app-common/app-common/zap-generated/callback.h b/zzz_generated/app-common/app-common/zap-generated/callback.h index 61bebcbc4720a2..6bd941ccbea9eb 100644 --- a/zzz_generated/app-common/app-common/zap-generated/callback.h +++ b/zzz_generated/app-common/app-common/zap-generated/callback.h @@ -7847,6 +7847,59 @@ bool emberAfCommodityTariffClusterGetTariffComponentCallback( bool emberAfCommodityTariffClusterGetDayEntryCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::CommodityTariff::Commands::GetDayEntry::DecodableType & commandData); + * @brief WebRTC Transport Provider Cluster SolicitOffer Command callback (from client) + */ +bool emberAfWebRTCTransportProviderClusterSolicitOfferCallback( + chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::WebRTCTransportProvider::Commands::SolicitOffer::DecodableType & commandData); +/** + * @brief WebRTC Transport Provider Cluster ProvideOffer Command callback (from client) + */ +bool emberAfWebRTCTransportProviderClusterProvideOfferCallback( + chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::WebRTCTransportProvider::Commands::ProvideOffer::DecodableType & commandData); +/** + * @brief WebRTC Transport Provider Cluster ProvideAnswer Command callback (from client) + */ +bool emberAfWebRTCTransportProviderClusterProvideAnswerCallback( + chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::WebRTCTransportProvider::Commands::ProvideAnswer::DecodableType & commandData); +/** + * @brief WebRTC Transport Provider Cluster ProvideICECandidate Command callback (from client) + */ +bool emberAfWebRTCTransportProviderClusterProvideICECandidateCallback( + chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::WebRTCTransportProvider::Commands::ProvideICECandidate::DecodableType & commandData); +/** + * @brief WebRTC Transport Provider Cluster EndSession Command callback (from client) + */ +bool emberAfWebRTCTransportProviderClusterEndSessionCallback( + chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::WebRTCTransportProvider::Commands::EndSession::DecodableType & commandData); +/** + * @brief WebRTC Transport Requestor Cluster Offer Command callback (from client) + */ +bool emberAfWebRTCTransportRequestorClusterOfferCallback( + chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::WebRTCTransportRequestor::Commands::Offer::DecodableType & commandData); +/** + * @brief WebRTC Transport Requestor Cluster Answer Command callback (from client) + */ +bool emberAfWebRTCTransportRequestorClusterAnswerCallback( + chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::WebRTCTransportRequestor::Commands::Answer::DecodableType & commandData); +/** + * @brief WebRTC Transport Requestor Cluster ICECandidates Command callback (from client) + */ +bool emberAfWebRTCTransportRequestorClusterICECandidatesCallback( + chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::WebRTCTransportRequestor::Commands::ICECandidates::DecodableType & commandData); +/** + * @brief WebRTC Transport Requestor Cluster End Command callback (from client) + */ +bool emberAfWebRTCTransportRequestorClusterEndCallback( + chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::WebRTCTransportRequestor::Commands::End::DecodableType & commandData); /** * @brief TLS Certificate Management Cluster ProvisionRootCertificate Command callback (from client) */ From 7f09b47dae594567f896986217bb7bdf671d0312 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Thu, 27 Feb 2025 09:03:59 +0000 Subject: [PATCH 02/22] Restyled by prettier-json --- src/app/zap_cluster_list.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/app/zap_cluster_list.json b/src/app/zap_cluster_list.json index bb7d635adac998..2b60dc74530379 100644 --- a/src/app/zap_cluster_list.json +++ b/src/app/zap_cluster_list.json @@ -252,9 +252,7 @@ "NITROGEN_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER": [ "concentration-measurement-server" ], - "PUSH_AV_STREAM_TRANSPORT_CLUSTER": [ - "push-av-stream-transport-server" - ], + "PUSH_AV_STREAM_TRANSPORT_CLUSTER": ["push-av-stream-transport-server"], "SAMPLE_MEI_CLUSTER": ["sample-mei-server"], "OCCUPANCY_SENSING_CLUSTER": ["occupancy-sensor-server"], "ON_OFF_CLUSTER": ["on-off-server"], From 558b68e1d72297a3e5c5f8bb788e8e4505006a34 Mon Sep 17 00:00:00 2001 From: Sayon Deep Date: Tue, 4 Mar 2025 14:55:28 +0530 Subject: [PATCH 03/22] add push av cluster to camera-app and some fixes --- .../camera-common/camera-app.matter | 205 +++++++- .../camera-app/camera-common/camera-app.zap | 489 ++++++++++++++++++ .../push-av-stream-transport-server.cpp | 61 +-- .../push-av-stream-transport-server.h | 61 +-- 4 files changed, 744 insertions(+), 72 deletions(-) diff --git a/examples/camera-app/camera-common/camera-app.matter b/examples/camera-app/camera-common/camera-app.matter index 671b974070a11b..52f4f8effc57c1 100644 --- a/examples/camera-app/camera-common/camera-app.matter +++ b/examples/camera-app/camera-common/camera-app.matter @@ -2169,7 +2169,11 @@ provisional cluster CameraAvStreamManagement = 1361 { kJPEG = 0; } +<<<<<<< HEAD shared enum StreamUsageEnum : enum8 { +======= + enum StreamUsageEnum : enum8 { +>>>>>>> 0d4f9fefb9 (add push av cluster to camera-app and some fixes) kInternal = 0; kRecording = 1; kAnalysis = 2; @@ -2205,7 +2209,10 @@ provisional cluster CameraAvStreamManagement = 1361 { kWatermark = 0x40; kOnScreenDisplay = 0x80; kLocalStorage = 0x100; +<<<<<<< HEAD kHighDynamicRange = 0x200; +======= +>>>>>>> 0d4f9fefb9 (add push av cluster to camera-app and some fixes) } struct VideoResolutionStruct { @@ -2274,24 +2281,74 @@ provisional cluster CameraAvStreamManagement = 1361 { struct VideoSensorParamsStruct { int16u sensorWidth = 0; int16u sensorHeight = 1; +<<<<<<< HEAD int16u maxFPS = 2; optional int16u maxHDRFPS = 3; } shared struct ViewportStruct { +======= + boolean HDRCapable = 2; + int16u maxFPS = 3; + int16u maxHDRFPS = 4; + } + + struct ViewportStruct { +>>>>>>> 0d4f9fefb9 (add push av cluster to camera-app and some fixes) int16u x1 = 0; int16u y1 = 1; int16u x2 = 2; int16u y2 = 3; } +<<<<<<< HEAD +======= + info event VideoStreamChanged = 0 { + int16u videoStreamID = 0; + optional StreamUsageEnum streamUsage = 1; + optional VideoCodecEnum videoCodec = 2; + optional int16u minFrameRate = 3; + optional int16u maxFrameRate = 4; + optional VideoResolutionStruct minResolution = 5; + optional VideoResolutionStruct maxResolution = 6; + optional int32u minBitRate = 7; + optional int32u maxBitRate = 8; + optional int16u minFragmentLen = 9; + optional int16u maxFragmentLen = 10; + } + + info event AudioStreamChanged = 1 { + int16u audioStreamID = 0; + optional StreamUsageEnum streamUsage = 1; + optional AudioCodecEnum audioCodec = 2; + optional int8u channelCount = 3; + optional int32u sampleRate = 4; + optional int32u bitRate = 5; + optional int8u bitDepth = 6; + } + + info event SnapshotStreamChanged = 2 { + int16u snapshotStreamID = 0; + optional ImageCodecEnum imageCodec = 1; + optional int16u frameRate = 2; + optional int32u bitRate = 3; + optional VideoResolutionStruct minResolution = 4; + optional VideoResolutionStruct maxResolution = 5; + optional int8u quality = 6; + } + +>>>>>>> 0d4f9fefb9 (add push av cluster to camera-app and some fixes) readonly attribute optional int8u maxConcurrentVideoEncoders = 0; readonly attribute optional int32u maxEncodedPixelRate = 1; readonly attribute optional VideoSensorParamsStruct videoSensorParams = 2; readonly attribute optional boolean nightVisionCapable = 3; readonly attribute optional VideoResolutionStruct minViewport = 4; readonly attribute optional RateDistortionTradeOffPointsStruct rateDistortionTradeOffPoints[] = 5; +<<<<<<< HEAD readonly attribute int32u maxContentBufferSize = 6; +======= + readonly attribute optional int32u maxContentBufferSize = 6; +>>>>>>> 0d4f9fefb9 (add push av cluster to camera-app and some fixes) readonly attribute optional AudioCapabilitiesStruct microphoneCapabilities = 7; readonly attribute optional AudioCapabilitiesStruct speakerCapabilities = 8; readonly attribute optional TwoWayTalkSupportTypeEnum twoWayTalkSupport = 9; @@ -2299,7 +2356,11 @@ provisional cluster CameraAvStreamManagement = 1361 { readonly attribute int32u maxNetworkBandwidth = 11; readonly attribute optional int16u currentFrameRate = 12; attribute access(read: manage, write: manage) optional boolean HDRModeEnabled = 13; +<<<<<<< HEAD readonly attribute StreamUsageEnum supportedStreamUsages[] = 14; +======= + readonly attribute fabric_idx fabricsUsingCamera[] = 14; +>>>>>>> 0d4f9fefb9 (add push av cluster to camera-app and some fixes) readonly attribute optional VideoStreamStruct allocatedVideoStreams[] = 15; readonly attribute optional AudioStreamStruct allocatedAudioStreams[] = 16; readonly attribute optional SnapshotStreamStruct allocatedSnapshotStreams[] = 17; @@ -2669,6 +2730,121 @@ provisional cluster Chime = 1366 { command PlayChimeSound(): DefaultSuccess = 0; } +/** This Cluster is used to manage TLS Client Certificates and to provision + TLS endpoints with enough information to facilitate subsequent connection. */ +provisional cluster TlsCertificateManagement = 2049 { + revision 1; + + struct TLSCertStruct { + int16u caid = 0; + long_octet_string<3000> certificate = 1; + } + + struct TLSClientCertificateDetailStruct { + int16u ccdid = 0; + long_octet_string<3000> clientCertificate = 1; + octet_string intermediateCertificates[] = 2; + } + + readonly attribute int8u maxRootCertificates = 0; + readonly attribute int8u currentRootCertificates = 1; + readonly attribute int8u maxClientCertificates = 2; + readonly attribute int8u currentClientCertificates = 3; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct ProvisionRootCertificateRequest { + long_octet_string<3000> certificate = 0; + nullable int16u caid = 1; + } + + response struct ProvisionRootCertificateResponse = 1 { + int16u caid = 0; + } + + request struct FindRootCertificateRequest { + nullable int16u caid = 0; + } + + response struct FindRootCertificateResponse = 3 { + TLSCertStruct certificateDetails[] = 0; + } + + request struct LookupRootCertificateRequest { + octet_string<64> fingerprint = 0; + } + + response struct LookupRootCertificateResponse = 5 { + int16u caid = 0; + } + + request struct RemoveRootCertificateRequest { + int16u caid = 0; + } + + request struct TLSClientCSRRequest { + octet_string nonce = 0; + } + + response struct TLSClientCSRResponse = 8 { + int16u ccdid = 0; + octet_string csr = 1; + octet_string nonce = 2; + } + + request struct ProvisionClientCertificateRequest { + int16u ccdid = 0; + TLSClientCertificateDetailStruct clientCertificateDetails = 1; + } + + response struct ProvisionClientCertificateResponse = 10 { + int16u ccdid = 0; + } + + request struct FindClientCertificateRequest { + int16u ccdid = 0; + } + + response struct FindClientCertificateResponse = 12 { + TLSClientCertificateDetailStruct certificateDetails[] = 0; + } + + request struct LookupClientCertificateRequest { + octet_string<64> fingerprint = 0; + } + + response struct LookupClientCertificateResponse = 14 { + int16u ccdid = 0; + } + + request struct RemoveClientCertificateRequest { + int16u ccdid = 0; + } + + /** This command SHALL provision the provided certificate for the passed in CAID. */ + command access(invoke: administer) ProvisionRootCertificate(ProvisionRootCertificateRequest): ProvisionRootCertificateResponse = 0; + /** This command SHALL return the TLSCertStruct for the passed in CAID. */ + command FindRootCertificate(FindRootCertificateRequest): FindRootCertificateResponse = 2; + /** This command SHALL return the CAID for the passed in fingerprint. */ + command LookupRootCertificate(LookupRootCertificateRequest): LookupRootCertificateResponse = 4; + /** This command SHALL be generated to request the server removes the certificate provisioned to the provided Certificate Authority ID. */ + command access(invoke: administer) RemoveRootCertificate(RemoveRootCertificateRequest): DefaultSuccess = 6; + /** This command SHALL be generated to request the Node generates a Certificate Signing Request. */ + command access(invoke: administer) TLSClientCSR(TLSClientCSRRequest): TLSClientCSRResponse = 7; + /** This command SHALL be generated to request the Node provisions the provided Client Certificate Details. */ + command access(invoke: administer) ProvisionClientCertificate(ProvisionClientCertificateRequest): ProvisionClientCertificateResponse = 9; + /** This command SHALL return the TLSClientCertificateDetailStruct for the passed in CCDID. */ + command FindClientCertificate(FindClientCertificateRequest): FindClientCertificateResponse = 11; + /** This command SHALL return the CCDID for the passed in Fingerprint. */ + command LookupClientCertificate(LookupClientCertificateRequest): LookupClientCertificateResponse = 13; + /** This command SHALL be generated to request the Node removes the certificate provisioned to the provided Client Certificate Details ID. */ + command access(invoke: administer) RemoveClientCertificate(RemoveClientCertificateRequest): DefaultSuccess = 15; +} + endpoint 0 { device type ma_rootdevice = 22, version 3; device type ma_otarequestor = 18, version 1; @@ -3186,6 +3362,33 @@ endpoint 1 { handle command PlayChimeSound; } -} + server cluster TlsCertificateManagement { + ram attribute maxRootCertificates; + ram attribute currentRootCertificates; + ram attribute maxClientCertificates; + ram attribute currentClientCertificates; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + handle command ProvisionRootCertificate; + handle command ProvisionRootCertificateResponse; + handle command FindRootCertificate; + handle command FindRootCertificateResponse; + handle command LookupRootCertificate; + handle command LookupRootCertificateResponse; + handle command RemoveRootCertificate; + handle command TLSClientCSR; + handle command TLSClientCSRResponse; + handle command ProvisionClientCertificate; + handle command ProvisionClientCertificateResponse; + handle command FindClientCertificate; + handle command FindClientCertificateResponse; + handle command LookupClientCertificate; + handle command LookupClientCertificateResponse; + handle command RemoveClientCertificate; + } +} diff --git a/examples/camera-app/camera-common/camera-app.zap b/examples/camera-app/camera-common/camera-app.zap index 4cdaaebdcb1fe2..9fcb6616414ab5 100644 --- a/examples/camera-app/camera-common/camera-app.zap +++ b/examples/camera-app/camera-common/camera-app.zap @@ -6090,6 +6090,210 @@ } ] }, + { + "name": "Push AV Stream Transport", + "code": 1365, + "mfgCode": null, + "define": "PUSH_AV_STREAM_TRANSPORT_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "AllocatePushTransport", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AllocatePushTransportResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "DeallocatePushTransport", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ModifyPushTransport", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "SetTransportStatus", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ManuallyTriggerTransport", + "code": 5, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "FindTransport", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "FindTransportResponse", + "code": 7, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "SupportedContainerFormats", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "SupportedContainerFormatsBitmap", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportedIngestMethods", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "SupportedIngestMethodsBitmap", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentConnections", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, { "name": "Chime", "code": 1366, @@ -6238,6 +6442,291 @@ "reportableChange": 0 } ] + }, + { + "name": "TLS Certificate Management", + "code": 2049, + "mfgCode": null, + "define": "TLS_CERTIFICATE_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "apiMaturity": "provisional", + "commands": [ + { + "name": "ProvisionRootCertificate", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ProvisionRootCertificateResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "FindRootCertificate", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "FindRootCertificateResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "LookupRootCertificate", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "LookupRootCertificateResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "RemoveRootCertificate", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TLSClientCSR", + "code": 7, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TLSClientCSRResponse", + "code": 8, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ProvisionClientCertificate", + "code": 9, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ProvisionClientCertificateResponse", + "code": 10, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "FindClientCertificate", + "code": 11, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "FindClientCertificateResponse", + "code": 12, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "LookupClientCertificate", + "code": 13, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "LookupClientCertificateResponse", + "code": 14, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "RemoveClientCertificate", + "code": 15, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "MaxRootCertificates", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentRootCertificates", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxClientCertificates", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentClientCertificates", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] } ] } diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp index f8d58ec89f5111..7fcd452a6b48ba 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp @@ -44,24 +44,16 @@ namespace Clusters { namespace PushAvStreamTransport { PushAvStreamTransportServer::PushAvStreamTransportServer(EndpointId aEndpointId, PushAvStreamTransportDelegate & aDelegate, - const BitFlags aFeature, + const BitFlags aFeatures, PersistentStorageDelegate & aPersistentStorage) : CommandHandlerInterface(MakeOptional(aEndpointId), CameraAvStreamManagement::Id), - AttributeAccessInterface(MakeOptional(aEndpointId), CameraAvStreamManagement::Id), mDelegate(aDelegate), - mEndpointId(aEndpointId), mFeature(aFeature) -{ - mDelegate.SetPushAvStreamTransportServer(this); -} + AttributeAccessInterface(MakeOptional(aEndpointId), CameraAvStreamManagement::Id), mDelegate(aDelegate), mFeature(aFeatures) +{} PushAvStreamTransportServer::~PushAvStreamTransportServer() { - // Explicitly set the PushAvStreamTransportServer pointer in the Delegate to null. + Shutdown(); - mDelegate.SetPushAvStreamTransportServer(nullptr); - - // Unregister command handler and attribute access interfaces - CommandHandlerInterfaceRegistry::Instance().UnregisterCommandHandler(this); - AttributeAccessInterfaceRegistry::Instance().Unregister(this); } CHIP_ERROR PushAvStreamTransportServer::Init() @@ -73,6 +65,12 @@ CHIP_ERROR PushAvStreamTransportServer::Init() return CHIP_NO_ERROR; } +void PushAvStreamTransportServer::Shutdown() +{ // Unregister command handler and attribute access interfaces + CommandHandlerInterfaceRegistry::Instance().UnregisterCommandHandler(this); + AttributeAccessInterfaceRegistry::Instance().Unregister(this); +} + bool PushAvStreamTransportServer::HasFeature(Feature feature) const { return mFeature.Has(feature); @@ -91,7 +89,7 @@ CHIP_ERROR PushAvStreamTransportServer::ReadAndEncodeCurrentConnections(const At CHIP_ERROR PushAvStreamTransportServer::AddStreamTransportConnection(const uint16_t transportConnectionId) { mCurrentConnections.push_back(transportConnectionId); - auto path = ConcreteAttributePath(mEndpointId, PushAvStreamTransport::Id, Attributes::CurrentConnections::Id); + auto path = ConcreteAttributePath(AttributeAccessInterface::GetEndpointId().Value(), PushAvStreamTransport::Id, Attributes::CurrentConnections::Id); mDelegate.OnAttributeChanged(Attributes::CurrentConnections::Id); MatterReportingAttributeChangeCallback(path); @@ -103,7 +101,7 @@ CHIP_ERROR PushAvStreamTransportServer::RemoveStreamTransportConnection(const ui mCurrentConnections.erase(std::remove_if(mCurrentConnections.begin(), mCurrentConnections.end(), [&](const uint16_t connectionID) { return connectionID == transportConnectionId; }), mCurrentConnections.end()); - auto path = ConcreteAttributePath(mEndpointId, PushAvStreamTransport::Id, Attributes::CurrentConnections::Id); + auto path = ConcreteAttributePath(AttributeAccessInterface::GetEndpointId().Value(), PushAvStreamTransport::Id, Attributes::CurrentConnections::Id); mDelegate.OnAttributeChanged(Attributes::CurrentConnections::Id); MatterReportingAttributeChangeCallback(path); @@ -113,7 +111,7 @@ CHIP_ERROR PushAvStreamTransportServer::RemoveStreamTransportConnection(const ui CHIP_ERROR PushAvStreamTransportServer::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) { VerifyOrDie(aPath.mClusterId == PushAvStreamTransport::Id); - ChipLogError(Zcl, "Push AV Stream Transport: Reading"); + ChipLogError(Zcl, "Push AV Stream Transport[ep=%d]: Reading",AttributeAccessInterface::GetEndpointId().Value()); switch (aPath.mAttributeId) { @@ -228,21 +226,18 @@ bool PushAvStreamTransportServer::FindStreamTransportConnection(const uint16_t c uint16_t PushAvStreamTransportServer::GenerateConnectionID() { - static uint16_t assignedConnectionID = 0; + static uint16_t lastAssignedConnectionID = 0; uint16_t nextConnectionID; - if (assignedConnectionID == MAX_PUSH_TRANSPORT_CONNECTION_ID) - nextConnectionID = 0; - else - nextConnectionID = assignedConnectionID + 1; - - while (FindStreamTransportConnection(nextConnectionID) != false) + do { - if (nextConnectionID == MAX_PUSH_TRANSPORT_CONNECTION_ID) + if (lastAssignedConnectionID == MAX_PUSH_TRANSPORT_CONNECTION_ID) nextConnectionID = 0; else - nextConnectionID = nextConnectionID + 1; - } + nextConnectionID = lastAssignedConnectionID + 1; + } while (FindStreamTransportConnection(nextConnectionID)); + + lastAssignedConnectionID = nextConnectionID; return nextConnectionID; } @@ -253,17 +248,17 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c Commands::AllocatePushTransportResponse::Type response; auto & transportOptions = commandData.transportOptions; - uint16_t connectionID = GenerateConnectionID(); - TransportStatusEnum outTranportStatus = TransportStatusEnum::kUnknownEnumValue; + uint16_t connectionID = GenerateConnectionID(); + TransportStatusEnum outTransportStatus = TransportStatusEnum::kUnknownEnumValue; // call the delegate - status = mDelegate.AllocatePushTransport(connectionID, transportOptions, outTranportStatus); + status = mDelegate.AllocatePushTransport(connectionID, transportOptions, outTransportStatus); if (status == Status::Success) { response.connectionID = connectionID; response.transportOptions = transportOptions; - response.transportStatus = outTranportStatus; + response.transportStatus = outTransportStatus; // add connection to CurrentConnections AddStreamTransportConnection(connectionID); @@ -308,12 +303,12 @@ void PushAvStreamTransportServer::HandleModifyPushTransport(HandlerContext & ctx void PushAvStreamTransportServer::HandleSetTransportStatus(HandlerContext & ctx, const Commands::SetTransportStatus::DecodableType & commandData) { - Status status = Status::Success; - uint16_t connectionID = commandData.connectionID; - auto & transportOptions = commandData.transportOptions; + Status status = Status::Success; + uint16_t connectionID = commandData.connectionID; + auto & transportStatus = commandData.transportStatus; // Call the delegate - status = mDelegate.SetTransportStatus(connectionID, transportOptions); + status = mDelegate.SetTransportStatus(connectionID, transportStatus); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h index fe4f60944bbf53..4cacef957eed2f 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2025 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -38,10 +38,8 @@ using TransportMotionTriggerTimeControlStruct = Structs::TransportMotionTriggerT using TransportOptionsStruct = Structs::TransportOptionsStruct::Type; using TransportConfigurationStruct = Structs::TransportConfigurationStruct::Type; -class PushAvStreamTransportServer; - /** @brief - * Defines interfaces for implementing application-specific logic for various aspects of the PushAvStreamTransport Cluster. + * Defines interfaces for implementing application-specific logic for various aspects of the PushAvStreamTransport Delegate. * Specifically, it defines interfaces for the command handling and loading of the allocated streams. */ class PushAvStreamTransportDelegate @@ -64,7 +62,7 @@ class PushAvStreamTransportDelegate * produced; otherwise, the command SHALL be rejected with an appropriate * error. */ - virtual Protocols::InteractionModel::Status AllocatePushTransport(uint16_t & connectionID, + virtual Protocols::InteractionModel::Status AllocatePushTransport(uint16_t connectionID, const TransportOptionsStruct & transportOptions, TransportStatusEnum & outTransportStatus) = 0; /** @@ -77,7 +75,7 @@ class PushAvStreamTransportDelegate * error. * */ - virtual Protocols::InteractionModel::Status DeallocatePushTransport(const uint16_t & connectionID) = 0; + virtual Protocols::InteractionModel::Status DeallocatePushTransport(const uint16_t connectionID) = 0; /** * @brief Handle Command Delegate for Stream transport modification. * @@ -88,7 +86,7 @@ class PushAvStreamTransportDelegate * @return Success if the stream transport modification is successful; otherwise, the command SHALL be rejected with an * appropriate error. */ - virtual Protocols::InteractionModel::Status ModifyPushTransport(const uint16_t & connectionID, + virtual Protocols::InteractionModel::Status ModifyPushTransport(const uint16_t connectionID, const TransportOptionsStruct & outTransportOptions) = 0; /** @@ -101,7 +99,7 @@ class PushAvStreamTransportDelegate * @return Success if the stream transport status is successfully set; otherwise, the command SHALL be rejected with an * appropriate error. */ - virtual Protocols::InteractionModel::Status SetTransportStatus(const uint16_t & connectionID, + virtual Protocols::InteractionModel::Status SetTransportStatus(const uint16_t connectionID, TransportStatusEnum transportStatus) = 0; /** @@ -118,7 +116,7 @@ appropriate * error. */ virtual Protocols::InteractionModel::Status - ManuallyTriggerTransport(const uint16_t & connectionID, TriggerActivationReasonEnum activationReason, + ManuallyTriggerTransport(const uint16_t connectionID, TriggerActivationReasonEnum activationReason, const TransportMotionTriggerTimeControlStruct & timeControl) = 0; /** @@ -158,24 +156,6 @@ appropriate */ virtual Protocols::InteractionModel::Status PersistentAttributesLoadedCallback() = 0; -private: - friend class PushAvStreamTransportServer; - - PushAvStreamTransportServer * mPushAvStreamTransportServer = nullptr; - - /** - * This method is used by the SDK to set the PushAvStreamTransportServer pointer member in the delegate. - * This is done in the constructor during the instantiation of the PushAvStreamTransportServer object. - * - * @param aPushAvStreamTransportServer A pointer to the PushAvStreamTransportServer object related to this delegate object. - */ - void SetPushAvStreamTransportServer(PushAvStreamTransportServer * aPushAvStreamTransportServer) - { - mPushAvStreamTransportServer = aPushAvStreamTransportServer; - } - -protected: - PushAvStreamTransportServer * GetPushAvStreamTransportServer() const { return mPushAvStreamTransportServer; } }; class PushAvStreamTransportServer : private AttributeAccessInterface, private CommandHandlerInterface @@ -188,7 +168,7 @@ class PushAvStreamTransportServer : private AttributeAccessInterface, private Co * @param aDelegate A reference to the delegate to be used by this server. * Note: the caller must ensure that the delegate lives throughout the instance's lifetime. */ - PushAvStreamTransportServer(EndpointId endpointId, PushAvStreamTransportDelegate & delegate, const BitFlags aFeature, + PushAvStreamTransportServer(EndpointId endpointId, PushAvStreamTransportDelegate & delegate, const BitFlags aFeatures, PersistentStorageDelegate & aPersistentStorage); ~PushAvStreamTransportServer() override; @@ -202,24 +182,20 @@ class PushAvStreamTransportServer : private AttributeAccessInterface, private Co */ CHIP_ERROR Init(); + /** + * @brief + * Unregisters the command handler and attribute interface, releasing resources. + */ + void Shutdown(); + bool HasFeature(Feature feature) const; // Attribute Getters BitMask GetSupportedContainerFormats() const { return mSupportedContainerFormats; } BitMask GetSupportedIngestMethods() const { return mSupportedIngestMethods; } - // Helper functions - bool FindStreamTransportConnection(const uint16_t connectionID); - uint16_t GenerateConnectionID(); - - // Add/Remove Management functions for transport - CHIP_ERROR AddStreamTransportConnection(const uint16_t transportConnectionId); - - CHIP_ERROR RemoveStreamTransportConnection(const uint16_t transportConnectionId); - private: PushAvStreamTransportDelegate & mDelegate; - EndpointId mEndpointId; const BitFlags mFeature; // Attributes @@ -266,6 +242,15 @@ class PushAvStreamTransportServer : private AttributeAccessInterface, private Co // Helpers to read list items via delegate APIs CHIP_ERROR ReadAndEncodeCurrentConnections(const AttributeValueEncoder::ListEncodeHelper & encoder); + // Helper functions + bool FindStreamTransportConnection(const uint16_t connectionID); + uint16_t GenerateConnectionID(); + + // Add/Remove Management functions for transport + CHIP_ERROR AddStreamTransportConnection(const uint16_t transportConnectionId); + + CHIP_ERROR RemoveStreamTransportConnection(const uint16_t transportConnectionId); + /** * @brief Inherited from CommandHandlerInterface */ From c2ff51c602fc5549fb87a4efed90935bc8831ade Mon Sep 17 00:00:00 2001 From: Sayon Deep Date: Thu, 3 Apr 2025 20:23:30 +0530 Subject: [PATCH 04/22] Address review comments --- .../push-av-stream-transport-server.cpp | 148 +++++++++++++----- .../push-av-stream-transport-server.h | 54 +++---- 2 files changed, 132 insertions(+), 70 deletions(-) diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp index 7fcd452a6b48ba..6baf34d283a256 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp @@ -37,23 +37,21 @@ using namespace chip::app::Clusters::PushAvStreamTransport; using namespace chip::app::Clusters::PushAvStreamTransport::Structs; using namespace chip::app::Clusters::PushAvStreamTransport::Attributes; using namespace Protocols::InteractionModel; +using chip::Protocols::InteractionModel::Status; namespace chip { namespace app { namespace Clusters { namespace PushAvStreamTransport { -PushAvStreamTransportServer::PushAvStreamTransportServer(EndpointId aEndpointId, PushAvStreamTransportDelegate & aDelegate, - const BitFlags aFeatures, - PersistentStorageDelegate & aPersistentStorage) : +PushAvStreamTransportServer::PushAvStreamTransportServer(EndpointId aEndpointId, PushAvStreamTransportDelegate & aDelegate) : CommandHandlerInterface(MakeOptional(aEndpointId), CameraAvStreamManagement::Id), - AttributeAccessInterface(MakeOptional(aEndpointId), CameraAvStreamManagement::Id), mDelegate(aDelegate), mFeature(aFeatures) + AttributeAccessInterface(MakeOptional(aEndpointId), CameraAvStreamManagement::Id), mDelegate(aDelegate) {} PushAvStreamTransportServer::~PushAvStreamTransportServer() { Shutdown(); - } CHIP_ERROR PushAvStreamTransportServer::Init() @@ -71,11 +69,6 @@ void PushAvStreamTransportServer::Shutdown() AttributeAccessInterfaceRegistry::Instance().Unregister(this); } -bool PushAvStreamTransportServer::HasFeature(Feature feature) const -{ - return mFeature.Has(feature); -} - CHIP_ERROR PushAvStreamTransportServer::ReadAndEncodeCurrentConnections(const AttributeValueEncoder::ListEncodeHelper & encoder) { for (const auto & currentConnections : mCurrentConnections) @@ -89,7 +82,8 @@ CHIP_ERROR PushAvStreamTransportServer::ReadAndEncodeCurrentConnections(const At CHIP_ERROR PushAvStreamTransportServer::AddStreamTransportConnection(const uint16_t transportConnectionId) { mCurrentConnections.push_back(transportConnectionId); - auto path = ConcreteAttributePath(AttributeAccessInterface::GetEndpointId().Value(), PushAvStreamTransport::Id, Attributes::CurrentConnections::Id); + auto path = ConcreteAttributePath(AttributeAccessInterface::GetEndpointId().Value(), PushAvStreamTransport::Id, + Attributes::CurrentConnections::Id); mDelegate.OnAttributeChanged(Attributes::CurrentConnections::Id); MatterReportingAttributeChangeCallback(path); @@ -101,7 +95,8 @@ CHIP_ERROR PushAvStreamTransportServer::RemoveStreamTransportConnection(const ui mCurrentConnections.erase(std::remove_if(mCurrentConnections.begin(), mCurrentConnections.end(), [&](const uint16_t connectionID) { return connectionID == transportConnectionId; }), mCurrentConnections.end()); - auto path = ConcreteAttributePath(AttributeAccessInterface::GetEndpointId().Value(), PushAvStreamTransport::Id, Attributes::CurrentConnections::Id); + auto path = ConcreteAttributePath(AttributeAccessInterface::GetEndpointId().Value(), PushAvStreamTransport::Id, + Attributes::CurrentConnections::Id); mDelegate.OnAttributeChanged(Attributes::CurrentConnections::Id); MatterReportingAttributeChangeCallback(path); @@ -111,44 +106,28 @@ CHIP_ERROR PushAvStreamTransportServer::RemoveStreamTransportConnection(const ui CHIP_ERROR PushAvStreamTransportServer::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) { VerifyOrDie(aPath.mClusterId == PushAvStreamTransport::Id); - ChipLogError(Zcl, "Push AV Stream Transport[ep=%d]: Reading",AttributeAccessInterface::GetEndpointId().Value()); + ChipLogError(Zcl, "Push AV Stream Transport[ep=%d]: Reading", AttributeAccessInterface::GetEndpointId().Value()); - switch (aPath.mAttributeId) + if (aPath.mClusterId == PushAvStreamTransport::Id && aPath.mAttributeId == Attributes::CurrentConnections::Id) { - case FeatureMap::Id: - ReturnErrorOnFailure(aEncoder.Encode(mFeature)); - break; - - case SupportedContainerFormats::Id: - ReturnErrorOnFailure(aEncoder.Encode(mSupportedContainerFormats)); - break; - case SupportedIngestMethods::Id: - ReturnErrorOnFailure(aEncoder.Encode(mSupportedIngestMethods)); - break; - - case CurrentConnections::Id: ReturnErrorOnFailure(aEncoder.EncodeList( [this](const auto & encoder) -> CHIP_ERROR { return this->ReadAndEncodeCurrentConnections(encoder); })); - break; } return CHIP_NO_ERROR; } -CHIP_ERROR PushAvStreamTransportServer::Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) -{ - VerifyOrDie(aPath.mClusterId == PushAvStreamTransport::Id); - - return CHIP_IM_GLOBAL_STATUS(UnsupportedAttribute); -} - void PushAvStreamTransportServer::LoadPersistentAttributes() { CHIP_ERROR err = CHIP_NO_ERROR; // Load currentConnections - mDelegate.LoadCurrentConnections(mCurrentConnections); + err = mDelegate.LoadCurrentConnections(mCurrentConnections); + if (err != CHIP_NO_ERROR) + { + ChipLogDetail(Zcl, "PushAVStreamTransport: Unable to load allocated connections from the KVS."); + } // Signal delegate that all persistent configuration attributes have been loaded. mDelegate.PersistentAttributesLoadedCallback(); @@ -211,14 +190,18 @@ void PushAvStreamTransportServer::InvokeCommand(HandlerContext & handlerContext) handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandleFindTransport(ctx, commandData); }); break; + default: + // Mark unrecognized command as UnsupportedCommand + handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, Status::UnsupportedCommand); + break; } } bool PushAvStreamTransportServer::FindStreamTransportConnection(const uint16_t connectionID) { - for (auto & id : mCurrentConnections) + for (auto & connection : mCurrentConnections) { - if (id == connectionID) + if (connection.connectionID == connectionID) return true; } return false; @@ -244,15 +227,67 @@ uint16_t PushAvStreamTransportServer::GenerateConnectionID() void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & ctx, const Commands::AllocatePushTransport::DecodableType & commandData) { - Status status = Status::Success; Commands::AllocatePushTransportResponse::Type response; auto & transportOptions = commandData.transportOptions; + FabricIndex peerFabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); + uint16_t ep = emberAfGetClusterServerEndpointIndex(transportOptions.endpointID, TlsCertificateManagement::Id, + MATTER_DM_TLS_CERTIFICATE_MANAGEMENT_CLUSTER_CLIENT_ENDPOINT_COUNT); + + if (ep == kEmberInvalidEndpointIndex) + { + auto status = StatusCodeEnum::kInvalidTLSEndpoint; + ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid TLSEndpointId not found"); + ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); + return; + } + + if (transportOptions.ingestMethod == IngestMethodsEnum::kUnknownEnumValue) + { + auto status = StatusCodeEnum::kUnsupportedIngestMethod; + ChipLogError(Zcl, "HandleAllocatePushTransport: Ingest method not supported"); + ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); + return; + } + + if (transportOptions.containerFormat == ContainerFormatEnum::kUnknownEnumValue) + { + auto status = StatusCodeEnum::kUnsupportedContainerFormat; + ChipLogError(Zcl, "HandleAllocatePushTransport: Container format not supported"); + ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); + return; + } + + if (transportOptions.triggerOptions.triggerType == TransportTriggerTypeEnum::kUnknownEnumValue) + { + auto status = StatusCodeEnum::kInvalidTriggerType; + ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid Trigger type"); + ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); + return; + } + + // Todo: Validate MotionZones list in the TransportTriggerOptionsStruct field + + // Validate the StreamUsageEnum as per resource management and stream priorities. + CHIP_ERROR err = + mDelegate.ValidateStreamUsage(transportOptions.streamUsage, transportOptions.videoStreamID, transportOptions.audioStreamID); + if (err != CHIP_NO_ERROR) + { + auto status = StatusCodeEnum::kInvalidStream; + ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid Stream"); + ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); + return; + } + uint16_t connectionID = GenerateConnectionID(); TransportStatusEnum outTransportStatus = TransportStatusEnum::kUnknownEnumValue; + TransportConfigurationStruct outTransportConfiguration; + outTransportConfiguration.connectionID = connectionID; + outTransportConfiguration.transportStatus = TransportStatusEnum::kInactive; + outTransportConfiguration.transportOptions = transportOptions; // call the delegate - status = mDelegate.AllocatePushTransport(connectionID, transportOptions, outTransportStatus); + Status status = mDelegate.AllocatePushTransport(transportOptions, outTransportConfiguration); if (status == Status::Success) { @@ -277,6 +312,13 @@ void PushAvStreamTransportServer::HandleDeallocatePushTransport( Status status = Status::Success; uint16_t connectionID = commandData.connectionID; + if (!FindStreamTransportConnection(connectionID)) + { + ChipLogError(Zcl, "HandleDeallocatePushTransport: ConnectionID Not Found."); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); + return; + } + // Call the delegate status = mDelegate.DeallocatePushTransport(connectionID); @@ -294,6 +336,13 @@ void PushAvStreamTransportServer::HandleModifyPushTransport(HandlerContext & ctx uint16_t connectionID = commandData.connectionID; auto & outTransportOptions = commandData.transportOptions; + if (!FindStreamTransportConnection(connectionID)) + { + ChipLogError(Zcl, "HandleModifyPushTransport: ConnectionID Not Found."); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); + return; + } + // Call the delegate status = mDelegate.ModifyPushTransport(connectionID, outTransportOptions); @@ -307,6 +356,13 @@ void PushAvStreamTransportServer::HandleSetTransportStatus(HandlerContext & ctx, uint16_t connectionID = commandData.connectionID; auto & transportStatus = commandData.transportStatus; + if (!FindStreamTransportConnection(connectionID)) + { + ChipLogError(Zcl, "HandleSetTransportStatus: ConnectionID Not Found."); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); + return; + } + // Call the delegate status = mDelegate.SetTransportStatus(connectionID, transportStatus); @@ -321,6 +377,13 @@ void PushAvStreamTransportServer::HandleManuallyTriggerTransport( auto & activationReason = commandData.activationReason; auto & timeControl = commandData.timeControl; + if (!FindStreamTransportConnection(connectionID)) + { + ChipLogError(Zcl, "HandleManuallyTriggerTransport: ConnectionID Not Found."); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); + return; + } + // Call the delegate status = mDelegate.ManuallyTriggerTransport(connectionID, activationReason, timeControl); @@ -339,6 +402,13 @@ void PushAvStreamTransportServer::HandleFindTransport(HandlerContext & ctx, // Call the delegate status = mDelegate.FindTransport(connectionID, outStreamConfigurations); + + if (connectionID.HasValue() && outStreamConfigurations.size() == 0) + { + ChipLogError(Zcl, "HandleFindTransport: No allocated transport for connectionID."); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); + return; + } if (status == Status::Success) { response.streamConfigurations = outStreamConfigurations; diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h index 4cacef957eed2f..09e5c1b57fadd2 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h @@ -135,6 +135,24 @@ appropriate FindTransport(const Optional> & connectionID, DataModel::List & outtransportConfigurations) = 0; + /** + * @brief Validates the requested stream usage against the camera's resource management + * and stream priority policies. + * + * The implementation SHALL ensure: + * - The requested stream usage (streamUsage) is allowed given the current allocation of + * camera resources (e.g. CPU, memory, network bandwidth) and the prioritized stream list. + * + * @param[in] streamUsage The desired usage type for the stream (e.g. live view, recording, etc.). + * @param[in] videoStreamId Optional identifier for the requested video stream. + * @param[in] audioStreamId Optional identifier for the requested audio stream. + * + * @return CHIP_ERROR CHIP_NO_ERROR if the stream usage is valid; an appropriate error code otherwise. + */ + virtual CHIP_ERROR ValidateStreamUsage(StreamUsageEnum streamUsage, + const Optional> & videoStreamId, + const Optional> & audioStreamId) = 0; + /** * @brief Delegate callback for notifying change in an attribute. * @@ -148,14 +166,13 @@ appropriate * list, at initialization. Once loaded, the cluster server would be serving Reads on these attributes. The list is updatable * via the Add/Remove functions for the respective transport connections. */ - virtual Protocols::InteractionModel::Status LoadCurrentConnections(std::vector & currentConnections) = 0; + virtual CHIP_ERROR LoadCurrentConnections(std::vector & currentConnections) = 0; /** * @brief Callback into the delegate once persistent attributes managed by * the Cluster have been loaded from Storage. */ - virtual Protocols::InteractionModel::Status PersistentAttributesLoadedCallback() = 0; - + virtual CHIP_ERROR PersistentAttributesLoadedCallback() = 0; }; class PushAvStreamTransportServer : private AttributeAccessInterface, private CommandHandlerInterface @@ -168,8 +185,7 @@ class PushAvStreamTransportServer : private AttributeAccessInterface, private Co * @param aDelegate A reference to the delegate to be used by this server. * Note: the caller must ensure that the delegate lives throughout the instance's lifetime. */ - PushAvStreamTransportServer(EndpointId endpointId, PushAvStreamTransportDelegate & delegate, const BitFlags aFeatures, - PersistentStorageDelegate & aPersistentStorage); + PushAvStreamTransportServer(EndpointId endpointId, PushAvStreamTransportDelegate & delegate); ~PushAvStreamTransportServer() override; @@ -196,31 +212,12 @@ class PushAvStreamTransportServer : private AttributeAccessInterface, private Co private: PushAvStreamTransportDelegate & mDelegate; - const BitFlags mFeature; // Attributes BitMask mSupportedContainerFormats; BitMask mSupportedIngestMethods; // lists - std::vector mCurrentConnections; - - // Utility function to set and persist attributes - template - CHIP_ERROR SetAttributeIfDifferent(T & currentValue, const T & newValue, AttributeId attributeId, bool shouldPersist = true) - { - if (currentValue != newValue) - { - currentValue = newValue; - auto path = ConcreteAttributePath(mEndpointId, PushAvStreamTransport::Id, attributeId); - if (shouldPersist) - { - ReturnErrorOnFailure(GetSafeAttributePersistenceProvider()->WriteScalarValue(path, currentValue)); - } - mDelegate.OnAttributeChanged(attributeId); - MatterReportingAttributeChangeCallback(path); - } - return CHIP_NO_ERROR; - } + std::vector mCurrentConnections; /** * IM-level implementation of read @@ -228,12 +225,6 @@ class PushAvStreamTransportServer : private AttributeAccessInterface, private Co */ CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; - /** - * IM-level implementation of write - * @return appropriately mapped CHIP_ERROR if applicable - */ - CHIP_ERROR Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) override; - /** * Helper function that loads all the persistent attributes from the KVS. */ @@ -243,6 +234,7 @@ class PushAvStreamTransportServer : private AttributeAccessInterface, private Co CHIP_ERROR ReadAndEncodeCurrentConnections(const AttributeValueEncoder::ListEncodeHelper & encoder); // Helper functions + bool FindStreamTransportConnection(const uint16_t connectionID); uint16_t GenerateConnectionID(); From f25fe397f104e48c320a972e444c53c3a9220814 Mon Sep 17 00:00:00 2001 From: Sayon Deep Date: Fri, 11 Apr 2025 03:29:53 +0530 Subject: [PATCH 05/22] Check cluster specific code --- .../push-av-stream-transport-server.cpp | 175 +++++++++++++----- .../push-av-stream-transport-server.h | 43 +++-- 2 files changed, 145 insertions(+), 73 deletions(-) diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp index 6baf34d283a256..088a3f15ae9f68 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp @@ -79,28 +79,49 @@ CHIP_ERROR PushAvStreamTransportServer::ReadAndEncodeCurrentConnections(const At return CHIP_NO_ERROR; } -CHIP_ERROR PushAvStreamTransportServer::AddStreamTransportConnection(const uint16_t transportConnectionId) +PushAvStreamTransportServer::UpsertResultEnum +PushAvStreamTransportServer::UpsertStreamTransportConnection(const TransportConfigurationStruct & transportConfiguration) { - mCurrentConnections.push_back(transportConnectionId); - auto path = ConcreteAttributePath(AttributeAccessInterface::GetEndpointId().Value(), PushAvStreamTransport::Id, - Attributes::CurrentConnections::Id); - mDelegate.OnAttributeChanged(Attributes::CurrentConnections::Id); - MatterReportingAttributeChangeCallback(path); + UpsertResultEnum result; + auto it = + std::find_if(mCurrentConnections.begin(), mCurrentConnections.end(), + [id = transportConfiguration.connectionID](const auto & existing) { return existing.connectionID == id; }); - return CHIP_NO_ERROR; + if (it != mCurrentConnections.end()) + { + *it = transportConfiguration; + result = UpsertResultEnum::kUpdated; + } + else + { + mCurrentConnections.push_back(transportConfiguration); + result = UpsertResultEnum::kInserted; + } + + MatterReportingAttributeChangeCallback(AttributeAccessInterface::GetEndpointId().Value(), PushAvStreamTransport::Id, + PushAvStreamTransport::Attributes::CurrentConnections::Id); + + return result; } -CHIP_ERROR PushAvStreamTransportServer::RemoveStreamTransportConnection(const uint16_t transportConnectionId) +void PushAvStreamTransportServer::RemoveStreamTransportConnection(const uint16_t transportConnectionId) { + size_t originalSize = mCurrentConnections.size(); + + // Erase-Remove idiom mCurrentConnections.erase(std::remove_if(mCurrentConnections.begin(), mCurrentConnections.end(), - [&](const uint16_t connectionID) { return connectionID == transportConnectionId; }), + [transportConnectionId](const TransportConfigurationStruct & s) { + return s.connectionID == transportConnectionId; + }), mCurrentConnections.end()); - auto path = ConcreteAttributePath(AttributeAccessInterface::GetEndpointId().Value(), PushAvStreamTransport::Id, - Attributes::CurrentConnections::Id); - mDelegate.OnAttributeChanged(Attributes::CurrentConnections::Id); - MatterReportingAttributeChangeCallback(path); - return CHIP_NO_ERROR; + // If a connection was removed, the size will be smaller. + if (mCurrentConnections.size() < originalSize) + { + // Notify the stack that the CurrentConnections attribute has changed. + MatterReportingAttributeChangeCallback(AttributeAccessInterface::GetEndpointId().Value(), PushAvStreamTransport::Id, + PushAvStreamTransport::Attributes::CurrentConnections::Id); + } } CHIP_ERROR PushAvStreamTransportServer::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) @@ -197,14 +218,14 @@ void PushAvStreamTransportServer::InvokeCommand(HandlerContext & handlerContext) } } -bool PushAvStreamTransportServer::FindStreamTransportConnection(const uint16_t connectionID) +TransportConfigurationStruct * PushAvStreamTransportServer::FindStreamTransportConnection(const uint16_t connectionID) { - for (auto & connection : mCurrentConnections) + for (auto & transportConnection : mCurrentConnections) { - if (connection.connectionID == connectionID) - return true; + if (transportConnection.connectionID == connectionID) + return &transportConnection; } - return false; + return nullptr; } uint16_t PushAvStreamTransportServer::GenerateConnectionID() @@ -236,7 +257,7 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c if (ep == kEmberInvalidEndpointIndex) { - auto status = StatusCodeEnum::kInvalidTLSEndpoint; + auto status = static_cast(StatusCodeEnum::kInvalidTLSEndpoint); ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid TLSEndpointId not found"); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); return; @@ -244,7 +265,7 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c if (transportOptions.ingestMethod == IngestMethodsEnum::kUnknownEnumValue) { - auto status = StatusCodeEnum::kUnsupportedIngestMethod; + auto status = static_cast(StatusCodeEnum::kUnsupportedIngestMethod); ChipLogError(Zcl, "HandleAllocatePushTransport: Ingest method not supported"); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); return; @@ -252,7 +273,7 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c if (transportOptions.containerFormat == ContainerFormatEnum::kUnknownEnumValue) { - auto status = StatusCodeEnum::kUnsupportedContainerFormat; + auto status = static_cast(StatusCodeEnum::kUnsupportedContainerFormat); ChipLogError(Zcl, "HandleAllocatePushTransport: Container format not supported"); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); return; @@ -260,7 +281,7 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c if (transportOptions.triggerOptions.triggerType == TransportTriggerTypeEnum::kUnknownEnumValue) { - auto status = StatusCodeEnum::kInvalidTriggerType; + auto status = static_cast(StatusCodeEnum::kInvalidTriggerType); ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid Trigger type"); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); return; @@ -273,30 +294,29 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c mDelegate.ValidateStreamUsage(transportOptions.streamUsage, transportOptions.videoStreamID, transportOptions.audioStreamID); if (err != CHIP_NO_ERROR) { - auto status = StatusCodeEnum::kInvalidStream; + auto status = static_cast(StatusCodeEnum::kInvalidStream); ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid Stream"); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); return; } - uint16_t connectionID = GenerateConnectionID(); - TransportStatusEnum outTransportStatus = TransportStatusEnum::kUnknownEnumValue; + uint16_t connectionID = GenerateConnectionID(); + TransportConfigurationStruct outTransportConfiguration; - outTransportConfiguration.connectionID = connectionID; + outTransportConfiguration.connectionID = connectionID; outTransportConfiguration.transportStatus = TransportStatusEnum::kInactive; - outTransportConfiguration.transportOptions = transportOptions; - // call the delegate + /** + * delegate should set the TransportOptions fields to the new values. + * Persistently store the resulting TransportConfigurationStruct and map it to the ConnectionID + */ Status status = mDelegate.AllocatePushTransport(transportOptions, outTransportConfiguration); if (status == Status::Success) { - response.connectionID = connectionID; - response.transportOptions = transportOptions; - response.transportStatus = outTransportStatus; - // add connection to CurrentConnections - AddStreamTransportConnection(connectionID); + UpsertStreamTransportConnection(outTransportConfiguration); + response.transportConfiguration = outTransportConfiguration; ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); } @@ -332,9 +352,9 @@ void PushAvStreamTransportServer::HandleDeallocatePushTransport( void PushAvStreamTransportServer::HandleModifyPushTransport(HandlerContext & ctx, const Commands::ModifyPushTransport::DecodableType & commandData) { - Status status = Status::Success; - uint16_t connectionID = commandData.connectionID; - auto & outTransportOptions = commandData.transportOptions; + Status status = Status::Success; + uint16_t connectionID = commandData.connectionID; + auto & transportOptions = commandData.transportOptions; if (!FindStreamTransportConnection(connectionID)) { @@ -344,7 +364,7 @@ void PushAvStreamTransportServer::HandleModifyPushTransport(HandlerContext & ctx } // Call the delegate - status = mDelegate.ModifyPushTransport(connectionID, outTransportOptions); + status = mDelegate.ModifyPushTransport(connectionID, transportOptions); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } @@ -352,19 +372,31 @@ void PushAvStreamTransportServer::HandleModifyPushTransport(HandlerContext & ctx void PushAvStreamTransportServer::HandleSetTransportStatus(HandlerContext & ctx, const Commands::SetTransportStatus::DecodableType & commandData) { - Status status = Status::Success; - uint16_t connectionID = commandData.connectionID; - auto & transportStatus = commandData.transportStatus; + Status status = Status::Success; + DataModel::Nullable connectionID = commandData.connectionID; + auto & transportStatus = commandData.transportStatus; + std::vector connectionIDList; - if (!FindStreamTransportConnection(connectionID)) + if (connectionID.IsNull()) + { + for (auto & transportConnection : mCurrentConnections) + { + connectionIDList.push_back(transportConnection.connectionID); + } + } + else if (!FindStreamTransportConnection(connectionID.Value())) { ChipLogError(Zcl, "HandleSetTransportStatus: ConnectionID Not Found."); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } + else + { + connectionIDList.push_back(connectionID.Value()); + } // Call the delegate - status = mDelegate.SetTransportStatus(connectionID, transportStatus); + status = mDelegate.SetTransportStatus(connectionIDList); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } @@ -377,13 +409,45 @@ void PushAvStreamTransportServer::HandleManuallyTriggerTransport( auto & activationReason = commandData.activationReason; auto & timeControl = commandData.timeControl; - if (!FindStreamTransportConnection(connectionID)) + TransportConfigurationStruct * transportConfiguration = FindStreamTransportConnection(connectionID); + + if (!transportConfiguration) { ChipLogError(Zcl, "HandleManuallyTriggerTransport: ConnectionID Not Found."); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } + if (transportConfiguration->transportStatus == TransportStatusEnum::kInactive) + { + auto status = static_cast(StatusCodeEnum::kInvalidTransportStatus); + ChipLogError(Zcl, "HandleManuallyTriggerTransport: Invalid Transport status"); + ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); + return; + } + if (transportConfiguration->transportOptions.HasValue()) + { + if (transportConfiguration->transportOptions.Value().triggerOptions.triggerType == TransportTriggerTypeEnum::kContinuous) + { + { + auto status = static_cast(StatusCodeEnum::kInvalidTriggerType); + ChipLogError(Zcl, "HandleManuallyTriggerTransport: Invalid Trigger type"); + ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); + return; + } + } + else if (transportConfiguration->transportOptions.Value().triggerOptions.triggerType == + TransportTriggerTypeEnum::kCommand && + !timeControl.HasValue()) + { + { + ChipLogError(Zcl, "HandleManuallyTriggerTransport: Time control field not present"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + return; + } + } + } + // Call the delegate status = mDelegate.ManuallyTriggerTransport(connectionID, activationReason, timeControl); @@ -398,20 +462,29 @@ void PushAvStreamTransportServer::HandleFindTransport(HandlerContext & ctx, Optional> connectionID = commandData.connectionID; - DataModel::List outStreamConfigurations; - - // Call the delegate - status = mDelegate.FindTransport(connectionID, outStreamConfigurations); + DataModel::List outTransportConfigurations; - if (connectionID.HasValue() && outStreamConfigurations.size() == 0) + if (connectionID.Value().IsNull()) { - ChipLogError(Zcl, "HandleFindTransport: No allocated transport for connectionID."); + if (mCurrentConnections.size() == 0) + { + ChipLogError(Zcl, "HandleFindTransport: ConnectionID not found"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); + return; + } + } + else if (!FindStreamTransportConnection(connectionID.Value().Value())) + { + ChipLogError(Zcl, "HandleFindTransport: ConnectionID not found"); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } + + // Call the delegate + status = mDelegate.FindTransport(connectionID,outTransportConfigurations); if (status == Status::Success) { - response.streamConfigurations = outStreamConfigurations; + response.transportConfigurations = outTransportConfigurations; ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); } diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h index 09e5c1b57fadd2..569785322986d4 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h @@ -38,6 +38,8 @@ using TransportMotionTriggerTimeControlStruct = Structs::TransportMotionTriggerT using TransportOptionsStruct = Structs::TransportOptionsStruct::Type; using TransportConfigurationStruct = Structs::TransportConfigurationStruct::Type; +using TransportOptionsDecodeableStruct = Structs::TransportOptionsStruct::DecodableType; + /** @brief * Defines interfaces for implementing application-specific logic for various aspects of the PushAvStreamTransport Delegate. * Specifically, it defines interfaces for the command handling and loading of the allocated streams. @@ -52,19 +54,16 @@ class PushAvStreamTransportDelegate /** * @brief Handle Command Delegate for stream transport allocation with the provided transport configuration option. * - * @param connectionID[in] Indicates the connectionID to allocate. - * * @param transportOptions[in] represent the configuration options of the transport to be allocated * - * @param outTransportStatus[out] represent the status of the transport allocation + * @param outTransporConfiguration[out] represent the configuration of the transport to be allocated * * @return Success if the allocation is successful and a PushTransportConnectionID was * produced; otherwise, the command SHALL be rejected with an appropriate * error. */ - virtual Protocols::InteractionModel::Status AllocatePushTransport(uint16_t connectionID, - const TransportOptionsStruct & transportOptions, - TransportStatusEnum & outTransportStatus) = 0; + virtual Protocols::InteractionModel::Status AllocatePushTransport(const TransportOptionsDecodeableStruct & transportOptions, + TransportConfigurationStruct & outTransporConfiguration) = 0; /** * @brief Handle Command Delegate for Stream transport deallocation for the * provided connectionID. @@ -81,27 +80,23 @@ class PushAvStreamTransportDelegate * * @param connectionID [in] Indicates the connectionID of the stream transport to modify. * - * @param outTransportOptions [out] represents the Trigger Options to modify. + * @param transportOptions [out] represents the Trigger Options to modify. * * @return Success if the stream transport modification is successful; otherwise, the command SHALL be rejected with an * appropriate error. */ virtual Protocols::InteractionModel::Status ModifyPushTransport(const uint16_t connectionID, - const TransportOptionsStruct & outTransportOptions) = 0; + const TransportOptionsDecodeableStruct & transportOptions) = 0; /** * @brief Handle Command Delegate for Stream transport modification. * - * @param connectionID [in] Indicates the connectionID of the stream transport to set status for. - * - * @param transportStatus [in] represent the new transport status to apply. + * @param connectionIDList [in] represent the list of connectionIDs for which new transport status to apply. * * @return Success if the stream transport status is successfully set; otherwise, the command SHALL be rejected with an * appropriate error. */ - virtual Protocols::InteractionModel::Status SetTransportStatus(const uint16_t connectionID, - TransportStatusEnum transportStatus) = 0; - + virtual Protocols::InteractionModel::Status SetTransportStatus(const std::vector connectionIDList) = 0; /** * @brief Handle Command Delegate to request the Node to manually start the specified push transport. * @@ -117,7 +112,7 @@ appropriate */ virtual Protocols::InteractionModel::Status ManuallyTriggerTransport(const uint16_t connectionID, TriggerActivationReasonEnum activationReason, - const TransportMotionTriggerTimeControlStruct & timeControl) = 0; + const Optional & timeControl) = 0; /** * @brief Handle Command Delegate to get the Stream Options Configuration for the specified push transport. @@ -133,7 +128,7 @@ appropriate */ virtual Protocols::InteractionModel::Status FindTransport(const Optional> & connectionID, - DataModel::List & outtransportConfigurations) = 0; + DataModel::List & outtransportConfigurations) = 0; /** * @brief Validates the requested stream usage against the camera's resource management @@ -166,7 +161,7 @@ appropriate * list, at initialization. Once loaded, the cluster server would be serving Reads on these attributes. The list is updatable * via the Add/Remove functions for the respective transport connections. */ - virtual CHIP_ERROR LoadCurrentConnections(std::vector & currentConnections) = 0; + virtual CHIP_ERROR LoadCurrentConnections(std::vector & currentConnections) = 0; /** * @brief Callback into the delegate once persistent attributes managed by @@ -211,6 +206,12 @@ class PushAvStreamTransportServer : private AttributeAccessInterface, private Co BitMask GetSupportedIngestMethods() const { return mSupportedIngestMethods; } private: + enum class UpsertResultEnum : uint8_t + { + kInserted = 0x00, + kUpdated = 0x01, + }; + PushAvStreamTransportDelegate & mDelegate; // Attributes @@ -234,14 +235,12 @@ class PushAvStreamTransportServer : private AttributeAccessInterface, private Co CHIP_ERROR ReadAndEncodeCurrentConnections(const AttributeValueEncoder::ListEncodeHelper & encoder); // Helper functions - - bool FindStreamTransportConnection(const uint16_t connectionID); uint16_t GenerateConnectionID(); - + TransportConfigurationStruct * FindStreamTransportConnection(const uint16_t connectionID); // Add/Remove Management functions for transport - CHIP_ERROR AddStreamTransportConnection(const uint16_t transportConnectionId); + UpsertResultEnum UpsertStreamTransportConnection(const TransportConfigurationStruct & transportConfiguration); - CHIP_ERROR RemoveStreamTransportConnection(const uint16_t transportConnectionId); + void RemoveStreamTransportConnection(const uint16_t connectionID); /** * @brief Inherited from CommandHandlerInterface From 8f22e903447437753d9fef9c0ae5fd056f137258 Mon Sep 17 00:00:00 2001 From: Sayon Deep Date: Fri, 11 Apr 2025 03:35:04 +0530 Subject: [PATCH 06/22] remove conflict to camera example app --- .../camera-common/camera-app.matter | 205 +------- .../camera-app/camera-common/camera-app.zap | 489 ------------------ .../app-common/zap-generated/callback.h | 53 -- 3 files changed, 1 insertion(+), 746 deletions(-) diff --git a/examples/camera-app/camera-common/camera-app.matter b/examples/camera-app/camera-common/camera-app.matter index 52f4f8effc57c1..671b974070a11b 100644 --- a/examples/camera-app/camera-common/camera-app.matter +++ b/examples/camera-app/camera-common/camera-app.matter @@ -2169,11 +2169,7 @@ provisional cluster CameraAvStreamManagement = 1361 { kJPEG = 0; } -<<<<<<< HEAD shared enum StreamUsageEnum : enum8 { -======= - enum StreamUsageEnum : enum8 { ->>>>>>> 0d4f9fefb9 (add push av cluster to camera-app and some fixes) kInternal = 0; kRecording = 1; kAnalysis = 2; @@ -2209,10 +2205,7 @@ provisional cluster CameraAvStreamManagement = 1361 { kWatermark = 0x40; kOnScreenDisplay = 0x80; kLocalStorage = 0x100; -<<<<<<< HEAD kHighDynamicRange = 0x200; -======= ->>>>>>> 0d4f9fefb9 (add push av cluster to camera-app and some fixes) } struct VideoResolutionStruct { @@ -2281,74 +2274,24 @@ provisional cluster CameraAvStreamManagement = 1361 { struct VideoSensorParamsStruct { int16u sensorWidth = 0; int16u sensorHeight = 1; -<<<<<<< HEAD int16u maxFPS = 2; optional int16u maxHDRFPS = 3; } shared struct ViewportStruct { -======= - boolean HDRCapable = 2; - int16u maxFPS = 3; - int16u maxHDRFPS = 4; - } - - struct ViewportStruct { ->>>>>>> 0d4f9fefb9 (add push av cluster to camera-app and some fixes) int16u x1 = 0; int16u y1 = 1; int16u x2 = 2; int16u y2 = 3; } -<<<<<<< HEAD -======= - info event VideoStreamChanged = 0 { - int16u videoStreamID = 0; - optional StreamUsageEnum streamUsage = 1; - optional VideoCodecEnum videoCodec = 2; - optional int16u minFrameRate = 3; - optional int16u maxFrameRate = 4; - optional VideoResolutionStruct minResolution = 5; - optional VideoResolutionStruct maxResolution = 6; - optional int32u minBitRate = 7; - optional int32u maxBitRate = 8; - optional int16u minFragmentLen = 9; - optional int16u maxFragmentLen = 10; - } - - info event AudioStreamChanged = 1 { - int16u audioStreamID = 0; - optional StreamUsageEnum streamUsage = 1; - optional AudioCodecEnum audioCodec = 2; - optional int8u channelCount = 3; - optional int32u sampleRate = 4; - optional int32u bitRate = 5; - optional int8u bitDepth = 6; - } - - info event SnapshotStreamChanged = 2 { - int16u snapshotStreamID = 0; - optional ImageCodecEnum imageCodec = 1; - optional int16u frameRate = 2; - optional int32u bitRate = 3; - optional VideoResolutionStruct minResolution = 4; - optional VideoResolutionStruct maxResolution = 5; - optional int8u quality = 6; - } - ->>>>>>> 0d4f9fefb9 (add push av cluster to camera-app and some fixes) readonly attribute optional int8u maxConcurrentVideoEncoders = 0; readonly attribute optional int32u maxEncodedPixelRate = 1; readonly attribute optional VideoSensorParamsStruct videoSensorParams = 2; readonly attribute optional boolean nightVisionCapable = 3; readonly attribute optional VideoResolutionStruct minViewport = 4; readonly attribute optional RateDistortionTradeOffPointsStruct rateDistortionTradeOffPoints[] = 5; -<<<<<<< HEAD readonly attribute int32u maxContentBufferSize = 6; -======= - readonly attribute optional int32u maxContentBufferSize = 6; ->>>>>>> 0d4f9fefb9 (add push av cluster to camera-app and some fixes) readonly attribute optional AudioCapabilitiesStruct microphoneCapabilities = 7; readonly attribute optional AudioCapabilitiesStruct speakerCapabilities = 8; readonly attribute optional TwoWayTalkSupportTypeEnum twoWayTalkSupport = 9; @@ -2356,11 +2299,7 @@ provisional cluster CameraAvStreamManagement = 1361 { readonly attribute int32u maxNetworkBandwidth = 11; readonly attribute optional int16u currentFrameRate = 12; attribute access(read: manage, write: manage) optional boolean HDRModeEnabled = 13; -<<<<<<< HEAD readonly attribute StreamUsageEnum supportedStreamUsages[] = 14; -======= - readonly attribute fabric_idx fabricsUsingCamera[] = 14; ->>>>>>> 0d4f9fefb9 (add push av cluster to camera-app and some fixes) readonly attribute optional VideoStreamStruct allocatedVideoStreams[] = 15; readonly attribute optional AudioStreamStruct allocatedAudioStreams[] = 16; readonly attribute optional SnapshotStreamStruct allocatedSnapshotStreams[] = 17; @@ -2730,121 +2669,6 @@ provisional cluster Chime = 1366 { command PlayChimeSound(): DefaultSuccess = 0; } -/** This Cluster is used to manage TLS Client Certificates and to provision - TLS endpoints with enough information to facilitate subsequent connection. */ -provisional cluster TlsCertificateManagement = 2049 { - revision 1; - - struct TLSCertStruct { - int16u caid = 0; - long_octet_string<3000> certificate = 1; - } - - struct TLSClientCertificateDetailStruct { - int16u ccdid = 0; - long_octet_string<3000> clientCertificate = 1; - octet_string intermediateCertificates[] = 2; - } - - readonly attribute int8u maxRootCertificates = 0; - readonly attribute int8u currentRootCertificates = 1; - readonly attribute int8u maxClientCertificates = 2; - readonly attribute int8u currentClientCertificates = 3; - readonly attribute command_id generatedCommandList[] = 65528; - readonly attribute command_id acceptedCommandList[] = 65529; - readonly attribute event_id eventList[] = 65530; - readonly attribute attrib_id attributeList[] = 65531; - readonly attribute bitmap32 featureMap = 65532; - readonly attribute int16u clusterRevision = 65533; - - request struct ProvisionRootCertificateRequest { - long_octet_string<3000> certificate = 0; - nullable int16u caid = 1; - } - - response struct ProvisionRootCertificateResponse = 1 { - int16u caid = 0; - } - - request struct FindRootCertificateRequest { - nullable int16u caid = 0; - } - - response struct FindRootCertificateResponse = 3 { - TLSCertStruct certificateDetails[] = 0; - } - - request struct LookupRootCertificateRequest { - octet_string<64> fingerprint = 0; - } - - response struct LookupRootCertificateResponse = 5 { - int16u caid = 0; - } - - request struct RemoveRootCertificateRequest { - int16u caid = 0; - } - - request struct TLSClientCSRRequest { - octet_string nonce = 0; - } - - response struct TLSClientCSRResponse = 8 { - int16u ccdid = 0; - octet_string csr = 1; - octet_string nonce = 2; - } - - request struct ProvisionClientCertificateRequest { - int16u ccdid = 0; - TLSClientCertificateDetailStruct clientCertificateDetails = 1; - } - - response struct ProvisionClientCertificateResponse = 10 { - int16u ccdid = 0; - } - - request struct FindClientCertificateRequest { - int16u ccdid = 0; - } - - response struct FindClientCertificateResponse = 12 { - TLSClientCertificateDetailStruct certificateDetails[] = 0; - } - - request struct LookupClientCertificateRequest { - octet_string<64> fingerprint = 0; - } - - response struct LookupClientCertificateResponse = 14 { - int16u ccdid = 0; - } - - request struct RemoveClientCertificateRequest { - int16u ccdid = 0; - } - - /** This command SHALL provision the provided certificate for the passed in CAID. */ - command access(invoke: administer) ProvisionRootCertificate(ProvisionRootCertificateRequest): ProvisionRootCertificateResponse = 0; - /** This command SHALL return the TLSCertStruct for the passed in CAID. */ - command FindRootCertificate(FindRootCertificateRequest): FindRootCertificateResponse = 2; - /** This command SHALL return the CAID for the passed in fingerprint. */ - command LookupRootCertificate(LookupRootCertificateRequest): LookupRootCertificateResponse = 4; - /** This command SHALL be generated to request the server removes the certificate provisioned to the provided Certificate Authority ID. */ - command access(invoke: administer) RemoveRootCertificate(RemoveRootCertificateRequest): DefaultSuccess = 6; - /** This command SHALL be generated to request the Node generates a Certificate Signing Request. */ - command access(invoke: administer) TLSClientCSR(TLSClientCSRRequest): TLSClientCSRResponse = 7; - /** This command SHALL be generated to request the Node provisions the provided Client Certificate Details. */ - command access(invoke: administer) ProvisionClientCertificate(ProvisionClientCertificateRequest): ProvisionClientCertificateResponse = 9; - /** This command SHALL return the TLSClientCertificateDetailStruct for the passed in CCDID. */ - command FindClientCertificate(FindClientCertificateRequest): FindClientCertificateResponse = 11; - /** This command SHALL return the CCDID for the passed in Fingerprint. */ - command LookupClientCertificate(LookupClientCertificateRequest): LookupClientCertificateResponse = 13; - /** This command SHALL be generated to request the Node removes the certificate provisioned to the provided Client Certificate Details ID. */ - command access(invoke: administer) RemoveClientCertificate(RemoveClientCertificateRequest): DefaultSuccess = 15; -} - endpoint 0 { device type ma_rootdevice = 22, version 3; device type ma_otarequestor = 18, version 1; @@ -3362,33 +3186,6 @@ endpoint 1 { handle command PlayChimeSound; } +} - server cluster TlsCertificateManagement { - ram attribute maxRootCertificates; - ram attribute currentRootCertificates; - ram attribute maxClientCertificates; - ram attribute currentClientCertificates; - callback attribute generatedCommandList; - callback attribute acceptedCommandList; - callback attribute attributeList; - ram attribute featureMap default = 0; - ram attribute clusterRevision default = 1; - handle command ProvisionRootCertificate; - handle command ProvisionRootCertificateResponse; - handle command FindRootCertificate; - handle command FindRootCertificateResponse; - handle command LookupRootCertificate; - handle command LookupRootCertificateResponse; - handle command RemoveRootCertificate; - handle command TLSClientCSR; - handle command TLSClientCSRResponse; - handle command ProvisionClientCertificate; - handle command ProvisionClientCertificateResponse; - handle command FindClientCertificate; - handle command FindClientCertificateResponse; - handle command LookupClientCertificate; - handle command LookupClientCertificateResponse; - handle command RemoveClientCertificate; - } -} diff --git a/examples/camera-app/camera-common/camera-app.zap b/examples/camera-app/camera-common/camera-app.zap index 9fcb6616414ab5..4cdaaebdcb1fe2 100644 --- a/examples/camera-app/camera-common/camera-app.zap +++ b/examples/camera-app/camera-common/camera-app.zap @@ -6090,210 +6090,6 @@ } ] }, - { - "name": "Push AV Stream Transport", - "code": 1365, - "mfgCode": null, - "define": "PUSH_AV_STREAM_TRANSPORT_CLUSTER", - "side": "server", - "enabled": 1, - "commands": [ - { - "name": "AllocatePushTransport", - "code": 0, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "AllocatePushTransportResponse", - "code": 1, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - }, - { - "name": "DeallocatePushTransport", - "code": 2, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "ModifyPushTransport", - "code": 3, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "SetTransportStatus", - "code": 4, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "ManuallyTriggerTransport", - "code": 5, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "FindTransport", - "code": 6, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "FindTransportResponse", - "code": 7, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - } - ], - "attributes": [ - { - "name": "SupportedContainerFormats", - "code": 0, - "mfgCode": null, - "side": "server", - "type": "SupportedContainerFormatsBitmap", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "SupportedIngestMethods", - "code": 1, - "mfgCode": null, - "side": "server", - "type": "SupportedIngestMethodsBitmap", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "CurrentConnections", - "code": 2, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "GeneratedCommandList", - "code": 65528, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "AcceptedCommandList", - "code": 65529, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "AttributeList", - "code": 65531, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "FeatureMap", - "code": 65532, - "mfgCode": null, - "side": "server", - "type": "bitmap32", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "0", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "ClusterRevision", - "code": 65533, - "mfgCode": null, - "side": "server", - "type": "int16u", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "1", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - } - ] - }, { "name": "Chime", "code": 1366, @@ -6442,291 +6238,6 @@ "reportableChange": 0 } ] - }, - { - "name": "TLS Certificate Management", - "code": 2049, - "mfgCode": null, - "define": "TLS_CERTIFICATE_MANAGEMENT_CLUSTER", - "side": "server", - "enabled": 1, - "apiMaturity": "provisional", - "commands": [ - { - "name": "ProvisionRootCertificate", - "code": 0, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "ProvisionRootCertificateResponse", - "code": 1, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - }, - { - "name": "FindRootCertificate", - "code": 2, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "FindRootCertificateResponse", - "code": 3, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - }, - { - "name": "LookupRootCertificate", - "code": 4, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "LookupRootCertificateResponse", - "code": 5, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - }, - { - "name": "RemoveRootCertificate", - "code": 6, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "TLSClientCSR", - "code": 7, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "TLSClientCSRResponse", - "code": 8, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - }, - { - "name": "ProvisionClientCertificate", - "code": 9, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "ProvisionClientCertificateResponse", - "code": 10, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - }, - { - "name": "FindClientCertificate", - "code": 11, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "FindClientCertificateResponse", - "code": 12, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - }, - { - "name": "LookupClientCertificate", - "code": 13, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - }, - { - "name": "LookupClientCertificateResponse", - "code": 14, - "mfgCode": null, - "source": "server", - "isIncoming": 0, - "isEnabled": 1 - }, - { - "name": "RemoveClientCertificate", - "code": 15, - "mfgCode": null, - "source": "client", - "isIncoming": 1, - "isEnabled": 1 - } - ], - "attributes": [ - { - "name": "MaxRootCertificates", - "code": 0, - "mfgCode": null, - "side": "server", - "type": "int8u", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "CurrentRootCertificates", - "code": 1, - "mfgCode": null, - "side": "server", - "type": "int8u", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "MaxClientCertificates", - "code": 2, - "mfgCode": null, - "side": "server", - "type": "int8u", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "CurrentClientCertificates", - "code": 3, - "mfgCode": null, - "side": "server", - "type": "int8u", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "GeneratedCommandList", - "code": 65528, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "AcceptedCommandList", - "code": 65529, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "AttributeList", - "code": 65531, - "mfgCode": null, - "side": "server", - "type": "array", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "FeatureMap", - "code": 65532, - "mfgCode": null, - "side": "server", - "type": "bitmap32", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "0", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "ClusterRevision", - "code": 65533, - "mfgCode": null, - "side": "server", - "type": "int16u", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "1", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - } - ] } ] } diff --git a/zzz_generated/app-common/app-common/zap-generated/callback.h b/zzz_generated/app-common/app-common/zap-generated/callback.h index 6bd941ccbea9eb..61bebcbc4720a2 100644 --- a/zzz_generated/app-common/app-common/zap-generated/callback.h +++ b/zzz_generated/app-common/app-common/zap-generated/callback.h @@ -7847,59 +7847,6 @@ bool emberAfCommodityTariffClusterGetTariffComponentCallback( bool emberAfCommodityTariffClusterGetDayEntryCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::CommodityTariff::Commands::GetDayEntry::DecodableType & commandData); - * @brief WebRTC Transport Provider Cluster SolicitOffer Command callback (from client) - */ -bool emberAfWebRTCTransportProviderClusterSolicitOfferCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::WebRTCTransportProvider::Commands::SolicitOffer::DecodableType & commandData); -/** - * @brief WebRTC Transport Provider Cluster ProvideOffer Command callback (from client) - */ -bool emberAfWebRTCTransportProviderClusterProvideOfferCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::WebRTCTransportProvider::Commands::ProvideOffer::DecodableType & commandData); -/** - * @brief WebRTC Transport Provider Cluster ProvideAnswer Command callback (from client) - */ -bool emberAfWebRTCTransportProviderClusterProvideAnswerCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::WebRTCTransportProvider::Commands::ProvideAnswer::DecodableType & commandData); -/** - * @brief WebRTC Transport Provider Cluster ProvideICECandidate Command callback (from client) - */ -bool emberAfWebRTCTransportProviderClusterProvideICECandidateCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::WebRTCTransportProvider::Commands::ProvideICECandidate::DecodableType & commandData); -/** - * @brief WebRTC Transport Provider Cluster EndSession Command callback (from client) - */ -bool emberAfWebRTCTransportProviderClusterEndSessionCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::WebRTCTransportProvider::Commands::EndSession::DecodableType & commandData); -/** - * @brief WebRTC Transport Requestor Cluster Offer Command callback (from client) - */ -bool emberAfWebRTCTransportRequestorClusterOfferCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::WebRTCTransportRequestor::Commands::Offer::DecodableType & commandData); -/** - * @brief WebRTC Transport Requestor Cluster Answer Command callback (from client) - */ -bool emberAfWebRTCTransportRequestorClusterAnswerCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::WebRTCTransportRequestor::Commands::Answer::DecodableType & commandData); -/** - * @brief WebRTC Transport Requestor Cluster ICECandidates Command callback (from client) - */ -bool emberAfWebRTCTransportRequestorClusterICECandidatesCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::WebRTCTransportRequestor::Commands::ICECandidates::DecodableType & commandData); -/** - * @brief WebRTC Transport Requestor Cluster End Command callback (from client) - */ -bool emberAfWebRTCTransportRequestorClusterEndCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::WebRTCTransportRequestor::Commands::End::DecodableType & commandData); /** * @brief TLS Certificate Management Cluster ProvisionRootCertificate Command callback (from client) */ From 14a243d7d1bc0960233472538afd28f8bb3d3c33 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Thu, 10 Apr 2025 22:11:31 +0000 Subject: [PATCH 07/22] Restyled by clang-format --- .../push-av-stream-transport-server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp index 088a3f15ae9f68..af678f6f9edd59 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp @@ -481,7 +481,7 @@ void PushAvStreamTransportServer::HandleFindTransport(HandlerContext & ctx, } // Call the delegate - status = mDelegate.FindTransport(connectionID,outTransportConfigurations); + status = mDelegate.FindTransport(connectionID, outTransportConfigurations); if (status == Status::Success) { response.transportConfigurations = outTransportConfigurations; From 2e0099bd7eee5e161684c8e9c7224e2bdc83c1d5 Mon Sep 17 00:00:00 2001 From: Sayon Deep Date: Fri, 18 Apr 2025 01:55:46 +0530 Subject: [PATCH 08/22] added delegate implementation in all_clusters_app --- .../all-clusters-app.matter | 387 ++++++++++++++++++ .../all-clusters-common/all-clusters-app.zap | 284 ++++++++++++- .../push-av-stream-transport-delegate-impl.h | 77 ++++ ...push-av-stream-transport-delegate-impl.cpp | 174 ++++++++ examples/all-clusters-app/linux/BUILD.gn | 1 + src/app/chip_data_model.gni | 1 - .../push-av-stream-transport-server.cpp | 6 +- .../push-av-stream-transport-server.h | 4 +- .../zcl/zcl-with-test-extensions.json | 5 +- src/app/zap-templates/zcl/zcl.json | 5 +- .../app-common/zap-generated/callback.h | 36 -- 11 files changed, 934 insertions(+), 46 deletions(-) create mode 100644 examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h create mode 100644 examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index 8f38a0739d2f5f..5b7b9f1c9a2fc8 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -7439,6 +7439,372 @@ provisional cluster CameraAvSettingsUserLevelManagement = 1362 { command DPTZRelativeMove(DPTZRelativeMoveRequest): DefaultSuccess = 6; } +/** This cluster implements the upload of Audio and Video streams from the Push AV Stream Transport Cluster using suitable push-based transports. */ +provisional cluster PushAvStreamTransport = 1365 { + revision 1; + + enum ContainerFormatEnum : enum8 { + kCMAF = 0; + } + + enum IngestMethodsEnum : enum8 { + kCMAFIngest = 0; + } + + enum StatusCodeEnum : enum8 { + kInvalidTLSEndpoint = 2; + kInvalidStream = 3; + kInvalidURL = 4; + kInvalidZone = 5; + kUnsupportedContainerFormat = 6; + kUnsupportedIngestMethod = 7; + kInvalidTriggerType = 8; + kInvalidTransportStatus = 9; + } + + shared enum StreamUsageEnum : enum8 { + kInternal = 0; + kRecording = 1; + kAnalysis = 2; + kLiveView = 3; + } + + enum TransportStatusEnum : enum8 { + kActive = 0; + kInactive = 1; + } + + enum TransportTriggerTypeEnum : enum8 { + kCommand = 0; + kMotion = 1; + kContinuous = 2; + } + + enum TriggerActivationReasonEnum : enum8 { + kUserInitiated = 0; + kAutomation = 1; + kEmergency = 2; + } + + bitmap Feature : bitmap32 { + kPerZoneSensitivity = 0x1; + kMetadata = 0x2; + } + + bitmap SupportedContainerFormatsBitmap : bitmap8 { + kCMAF = 0x1; + } + + bitmap SupportedIngestMethodsBitmap : bitmap8 { + kCMAFIngest = 0x1; + } + + struct TransportMotionTriggerTimeControlStruct { + int16u initialDuration = 0; + int16u augmentationDuration = 1; + elapsed_s maxDuration = 2; + int16u blindDuration = 3; + } + + struct TransportZoneOptionsStruct { + nullable int16u zone = 1; + optional int8u sensitivity = 2; + } + + struct TransportTriggerOptionsStruct { + TransportTriggerTypeEnum triggerType = 0; + optional nullable TransportZoneOptionsStruct motionZones[] = 1; + optional nullable int8u motionSensitivity = 2; + optional TransportMotionTriggerTimeControlStruct motionTimeControl = 3; + optional int16u maxPreRollLen = 4; + } + + struct CMAFContainerOptionsStruct { + int16u chunkDuration = 0; + optional octet_string<16> CENCKey = 1; + optional boolean metadataEnabled = 2; + } + + struct ContainerOptionsStruct { + ContainerFormatEnum containerType = 0; + optional CMAFContainerOptionsStruct CMAFContainerOptions = 1; + } + + struct TransportOptionsStruct { + StreamUsageEnum streamUsage = 0; + optional nullable int16u videoStreamID = 1; + optional nullable int16u audioStreamID = 2; + int16u endpointID = 3; + long_char_string<2000> url = 4; + TransportTriggerOptionsStruct triggerOptions = 5; + IngestMethodsEnum ingestMethod = 6; + ContainerFormatEnum containerFormat = 7; + ContainerOptionsStruct containerOptions = 8; + optional epoch_s expiryTime = 9; + } + + fabric_scoped struct TransportConfigurationStruct { + int16u connectionID = 0; + TransportStatusEnum transportStatus = 1; + optional TransportOptionsStruct transportOptions = 2; + fabric_idx fabricIndex = 254; + } + + info event PushTransportBegin = 0 { + int16u connectionID = 0; + TransportTriggerTypeEnum triggerType = 1; + optional TriggerActivationReasonEnum activationReason = 2; + } + + info event PushTransportEnd = 1 { + int16u connectionID = 0; + TransportTriggerTypeEnum triggerType = 1; + optional TriggerActivationReasonEnum activationReason = 2; + } + + readonly attribute SupportedContainerFormatsBitmap supportedContainerFormats = 0; + readonly attribute SupportedIngestMethodsBitmap supportedIngestMethods = 1; + readonly attribute TransportConfigurationStruct currentConnections[] = 2; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct AllocatePushTransportRequest { + TransportOptionsStruct transportOptions = 0; + } + + response struct AllocatePushTransportResponse = 1 { + TransportConfigurationStruct transportConfiguration = 0; + } + + request struct DeallocatePushTransportRequest { + int16u connectionID = 0; + } + + request struct ModifyPushTransportRequest { + int16u connectionID = 0; + TransportOptionsStruct transportOptions = 1; + } + + request struct SetTransportStatusRequest { + nullable int16u connectionID = 0; + TransportStatusEnum transportStatus = 1; + } + + request struct ManuallyTriggerTransportRequest { + int16u connectionID = 0; + TriggerActivationReasonEnum activationReason = 1; + optional TransportMotionTriggerTimeControlStruct timeControl = 2; + } + + request struct FindTransportRequest { + optional nullable int16u connectionID = 0; + } + + response struct FindTransportResponse = 7 { + TransportConfigurationStruct transportConfigurations[] = 0; + } + + /** This command SHALL allocate a transport and return a PushTransportConnectionID. */ + fabric command access(invoke: manage) AllocatePushTransport(AllocatePushTransportRequest): AllocatePushTransportResponse = 0; + /** This command SHALL be generated to request the Node deallocates the specified transport. */ + fabric command access(invoke: manage) DeallocatePushTransport(DeallocatePushTransportRequest): DefaultSuccess = 2; + /** This command is used to request the Node modifies the configuration of the specified push transport. */ + fabric command access(invoke: manage) ModifyPushTransport(ModifyPushTransportRequest): DefaultSuccess = 3; + /** This command SHALL be generated to request the Node modifies the Transport Status of a specified transport or all transports. */ + fabric command access(invoke: manage) SetTransportStatus(SetTransportStatusRequest): DefaultSuccess = 4; + /** This command SHALL be generated to request the Node to manually start the specified push transport. */ + fabric command ManuallyTriggerTransport(ManuallyTriggerTransportRequest): DefaultSuccess = 5; + /** This command SHALL return the Transport Configuration for the specified push transport or all allocated transports for the fabric if null. */ + fabric command FindTransport(FindTransportRequest): FindTransportResponse = 6; +} + +/** This cluster implements the upload of Audio and Video streams from the Push AV Stream Transport Cluster using suitable push-based transports. */ +provisional cluster PushAvStreamTransport = 1365 { + revision 1; + + enum ContainerFormatEnum : enum8 { + kCMAF = 0; + } + + enum IngestMethodsEnum : enum8 { + kCMAFIngest = 0; + } + + enum StatusCodeEnum : enum8 { + kInvalidTLSEndpoint = 2; + kInvalidStream = 3; + kInvalidURL = 4; + kInvalidZone = 5; + kUnsupportedContainerFormat = 6; + kUnsupportedIngestMethod = 7; + kInvalidTriggerType = 8; + kInvalidTransportStatus = 9; + } + + shared enum StreamUsageEnum : enum8 { + kInternal = 0; + kRecording = 1; + kAnalysis = 2; + kLiveView = 3; + } + + enum TransportStatusEnum : enum8 { + kActive = 0; + kInactive = 1; + } + + enum TransportTriggerTypeEnum : enum8 { + kCommand = 0; + kMotion = 1; + kContinuous = 2; + } + + enum TriggerActivationReasonEnum : enum8 { + kUserInitiated = 0; + kAutomation = 1; + kEmergency = 2; + } + + bitmap Feature : bitmap32 { + kPerZoneSensitivity = 0x1; + kMetadata = 0x2; + } + + bitmap SupportedContainerFormatsBitmap : bitmap8 { + kCMAF = 0x1; + } + + bitmap SupportedIngestMethodsBitmap : bitmap8 { + kCMAFIngest = 0x1; + } + + struct TransportMotionTriggerTimeControlStruct { + int16u initialDuration = 0; + int16u augmentationDuration = 1; + elapsed_s maxDuration = 2; + int16u blindDuration = 3; + } + + struct TransportZoneOptionsStruct { + nullable int16u zone = 1; + optional int8u sensitivity = 2; + } + + struct TransportTriggerOptionsStruct { + TransportTriggerTypeEnum triggerType = 0; + optional nullable TransportZoneOptionsStruct motionZones[] = 1; + optional nullable int8u motionSensitivity = 2; + optional TransportMotionTriggerTimeControlStruct motionTimeControl = 3; + optional int16u maxPreRollLen = 4; + } + + struct CMAFContainerOptionsStruct { + int16u chunkDuration = 0; + optional octet_string<16> CENCKey = 1; + optional boolean metadataEnabled = 2; + } + + struct ContainerOptionsStruct { + ContainerFormatEnum containerType = 0; + optional CMAFContainerOptionsStruct CMAFContainerOptions = 1; + } + + struct TransportOptionsStruct { + StreamUsageEnum streamUsage = 0; + optional nullable int16u videoStreamID = 1; + optional nullable int16u audioStreamID = 2; + int16u endpointID = 3; + long_char_string<2000> url = 4; + TransportTriggerOptionsStruct triggerOptions = 5; + IngestMethodsEnum ingestMethod = 6; + ContainerFormatEnum containerFormat = 7; + ContainerOptionsStruct containerOptions = 8; + optional epoch_s expiryTime = 9; + } + + fabric_scoped struct TransportConfigurationStruct { + int16u connectionID = 0; + TransportStatusEnum transportStatus = 1; + optional TransportOptionsStruct transportOptions = 2; + fabric_idx fabricIndex = 254; + } + + info event PushTransportBegin = 0 { + int16u connectionID = 0; + TransportTriggerTypeEnum triggerType = 1; + optional TriggerActivationReasonEnum activationReason = 2; + } + + info event PushTransportEnd = 1 { + int16u connectionID = 0; + TransportTriggerTypeEnum triggerType = 1; + optional TriggerActivationReasonEnum activationReason = 2; + } + + readonly attribute SupportedContainerFormatsBitmap supportedContainerFormats = 0; + readonly attribute SupportedIngestMethodsBitmap supportedIngestMethods = 1; + readonly attribute TransportConfigurationStruct currentConnections[] = 2; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct AllocatePushTransportRequest { + TransportOptionsStruct transportOptions = 0; + } + + response struct AllocatePushTransportResponse = 1 { + TransportConfigurationStruct transportConfiguration = 0; + } + + request struct DeallocatePushTransportRequest { + int16u connectionID = 0; + } + + request struct ModifyPushTransportRequest { + int16u connectionID = 0; + TransportOptionsStruct transportOptions = 1; + } + + request struct SetTransportStatusRequest { + nullable int16u connectionID = 0; + TransportStatusEnum transportStatus = 1; + } + + request struct ManuallyTriggerTransportRequest { + int16u connectionID = 0; + TriggerActivationReasonEnum activationReason = 1; + optional TransportMotionTriggerTimeControlStruct timeControl = 2; + } + + request struct FindTransportRequest { + optional nullable int16u connectionID = 0; + } + + response struct FindTransportResponse = 7 { + TransportConfigurationStruct transportConfigurations[] = 0; + } + + /** This command SHALL allocate a transport and return a PushTransportConnectionID. */ + fabric command access(invoke: manage) AllocatePushTransport(AllocatePushTransportRequest): AllocatePushTransportResponse = 0; + /** This command SHALL be generated to request the Node deallocates the specified transport. */ + fabric command access(invoke: manage) DeallocatePushTransport(DeallocatePushTransportRequest): DefaultSuccess = 2; + /** This command is used to request the Node modifies the configuration of the specified push transport. */ + fabric command access(invoke: manage) ModifyPushTransport(ModifyPushTransportRequest): DefaultSuccess = 3; + /** This command SHALL be generated to request the Node modifies the Transport Status of a specified transport or all transports. */ + fabric command access(invoke: manage) SetTransportStatus(SetTransportStatusRequest): DefaultSuccess = 4; + /** This command SHALL be generated to request the Node to manually start the specified push transport. */ + fabric command ManuallyTriggerTransport(ManuallyTriggerTransportRequest): DefaultSuccess = 5; + /** This command SHALL return the Transport Configuration for the specified push transport or all allocated transports for the fabric if null. */ + fabric command FindTransport(FindTransportRequest): FindTransportResponse = 6; +} + /** This cluster provides facilities to configure and play Chime sounds, such as those used in a doorbell. */ provisional cluster Chime = 1366 { revision 1; @@ -8513,6 +8879,7 @@ endpoint 1 { device type ma_onofflight = 256, version 1; binding cluster OnOff; + binding cluster PushAvStreamTransport; server cluster Identify { ram attribute identifyTime default = 0x0000; @@ -9787,6 +10154,26 @@ endpoint 1 { handle command DPTZRelativeMove; } + server cluster PushAvStreamTransport { + ram attribute supportedContainerFormats; + ram attribute supportedIngestMethods; + callback attribute currentConnections; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command AllocatePushTransport; + handle command AllocatePushTransportResponse; + handle command DeallocatePushTransport; + handle command ModifyPushTransport; + handle command SetTransportStatus; + handle command ManuallyTriggerTransport; + handle command FindTransport; + handle command FindTransportResponse; + } + server cluster Chime { callback attribute installedChimeSounds; callback attribute selectedChime; diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap index 501ad53f16c5a5..465dba98b96499 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap @@ -21195,7 +21195,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -21355,7 +21355,7 @@ "code": 4, "mfgCode": null, "side": "server", - "type": "uint8s", + "type": "int8u", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -21512,6 +21512,286 @@ } ] }, + { + "name": "Push AV Stream Transport", + "code": 1365, + "mfgCode": null, + "define": "PUSH_AV_STREAM_TRANSPORT_CLUSTER", + "side": "client", + "enabled": 1, + "apiMaturity": "provisional", + "commands": [ + { + "name": "AllocatePushTransport", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "AllocatePushTransportResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "DeallocatePushTransport", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ModifyPushTransport", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "SetTransportStatus", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ManuallyTriggerTransport", + "code": 5, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "FindTransport", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "FindTransportResponse", + "code": 7, + "mfgCode": null, + "source": "server", + "isIncoming": 1, + "isEnabled": 1 + } + ] + }, + { + "name": "Push AV Stream Transport", + "code": 1365, + "mfgCode": null, + "define": "PUSH_AV_STREAM_TRANSPORT_CLUSTER", + "side": "server", + "enabled": 1, + "apiMaturity": "provisional", + "commands": [ + { + "name": "AllocatePushTransport", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AllocatePushTransportResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "DeallocatePushTransport", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ModifyPushTransport", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "SetTransportStatus", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ManuallyTriggerTransport", + "code": 5, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "FindTransport", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "FindTransportResponse", + "code": 7, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "SupportedContainerFormats", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "SupportedContainerFormatsBitmap", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportedIngestMethods", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "SupportedIngestMethodsBitmap", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "CurrentConnections", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, { "name": "Chime", "code": 1366, diff --git a/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h b/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h new file mode 100644 index 00000000000000..4625ad622d3b0e --- /dev/null +++ b/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 2025 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 +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace PushAvStreamTransport { + +struct PushAvStream +{ + uint16_t id; + TransportConfigurationStruct transportConfig; +}; + +/** + * The application delegate to define the options & implement commands. + */ +class PushAvStreamTransportManager : public PushAvStreamTransportDelegate +{ +public: + Protocols::InteractionModel::Status AllocatePushTransport(const TransportOptionsDecodeableStruct & transportOptions, + TransportConfigurationStruct & outTransporConfiguration); + Protocols::InteractionModel::Status DeallocatePushTransport(const uint16_t connectionID); + Protocols::InteractionModel::Status ModifyPushTransport(const uint16_t connectionID, + const TransportOptionsDecodeableStruct & transportOptions); + Protocols::InteractionModel::Status SetTransportStatus(const std::vector connectionIDList, TransportStatusEnum transportStatus); + + Protocols::InteractionModel::Status + ManuallyTriggerTransport(const uint16_t connectionID, TriggerActivationReasonEnum activationReason, + const Optional & timeControl); + Protocols::InteractionModel::Status + FindTransport(const Optional> & connectionID, + DataModel::List & outtransportConfigurations); + + CHIP_ERROR ValidateStreamUsage(StreamUsageEnum streamUsage, + const Optional> & videoStreamId, + const Optional> & audioStreamId); + + void OnAttributeChanged(AttributeId attributeId); + CHIP_ERROR LoadCurrentConnections(std::vector & currentConnections); + CHIP_ERROR PersistentAttributesLoadedCallback(); + + void Init(); + PushAvStreamTransportManager() = default; + + ~PushAvStreamTransportManager() = default; + +private: + std::vector pushavStreams; + std::vector configList; +}; + +} // namespace PushAvStreamTransport +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp new file mode 100644 index 00000000000000..a493ff1f504719 --- /dev/null +++ b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp @@ -0,0 +1,174 @@ +/* + * + * Copyright (c) 2025 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 +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::DataModel; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::PushAvStreamTransport; +using chip::Protocols::InteractionModel::Status; + +// Global pointer to overall PushAV Stream Transport implementing the Cluster delegate. +std::unique_ptr sPushAvStramTransportInstance; +// Global pointer to PushAV Stream Transport Server SDK cluster; +std::unique_ptr sPushAvStramTransportClusterServerInstance; + +Protocols::InteractionModel::Status +PushAvStreamTransportManager::AllocatePushTransport(const TransportOptionsDecodeableStruct & transportOptions, + TransportConfigurationStruct & outTransporConfiguration) +{ + PushAvStream stream{ outTransporConfiguration.connectionID, outTransporConfiguration }; + + /*Store the allocated stream persistently*/ + pushavStreams.push_back(stream); + + return Status::Success; +} + +Protocols::InteractionModel::Status PushAvStreamTransportManager::DeallocatePushTransport(const uint16_t connectionID) +{ + pushavStreams.erase(std::remove_if(pushavStreams.begin(), pushavStreams.end(), + [connectionID](const PushAvStream & stream) { return stream.id == connectionID; }), + pushavStreams.end()); + return Status::Success; +} + +Protocols::InteractionModel::Status +PushAvStreamTransportManager::ModifyPushTransport(const uint16_t connectionID, + const TransportOptionsDecodeableStruct & transportOptions) +{ + for (PushAvStream & stream : pushavStreams) + { + if (stream.id == connectionID) + { + ChipLogError(Zcl, "Modified Push AV Stream with ID: %d", connectionID); + return Status::Success; + } + } + ChipLogError(Zcl, "Allocated Push AV Stream with ID: %d not found", connectionID); + return Status::NotFound; +} + +Protocols::InteractionModel::Status PushAvStreamTransportManager::SetTransportStatus(const std::vector connectionIDList, + TransportStatusEnum transportStatus) +{ + for (PushAvStream & stream : pushavStreams) + { + for(uint16_t connectionID : connectionIDList) + { + if (stream.id == connectionID) + { + stream.transportConfig.transportStatus = transportStatus; + ChipLogError(Zcl, "Set Transport Status for Push AV Stream with ID: %d", connectionID); + + } + else + { + return Status::NotFound; + } + } + } + return Status::Success; +} + +Protocols::InteractionModel::Status + PushAvStreamTransportManager::ManuallyTriggerTransport(const uint16_t connectionID, TriggerActivationReasonEnum activationReason, + const Optional & timeControl) +{ + // TODO: Validates the requested stream usage against the camera's resource management and stream priority policies. + return Status::Success; +} + +Protocols::InteractionModel::Status + PushAvStreamTransportManager::FindTransport(const Optional> & connectionID, + DataModel::List & outtransportConfigurations) +{ + configList.clear(); + for (PushAvStream & stream : pushavStreams) + { + if (connectionID.Value().IsNull()) + { + configList.push_back(stream.transportConfig); + } + else if (connectionID.Value().Value() == stream.id) + { + configList.push_back(stream.transportConfig); + + } + } + outtransportConfigurations = DataModel::List(configList.data(),configList.size()); + return Status::Success; +} + +CHIP_ERROR +PushAvStreamTransportManager::ValidateStreamUsage(StreamUsageEnum streamUsage, + const Optional> & videoStreamId, + const Optional> & audioStreamId) +{ + // TODO: Validates the requested stream usage against the camera's resource management and stream priority policies. + return CHIP_NO_ERROR; +} + +void PushAvStreamTransportManager::OnAttributeChanged(AttributeId attributeId) +{ + ChipLogProgress(Zcl, "Attribute changed for AttributeId = " ChipLogFormatMEI, ChipLogValueMEI(attributeId)); +} + +void PushAvStreamTransportManager::Init() +{ + return; +} +CHIP_ERROR PushAvStreamTransportManager::LoadCurrentConnections(std::vector & currentConnections) +{ + ChipLogError(Zcl, "Push AV Current Connections loaded"); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR +PushAvStreamTransportManager::PersistentAttributesLoadedCallback() +{ + ChipLogError(Zcl, "Persistent attributes loaded"); + + return CHIP_NO_ERROR; +} + +void emberAfPushAvStreamTransportClusterInitCallback(EndpointId endpoint) +{ + VerifyOrReturn( + endpoint == 1, // this cluster is only enabled for endpoint 1. + ChipLogError(Zcl, "Push AV Stream Transport cluster delegate is not implemented for endpoint with id %d.", endpoint)); + + VerifyOrReturn(!sPushAvStramTransportInstance && !sPushAvStramTransportClusterServerInstance); + + sPushAvStramTransportInstance = std::make_unique(); + sPushAvStramTransportInstance->Init(); + + sPushAvStramTransportClusterServerInstance = + std::make_unique(endpoint, *sPushAvStramTransportInstance.get()); + sPushAvStramTransportClusterServerInstance->Init(); +} diff --git a/examples/all-clusters-app/linux/BUILD.gn b/examples/all-clusters-app/linux/BUILD.gn index 1647cffbf392b6..14aab15d754547 100644 --- a/examples/all-clusters-app/linux/BUILD.gn +++ b/examples/all-clusters-app/linux/BUILD.gn @@ -55,6 +55,7 @@ source_set("chip-all-clusters-common") { "${chip_root}/examples/all-clusters-app/all-clusters-common/src/oven-modes.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/oven-operational-state-delegate.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/power-topology-stub.cpp", + "${chip_root}/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/resource-monitoring-delegates.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/rvc-modes.cpp", "${chip_root}/examples/all-clusters-app/all-clusters-common/src/rvc-operational-state-delegate-impl.cpp", diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni index 846827c7663b49..ccdf551fc9e267 100644 --- a/src/app/chip_data_model.gni +++ b/src/app/chip_data_model.gni @@ -468,7 +468,6 @@ template("chip_data_model") { "${_app_root}/clusters/${cluster}/closure-control-cluster-objects.h", ] } else if (cluster == "camera-av-stream-management-server") { - } else if (cluster == "push-av-stream-transport-server") { sources += [ "${_app_root}/clusters/${cluster}/${cluster}.cpp", "${_app_root}/clusters/${cluster}/${cluster}.h", diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp index af678f6f9edd59..ec533383a404ae 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp @@ -45,8 +45,8 @@ namespace Clusters { namespace PushAvStreamTransport { PushAvStreamTransportServer::PushAvStreamTransportServer(EndpointId aEndpointId, PushAvStreamTransportDelegate & aDelegate) : - CommandHandlerInterface(MakeOptional(aEndpointId), CameraAvStreamManagement::Id), - AttributeAccessInterface(MakeOptional(aEndpointId), CameraAvStreamManagement::Id), mDelegate(aDelegate) + CommandHandlerInterface(MakeOptional(aEndpointId), PushAvStreamTransport::Id), + AttributeAccessInterface(MakeOptional(aEndpointId), PushAvStreamTransport::Id), mDelegate(aDelegate) {} PushAvStreamTransportServer::~PushAvStreamTransportServer() @@ -396,7 +396,7 @@ void PushAvStreamTransportServer::HandleSetTransportStatus(HandlerContext & ctx, } // Call the delegate - status = mDelegate.SetTransportStatus(connectionIDList); + status = mDelegate.SetTransportStatus(connectionIDList, transportStatus); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h index 569785322986d4..939b9eb813c2d4 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h @@ -29,7 +29,6 @@ namespace app { namespace Clusters { namespace PushAvStreamTransport { -using MetadataOptionsStruct = Structs::MetadataOptionsStruct::Type; using CMAFContainerOptionsStruct = Structs::CMAFContainerOptionsStruct::Type; using ContainerOptionsStruct = Structs::ContainerOptionsStruct::Type; using TransportZoneOptionsStruct = Structs::TransportZoneOptionsStruct::Type; @@ -92,11 +91,12 @@ class PushAvStreamTransportDelegate * @brief Handle Command Delegate for Stream transport modification. * * @param connectionIDList [in] represent the list of connectionIDs for which new transport status to apply. + * @param transportStatus [in] represents the updated status of the connection(s). * * @return Success if the stream transport status is successfully set; otherwise, the command SHALL be rejected with an * appropriate error. */ - virtual Protocols::InteractionModel::Status SetTransportStatus(const std::vector connectionIDList) = 0; + virtual Protocols::InteractionModel::Status SetTransportStatus(const std::vector connectionIDList, TransportStatusEnum transportStatus) = 0; /** * @brief Handle Command Delegate to request the Node to manually start the specified push transport. * diff --git a/src/app/zap-templates/zcl/zcl-with-test-extensions.json b/src/app/zap-templates/zcl/zcl-with-test-extensions.json index c623416002f78e..69f80c927e3010 100644 --- a/src/app/zap-templates/zcl/zcl-with-test-extensions.json +++ b/src/app/zap-templates/zcl/zcl-with-test-extensions.json @@ -748,7 +748,10 @@ "StatusLightBrightness", "FeatureMap" ], - "Camera AV Settings User Level Management": ["MPTZPosition"] + "Camera AV Settings User Level Management": ["MPTZPosition"], + "Push AV Stream Transport" :[ + "CurrentConnections" + ] }, "mandatoryDeviceTypes": "0x0016", "defaultReportingPolicy": "mandatory", diff --git a/src/app/zap-templates/zcl/zcl.json b/src/app/zap-templates/zcl/zcl.json index 7e32b1a2987302..3a0754247fcab1 100644 --- a/src/app/zap-templates/zcl/zcl.json +++ b/src/app/zap-templates/zcl/zcl.json @@ -742,7 +742,10 @@ "StatusLightBrightness", "FeatureMap" ], - "Camera AV Settings User Level Management": ["MPTZPosition"] + "Camera AV Settings User Level Management": ["MPTZPosition"], + "Push AV Stream Transport" :[ + "CurrentConnections" + ] }, "mandatoryDeviceTypes": "0x0016", "defaultReportingPolicy": "mandatory", diff --git a/zzz_generated/app-common/app-common/zap-generated/callback.h b/zzz_generated/app-common/app-common/zap-generated/callback.h index 61bebcbc4720a2..0fa4bbd7bd781e 100644 --- a/zzz_generated/app-common/app-common/zap-generated/callback.h +++ b/zzz_generated/app-common/app-common/zap-generated/callback.h @@ -7799,42 +7799,6 @@ bool emberAfZoneManagementClusterGetTwoDCartesianZoneCallback( bool emberAfZoneManagementClusterRemoveZoneCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::ZoneManagement::Commands::RemoveZone::DecodableType & commandData); -/** - * @brief Push AV Stream Transport Cluster AllocatePushTransport Command callback (from client) - */ -bool emberAfPushAvStreamTransportClusterAllocatePushTransportCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::PushAvStreamTransport::Commands::AllocatePushTransport::DecodableType & commandData); -/** - * @brief Push AV Stream Transport Cluster DeallocatePushTransport Command callback (from client) - */ -bool emberAfPushAvStreamTransportClusterDeallocatePushTransportCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::PushAvStreamTransport::Commands::DeallocatePushTransport::DecodableType & commandData); -/** - * @brief Push AV Stream Transport Cluster ModifyPushTransport Command callback (from client) - */ -bool emberAfPushAvStreamTransportClusterModifyPushTransportCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::PushAvStreamTransport::Commands::ModifyPushTransport::DecodableType & commandData); -/** - * @brief Push AV Stream Transport Cluster SetTransportStatus Command callback (from client) - */ -bool emberAfPushAvStreamTransportClusterSetTransportStatusCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::PushAvStreamTransport::Commands::SetTransportStatus::DecodableType & commandData); -/** - * @brief Push AV Stream Transport Cluster ManuallyTriggerTransport Command callback (from client) - */ -bool emberAfPushAvStreamTransportClusterManuallyTriggerTransportCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::PushAvStreamTransport::Commands::ManuallyTriggerTransport::DecodableType & commandData); -/** - * @brief Push AV Stream Transport Cluster FindTransport Command callback (from client) - */ -bool emberAfPushAvStreamTransportClusterFindTransportCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::PushAvStreamTransport::Commands::FindTransport::DecodableType & commandData); /** * @brief Commodity Tariff Cluster GetTariffComponent Command callback (from client) */ From e92ecc2f8208f37310aea411f65a61dc2faf93f0 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Fri, 25 Apr 2025 09:17:11 +0000 Subject: [PATCH 09/22] Restyled by clang-format --- .../push-av-stream-transport-delegate-impl.h | 8 ++++---- .../push-av-stream-transport-delegate-impl.cpp | 16 +++++++--------- .../push-av-stream-transport-server.h | 3 ++- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h b/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h index 4625ad622d3b0e..3de7cc1f3e5631 100644 --- a/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h +++ b/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h @@ -44,7 +44,8 @@ class PushAvStreamTransportManager : public PushAvStreamTransportDelegate Protocols::InteractionModel::Status DeallocatePushTransport(const uint16_t connectionID); Protocols::InteractionModel::Status ModifyPushTransport(const uint16_t connectionID, const TransportOptionsDecodeableStruct & transportOptions); - Protocols::InteractionModel::Status SetTransportStatus(const std::vector connectionIDList, TransportStatusEnum transportStatus); + Protocols::InteractionModel::Status SetTransportStatus(const std::vector connectionIDList, + TransportStatusEnum transportStatus); Protocols::InteractionModel::Status ManuallyTriggerTransport(const uint16_t connectionID, TriggerActivationReasonEnum activationReason, @@ -53,9 +54,8 @@ class PushAvStreamTransportManager : public PushAvStreamTransportDelegate FindTransport(const Optional> & connectionID, DataModel::List & outtransportConfigurations); - CHIP_ERROR ValidateStreamUsage(StreamUsageEnum streamUsage, - const Optional> & videoStreamId, - const Optional> & audioStreamId); + CHIP_ERROR ValidateStreamUsage(StreamUsageEnum streamUsage, const Optional> & videoStreamId, + const Optional> & audioStreamId); void OnAttributeChanged(AttributeId attributeId); CHIP_ERROR LoadCurrentConnections(std::vector & currentConnections); diff --git a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp index a493ff1f504719..d070384aa6d7ac 100644 --- a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp @@ -78,13 +78,12 @@ Protocols::InteractionModel::Status PushAvStreamTransportManager::SetTransportSt { for (PushAvStream & stream : pushavStreams) { - for(uint16_t connectionID : connectionIDList) + for (uint16_t connectionID : connectionIDList) { if (stream.id == connectionID) { stream.transportConfig.transportStatus = transportStatus; ChipLogError(Zcl, "Set Transport Status for Push AV Stream with ID: %d", connectionID); - } else { @@ -95,17 +94,17 @@ Protocols::InteractionModel::Status PushAvStreamTransportManager::SetTransportSt return Status::Success; } -Protocols::InteractionModel::Status - PushAvStreamTransportManager::ManuallyTriggerTransport(const uint16_t connectionID, TriggerActivationReasonEnum activationReason, - const Optional & timeControl) +Protocols::InteractionModel::Status PushAvStreamTransportManager::ManuallyTriggerTransport( + const uint16_t connectionID, TriggerActivationReasonEnum activationReason, + const Optional & timeControl) { // TODO: Validates the requested stream usage against the camera's resource management and stream priority policies. return Status::Success; } Protocols::InteractionModel::Status - PushAvStreamTransportManager::FindTransport(const Optional> & connectionID, - DataModel::List & outtransportConfigurations) +PushAvStreamTransportManager::FindTransport(const Optional> & connectionID, + DataModel::List & outtransportConfigurations) { configList.clear(); for (PushAvStream & stream : pushavStreams) @@ -117,10 +116,9 @@ Protocols::InteractionModel::Status else if (connectionID.Value().Value() == stream.id) { configList.push_back(stream.transportConfig); - } } - outtransportConfigurations = DataModel::List(configList.data(),configList.size()); + outtransportConfigurations = DataModel::List(configList.data(), configList.size()); return Status::Success; } diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h index 939b9eb813c2d4..890f056a461cd6 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h @@ -96,7 +96,8 @@ class PushAvStreamTransportDelegate * @return Success if the stream transport status is successfully set; otherwise, the command SHALL be rejected with an * appropriate error. */ - virtual Protocols::InteractionModel::Status SetTransportStatus(const std::vector connectionIDList, TransportStatusEnum transportStatus) = 0; + virtual Protocols::InteractionModel::Status SetTransportStatus(const std::vector connectionIDList, + TransportStatusEnum transportStatus) = 0; /** * @brief Handle Command Delegate to request the Node to manually start the specified push transport. * From d26464a4629750f7be6ad06fe089d6a9548f90a0 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Fri, 25 Apr 2025 09:17:18 +0000 Subject: [PATCH 10/22] Restyled by prettier-json --- src/app/zap-templates/zcl/zcl-with-test-extensions.json | 4 +--- src/app/zap-templates/zcl/zcl.json | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/app/zap-templates/zcl/zcl-with-test-extensions.json b/src/app/zap-templates/zcl/zcl-with-test-extensions.json index 39d89eca8066b2..0b34ef3a59486d 100644 --- a/src/app/zap-templates/zcl/zcl-with-test-extensions.json +++ b/src/app/zap-templates/zcl/zcl-with-test-extensions.json @@ -761,9 +761,7 @@ "FeatureMap" ], "Camera AV Settings User Level Management": ["MPTZPosition"], - "Push AV Stream Transport" :[ - "CurrentConnections" - ] + "Push AV Stream Transport": ["CurrentConnections"] }, "mandatoryDeviceTypes": "0x0016", "defaultReportingPolicy": "mandatory", diff --git a/src/app/zap-templates/zcl/zcl.json b/src/app/zap-templates/zcl/zcl.json index 61c3847ace373d..e18c7732bc3c5e 100644 --- a/src/app/zap-templates/zcl/zcl.json +++ b/src/app/zap-templates/zcl/zcl.json @@ -755,9 +755,7 @@ "FeatureMap" ], "Camera AV Settings User Level Management": ["MPTZPosition"], - "Push AV Stream Transport" :[ - "CurrentConnections" - ] + "Push AV Stream Transport": ["CurrentConnections"] }, "mandatoryDeviceTypes": "0x0016", "defaultReportingPolicy": "mandatory", From 2bf0317740e183d99b32ac1e5c995614ca52b363 Mon Sep 17 00:00:00 2001 From: Sayon Deep Date: Sat, 26 Apr 2025 01:36:39 +0530 Subject: [PATCH 11/22] all-clusters-app build fix --- .../src/push-av-stream-transport-delegate-impl.cpp | 2 +- .../push-av-stream-transport-server.cpp | 14 +++++++------- .../push-av-stream-transport-server.h | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp index d070384aa6d7ac..752a227b3c002a 100644 --- a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp @@ -167,6 +167,6 @@ void emberAfPushAvStreamTransportClusterInitCallback(EndpointId endpoint) sPushAvStramTransportInstance->Init(); sPushAvStramTransportClusterServerInstance = - std::make_unique(endpoint, *sPushAvStramTransportInstance.get()); + std::make_unique(*sPushAvStramTransportInstance.get(), endpoint); sPushAvStramTransportClusterServerInstance->Init(); } diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp index ec533383a404ae..832050a2853f4a 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp @@ -44,9 +44,10 @@ namespace app { namespace Clusters { namespace PushAvStreamTransport { -PushAvStreamTransportServer::PushAvStreamTransportServer(EndpointId aEndpointId, PushAvStreamTransportDelegate & aDelegate) : +PushAvStreamTransportServer::PushAvStreamTransportServer(PushAvStreamTransportDelegate & aDelegate, EndpointId aEndpointId) : + AttributeAccessInterface(MakeOptional(aEndpointId), PushAvStreamTransport::Id), CommandHandlerInterface(MakeOptional(aEndpointId), PushAvStreamTransport::Id), - AttributeAccessInterface(MakeOptional(aEndpointId), PushAvStreamTransport::Id), mDelegate(aDelegate) + mDelegate(aDelegate) {} PushAvStreamTransportServer::~PushAvStreamTransportServer() @@ -251,7 +252,6 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c Commands::AllocatePushTransportResponse::Type response; auto & transportOptions = commandData.transportOptions; - FabricIndex peerFabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); uint16_t ep = emberAfGetClusterServerEndpointIndex(transportOptions.endpointID, TlsCertificateManagement::Id, MATTER_DM_TLS_CERTIFICATE_MANAGEMENT_CLUSTER_CLIENT_ENDPOINT_COUNT); @@ -420,9 +420,9 @@ void PushAvStreamTransportServer::HandleManuallyTriggerTransport( if (transportConfiguration->transportStatus == TransportStatusEnum::kInactive) { - auto status = static_cast(StatusCodeEnum::kInvalidTransportStatus); + auto clusterStatus = static_cast(StatusCodeEnum::kInvalidTransportStatus); ChipLogError(Zcl, "HandleManuallyTriggerTransport: Invalid Transport status"); - ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); + ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, clusterStatus); return; } if (transportConfiguration->transportOptions.HasValue()) @@ -430,9 +430,9 @@ void PushAvStreamTransportServer::HandleManuallyTriggerTransport( if (transportConfiguration->transportOptions.Value().triggerOptions.triggerType == TransportTriggerTypeEnum::kContinuous) { { - auto status = static_cast(StatusCodeEnum::kInvalidTriggerType); + auto clusterStatus = static_cast(StatusCodeEnum::kInvalidTriggerType); ChipLogError(Zcl, "HandleManuallyTriggerTransport: Invalid Trigger type"); - ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); + ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, clusterStatus); return; } } diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h index 890f056a461cd6..4fcfd5f1a6a1e7 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h @@ -171,17 +171,17 @@ appropriate virtual CHIP_ERROR PersistentAttributesLoadedCallback() = 0; }; -class PushAvStreamTransportServer : private AttributeAccessInterface, private CommandHandlerInterface +class PushAvStreamTransportServer : public AttributeAccessInterface, public CommandHandlerInterface { public: /** * Creates a Push AV Stream Transport server instance. The Init() function needs to be called for this instance to be registered * and called by the interaction model at the appropriate times. - * @param aEndpointId The endpoint on which this cluster exists. This must match the zap configuration. * @param aDelegate A reference to the delegate to be used by this server. + * @param aEndpointId The endpoint on which this cluster exists. This must match the zap configuration. * Note: the caller must ensure that the delegate lives throughout the instance's lifetime. */ - PushAvStreamTransportServer(EndpointId endpointId, PushAvStreamTransportDelegate & delegate); + PushAvStreamTransportServer(PushAvStreamTransportDelegate & delegate, EndpointId endpointId); ~PushAvStreamTransportServer() override; From e6a206007a3c7cdad12bbbe5d0c1ffb05d0fe4ec Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Fri, 25 Apr 2025 20:26:26 +0000 Subject: [PATCH 12/22] Restyled by clang-format --- .../push-av-stream-transport-server.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp index 832050a2853f4a..2b1245a47feec3 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp @@ -46,8 +46,7 @@ namespace PushAvStreamTransport { PushAvStreamTransportServer::PushAvStreamTransportServer(PushAvStreamTransportDelegate & aDelegate, EndpointId aEndpointId) : AttributeAccessInterface(MakeOptional(aEndpointId), PushAvStreamTransport::Id), - CommandHandlerInterface(MakeOptional(aEndpointId), PushAvStreamTransport::Id), - mDelegate(aDelegate) + CommandHandlerInterface(MakeOptional(aEndpointId), PushAvStreamTransport::Id), mDelegate(aDelegate) {} PushAvStreamTransportServer::~PushAvStreamTransportServer() @@ -252,8 +251,8 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c Commands::AllocatePushTransportResponse::Type response; auto & transportOptions = commandData.transportOptions; - uint16_t ep = emberAfGetClusterServerEndpointIndex(transportOptions.endpointID, TlsCertificateManagement::Id, - MATTER_DM_TLS_CERTIFICATE_MANAGEMENT_CLUSTER_CLIENT_ENDPOINT_COUNT); + uint16_t ep = emberAfGetClusterServerEndpointIndex(transportOptions.endpointID, TlsCertificateManagement::Id, + MATTER_DM_TLS_CERTIFICATE_MANAGEMENT_CLUSTER_CLIENT_ENDPOINT_COUNT); if (ep == kEmberInvalidEndpointIndex) { From ece1e97bf8a06f2312a963487ad954866c156248 Mon Sep 17 00:00:00 2001 From: Sayon Deep Date: Sat, 26 Apr 2025 02:16:05 +0530 Subject: [PATCH 13/22] ci fix to include vector --- scripts/tools/check_includes_config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/tools/check_includes_config.py b/scripts/tools/check_includes_config.py index 94b3742ca6d873..c515e09344bad5 100644 --- a/scripts/tools/check_includes_config.py +++ b/scripts/tools/check_includes_config.py @@ -142,6 +142,7 @@ 'src/app/clusters/camera-av-stream-management-server/camera-av-stream-management-server.h': {'vector'}, 'src/app/clusters/camera-av-settings-user-level-management-server/camera-av-settings-user-level-management-server.h': {'string', 'vector'}, 'src/app/clusters/webrtc-transport-requestor-server/webrtc-transport-requestor-server.h': {'string', 'vector'}, + 'src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h': {'vector'}, 'src/credentials/attestation_verifier/FileAttestationTrustStore.h': {'vector'}, 'src/credentials/attestation_verifier/FileAttestationTrustStore.cpp': {'string'}, 'src/credentials/attestation_verifier/TestDACRevocationDelegateImpl.cpp': {'fstream'}, From d27306db9d1a62f3b1ed4c2337c5234b90f812f1 Mon Sep 17 00:00:00 2001 From: Sayon Deep Date: Sat, 26 Apr 2025 11:02:22 +0530 Subject: [PATCH 14/22] update all-cluster-app to spec changes --- .../all-clusters-app.matter | 6 ++-- ...push-av-stream-transport-delegate-impl.cpp | 2 +- .../push-av-stream-transport-server.cpp | 29 +++++++++++-------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index da4959992e80b3..bd72eea6e01757 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -7508,11 +7508,10 @@ provisional cluster PushAvStreamTransport = 1365 { optional epoch_s expiryTime = 9; } - fabric_scoped struct TransportConfigurationStruct { + struct TransportConfigurationStruct { int16u connectionID = 0; TransportStatusEnum transportStatus = 1; optional TransportOptionsStruct transportOptions = 2; - fabric_idx fabricIndex = 254; } info event PushTransportBegin = 0 { @@ -7691,11 +7690,10 @@ provisional cluster PushAvStreamTransport = 1365 { optional epoch_s expiryTime = 9; } - fabric_scoped struct TransportConfigurationStruct { + struct TransportConfigurationStruct { int16u connectionID = 0; TransportStatusEnum transportStatus = 1; optional TransportOptionsStruct transportOptions = 2; - fabric_idx fabricIndex = 254; } info event PushTransportBegin = 0 { diff --git a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp index 752a227b3c002a..e1fb924d986cbb 100644 --- a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp @@ -138,7 +138,7 @@ void PushAvStreamTransportManager::OnAttributeChanged(AttributeId attributeId) void PushAvStreamTransportManager::Init() { - return; + ChipLogError(Zcl, "Push AV Stream Transport Initialized"); } CHIP_ERROR PushAvStreamTransportManager::LoadCurrentConnections(std::vector & currentConnections) { diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp index 2b1245a47feec3..1de7f24a2b5762 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp @@ -231,18 +231,23 @@ TransportConfigurationStruct * PushAvStreamTransportServer::FindStreamTransportC uint16_t PushAvStreamTransportServer::GenerateConnectionID() { static uint16_t lastAssignedConnectionID = 0; - uint16_t nextConnectionID; - do { + uint16_t nextConnectionID; if (lastAssignedConnectionID == MAX_PUSH_TRANSPORT_CONNECTION_ID) + { nextConnectionID = 0; + } else - nextConnectionID = lastAssignedConnectionID + 1; - } while (FindStreamTransportConnection(nextConnectionID)); - - lastAssignedConnectionID = nextConnectionID; - return nextConnectionID; + { + nextConnectionID = static_cast(lastAssignedConnectionID + 1); + } + lastAssignedConnectionID = nextConnectionID; + if (FindStreamTransportConnection(nextConnectionID) == nullptr) + { + return nextConnectionID; + } + } while (true); } void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & ctx, @@ -257,7 +262,7 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c if (ep == kEmberInvalidEndpointIndex) { auto status = static_cast(StatusCodeEnum::kInvalidTLSEndpoint); - ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid TLSEndpointId not found"); + ChipLogError(Zcl, "HandleAllocatePushTransport: Valid TLSEndpointId not found"); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); return; } @@ -331,7 +336,7 @@ void PushAvStreamTransportServer::HandleDeallocatePushTransport( Status status = Status::Success; uint16_t connectionID = commandData.connectionID; - if (!FindStreamTransportConnection(connectionID)) + if (FindStreamTransportConnection(connectionID) == nullptr) { ChipLogError(Zcl, "HandleDeallocatePushTransport: ConnectionID Not Found."); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); @@ -355,7 +360,7 @@ void PushAvStreamTransportServer::HandleModifyPushTransport(HandlerContext & ctx uint16_t connectionID = commandData.connectionID; auto & transportOptions = commandData.transportOptions; - if (!FindStreamTransportConnection(connectionID)) + if (FindStreamTransportConnection(connectionID) == nullptr) { ChipLogError(Zcl, "HandleModifyPushTransport: ConnectionID Not Found."); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); @@ -383,7 +388,7 @@ void PushAvStreamTransportServer::HandleSetTransportStatus(HandlerContext & ctx, connectionIDList.push_back(transportConnection.connectionID); } } - else if (!FindStreamTransportConnection(connectionID.Value())) + else if (FindStreamTransportConnection(connectionID.Value()) == nullptr) { ChipLogError(Zcl, "HandleSetTransportStatus: ConnectionID Not Found."); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); @@ -410,7 +415,7 @@ void PushAvStreamTransportServer::HandleManuallyTriggerTransport( TransportConfigurationStruct * transportConfiguration = FindStreamTransportConnection(connectionID); - if (!transportConfiguration) + if (transportConfiguration == nullptr) { ChipLogError(Zcl, "HandleManuallyTriggerTransport: ConnectionID Not Found."); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); From 11f781a14ec1ce010b4182f2d9ef06d9c063cbf6 Mon Sep 17 00:00:00 2001 From: Sayon Deep Date: Mon, 28 Apr 2025 01:59:17 +0530 Subject: [PATCH 15/22] Address review comments --- .../push-av-stream-transport-delegate-impl.h | 10 +- ...push-av-stream-transport-delegate-impl.cpp | 44 +++- .../push-av-stream-transport-server.cpp | 210 ++++++++++++++---- .../push-av-stream-transport-server.h | 53 ++++- .../zcl/zcl-with-test-extensions.json | 3 +- src/app/zap-templates/zcl/zcl.json | 3 +- 6 files changed, 247 insertions(+), 76 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h b/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h index 3de7cc1f3e5631..bb79d361fa7cae 100644 --- a/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h +++ b/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h @@ -31,6 +31,7 @@ struct PushAvStream { uint16_t id; TransportConfigurationStruct transportConfig; + PushAvStreamTransportStatusEnum status; }; /** @@ -50,15 +51,16 @@ class PushAvStreamTransportManager : public PushAvStreamTransportDelegate Protocols::InteractionModel::Status ManuallyTriggerTransport(const uint16_t connectionID, TriggerActivationReasonEnum activationReason, const Optional & timeControl); - Protocols::InteractionModel::Status - FindTransport(const Optional> & connectionID, - DataModel::List & outtransportConfigurations); + Protocols::InteractionModel::Status FindTransport(const Optional> & connectionID); CHIP_ERROR ValidateStreamUsage(StreamUsageEnum streamUsage, const Optional> & videoStreamId, const Optional> & audioStreamId); + CHIP_ERROR ValidateBandwidthLimit(StreamUsageEnum streamUsage, const Optional> & videoStreamId, + const Optional> & audioStreamId); + PushAvStreamTransportStatusEnum GetTransportStatus(const uint16_t connectionID); void OnAttributeChanged(AttributeId attributeId); - CHIP_ERROR LoadCurrentConnections(std::vector & currentConnections); + CHIP_ERROR LoadCurrentConnections(std::vector & currentConnections); CHIP_ERROR PersistentAttributesLoadedCallback(); void Init(); diff --git a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp index e1fb924d986cbb..0b881a3af942f1 100644 --- a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp @@ -41,7 +41,7 @@ Protocols::InteractionModel::Status PushAvStreamTransportManager::AllocatePushTransport(const TransportOptionsDecodeableStruct & transportOptions, TransportConfigurationStruct & outTransporConfiguration) { - PushAvStream stream{ outTransporConfiguration.connectionID, outTransporConfiguration }; + PushAvStream stream{ outTransporConfiguration.connectionID, outTransporConfiguration, PushAvStreamTransportStatusEnum::kIdle }; /*Store the allocated stream persistently*/ pushavStreams.push_back(stream); @@ -85,10 +85,6 @@ Protocols::InteractionModel::Status PushAvStreamTransportManager::SetTransportSt stream.transportConfig.transportStatus = transportStatus; ChipLogError(Zcl, "Set Transport Status for Push AV Stream with ID: %d", connectionID); } - else - { - return Status::NotFound; - } } } return Status::Success; @@ -99,12 +95,19 @@ Protocols::InteractionModel::Status PushAvStreamTransportManager::ManuallyTrigge const Optional & timeControl) { // TODO: Validates the requested stream usage against the camera's resource management and stream priority policies. + for (PushAvStream & stream : pushavStreams) + { + if (stream.id == connectionID) + { + stream.status = PushAvStreamTransportStatusEnum::kBusy; + ChipLogError(Zcl, "Transport triggered for Push AV Stream with ID: %d", connectionID); + } + } return Status::Success; } Protocols::InteractionModel::Status -PushAvStreamTransportManager::FindTransport(const Optional> & connectionID, - DataModel::List & outtransportConfigurations) +PushAvStreamTransportManager::FindTransport(const Optional> & connectionID) { configList.clear(); for (PushAvStream & stream : pushavStreams) @@ -115,20 +118,40 @@ PushAvStreamTransportManager::FindTransport(const Optional(configList.data(), configList.size()); return Status::Success; } +CHIP_ERROR PushAvStreamTransportManager::ValidateBandwidthLimit(StreamUsageEnum streamUsage, + const Optional> & videoStreamId, + const Optional> & audioStreamId) +{ + // TODO: Validates the requested stream usage against the camera's resource management. + return CHIP_ERROR_NOT_IMPLEMENTED; +} + CHIP_ERROR PushAvStreamTransportManager::ValidateStreamUsage(StreamUsageEnum streamUsage, const Optional> & videoStreamId, const Optional> & audioStreamId) { // TODO: Validates the requested stream usage against the camera's resource management and stream priority policies. - return CHIP_NO_ERROR; + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +PushAvStreamTransportStatusEnum PushAvStreamTransportManager::GetTransportStatus(const uint16_t connectionID) +{ + for (PushAvStream & stream : pushavStreams) + { + if (stream.id == connectionID) + { + return stream.status; + } + } + return PushAvStreamTransportStatusEnum::kUnknown; } void PushAvStreamTransportManager::OnAttributeChanged(AttributeId attributeId) @@ -140,7 +163,8 @@ void PushAvStreamTransportManager::Init() { ChipLogError(Zcl, "Push AV Stream Transport Initialized"); } -CHIP_ERROR PushAvStreamTransportManager::LoadCurrentConnections(std::vector & currentConnections) +CHIP_ERROR +PushAvStreamTransportManager::LoadCurrentConnections(std::vector & currentConnections) { ChipLogError(Zcl, "Push AV Current Connections loaded"); diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp index 1de7f24a2b5762..a79b94010e31d5 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp @@ -73,19 +73,20 @@ CHIP_ERROR PushAvStreamTransportServer::ReadAndEncodeCurrentConnections(const At { for (const auto & currentConnections : mCurrentConnections) { - ReturnErrorOnFailure(encoder.Encode(currentConnections)); + ReturnErrorOnFailure(encoder.Encode(currentConnections.transportConfiguration)); } return CHIP_NO_ERROR; } -PushAvStreamTransportServer::UpsertResultEnum -PushAvStreamTransportServer::UpsertStreamTransportConnection(const TransportConfigurationStruct & transportConfiguration) +PushAvStreamTransportServer::UpsertResultEnum PushAvStreamTransportServer::UpsertStreamTransportConnection( + const TransportConfigurationStructWithFabricIndex & transportConfiguration) { UpsertResultEnum result; - auto it = - std::find_if(mCurrentConnections.begin(), mCurrentConnections.end(), - [id = transportConfiguration.connectionID](const auto & existing) { return existing.connectionID == id; }); + auto it = std::find_if(mCurrentConnections.begin(), mCurrentConnections.end(), + [id = transportConfiguration.transportConfiguration.connectionID](const auto & existing) { + return existing.transportConfiguration.connectionID == id; + }); if (it != mCurrentConnections.end()) { @@ -110,8 +111,8 @@ void PushAvStreamTransportServer::RemoveStreamTransportConnection(const uint16_t // Erase-Remove idiom mCurrentConnections.erase(std::remove_if(mCurrentConnections.begin(), mCurrentConnections.end(), - [transportConnectionId](const TransportConfigurationStruct & s) { - return s.connectionID == transportConnectionId; + [transportConnectionId](const TransportConfigurationStructWithFabricIndex & s) { + return s.transportConfiguration.connectionID == transportConnectionId; }), mCurrentConnections.end()); @@ -218,11 +219,12 @@ void PushAvStreamTransportServer::InvokeCommand(HandlerContext & handlerContext) } } -TransportConfigurationStruct * PushAvStreamTransportServer::FindStreamTransportConnection(const uint16_t connectionID) +TransportConfigurationStructWithFabricIndex * +PushAvStreamTransportServer::FindStreamTransportConnection(const uint16_t connectionID) { for (auto & transportConnection : mCurrentConnections) { - if (transportConnection.connectionID == connectionID) + if (transportConnection.transportConfiguration.connectionID == connectionID) return &transportConnection; } return nullptr; @@ -267,6 +269,8 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c return; } + // Todo: Match Fabric index of TLSEndpointID + if (transportOptions.ingestMethod == IngestMethodsEnum::kUnknownEnumValue) { auto status = static_cast(StatusCodeEnum::kUnsupportedIngestMethod); @@ -283,6 +287,9 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c return; } + // Todo: Check combination of Ingest method, Container format in Supported Formats + // https://github.com/CHIP-Specifications/connectedhomeip-spec/pull/11504 + if (transportOptions.triggerOptions.triggerType == TransportTriggerTypeEnum::kUnknownEnumValue) { auto status = static_cast(StatusCodeEnum::kInvalidTriggerType); @@ -292,9 +299,18 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c } // Todo: Validate MotionZones list in the TransportTriggerOptionsStruct field + // Validate Bandwidth Requirement + CHIP_ERROR err = mDelegate.ValidateBandwidthLimit(transportOptions.streamUsage, transportOptions.videoStreamID, + transportOptions.audioStreamID); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "HandleAllocatePushTransport: Resource Exhausted"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ResourceExhausted); + return; + } // Validate the StreamUsageEnum as per resource management and stream priorities. - CHIP_ERROR err = + err = mDelegate.ValidateStreamUsage(transportOptions.streamUsage, transportOptions.videoStreamID, transportOptions.audioStreamID); if (err != CHIP_NO_ERROR) { @@ -319,7 +335,9 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c if (status == Status::Success) { // add connection to CurrentConnections - UpsertStreamTransportConnection(outTransportConfiguration); + FabricIndex peerFabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); + TransportConfigurationStructWithFabricIndex transportConfiguration({ outTransportConfiguration, peerFabricIndex }); + UpsertStreamTransportConnection(transportConfiguration); response.transportConfiguration = outTransportConfiguration; ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); @@ -333,10 +351,17 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c void PushAvStreamTransportServer::HandleDeallocatePushTransport( HandlerContext & ctx, const Commands::DeallocatePushTransport::DecodableType & commandData) { - Status status = Status::Success; - uint16_t connectionID = commandData.connectionID; + Status status = Status::Success; + uint16_t connectionID = commandData.connectionID; + TransportConfigurationStructWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID); + if (transportConfiguration == nullptr) + { + ChipLogError(Zcl, "HandleDeallocatePushTransport: ConnectionID Not Found."); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); + return; + } - if (FindStreamTransportConnection(connectionID) == nullptr) + if (transportConfiguration->fabricIndex != ctx.mCommandHandler.GetAccessingFabricIndex()) { ChipLogError(Zcl, "HandleDeallocatePushTransport: ConnectionID Not Found."); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); @@ -360,16 +385,55 @@ void PushAvStreamTransportServer::HandleModifyPushTransport(HandlerContext & ctx uint16_t connectionID = commandData.connectionID; auto & transportOptions = commandData.transportOptions; - if (FindStreamTransportConnection(connectionID) == nullptr) + TransportConfigurationStructWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID); + + if (transportConfiguration == nullptr) { ChipLogError(Zcl, "HandleModifyPushTransport: ConnectionID Not Found."); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } + if (transportConfiguration->fabricIndex != ctx.mCommandHandler.GetAccessingFabricIndex()) + { + ChipLogError(Zcl, "HandleModifyPushTransport: ConnectionID Not Found."); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); + return; + } + + if (mDelegate.GetTransportStatus(connectionID) == PushAvStreamTransportStatusEnum::kBusy) + { + ChipLogError(Zcl, "HandleModifyPushTransport: Connection is Busy"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Busy); + return; + } + // Call the delegate status = mDelegate.ModifyPushTransport(connectionID, transportOptions); + if (status == Status::Success) + { + if (transportConfiguration->transportConfiguration.transportOptions.HasValue()) + { + TransportOptionsStruct transportOptionToModify = + transportConfiguration->transportConfiguration.transportOptions.Value(); + transportOptionToModify.streamUsage = transportOptions.streamUsage; + transportOptionToModify.videoStreamID = transportOptions.videoStreamID; + transportOptionToModify.audioStreamID = transportOptions.audioStreamID; + transportOptionToModify.endpointID = transportOptions.endpointID; + transportOptionToModify.url = transportOptions.url; + transportOptionToModify.triggerOptions.triggerType = transportOptions.triggerOptions.triggerType; + // Todo: copy motion zones + transportOptionToModify.triggerOptions.motionSensitivity = transportOptions.triggerOptions.motionSensitivity; + transportOptionToModify.triggerOptions.motionTimeControl = transportOptions.triggerOptions.motionTimeControl; + transportOptionToModify.triggerOptions.maxPreRollLen = transportOptions.triggerOptions.maxPreRollLen; + transportOptionToModify.ingestMethod = transportOptions.ingestMethod; + transportOptionToModify.containerFormat = transportOptions.containerFormat; + transportOptionToModify.containerOptions = transportOptions.containerOptions; + transportOptionToModify.expiryTime = transportOptions.expiryTime; + } + } + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } @@ -385,23 +449,34 @@ void PushAvStreamTransportServer::HandleSetTransportStatus(HandlerContext & ctx, { for (auto & transportConnection : mCurrentConnections) { - connectionIDList.push_back(transportConnection.connectionID); + if (transportConnection.fabricIndex == ctx.mCommandHandler.GetAccessingFabricIndex()) + { + transportConnection.transportConfiguration.transportStatus = transportStatus; + connectionIDList.push_back(transportConnection.transportConfiguration.connectionID); + } } } - else if (FindStreamTransportConnection(connectionID.Value()) == nullptr) - { - ChipLogError(Zcl, "HandleSetTransportStatus: ConnectionID Not Found."); - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); - return; - } else { + TransportConfigurationStructWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID.Value()); + if (transportConfiguration == nullptr) + { + ChipLogError(Zcl, "HandleSetTransportStatus: ConnectionID Not Found."); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); + return; + } + if (transportConfiguration->fabricIndex != ctx.mCommandHandler.GetAccessingFabricIndex()) + { + ChipLogError(Zcl, "HandleSetTransportStatus: ConnectionID Not Found."); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); + return; + } + + transportConfiguration->transportConfiguration.transportStatus = transportStatus; connectionIDList.push_back(connectionID.Value()); } - // Call the delegate status = mDelegate.SetTransportStatus(connectionIDList, transportStatus); - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } @@ -413,7 +488,7 @@ void PushAvStreamTransportServer::HandleManuallyTriggerTransport( auto & activationReason = commandData.activationReason; auto & timeControl = commandData.timeControl; - TransportConfigurationStruct * transportConfiguration = FindStreamTransportConnection(connectionID); + TransportConfigurationStructWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID); if (transportConfiguration == nullptr) { @@ -422,39 +497,51 @@ void PushAvStreamTransportServer::HandleManuallyTriggerTransport( return; } - if (transportConfiguration->transportStatus == TransportStatusEnum::kInactive) + if (transportConfiguration->fabricIndex != ctx.mCommandHandler.GetAccessingFabricIndex()) + { + ChipLogError(Zcl, "HandleManuallyTriggerTransport: ConnectionID Not Found."); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); + return; + } + + if (mDelegate.GetTransportStatus(connectionID) == PushAvStreamTransportStatusEnum::kBusy) + { + ChipLogError(Zcl, "HandleManuallyTriggerTransport: Connection is Busy"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Busy); + return; + } + + if (transportConfiguration->transportConfiguration.transportStatus == TransportStatusEnum::kInactive) { auto clusterStatus = static_cast(StatusCodeEnum::kInvalidTransportStatus); ChipLogError(Zcl, "HandleManuallyTriggerTransport: Invalid Transport status"); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, clusterStatus); return; } - if (transportConfiguration->transportOptions.HasValue()) + if (transportConfiguration->transportConfiguration.transportOptions.HasValue()) { - if (transportConfiguration->transportOptions.Value().triggerOptions.triggerType == TransportTriggerTypeEnum::kContinuous) + if (transportConfiguration->transportConfiguration.transportOptions.Value().triggerOptions.triggerType == + TransportTriggerTypeEnum::kContinuous) { - { - auto clusterStatus = static_cast(StatusCodeEnum::kInvalidTriggerType); - ChipLogError(Zcl, "HandleManuallyTriggerTransport: Invalid Trigger type"); - ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, clusterStatus); - return; - } + + auto clusterStatus = static_cast(StatusCodeEnum::kInvalidTriggerType); + ChipLogError(Zcl, "HandleManuallyTriggerTransport: Invalid Trigger type"); + ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, clusterStatus); + return; } - else if (transportConfiguration->transportOptions.Value().triggerOptions.triggerType == - TransportTriggerTypeEnum::kCommand && - !timeControl.HasValue()) + if (transportConfiguration->transportConfiguration.transportOptions.Value().triggerOptions.triggerType == + TransportTriggerTypeEnum::kCommand && + !timeControl.HasValue()) { - { - ChipLogError(Zcl, "HandleManuallyTriggerTransport: Time control field not present"); - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); - return; - } + + ChipLogError(Zcl, "HandleManuallyTriggerTransport: Time control field not present"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + return; } } // Call the delegate status = mDelegate.ManuallyTriggerTransport(connectionID, activationReason, timeControl); - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } @@ -466,6 +553,8 @@ void PushAvStreamTransportServer::HandleFindTransport(HandlerContext & ctx, Optional> connectionID = commandData.connectionID; + static std::vector transportConfigurations{}; + DataModel::List outTransportConfigurations; if (connectionID.Value().IsNull()) @@ -476,16 +565,39 @@ void PushAvStreamTransportServer::HandleFindTransport(HandlerContext & ctx, ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } + + for (auto & connection : mCurrentConnections) + { + if (connection.fabricIndex == ctx.mCommandHandler.GetAccessingFabricIndex()) + { + transportConfigurations.push_back(connection.transportConfiguration); + } + } } - else if (!FindStreamTransportConnection(connectionID.Value().Value())) + else { - ChipLogError(Zcl, "HandleFindTransport: ConnectionID not found"); - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); - return; + TransportConfigurationStructWithFabricIndex * transportConfiguration = + FindStreamTransportConnection(connectionID.Value().Value()); + if (transportConfiguration == nullptr) + { + ChipLogError(Zcl, "HandleFindTransport: ConnectionID not found"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); + return; + } + if (transportConfiguration->fabricIndex != ctx.mCommandHandler.GetAccessingFabricIndex()) + { + ChipLogError(Zcl, "HandleFindTransport: ConnectionID Not Found."); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); + return; + } + transportConfigurations.push_back(transportConfiguration->transportConfiguration); } + outTransportConfigurations = + DataModel::List(transportConfigurations.data(), transportConfigurations.size()); + // Call the delegate - status = mDelegate.FindTransport(connectionID, outTransportConfigurations); + status = mDelegate.FindTransport(connectionID); if (status == Status::Success) { response.transportConfigurations = outTransportConfigurations; diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h index 4fcfd5f1a6a1e7..a79fe0a182a41e 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h @@ -39,6 +39,19 @@ using TransportConfigurationStruct = Structs::TransportConfigurationS using TransportOptionsDecodeableStruct = Structs::TransportOptionsStruct::DecodableType; +struct TransportConfigurationStructWithFabricIndex +{ + TransportConfigurationStruct transportConfiguration; + chip::FabricIndex fabricIndex; +}; + +enum class PushAvStreamTransportStatusEnum : uint8_t +{ + kBusy = 0x00, + kIdle = 0x01, + kUnknown = 0x02 +}; + /** @brief * Defines interfaces for implementing application-specific logic for various aspects of the PushAvStreamTransport Delegate. * Specifically, it defines interfaces for the command handling and loading of the allocated streams. @@ -119,17 +132,29 @@ appropriate * @brief Handle Command Delegate to get the Stream Options Configuration for the specified push transport. * * @param connectionID [in] Indicates the allocated connectionID to get the Stream Options Configuration of. - * - * @param outtransportConfigurations [out] Single item list of mapped transport configuration or list if connectionID is - * NULL. - * * @return Success if the transport is already allocated; otherwise, the command SHALL be rejected with an appropriate * error. * */ - virtual Protocols::InteractionModel::Status - FindTransport(const Optional> & connectionID, - DataModel::List & outtransportConfigurations) = 0; + virtual Protocols::InteractionModel::Status FindTransport(const Optional> & connectionID) = 0; + + /** + * @brief Validates the bandwidth requirement against the camera's resource management + * + * The implementation SHALL ensure: + * - The requested stream usage (streamUsage) is allowed given the current allocation of + * camera resources (e.g. CPU, memory, network bandwidth). + * + * @param[in] streamUsage The desired usage type for the stream (e.g. live view, recording, etc.). + * @param[in] videoStreamId Optional identifier for the requested video stream. + * @param[in] audioStreamId Optional identifier for the requested audio stream. + * + * @return CHIP_ERROR CHIP_NO_ERROR if the stream usage is valid; an appropriate error code otherwise. + */ + + virtual CHIP_ERROR ValidateBandwidthLimit(StreamUsageEnum streamUsage, + const Optional> & videoStreamId, + const Optional> & audioStreamId) = 0; /** * @brief Validates the requested stream usage against the camera's resource management @@ -149,6 +174,8 @@ appropriate const Optional> & videoStreamId, const Optional> & audioStreamId) = 0; + virtual PushAvStreamTransportStatusEnum GetTransportStatus(const uint16_t connectionID) = 0; + /** * @brief Delegate callback for notifying change in an attribute. * @@ -162,7 +189,7 @@ appropriate * list, at initialization. Once loaded, the cluster server would be serving Reads on these attributes. The list is updatable * via the Add/Remove functions for the respective transport connections. */ - virtual CHIP_ERROR LoadCurrentConnections(std::vector & currentConnections) = 0; + virtual CHIP_ERROR LoadCurrentConnections(std::vector & currentConnections) = 0; /** * @brief Callback into the delegate once persistent attributes managed by @@ -216,10 +243,14 @@ class PushAvStreamTransportServer : public AttributeAccessInterface, public Comm PushAvStreamTransportDelegate & mDelegate; // Attributes + // Todo: Add SupportedFormats attribute form https://github.com/CHIP-Specifications/connectedhomeip-spec/pull/11504 BitMask mSupportedContainerFormats; BitMask mSupportedIngestMethods; // lists - std::vector mCurrentConnections; + /*Moved from TransportConfigurationStruct to TransportConfigurationStructWithFabricIndex + * to perform fabric index checks + */ + std::vector mCurrentConnections; /** * IM-level implementation of read @@ -237,9 +268,9 @@ class PushAvStreamTransportServer : public AttributeAccessInterface, public Comm // Helper functions uint16_t GenerateConnectionID(); - TransportConfigurationStruct * FindStreamTransportConnection(const uint16_t connectionID); + TransportConfigurationStructWithFabricIndex * FindStreamTransportConnection(const uint16_t connectionID); // Add/Remove Management functions for transport - UpsertResultEnum UpsertStreamTransportConnection(const TransportConfigurationStruct & transportConfiguration); + UpsertResultEnum UpsertStreamTransportConnection(const TransportConfigurationStructWithFabricIndex & transportConfiguration); void RemoveStreamTransportConnection(const uint16_t connectionID); diff --git a/src/app/zap-templates/zcl/zcl-with-test-extensions.json b/src/app/zap-templates/zcl/zcl-with-test-extensions.json index 77da4e9fe7cb7f..18d63c689e4541 100644 --- a/src/app/zap-templates/zcl/zcl-with-test-extensions.json +++ b/src/app/zap-templates/zcl/zcl-with-test-extensions.json @@ -767,7 +767,8 @@ "FeatureMap" ], "Camera AV Settings User Level Management": ["MPTZPosition"], - "Push AV Stream Transport": ["CurrentConnections"] + "Push AV Stream Transport": ["CurrentConnections"], + "Soil Measurement": ["SoilMoistureMeasurementLimits"] }, "mandatoryDeviceTypes": "0x0016", "defaultReportingPolicy": "mandatory", diff --git a/src/app/zap-templates/zcl/zcl.json b/src/app/zap-templates/zcl/zcl.json index bb54aef27467bc..c04ab1357a5095 100644 --- a/src/app/zap-templates/zcl/zcl.json +++ b/src/app/zap-templates/zcl/zcl.json @@ -760,8 +760,9 @@ "StatusLightBrightness", "FeatureMap" ], + "Push AV Stream Transport": ["CurrentConnections"], "Camera AV Settings User Level Management": ["MPTZPosition"], - "Push AV Stream Transport": ["CurrentConnections"] + "Soil Measurement": ["SoilMoistureMeasurementLimits"] }, "mandatoryDeviceTypes": "0x0016", "defaultReportingPolicy": "mandatory", From 592e3f7c17c07a7da176b8d0bc0b184e6c090949 Mon Sep 17 00:00:00 2001 From: Sayon Deep Date: Wed, 14 May 2025 17:43:30 +0530 Subject: [PATCH 16/22] Update to latest spec changes --- .../all-clusters-app.matter | 79 ++++---- .../all-clusters-common/all-clusters-app.zap | 56 ++---- .../push-av-stream-transport-delegate-impl.h | 15 +- ...push-av-stream-transport-delegate-impl.cpp | 66 +++---- .../push-av-stream-transport-server/BUILD.gn | 15 ++ .../app_config_dependent_sources.cmake | 21 ++ .../app_config_dependent_sources.gni | 17 ++ .../push-av-stream-transport-server.cpp | 182 ++++++++++-------- .../push-av-stream-transport-server.h | 144 +++++++++++--- .../zcl/zcl-with-test-extensions.json | 1 - src/app/zap-templates/zcl/zcl.json | 1 - 11 files changed, 366 insertions(+), 231 deletions(-) create mode 100644 src/app/clusters/push-av-stream-transport-server/BUILD.gn create mode 100644 src/app/clusters/push-av-stream-transport-server/app_config_dependent_sources.cmake create mode 100644 src/app/clusters/push-av-stream-transport-server/app_config_dependent_sources.gni diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index 682ab5c653c2e8..3bb1668758d8a7 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -7453,7 +7453,7 @@ provisional cluster PushAvStreamTransport = 1365 { revision 1; enum ContainerFormatEnum : enum8 { - kCMAF = 0; + kCMAF = 0 [spec_name = "CMAF"]; } enum IngestMethodsEnum : enum8 { @@ -7465,10 +7465,9 @@ provisional cluster PushAvStreamTransport = 1365 { kInvalidStream = 3; kInvalidURL = 4; kInvalidZone = 5; - kUnsupportedContainerFormat = 6; - kUnsupportedIngestMethod = 7; - kInvalidTriggerType = 8; - kInvalidTransportStatus = 9; + kInvalidCombination = 6; + kInvalidTriggerType = 7; + kInvalidTransportStatus = 8; } shared enum StreamUsageEnum : enum8 { @@ -7500,14 +7499,6 @@ provisional cluster PushAvStreamTransport = 1365 { kMetadata = 0x2; } - bitmap SupportedContainerFormatsBitmap : bitmap8 { - kCMAF = 0x1; - } - - bitmap SupportedIngestMethodsBitmap : bitmap8 { - kCMAFIngest = 0x1; - } - struct TransportMotionTriggerTimeControlStruct { int16u initialDuration = 0; int16u augmentationDuration = 1; @@ -7516,8 +7507,8 @@ provisional cluster PushAvStreamTransport = 1365 { } struct TransportZoneOptionsStruct { - nullable int16u zone = 1; - optional int8u sensitivity = 2; + nullable int16u zone = 0; + optional int8u sensitivity = 1; } struct TransportTriggerOptionsStruct { @@ -7532,6 +7523,7 @@ provisional cluster PushAvStreamTransport = 1365 { int16u chunkDuration = 0; optional octet_string<16> CENCKey = 1; optional boolean metadataEnabled = 2; + optional octet_string<16> CENCKeyID = 3; } struct ContainerOptionsStruct { @@ -7547,9 +7539,8 @@ provisional cluster PushAvStreamTransport = 1365 { long_char_string<2000> url = 4; TransportTriggerOptionsStruct triggerOptions = 5; IngestMethodsEnum ingestMethod = 6; - ContainerFormatEnum containerFormat = 7; - ContainerOptionsStruct containerOptions = 8; - optional epoch_s expiryTime = 9; + ContainerOptionsStruct containerOptions = 7; + optional epoch_s expiryTime = 8; } struct TransportConfigurationStruct { @@ -7558,6 +7549,11 @@ provisional cluster PushAvStreamTransport = 1365 { optional TransportOptionsStruct transportOptions = 2; } + struct SupportedFormatStruct { + ContainerFormatEnum containerFormat = 0; + IngestMethodsEnum ingestMethod = 1; + } + info event PushTransportBegin = 0 { int16u connectionID = 0; TransportTriggerTypeEnum triggerType = 1; @@ -7570,12 +7566,10 @@ provisional cluster PushAvStreamTransport = 1365 { optional TriggerActivationReasonEnum activationReason = 2; } - readonly attribute SupportedContainerFormatsBitmap supportedContainerFormats = 0; - readonly attribute SupportedIngestMethodsBitmap supportedIngestMethods = 1; - readonly attribute TransportConfigurationStruct currentConnections[] = 2; + readonly attribute SupportedFormatStruct supportedFormats[] = 0; + readonly attribute TransportConfigurationStruct currentConnections[] = 1; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; - readonly attribute event_id eventList[] = 65530; readonly attribute attrib_id attributeList[] = 65531; readonly attribute bitmap32 featureMap = 65532; readonly attribute int16u clusterRevision = 65533; @@ -7635,7 +7629,7 @@ provisional cluster PushAvStreamTransport = 1365 { revision 1; enum ContainerFormatEnum : enum8 { - kCMAF = 0; + kCMAF = 0 [spec_name = "CMAF"]; } enum IngestMethodsEnum : enum8 { @@ -7647,10 +7641,9 @@ provisional cluster PushAvStreamTransport = 1365 { kInvalidStream = 3; kInvalidURL = 4; kInvalidZone = 5; - kUnsupportedContainerFormat = 6; - kUnsupportedIngestMethod = 7; - kInvalidTriggerType = 8; - kInvalidTransportStatus = 9; + kInvalidCombination = 6; + kInvalidTriggerType = 7; + kInvalidTransportStatus = 8; } shared enum StreamUsageEnum : enum8 { @@ -7682,14 +7675,6 @@ provisional cluster PushAvStreamTransport = 1365 { kMetadata = 0x2; } - bitmap SupportedContainerFormatsBitmap : bitmap8 { - kCMAF = 0x1; - } - - bitmap SupportedIngestMethodsBitmap : bitmap8 { - kCMAFIngest = 0x1; - } - struct TransportMotionTriggerTimeControlStruct { int16u initialDuration = 0; int16u augmentationDuration = 1; @@ -7698,8 +7683,8 @@ provisional cluster PushAvStreamTransport = 1365 { } struct TransportZoneOptionsStruct { - nullable int16u zone = 1; - optional int8u sensitivity = 2; + nullable int16u zone = 0; + optional int8u sensitivity = 1; } struct TransportTriggerOptionsStruct { @@ -7714,6 +7699,7 @@ provisional cluster PushAvStreamTransport = 1365 { int16u chunkDuration = 0; optional octet_string<16> CENCKey = 1; optional boolean metadataEnabled = 2; + optional octet_string<16> CENCKeyID = 3; } struct ContainerOptionsStruct { @@ -7729,9 +7715,8 @@ provisional cluster PushAvStreamTransport = 1365 { long_char_string<2000> url = 4; TransportTriggerOptionsStruct triggerOptions = 5; IngestMethodsEnum ingestMethod = 6; - ContainerFormatEnum containerFormat = 7; - ContainerOptionsStruct containerOptions = 8; - optional epoch_s expiryTime = 9; + ContainerOptionsStruct containerOptions = 7; + optional epoch_s expiryTime = 8; } struct TransportConfigurationStruct { @@ -7740,6 +7725,11 @@ provisional cluster PushAvStreamTransport = 1365 { optional TransportOptionsStruct transportOptions = 2; } + struct SupportedFormatStruct { + ContainerFormatEnum containerFormat = 0; + IngestMethodsEnum ingestMethod = 1; + } + info event PushTransportBegin = 0 { int16u connectionID = 0; TransportTriggerTypeEnum triggerType = 1; @@ -7752,12 +7742,10 @@ provisional cluster PushAvStreamTransport = 1365 { optional TriggerActivationReasonEnum activationReason = 2; } - readonly attribute SupportedContainerFormatsBitmap supportedContainerFormats = 0; - readonly attribute SupportedIngestMethodsBitmap supportedIngestMethods = 1; - readonly attribute TransportConfigurationStruct currentConnections[] = 2; + readonly attribute SupportedFormatStruct supportedFormats[] = 0; + readonly attribute TransportConfigurationStruct currentConnections[] = 1; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; - readonly attribute event_id eventList[] = 65530; readonly attribute attrib_id attributeList[] = 65531; readonly attribute bitmap32 featureMap = 65532; readonly attribute int16u clusterRevision = 65533; @@ -10183,8 +10171,7 @@ endpoint 1 { } server cluster PushAvStreamTransport { - ram attribute supportedContainerFormats; - ram attribute supportedIngestMethods; + callback attribute supportedFormats; callback attribute currentConnections; callback attribute generatedCommandList; callback attribute acceptedCommandList; diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap index d3abb0fb7726fb..97dac5e96c8644 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap @@ -1582,7 +1582,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -21583,32 +21583,16 @@ ], "attributes": [ { - "name": "SupportedContainerFormats", + "name": "SupportedFormats", "code": 0, "mfgCode": null, "side": "server", - "type": "SupportedContainerFormatsBitmap", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "SupportedIngestMethods", - "code": 1, - "mfgCode": null, - "side": "server", - "type": "SupportedIngestMethodsBitmap", + "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -21616,7 +21600,7 @@ }, { "name": "CurrentConnections", - "code": 2, + "code": 1, "mfgCode": null, "side": "server", "type": "array", @@ -21877,10 +21861,10 @@ "side": "server", "type": "MeterTypeEnum", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -21893,10 +21877,10 @@ "side": "server", "type": "char_string", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -21909,10 +21893,10 @@ "side": "server", "type": "char_string", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -21925,10 +21909,10 @@ "side": "server", "type": "char_string", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -21944,7 +21928,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -21960,7 +21944,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -21976,7 +21960,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -21992,7 +21976,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -22005,10 +21989,10 @@ "side": "server", "type": "bitmap32", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, diff --git a/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h b/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h index bb79d361fa7cae..9a219955f7eac2 100644 --- a/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h +++ b/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h @@ -30,8 +30,9 @@ namespace PushAvStreamTransport { struct PushAvStream { uint16_t id; - TransportConfigurationStruct transportConfig; - PushAvStreamTransportStatusEnum status; + TransportOptionsStruct transportOptions; + TransportStatusEnum transportStatus; + PushAvStreamTransportStatusEnum connectionStatus; }; /** @@ -40,18 +41,19 @@ struct PushAvStream class PushAvStreamTransportManager : public PushAvStreamTransportDelegate { public: - Protocols::InteractionModel::Status AllocatePushTransport(const TransportOptionsDecodeableStruct & transportOptions, - TransportConfigurationStruct & outTransporConfiguration); + Protocols::InteractionModel::Status AllocatePushTransport(const TransportOptionsStruct & transportOptions, + const uint16_t connectionID); Protocols::InteractionModel::Status DeallocatePushTransport(const uint16_t connectionID); Protocols::InteractionModel::Status ModifyPushTransport(const uint16_t connectionID, - const TransportOptionsDecodeableStruct & transportOptions); + const TransportOptionsStruct & transportOptions); Protocols::InteractionModel::Status SetTransportStatus(const std::vector connectionIDList, TransportStatusEnum transportStatus); Protocols::InteractionModel::Status ManuallyTriggerTransport(const uint16_t connectionID, TriggerActivationReasonEnum activationReason, const Optional & timeControl); - Protocols::InteractionModel::Status FindTransport(const Optional> & connectionID); + + bool validateUrl(std::string url); CHIP_ERROR ValidateStreamUsage(StreamUsageEnum streamUsage, const Optional> & videoStreamId, const Optional> & audioStreamId); @@ -70,7 +72,6 @@ class PushAvStreamTransportManager : public PushAvStreamTransportDelegate private: std::vector pushavStreams; - std::vector configList; }; } // namespace PushAvStreamTransport diff --git a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp index 0b881a3af942f1..0ab561a0f75d59 100644 --- a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp @@ -38,10 +38,9 @@ std::unique_ptr sPushAvStramTransportInstance; std::unique_ptr sPushAvStramTransportClusterServerInstance; Protocols::InteractionModel::Status -PushAvStreamTransportManager::AllocatePushTransport(const TransportOptionsDecodeableStruct & transportOptions, - TransportConfigurationStruct & outTransporConfiguration) +PushAvStreamTransportManager::AllocatePushTransport(const TransportOptionsStruct & transportOptions, const uint16_t connectionID) { - PushAvStream stream{ outTransporConfiguration.connectionID, outTransporConfiguration, PushAvStreamTransportStatusEnum::kIdle }; + PushAvStream stream{ connectionID, transportOptions, TransportStatusEnum::kInactive, PushAvStreamTransportStatusEnum::kIdle }; /*Store the allocated stream persistently*/ pushavStreams.push_back(stream); @@ -58,14 +57,13 @@ Protocols::InteractionModel::Status PushAvStreamTransportManager::DeallocatePush } Protocols::InteractionModel::Status -PushAvStreamTransportManager::ModifyPushTransport(const uint16_t connectionID, - const TransportOptionsDecodeableStruct & transportOptions) +PushAvStreamTransportManager::ModifyPushTransport(const uint16_t connectionID, const TransportOptionsStruct & transportOptions) { for (PushAvStream & stream : pushavStreams) { if (stream.id == connectionID) { - ChipLogError(Zcl, "Modified Push AV Stream with ID: %d", connectionID); + ChipLogProgress(Zcl, "Modified Push AV Stream with ID: %d", connectionID); return Status::Success; } } @@ -82,8 +80,8 @@ Protocols::InteractionModel::Status PushAvStreamTransportManager::SetTransportSt { if (stream.id == connectionID) { - stream.transportConfig.transportStatus = transportStatus; - ChipLogError(Zcl, "Set Transport Status for Push AV Stream with ID: %d", connectionID); + stream.transportStatus = transportStatus; + ChipLogProgress(Zcl, "Set Transport Status for Push AV Stream with ID: %d", connectionID); } } } @@ -99,27 +97,8 @@ Protocols::InteractionModel::Status PushAvStreamTransportManager::ManuallyTrigge { if (stream.id == connectionID) { - stream.status = PushAvStreamTransportStatusEnum::kBusy; - ChipLogError(Zcl, "Transport triggered for Push AV Stream with ID: %d", connectionID); - } - } - return Status::Success; -} - -Protocols::InteractionModel::Status -PushAvStreamTransportManager::FindTransport(const Optional> & connectionID) -{ - configList.clear(); - for (PushAvStream & stream : pushavStreams) - { - if (connectionID.Value().IsNull()) - { - configList.push_back(stream.transportConfig); - } - else if (connectionID.Value().Value() == stream.id) - { - ChipLogError(Zcl, "Transport Found for Push AV Stream with ID: %d", connectionID.Value().Value()); - configList.push_back(stream.transportConfig); + stream.connectionStatus = PushAvStreamTransportStatusEnum::kBusy; + ChipLogProgress(Zcl, "Transport triggered for Push AV Stream with ID: %d", connectionID); } } return Status::Success; @@ -130,7 +109,13 @@ CHIP_ERROR PushAvStreamTransportManager::ValidateBandwidthLimit(StreamUsageEnum const Optional> & audioStreamId) { // TODO: Validates the requested stream usage against the camera's resource management. - return CHIP_ERROR_NOT_IMPLEMENTED; + // Returning CHIP_NO_ERROR to pass through checks in the Server Implementation. + return CHIP_NO_ERROR; +} + +bool PushAvStreamTransportManager::validateUrl(std::string url) +{ + return true; } CHIP_ERROR @@ -139,7 +124,8 @@ PushAvStreamTransportManager::ValidateStreamUsage(StreamUsageEnum streamUsage, const Optional> & audioStreamId) { // TODO: Validates the requested stream usage against the camera's resource management and stream priority policies. - return CHIP_ERROR_NOT_IMPLEMENTED; + // Returning CHIP_NO_ERROR to pass through checks in the Server Implementation. + return CHIP_NO_ERROR; } PushAvStreamTransportStatusEnum PushAvStreamTransportManager::GetTransportStatus(const uint16_t connectionID) @@ -148,7 +134,7 @@ PushAvStreamTransportStatusEnum PushAvStreamTransportManager::GetTransportStatus { if (stream.id == connectionID) { - return stream.status; + return stream.connectionStatus; } } return PushAvStreamTransportStatusEnum::kUnknown; @@ -161,12 +147,12 @@ void PushAvStreamTransportManager::OnAttributeChanged(AttributeId attributeId) void PushAvStreamTransportManager::Init() { - ChipLogError(Zcl, "Push AV Stream Transport Initialized"); + ChipLogProgress(Zcl, "Push AV Stream Transport Initialized"); } CHIP_ERROR PushAvStreamTransportManager::LoadCurrentConnections(std::vector & currentConnections) { - ChipLogError(Zcl, "Push AV Current Connections loaded"); + ChipLogProgress(Zcl, "Push AV Current Connections loaded"); return CHIP_NO_ERROR; } @@ -174,7 +160,7 @@ PushAvStreamTransportManager::LoadCurrentConnections(std::vector(); sPushAvStramTransportInstance->Init(); + BitFlags features; + sPushAvStramTransportClusterServerInstance = - std::make_unique(*sPushAvStramTransportInstance.get(), endpoint); + std::make_unique(*sPushAvStramTransportInstance.get(), endpoint, features); sPushAvStramTransportClusterServerInstance->Init(); } + +void emberAfPushAvStreamTransportClusterShutdownCallback(EndpointId endpoint) +{ + sPushAvStramTransportClusterServerInstance = nullptr; + sPushAvStramTransportInstance = nullptr; +} diff --git a/src/app/clusters/push-av-stream-transport-server/BUILD.gn b/src/app/clusters/push-av-stream-transport-server/BUILD.gn new file mode 100644 index 00000000000000..a309e9b59916ff --- /dev/null +++ b/src/app/clusters/push-av-stream-transport-server/BUILD.gn @@ -0,0 +1,15 @@ +# Copyright (c) 2025 Project CHIP Authors +# +# 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. +group("push-av-stream-transport-server") { +} diff --git a/src/app/clusters/push-av-stream-transport-server/app_config_dependent_sources.cmake b/src/app/clusters/push-av-stream-transport-server/app_config_dependent_sources.cmake new file mode 100644 index 00000000000000..f7ada4d5188470 --- /dev/null +++ b/src/app/clusters/push-av-stream-transport-server/app_config_dependent_sources.cmake @@ -0,0 +1,21 @@ +# Copyright (c) 2025 Project CHIP Authors +# +# 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. + +# This is the equivalent to app_config_dependent_sources.gni +TARGET_SOURCES( + ${APP_TARGET} + PRIVATE + "${CLUSTER_DIR}/push-av-stream-transport-server.cpp" + "${CLUSTER_DIR}/push-av-stream-transport-server.h" +) \ No newline at end of file diff --git a/src/app/clusters/push-av-stream-transport-server/app_config_dependent_sources.gni b/src/app/clusters/push-av-stream-transport-server/app_config_dependent_sources.gni new file mode 100644 index 00000000000000..786feca9b86f84 --- /dev/null +++ b/src/app/clusters/push-av-stream-transport-server/app_config_dependent_sources.gni @@ -0,0 +1,17 @@ +# Copyright (c) 2025 Project CHIP Authors +# +# 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. +app_config_dependent_sources = [ + "push-av-stream-transport-server.cpp", + "push-av-stream-transport-server.h", +] diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp index a79b94010e31d5..0d655fd4fe3d1a 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp @@ -28,7 +28,7 @@ #include #include -#define MAX_PUSH_TRANSPORT_CONNECTION_ID 65535 +static constexpr uint16_t kMaxConnectionId = 65535; // This is also invalid connectionID using namespace chip; using namespace chip::app; @@ -44,9 +44,11 @@ namespace app { namespace Clusters { namespace PushAvStreamTransport { -PushAvStreamTransportServer::PushAvStreamTransportServer(PushAvStreamTransportDelegate & aDelegate, EndpointId aEndpointId) : +PushAvStreamTransportServer::PushAvStreamTransportServer(PushAvStreamTransportDelegate & aDelegate, EndpointId aEndpointId, + const BitFlags aFeatures) : AttributeAccessInterface(MakeOptional(aEndpointId), PushAvStreamTransport::Id), - CommandHandlerInterface(MakeOptional(aEndpointId), PushAvStreamTransport::Id), mDelegate(aDelegate) + CommandHandlerInterface(MakeOptional(aEndpointId), PushAvStreamTransport::Id), mDelegate(aDelegate), mFeatures(aFeatures), + mSupportedFormats{ SupportedFormatStruct{ ContainerFormatEnum::kCmaf, IngestMethodsEnum::kCMAFIngest } } {} PushAvStreamTransportServer::~PushAvStreamTransportServer() @@ -69,6 +71,21 @@ void PushAvStreamTransportServer::Shutdown() AttributeAccessInterfaceRegistry::Instance().Unregister(this); } +bool PushAvStreamTransportServer::HasFeature(Feature feature) const +{ + return mFeatures.Has(feature); +} + +CHIP_ERROR PushAvStreamTransportServer::ReadAndEncodeSupportedFormats(const AttributeValueEncoder::ListEncodeHelper & encoder) +{ + for (const auto & supportsFormat : mSupportedFormats) + { + ReturnErrorOnFailure(encoder.Encode(supportsFormat)); + } + + return CHIP_NO_ERROR; +} + CHIP_ERROR PushAvStreamTransportServer::ReadAndEncodeCurrentConnections(const AttributeValueEncoder::ListEncodeHelper & encoder) { for (const auto & currentConnections : mCurrentConnections) @@ -128,13 +145,23 @@ void PushAvStreamTransportServer::RemoveStreamTransportConnection(const uint16_t CHIP_ERROR PushAvStreamTransportServer::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) { VerifyOrDie(aPath.mClusterId == PushAvStreamTransport::Id); - ChipLogError(Zcl, "Push AV Stream Transport[ep=%d]: Reading", AttributeAccessInterface::GetEndpointId().Value()); + ChipLogProgress(Zcl, "Push AV Stream Transport[ep=%d]: Reading", AttributeAccessInterface::GetEndpointId().Value()); - if (aPath.mClusterId == PushAvStreamTransport::Id && aPath.mAttributeId == Attributes::CurrentConnections::Id) + switch (aPath.mAttributeId) { + case FeatureMap::Id: + ReturnErrorOnFailure(aEncoder.Encode(mFeatures)); + break; + case SupportedFormats::Id: + ReturnErrorOnFailure(aEncoder.EncodeList( + [this](const auto & encoder) -> CHIP_ERROR { return this->ReadAndEncodeSupportedFormats(encoder); })); + break; + + case CurrentConnections::Id: ReturnErrorOnFailure(aEncoder.EncodeList( [this](const auto & encoder) -> CHIP_ERROR { return this->ReadAndEncodeCurrentConnections(encoder); })); + break; } return CHIP_NO_ERROR; @@ -232,24 +259,19 @@ PushAvStreamTransportServer::FindStreamTransportConnection(const uint16_t connec uint16_t PushAvStreamTransportServer::GenerateConnectionID() { - static uint16_t lastAssignedConnectionID = 0; - do + static uint16_t lastID = 0; + + for (uint16_t i = 0; i < kMaxConnectionId; ++i) { - uint16_t nextConnectionID; - if (lastAssignedConnectionID == MAX_PUSH_TRANSPORT_CONNECTION_ID) - { - nextConnectionID = 0; - } - else - { - nextConnectionID = static_cast(lastAssignedConnectionID + 1); - } - lastAssignedConnectionID = nextConnectionID; - if (FindStreamTransportConnection(nextConnectionID) == nullptr) + uint16_t candidateID = static_cast((lastID + i + 1) % kMaxConnectionId); // Wrap from 0 to 65534 + if (FindStreamTransportConnection(candidateID) == nullptr) { - return nextConnectionID; + lastID = candidateID; + return candidateID; } - } while (true); + } + + return kMaxConnectionId; // All 0 to 65534 IDs are in use } void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & ctx, @@ -258,38 +280,38 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c Commands::AllocatePushTransportResponse::Type response; auto & transportOptions = commandData.transportOptions; - uint16_t ep = emberAfGetClusterServerEndpointIndex(transportOptions.endpointID, TlsCertificateManagement::Id, - MATTER_DM_TLS_CERTIFICATE_MANAGEMENT_CLUSTER_CLIENT_ENDPOINT_COUNT); + // Todo: TLSEndpointID Validation - if (ep == kEmberInvalidEndpointIndex) + bool isFormatSupported = false; + IngestMethodsEnum ingestMethod = commandData.transportOptions.ingestMethod; + ContainerOptionsStruct containerOptions = commandData.transportOptions.containerOptions; + + for (auto & supportsFormat : mSupportedFormats) { - auto status = static_cast(StatusCodeEnum::kInvalidTLSEndpoint); - ChipLogError(Zcl, "HandleAllocatePushTransport: Valid TLSEndpointId not found"); - ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); - return; + if ((supportsFormat.ingestMethod == ingestMethod) && (supportsFormat.containerFormat == containerOptions.containerType)) + { + isFormatSupported = true; + } } - // Todo: Match Fabric index of TLSEndpointID - - if (transportOptions.ingestMethod == IngestMethodsEnum::kUnknownEnumValue) + if (isFormatSupported == false) { - auto status = static_cast(StatusCodeEnum::kUnsupportedIngestMethod); - ChipLogError(Zcl, "HandleAllocatePushTransport: Ingest method not supported"); + auto status = static_cast(StatusCodeEnum::kInvalidCombination); + ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid Format Combination"); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); return; } - if (transportOptions.containerFormat == ContainerFormatEnum::kUnknownEnumValue) + bool isValidUrl = mDelegate.validateUrl(std::string(transportOptions.url.data(), transportOptions.url.size())); + + if (isValidUrl == false) { - auto status = static_cast(StatusCodeEnum::kUnsupportedContainerFormat); - ChipLogError(Zcl, "HandleAllocatePushTransport: Container format not supported"); + auto status = static_cast(StatusCodeEnum::kInvalidURL); + ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid Url"); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); return; } - // Todo: Check combination of Ingest method, Container format in Supported Formats - // https://github.com/CHIP-Specifications/connectedhomeip-spec/pull/11504 - if (transportOptions.triggerOptions.triggerType == TransportTriggerTypeEnum::kUnknownEnumValue) { auto status = static_cast(StatusCodeEnum::kInvalidTriggerType); @@ -322,20 +344,25 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c uint16_t connectionID = GenerateConnectionID(); + if (connectionID == kMaxConnectionId) + { + ChipLogError(Zcl, "HandleAllocatePushTransport: Max Connections Exhausted"); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ResourceExhausted); + return; + } + TransportConfigurationStruct outTransportConfiguration; outTransportConfiguration.connectionID = connectionID; outTransportConfiguration.transportStatus = TransportStatusEnum::kInactive; - /** - * delegate should set the TransportOptions fields to the new values. - * Persistently store the resulting TransportConfigurationStruct and map it to the ConnectionID - */ - Status status = mDelegate.AllocatePushTransport(transportOptions, outTransportConfiguration); + TransportOptionsStorage transportOptionArgs(transportOptions); + Status status = mDelegate.AllocatePushTransport(transportOptionArgs, connectionID); if (status == Status::Success) { // add connection to CurrentConnections FabricIndex peerFabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); + outTransportConfiguration.transportOptions.SetValue(transportOptionArgs); TransportConfigurationStructWithFabricIndex transportConfiguration({ outTransportConfiguration, peerFabricIndex }); UpsertStreamTransportConnection(transportConfiguration); response.transportConfiguration = outTransportConfiguration; @@ -408,29 +435,30 @@ void PushAvStreamTransportServer::HandleModifyPushTransport(HandlerContext & ctx return; } + TransportOptionsStruct transportOptionArgs; + transportOptionArgs.streamUsage = transportOptions.streamUsage; + transportOptionArgs.videoStreamID = transportOptions.videoStreamID; + transportOptionArgs.audioStreamID = transportOptions.audioStreamID; + transportOptionArgs.endpointID = transportOptions.endpointID; + transportOptionArgs.url = transportOptions.url; + transportOptionArgs.triggerOptions.triggerType = transportOptions.triggerOptions.triggerType; + // Todo: copy motion zones + transportOptionArgs.triggerOptions.motionSensitivity = transportOptions.triggerOptions.motionSensitivity; + transportOptionArgs.triggerOptions.motionTimeControl = transportOptions.triggerOptions.motionTimeControl; + transportOptionArgs.triggerOptions.maxPreRollLen = transportOptions.triggerOptions.maxPreRollLen; + transportOptionArgs.ingestMethod = transportOptions.ingestMethod; + transportOptionArgs.containerOptions = transportOptions.containerOptions; + transportOptionArgs.expiryTime = transportOptions.expiryTime; + // Call the delegate - status = mDelegate.ModifyPushTransport(connectionID, transportOptions); + status = mDelegate.ModifyPushTransport(connectionID, transportOptionArgs); if (status == Status::Success) { if (transportConfiguration->transportConfiguration.transportOptions.HasValue()) { - TransportOptionsStruct transportOptionToModify = - transportConfiguration->transportConfiguration.transportOptions.Value(); - transportOptionToModify.streamUsage = transportOptions.streamUsage; - transportOptionToModify.videoStreamID = transportOptions.videoStreamID; - transportOptionToModify.audioStreamID = transportOptions.audioStreamID; - transportOptionToModify.endpointID = transportOptions.endpointID; - transportOptionToModify.url = transportOptions.url; - transportOptionToModify.triggerOptions.triggerType = transportOptions.triggerOptions.triggerType; - // Todo: copy motion zones - transportOptionToModify.triggerOptions.motionSensitivity = transportOptions.triggerOptions.motionSensitivity; - transportOptionToModify.triggerOptions.motionTimeControl = transportOptions.triggerOptions.motionTimeControl; - transportOptionToModify.triggerOptions.maxPreRollLen = transportOptions.triggerOptions.maxPreRollLen; - transportOptionToModify.ingestMethod = transportOptions.ingestMethod; - transportOptionToModify.containerFormat = transportOptions.containerFormat; - transportOptionToModify.containerOptions = transportOptions.containerOptions; - transportOptionToModify.expiryTime = transportOptions.expiryTime; + transportConfiguration->transportConfiguration.transportOptions = + static_cast>(transportOptionArgs); } } @@ -548,16 +576,23 @@ void PushAvStreamTransportServer::HandleManuallyTriggerTransport( void PushAvStreamTransportServer::HandleFindTransport(HandlerContext & ctx, const Commands::FindTransport::DecodableType & commandData) { - Status status = Status::Success; Commands::FindTransportResponse::Type response; Optional> connectionID = commandData.connectionID; - static std::vector transportConfigurations{}; + size_t count = 0; + size_t bufferSize = mCurrentConnections.size(); + + Platform::ScopedMemoryBuffer transportConfigurations; + if (!transportConfigurations.Calloc(bufferSize)) + { + ChipLogError(Zcl, "Memory allocation failed for forecast buffer"); + return; + } DataModel::List outTransportConfigurations; - if (connectionID.Value().IsNull()) + if ((connectionID.HasValue() == false) || connectionID.Value().IsNull()) { if (mCurrentConnections.size() == 0) { @@ -570,7 +605,7 @@ void PushAvStreamTransportServer::HandleFindTransport(HandlerContext & ctx, { if (connection.fabricIndex == ctx.mCommandHandler.GetAccessingFabricIndex()) { - transportConfigurations.push_back(connection.transportConfiguration); + transportConfigurations[count++] = connection.transportConfiguration; } } } @@ -590,24 +625,13 @@ void PushAvStreamTransportServer::HandleFindTransport(HandlerContext & ctx, ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } - transportConfigurations.push_back(transportConfiguration->transportConfiguration); + transportConfigurations[count++] = transportConfiguration->transportConfiguration; } - outTransportConfigurations = - DataModel::List(transportConfigurations.data(), transportConfigurations.size()); - - // Call the delegate - status = mDelegate.FindTransport(connectionID); - if (status == Status::Success) - { - response.transportConfigurations = outTransportConfigurations; + response.transportConfigurations = DataModel::List( + Span(transportConfigurations.Get(), count)); - ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); - } - else - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); - } + ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); } } // namespace PushAvStreamTransport diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h index a79fe0a182a41e..d44d88bb1f97d8 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h @@ -29,6 +29,9 @@ namespace app { namespace Clusters { namespace PushAvStreamTransport { +static constexpr size_t kMaxUrlLength = 2000u; + +using SupportedFormatStruct = Structs::SupportedFormatStruct::Type; using CMAFContainerOptionsStruct = Structs::CMAFContainerOptionsStruct::Type; using ContainerOptionsStruct = Structs::ContainerOptionsStruct::Type; using TransportZoneOptionsStruct = Structs::TransportZoneOptionsStruct::Type; @@ -37,8 +40,6 @@ using TransportMotionTriggerTimeControlStruct = Structs::TransportMotionTriggerT using TransportOptionsStruct = Structs::TransportOptionsStruct::Type; using TransportConfigurationStruct = Structs::TransportConfigurationStruct::Type; -using TransportOptionsDecodeableStruct = Structs::TransportOptionsStruct::DecodableType; - struct TransportConfigurationStructWithFabricIndex { TransportConfigurationStruct transportConfiguration; @@ -52,6 +53,90 @@ enum class PushAvStreamTransportStatusEnum : uint8_t kUnknown = 0x02 }; +struct TransportTriggerOptionsStorage : public TransportTriggerOptionsStruct +{ + TransportTriggerOptionsStorage() {}; + + TransportTriggerOptionsStorage(Structs::TransportTriggerOptionsStruct::DecodableType triggerOptions) + { + triggerType = triggerOptions.triggerType; + // motionZones = triggerOptions.motionZones; //Todo: Create Storage for motion zones + motionSensitivity = triggerOptions.motionSensitivity; + motionTimeControl = triggerOptions.motionTimeControl; + maxPreRollLen = triggerOptions.maxPreRollLen; + } +}; + +struct CMAFContainerOptionsStorage : public CMAFContainerOptionsStruct +{ + CMAFContainerOptionsStorage() {}; + + CMAFContainerOptionsStorage(Optional CMAFContainerOptions) + { + if (CMAFContainerOptions.HasValue() == true) + { + chunkDuration = CMAFContainerOptions.Value().chunkDuration; + + MutableByteSpan CENCKeyBuffer(mCENCKeyBuffer); + CopySpanToMutableSpan(CMAFContainerOptions.Value().CENCKey.Value(), CENCKeyBuffer); + CENCKey.SetValue(CENCKeyBuffer); + + metadataEnabled = CMAFContainerOptions.Value().metadataEnabled; + + MutableByteSpan CENCKeyIDBuffer(mCENCKeyIDBuffer); + CopySpanToMutableSpan(CMAFContainerOptions.Value().CENCKeyID.Value(), CENCKeyIDBuffer); + CENCKeyID.SetValue(CENCKeyIDBuffer); + } + } + +private: + uint8_t mCENCKeyBuffer[16]; + uint8_t mCENCKeyIDBuffer[16]; +}; + +struct ContainerOptionsStorage : public ContainerOptionsStruct +{ + ContainerOptionsStorage() {}; + + ContainerOptionsStorage(Structs::ContainerOptionsStruct::DecodableType containerOptions) + { + containerType = containerOptions.containerType; + + CMAFContainerOptionsStorage cmafContainerStorage(containerOptions.CMAFContainerOptions); + CMAFContainerOptions.SetValue(cmafContainerStorage); + } +}; + +struct TransportOptionsStorage : public TransportOptionsStruct +{ + TransportOptionsStorage() {}; + + TransportOptionsStorage(Structs::TransportOptionsStruct::DecodableType transportOptions) + { + streamUsage = transportOptions.streamUsage; + videoStreamID = transportOptions.videoStreamID; + audioStreamID = transportOptions.audioStreamID; + endpointID = transportOptions.endpointID; + + MutableCharSpan urlBuffer(mUrlBuffer); + CopyCharSpanToMutableCharSpan(transportOptions.url, urlBuffer); + url = urlBuffer; + + TransportTriggerOptionsStorage triggerOptionsStorage(transportOptions.triggerOptions); + triggerOptions = triggerOptionsStorage; + + ingestMethod = transportOptions.ingestMethod; + + ContainerOptionsStorage containerOptionsStorage(transportOptions.containerOptions); + containerOptions = containerOptionsStorage; + + expiryTime = transportOptions.expiryTime; + } + +private: + char mUrlBuffer[kMaxUrlLength]; +}; + /** @brief * Defines interfaces for implementing application-specific logic for various aspects of the PushAvStreamTransport Delegate. * Specifically, it defines interfaces for the command handling and loading of the allocated streams. @@ -68,14 +153,14 @@ class PushAvStreamTransportDelegate * * @param transportOptions[in] represent the configuration options of the transport to be allocated * - * @param outTransporConfiguration[out] represent the configuration of the transport to be allocated + * @param connectionID[in] Indicates the connectionID to allocate. * - * @return Success if the allocation is successful and a PushTransportConnectionID was - * produced; otherwise, the command SHALL be rejected with an appropriate - * error. + * @return Success if the allocation is successful and a PushTransportConnectionID was produced; otherwise, the command SHALL + * be rejected with an appropriate error. The delegate is expected the process the transport options, allocate the transport and + * map it to the connectionID. On Success TransportConfigurationStruct is sent as response by the server. */ - virtual Protocols::InteractionModel::Status AllocatePushTransport(const TransportOptionsDecodeableStruct & transportOptions, - TransportConfigurationStruct & outTransporConfiguration) = 0; + virtual Protocols::InteractionModel::Status AllocatePushTransport(const TransportOptionsStruct & transportOptions, + const uint16_t connectionID) = 0; /** * @brief Handle Command Delegate for Stream transport deallocation for the * provided connectionID. @@ -98,7 +183,7 @@ class PushAvStreamTransportDelegate * appropriate error. */ virtual Protocols::InteractionModel::Status ModifyPushTransport(const uint16_t connectionID, - const TransportOptionsDecodeableStruct & transportOptions) = 0; + const TransportOptionsStruct & transportOptions) = 0; /** * @brief Handle Command Delegate for Stream transport modification. @@ -129,14 +214,12 @@ appropriate const Optional & timeControl) = 0; /** - * @brief Handle Command Delegate to get the Stream Options Configuration for the specified push transport. - * - * @param connectionID [in] Indicates the allocated connectionID to get the Stream Options Configuration of. - * @return Success if the transport is already allocated; otherwise, the command SHALL be rejected with an appropriate - * error. + * @brief Validates the url + * @param[in] url The url to validate * + * @return boolean value true if the url is valid else false. */ - virtual Protocols::InteractionModel::Status FindTransport(const Optional> & connectionID) = 0; + virtual bool validateUrl(std::string url) = 0; /** * @brief Validates the bandwidth requirement against the camera's resource management @@ -174,6 +257,13 @@ appropriate const Optional> & videoStreamId, const Optional> & audioStreamId) = 0; + /** + * @brief Gets the status of the transport + * + * @param[in] connectionID Indicates the connectionID of the stream transport to check status + * + * @return busy if transport is active else idle + */ virtual PushAvStreamTransportStatusEnum GetTransportStatus(const uint16_t connectionID) = 0; /** @@ -183,11 +273,16 @@ appropriate virtual void OnAttributeChanged(AttributeId attributeId) = 0; /** + * @brief * Delegate functions to load the allocated transport connections. * The delegate application is responsible for creating and persisting these connections ( based on the Allocation commands ). * These Load APIs would be used to load the pre-allocated transport connections context information into the cluster server - * list, at initialization. Once loaded, the cluster server would be serving Reads on these attributes. The list is updatable - * via the Add/Remove functions for the respective transport connections. + * list, at initialization. Once loaded, the cluster server would be serving Reads on these attributes. The list is updatable + * via the Add/Remove functions for the respective transport connections. + * + * @note + * The callee is responsible for allocating the buffer that holds the currentConnections. + * The buffer is allocated internally by the function and returned to the caller via an output parameter. */ virtual CHIP_ERROR LoadCurrentConnections(std::vector & currentConnections) = 0; @@ -204,11 +299,12 @@ class PushAvStreamTransportServer : public AttributeAccessInterface, public Comm /** * Creates a Push AV Stream Transport server instance. The Init() function needs to be called for this instance to be registered * and called by the interaction model at the appropriate times. - * @param aDelegate A reference to the delegate to be used by this server. + * @param aDelegate A reference to the delegate to be used by this server. * @param aEndpointId The endpoint on which this cluster exists. This must match the zap configuration. + * @param aFeatures The bitflags value that identifies which features are supported by this instance. * Note: the caller must ensure that the delegate lives throughout the instance's lifetime. */ - PushAvStreamTransportServer(PushAvStreamTransportDelegate & delegate, EndpointId endpointId); + PushAvStreamTransportServer(PushAvStreamTransportDelegate & delegate, EndpointId endpointId, const BitFlags aFeatures); ~PushAvStreamTransportServer() override; @@ -230,8 +326,6 @@ class PushAvStreamTransportServer : public AttributeAccessInterface, public Comm bool HasFeature(Feature feature) const; // Attribute Getters - BitMask GetSupportedContainerFormats() const { return mSupportedContainerFormats; } - BitMask GetSupportedIngestMethods() const { return mSupportedIngestMethods; } private: enum class UpsertResultEnum : uint8_t @@ -242,11 +336,10 @@ class PushAvStreamTransportServer : public AttributeAccessInterface, public Comm PushAvStreamTransportDelegate & mDelegate; + const BitFlags mFeatures; + // Attributes - // Todo: Add SupportedFormats attribute form https://github.com/CHIP-Specifications/connectedhomeip-spec/pull/11504 - BitMask mSupportedContainerFormats; - BitMask mSupportedIngestMethods; - // lists + std::vector mSupportedFormats; /*Moved from TransportConfigurationStruct to TransportConfigurationStructWithFabricIndex * to perform fabric index checks */ @@ -265,6 +358,7 @@ class PushAvStreamTransportServer : public AttributeAccessInterface, public Comm // Helpers to read list items via delegate APIs CHIP_ERROR ReadAndEncodeCurrentConnections(const AttributeValueEncoder::ListEncodeHelper & encoder); + CHIP_ERROR ReadAndEncodeSupportedFormats(const AttributeValueEncoder::ListEncodeHelper & encoder); // Helper functions uint16_t GenerateConnectionID(); diff --git a/src/app/zap-templates/zcl/zcl-with-test-extensions.json b/src/app/zap-templates/zcl/zcl-with-test-extensions.json index 40fa9d6632e182..056b0d2aa3f0d6 100644 --- a/src/app/zap-templates/zcl/zcl-with-test-extensions.json +++ b/src/app/zap-templates/zcl/zcl-with-test-extensions.json @@ -774,7 +774,6 @@ "FeatureMap" ], "Camera AV Settings User Level Management": ["MPTZPosition"], - "Push AV Stream Transport": ["CurrentConnections"], "Soil Measurement": ["SoilMoistureMeasurementLimits"], "Unit Localization": ["TemperatureUnit"] }, diff --git a/src/app/zap-templates/zcl/zcl.json b/src/app/zap-templates/zcl/zcl.json index c07d12f8768478..1f5f3df6802a08 100644 --- a/src/app/zap-templates/zcl/zcl.json +++ b/src/app/zap-templates/zcl/zcl.json @@ -768,7 +768,6 @@ "FeatureMap" ], "Camera AV Settings User Level Management": ["MPTZPosition"], - "Push AV Stream Transport": ["CurrentConnections"], "Soil Measurement": ["SoilMoistureMeasurementLimits"], "Unit Localization": ["TemperatureUnit"] }, From 69d8bde8da9ba2d989e76b756c8b9b7a97d90b73 Mon Sep 17 00:00:00 2001 From: Sayon Deep Date: Thu, 15 May 2025 13:31:49 +0000 Subject: [PATCH 17/22] Restyled by clang-format --- .../push-av-stream-transport-delegate-impl.h | 2 +- ...push-av-stream-transport-delegate-impl.cpp | 2 +- .../push-av-stream-transport-server.cpp | 36 ++++++------ .../push-av-stream-transport-server.h | 58 +++++++++++++------ 4 files changed, 60 insertions(+), 38 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h b/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h index 9a219955f7eac2..f74ae2c24df826 100644 --- a/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h +++ b/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h @@ -62,7 +62,7 @@ class PushAvStreamTransportManager : public PushAvStreamTransportDelegate PushAvStreamTransportStatusEnum GetTransportStatus(const uint16_t connectionID); void OnAttributeChanged(AttributeId attributeId); - CHIP_ERROR LoadCurrentConnections(std::vector & currentConnections); + CHIP_ERROR LoadCurrentConnections(std::vector & currentConnections); CHIP_ERROR PersistentAttributesLoadedCallback(); void Init(); diff --git a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp index 0ab561a0f75d59..9100e14f37e00c 100644 --- a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp @@ -150,7 +150,7 @@ void PushAvStreamTransportManager::Init() ChipLogProgress(Zcl, "Push AV Stream Transport Initialized"); } CHIP_ERROR -PushAvStreamTransportManager::LoadCurrentConnections(std::vector & currentConnections) +PushAvStreamTransportManager::LoadCurrentConnections(std::vector & currentConnections) { ChipLogProgress(Zcl, "Push AV Current Connections loaded"); diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp index 0d655fd4fe3d1a..34aa419efbfa98 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp @@ -97,7 +97,7 @@ CHIP_ERROR PushAvStreamTransportServer::ReadAndEncodeCurrentConnections(const At } PushAvStreamTransportServer::UpsertResultEnum PushAvStreamTransportServer::UpsertStreamTransportConnection( - const TransportConfigurationStructWithFabricIndex & transportConfiguration) + const TransportConfigurationStorageWithFabricIndex & transportConfiguration) { UpsertResultEnum result; auto it = std::find_if(mCurrentConnections.begin(), mCurrentConnections.end(), @@ -128,7 +128,7 @@ void PushAvStreamTransportServer::RemoveStreamTransportConnection(const uint16_t // Erase-Remove idiom mCurrentConnections.erase(std::remove_if(mCurrentConnections.begin(), mCurrentConnections.end(), - [transportConnectionId](const TransportConfigurationStructWithFabricIndex & s) { + [transportConnectionId](const TransportConfigurationStorageWithFabricIndex & s) { return s.transportConfiguration.connectionID == transportConnectionId; }), mCurrentConnections.end()); @@ -246,7 +246,7 @@ void PushAvStreamTransportServer::InvokeCommand(HandlerContext & handlerContext) } } -TransportConfigurationStructWithFabricIndex * +TransportConfigurationStorageWithFabricIndex * PushAvStreamTransportServer::FindStreamTransportConnection(const uint16_t connectionID) { for (auto & transportConnection : mCurrentConnections) @@ -351,19 +351,19 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c return; } - TransportConfigurationStruct outTransportConfiguration; - outTransportConfiguration.connectionID = connectionID; - outTransportConfiguration.transportStatus = TransportStatusEnum::kInactive; + std::shared_ptr transportOptionsPtr = std::make_shared(transportOptions); - TransportOptionsStorage transportOptionArgs(transportOptions); - Status status = mDelegate.AllocatePushTransport(transportOptionArgs, connectionID); + TransportConfigurationStorage outTransportConfiguration(connectionID, transportOptionsPtr); + + Status status = mDelegate.AllocatePushTransport(*transportOptionsPtr, connectionID); if (status == Status::Success) { // add connection to CurrentConnections FabricIndex peerFabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); - outTransportConfiguration.transportOptions.SetValue(transportOptionArgs); - TransportConfigurationStructWithFabricIndex transportConfiguration({ outTransportConfiguration, peerFabricIndex }); + + TransportConfigurationStorageWithFabricIndex transportConfiguration({ outTransportConfiguration, peerFabricIndex }); + UpsertStreamTransportConnection(transportConfiguration); response.transportConfiguration = outTransportConfiguration; @@ -378,9 +378,9 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c void PushAvStreamTransportServer::HandleDeallocatePushTransport( HandlerContext & ctx, const Commands::DeallocatePushTransport::DecodableType & commandData) { - Status status = Status::Success; - uint16_t connectionID = commandData.connectionID; - TransportConfigurationStructWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID); + Status status = Status::Success; + uint16_t connectionID = commandData.connectionID; + TransportConfigurationStorageWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID); if (transportConfiguration == nullptr) { ChipLogError(Zcl, "HandleDeallocatePushTransport: ConnectionID Not Found."); @@ -412,7 +412,7 @@ void PushAvStreamTransportServer::HandleModifyPushTransport(HandlerContext & ctx uint16_t connectionID = commandData.connectionID; auto & transportOptions = commandData.transportOptions; - TransportConfigurationStructWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID); + TransportConfigurationStorageWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID); if (transportConfiguration == nullptr) { @@ -486,7 +486,7 @@ void PushAvStreamTransportServer::HandleSetTransportStatus(HandlerContext & ctx, } else { - TransportConfigurationStructWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID.Value()); + TransportConfigurationStorageWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID.Value()); if (transportConfiguration == nullptr) { ChipLogError(Zcl, "HandleSetTransportStatus: ConnectionID Not Found."); @@ -516,7 +516,7 @@ void PushAvStreamTransportServer::HandleManuallyTriggerTransport( auto & activationReason = commandData.activationReason; auto & timeControl = commandData.timeControl; - TransportConfigurationStructWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID); + TransportConfigurationStorageWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID); if (transportConfiguration == nullptr) { @@ -590,8 +590,6 @@ void PushAvStreamTransportServer::HandleFindTransport(HandlerContext & ctx, return; } - DataModel::List outTransportConfigurations; - if ((connectionID.HasValue() == false) || connectionID.Value().IsNull()) { if (mCurrentConnections.size() == 0) @@ -611,7 +609,7 @@ void PushAvStreamTransportServer::HandleFindTransport(HandlerContext & ctx, } else { - TransportConfigurationStructWithFabricIndex * transportConfiguration = + TransportConfigurationStorageWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID.Value().Value()); if (transportConfiguration == nullptr) { diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h index d44d88bb1f97d8..fab51d66569f43 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h @@ -40,12 +40,6 @@ using TransportMotionTriggerTimeControlStruct = Structs::TransportMotionTriggerT using TransportOptionsStruct = Structs::TransportOptionsStruct::Type; using TransportConfigurationStruct = Structs::TransportConfigurationStruct::Type; -struct TransportConfigurationStructWithFabricIndex -{ - TransportConfigurationStruct transportConfiguration; - chip::FabricIndex fabricIndex; -}; - enum class PushAvStreamTransportStatusEnum : uint8_t { kBusy = 0x00, @@ -102,9 +96,12 @@ struct ContainerOptionsStorage : public ContainerOptionsStruct { containerType = containerOptions.containerType; - CMAFContainerOptionsStorage cmafContainerStorage(containerOptions.CMAFContainerOptions); - CMAFContainerOptions.SetValue(cmafContainerStorage); + mCMAFContainerStorage = CMAFContainerOptionsStorage(containerOptions.CMAFContainerOptions); + CMAFContainerOptions.SetValue(mCMAFContainerStorage); } + +private: + CMAFContainerOptionsStorage mCMAFContainerStorage; }; struct TransportOptionsStorage : public TransportOptionsStruct @@ -119,22 +116,49 @@ struct TransportOptionsStorage : public TransportOptionsStruct endpointID = transportOptions.endpointID; MutableCharSpan urlBuffer(mUrlBuffer); - CopyCharSpanToMutableCharSpan(transportOptions.url, urlBuffer); + CopyCharSpanToMutableCharSpanWithTruncation(transportOptions.url, urlBuffer); url = urlBuffer; - TransportTriggerOptionsStorage triggerOptionsStorage(transportOptions.triggerOptions); - triggerOptions = triggerOptionsStorage; + mTriggerOptionsStorage = TransportTriggerOptionsStorage(transportOptions.triggerOptions); + triggerOptions = mTriggerOptionsStorage; ingestMethod = transportOptions.ingestMethod; - ContainerOptionsStorage containerOptionsStorage(transportOptions.containerOptions); - containerOptions = containerOptionsStorage; + mContainerOptionsStorage = ContainerOptionsStorage(transportOptions.containerOptions); + containerOptions = mContainerOptionsStorage; expiryTime = transportOptions.expiryTime; } private: char mUrlBuffer[kMaxUrlLength]; + TransportTriggerOptionsStorage mTriggerOptionsStorage; + ContainerOptionsStorage mContainerOptionsStorage; +}; + +struct TransportConfigurationStorage : public TransportConfigurationStruct +{ + TransportConfigurationStorage() {} + + TransportConfigurationStorage(const uint16_t aConnectionID, std::shared_ptr aTransportOptionsPtr) + { + connectionID = aConnectionID; + transportStatus = TransportStatusEnum::kInactive; + /*Store the pointer to keep buffer alive*/ + mTransportOptionsPtr = aTransportOptionsPtr; + /*Convert Storage type to base type*/ + transportOptions.SetValue(*aTransportOptionsPtr); + } + std::shared_ptr GetTransportOptionsPtr() const { return mTransportOptionsPtr; } + +private: + std::shared_ptr mTransportOptionsPtr; +}; + +struct TransportConfigurationStorageWithFabricIndex +{ + TransportConfigurationStorage transportConfiguration; + chip::FabricIndex fabricIndex; }; /** @brief @@ -284,7 +308,7 @@ appropriate * The callee is responsible for allocating the buffer that holds the currentConnections. * The buffer is allocated internally by the function and returned to the caller via an output parameter. */ - virtual CHIP_ERROR LoadCurrentConnections(std::vector & currentConnections) = 0; + virtual CHIP_ERROR LoadCurrentConnections(std::vector & currentConnections) = 0; /** * @brief Callback into the delegate once persistent attributes managed by @@ -343,7 +367,7 @@ class PushAvStreamTransportServer : public AttributeAccessInterface, public Comm /*Moved from TransportConfigurationStruct to TransportConfigurationStructWithFabricIndex * to perform fabric index checks */ - std::vector mCurrentConnections; + std::vector mCurrentConnections; /** * IM-level implementation of read @@ -362,9 +386,9 @@ class PushAvStreamTransportServer : public AttributeAccessInterface, public Comm // Helper functions uint16_t GenerateConnectionID(); - TransportConfigurationStructWithFabricIndex * FindStreamTransportConnection(const uint16_t connectionID); + TransportConfigurationStorageWithFabricIndex * FindStreamTransportConnection(const uint16_t connectionID); // Add/Remove Management functions for transport - UpsertResultEnum UpsertStreamTransportConnection(const TransportConfigurationStructWithFabricIndex & transportConfiguration); + UpsertResultEnum UpsertStreamTransportConnection(const TransportConfigurationStorageWithFabricIndex & transportConfiguration); void RemoveStreamTransportConnection(const uint16_t connectionID); From 1fdc58660a4de0e49cc88eec481cecf01bfbaa70 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Thu, 15 May 2025 21:40:01 +0000 Subject: [PATCH 18/22] Restyled by clang-format --- .../push-av-stream-transport-server.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h index fab51d66569f43..3260ca5928ab65 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h @@ -49,7 +49,7 @@ enum class PushAvStreamTransportStatusEnum : uint8_t struct TransportTriggerOptionsStorage : public TransportTriggerOptionsStruct { - TransportTriggerOptionsStorage() {}; + TransportTriggerOptionsStorage(){}; TransportTriggerOptionsStorage(Structs::TransportTriggerOptionsStruct::DecodableType triggerOptions) { @@ -63,7 +63,7 @@ struct TransportTriggerOptionsStorage : public TransportTriggerOptionsStruct struct CMAFContainerOptionsStorage : public CMAFContainerOptionsStruct { - CMAFContainerOptionsStorage() {}; + CMAFContainerOptionsStorage(){}; CMAFContainerOptionsStorage(Optional CMAFContainerOptions) { @@ -90,7 +90,7 @@ struct CMAFContainerOptionsStorage : public CMAFContainerOptionsStruct struct ContainerOptionsStorage : public ContainerOptionsStruct { - ContainerOptionsStorage() {}; + ContainerOptionsStorage(){}; ContainerOptionsStorage(Structs::ContainerOptionsStruct::DecodableType containerOptions) { @@ -106,7 +106,7 @@ struct ContainerOptionsStorage : public ContainerOptionsStruct struct TransportOptionsStorage : public TransportOptionsStruct { - TransportOptionsStorage() {}; + TransportOptionsStorage(){}; TransportOptionsStorage(Structs::TransportOptionsStruct::DecodableType transportOptions) { From bb9e0531f166bdd667a54ff77079292ee85ae3ef Mon Sep 17 00:00:00 2001 From: Sayon Deep Date: Tue, 20 May 2025 13:10:33 +0530 Subject: [PATCH 19/22] Address review comments --- .../push-av-stream-transport-delegate-impl.h | 2 +- ...push-av-stream-transport-delegate-impl.cpp | 2 +- .../push-av-stream-transport-server.cpp | 17 +-- .../push-av-stream-transport-server.h | 106 +++++++++++++----- 4 files changed, 88 insertions(+), 39 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h b/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h index f74ae2c24df826..574b07a4ef59a4 100644 --- a/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h +++ b/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h @@ -53,7 +53,7 @@ class PushAvStreamTransportManager : public PushAvStreamTransportDelegate ManuallyTriggerTransport(const uint16_t connectionID, TriggerActivationReasonEnum activationReason, const Optional & timeControl); - bool validateUrl(std::string url); + bool ValidateUrl(std::string url); CHIP_ERROR ValidateStreamUsage(StreamUsageEnum streamUsage, const Optional> & videoStreamId, const Optional> & audioStreamId); diff --git a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp index 9100e14f37e00c..7687fb24b8727b 100644 --- a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp @@ -113,7 +113,7 @@ CHIP_ERROR PushAvStreamTransportManager::ValidateBandwidthLimit(StreamUsageEnum return CHIP_NO_ERROR; } -bool PushAvStreamTransportManager::validateUrl(std::string url) +bool PushAvStreamTransportManager::ValidateUrl(std::string url) { return true; } diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp index 34aa419efbfa98..f61045c1976b57 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp @@ -296,17 +296,17 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c if (isFormatSupported == false) { - auto status = static_cast(StatusCodeEnum::kInvalidCombination); + auto status = to_underlying(StatusCodeEnum::kInvalidCombination); ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid Format Combination"); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); return; } - bool isValidUrl = mDelegate.validateUrl(std::string(transportOptions.url.data(), transportOptions.url.size())); + bool isValidUrl = mDelegate.ValidateUrl(std::string(transportOptions.url.data(), transportOptions.url.size())); if (isValidUrl == false) { - auto status = static_cast(StatusCodeEnum::kInvalidURL); + auto status = to_underlying(StatusCodeEnum::kInvalidURL); ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid Url"); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); return; @@ -314,7 +314,7 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c if (transportOptions.triggerOptions.triggerType == TransportTriggerTypeEnum::kUnknownEnumValue) { - auto status = static_cast(StatusCodeEnum::kInvalidTriggerType); + auto status = to_underlying(StatusCodeEnum::kInvalidTriggerType); ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid Trigger type"); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); return; @@ -336,7 +336,7 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c mDelegate.ValidateStreamUsage(transportOptions.streamUsage, transportOptions.videoStreamID, transportOptions.audioStreamID); if (err != CHIP_NO_ERROR) { - auto status = static_cast(StatusCodeEnum::kInvalidStream); + auto status = to_underlying(StatusCodeEnum::kInvalidStream); ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid Stream"); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); return; @@ -351,7 +351,8 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c return; } - std::shared_ptr transportOptionsPtr = std::make_shared(transportOptions); + std::shared_ptr transportOptionsPtr = + std::make_shared(transportOptions, mFeatures); TransportConfigurationStorage outTransportConfiguration(connectionID, transportOptionsPtr); @@ -541,7 +542,7 @@ void PushAvStreamTransportServer::HandleManuallyTriggerTransport( if (transportConfiguration->transportConfiguration.transportStatus == TransportStatusEnum::kInactive) { - auto clusterStatus = static_cast(StatusCodeEnum::kInvalidTransportStatus); + auto clusterStatus = to_underlying(StatusCodeEnum::kInvalidTransportStatus); ChipLogError(Zcl, "HandleManuallyTriggerTransport: Invalid Transport status"); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, clusterStatus); return; @@ -552,7 +553,7 @@ void PushAvStreamTransportServer::HandleManuallyTriggerTransport( TransportTriggerTypeEnum::kContinuous) { - auto clusterStatus = static_cast(StatusCodeEnum::kInvalidTriggerType); + auto clusterStatus = to_underlying(StatusCodeEnum::kInvalidTriggerType); ChipLogError(Zcl, "HandleManuallyTriggerTransport: Invalid Trigger type"); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, clusterStatus); return; diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h index 3260ca5928ab65..c66e620cfb22fe 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h @@ -49,37 +49,77 @@ enum class PushAvStreamTransportStatusEnum : uint8_t struct TransportTriggerOptionsStorage : public TransportTriggerOptionsStruct { - TransportTriggerOptionsStorage(){}; + TransportTriggerOptionsStorage() {}; - TransportTriggerOptionsStorage(Structs::TransportTriggerOptionsStruct::DecodableType triggerOptions) + TransportTriggerOptionsStorage(Structs::TransportTriggerOptionsStruct::DecodableType triggerOptions, + const BitFlags features) { triggerType = triggerOptions.triggerType; - // motionZones = triggerOptions.motionZones; //Todo: Create Storage for motion zones + + if (triggerOptions.triggerType == TransportTriggerTypeEnum::kMotion && triggerOptions.motionZones.HasValue()) + { + if (triggerOptions.motionZones.Value().IsNull() == false) + { + auto & motionZonesList = triggerOptions.motionZones; + auto iter = motionZonesList.Value().Value().begin(); + + while (iter.Next()) + { + auto & transportZoneOption = iter.GetValue(); + mTransportZoneOptions.push_back(transportZoneOption); + } + + motionZones.SetValue(DataModel::Nullable>( + Span(mTransportZoneOptions.data(), mTransportZoneOptions.size()))); + } + } + else + { + motionZones.Missing(); + } + motionSensitivity = triggerOptions.motionSensitivity; motionTimeControl = triggerOptions.motionTimeControl; maxPreRollLen = triggerOptions.maxPreRollLen; } + +private: + std::vector mTransportZoneOptions; }; struct CMAFContainerOptionsStorage : public CMAFContainerOptionsStruct { - CMAFContainerOptionsStorage(){}; + CMAFContainerOptionsStorage() {}; - CMAFContainerOptionsStorage(Optional CMAFContainerOptions) + CMAFContainerOptionsStorage(Optional CMAFContainerOptions, + const BitFlags features) { if (CMAFContainerOptions.HasValue() == true) { chunkDuration = CMAFContainerOptions.Value().chunkDuration; - MutableByteSpan CENCKeyBuffer(mCENCKeyBuffer); - CopySpanToMutableSpan(CMAFContainerOptions.Value().CENCKey.Value(), CENCKeyBuffer); - CENCKey.SetValue(CENCKeyBuffer); - - metadataEnabled = CMAFContainerOptions.Value().metadataEnabled; - - MutableByteSpan CENCKeyIDBuffer(mCENCKeyIDBuffer); - CopySpanToMutableSpan(CMAFContainerOptions.Value().CENCKeyID.Value(), CENCKeyIDBuffer); - CENCKeyID.SetValue(CENCKeyIDBuffer); + if (CMAFContainerOptions.Value().CENCKey.HasValue()) + { + MutableByteSpan CENCKeyBuffer(mCENCKeyBuffer); + CopySpanToMutableSpan(CMAFContainerOptions.Value().CENCKey.Value(), CENCKeyBuffer); + CENCKey.SetValue(CENCKeyBuffer); + } + + if (features.Has(Feature::kMetadata) && CMAFContainerOptions.HasValue()) + { + metadataEnabled = CMAFContainerOptions.Value().metadataEnabled; + } + else + { + metadataEnabled.Missing(); + } + + if (CMAFContainerOptions.Value().CENCKey.HasValue()) + { + MutableByteSpan CENCKeyIDBuffer(mCENCKeyIDBuffer); + CopySpanToMutableSpan(CMAFContainerOptions.Value().CENCKeyID.Value(), CENCKeyIDBuffer); + CENCKeyID.SetValue(CENCKeyIDBuffer); + } } } @@ -90,14 +130,21 @@ struct CMAFContainerOptionsStorage : public CMAFContainerOptionsStruct struct ContainerOptionsStorage : public ContainerOptionsStruct { - ContainerOptionsStorage(){}; + ContainerOptionsStorage() {}; - ContainerOptionsStorage(Structs::ContainerOptionsStruct::DecodableType containerOptions) + ContainerOptionsStorage(Structs::ContainerOptionsStruct::DecodableType containerOptions, const BitFlags features) { containerType = containerOptions.containerType; - mCMAFContainerStorage = CMAFContainerOptionsStorage(containerOptions.CMAFContainerOptions); - CMAFContainerOptions.SetValue(mCMAFContainerStorage); + if (containerType == ContainerFormatEnum::kCmaf) + { + mCMAFContainerStorage = CMAFContainerOptionsStorage(containerOptions.CMAFContainerOptions, features); + CMAFContainerOptions.SetValue(mCMAFContainerStorage); + } + else + { + CMAFContainerOptions.Missing(); + } } private: @@ -106,9 +153,9 @@ struct ContainerOptionsStorage : public ContainerOptionsStruct struct TransportOptionsStorage : public TransportOptionsStruct { - TransportOptionsStorage(){}; + TransportOptionsStorage() {}; - TransportOptionsStorage(Structs::TransportOptionsStruct::DecodableType transportOptions) + TransportOptionsStorage(Structs::TransportOptionsStruct::DecodableType transportOptions, const BitFlags features) { streamUsage = transportOptions.streamUsage; videoStreamID = transportOptions.videoStreamID; @@ -119,12 +166,12 @@ struct TransportOptionsStorage : public TransportOptionsStruct CopyCharSpanToMutableCharSpanWithTruncation(transportOptions.url, urlBuffer); url = urlBuffer; - mTriggerOptionsStorage = TransportTriggerOptionsStorage(transportOptions.triggerOptions); + mTriggerOptionsStorage = TransportTriggerOptionsStorage(transportOptions.triggerOptions, features); triggerOptions = mTriggerOptionsStorage; ingestMethod = transportOptions.ingestMethod; - mContainerOptionsStorage = ContainerOptionsStorage(transportOptions.containerOptions); + mContainerOptionsStorage = ContainerOptionsStorage(transportOptions.containerOptions, features); containerOptions = mContainerOptionsStorage; expiryTime = transportOptions.expiryTime; @@ -158,7 +205,7 @@ struct TransportConfigurationStorage : public TransportConfigurationStruct struct TransportConfigurationStorageWithFabricIndex { TransportConfigurationStorage transportConfiguration; - chip::FabricIndex fabricIndex; + FabricIndex fabricIndex; }; /** @brief @@ -180,8 +227,8 @@ class PushAvStreamTransportDelegate * @param connectionID[in] Indicates the connectionID to allocate. * * @return Success if the allocation is successful and a PushTransportConnectionID was produced; otherwise, the command SHALL - * be rejected with an appropriate error. The delegate is expected the process the transport options, allocate the transport and - * map it to the connectionID. On Success TransportConfigurationStruct is sent as response by the server. + * be rejected with an appropriate error. The delegate is expected to process the transport options, allocate the transport + * and map it to the connectionID. On Success TransportConfigurationStruct is sent as response by the server. */ virtual Protocols::InteractionModel::Status AllocatePushTransport(const TransportOptionsStruct & transportOptions, const uint16_t connectionID) = 0; @@ -235,7 +282,7 @@ appropriate */ virtual Protocols::InteractionModel::Status ManuallyTriggerTransport(const uint16_t connectionID, TriggerActivationReasonEnum activationReason, - const Optional & timeControl) = 0; + const Optional & timeControl) = 0; /** * @brief Validates the url @@ -243,7 +290,7 @@ appropriate * * @return boolean value true if the url is valid else false. */ - virtual bool validateUrl(std::string url) = 0; + virtual bool ValidateUrl(std::string url) = 0; /** * @brief Validates the bandwidth requirement against the camera's resource management @@ -305,8 +352,9 @@ appropriate * via the Add/Remove functions for the respective transport connections. * * @note - * The callee is responsible for allocating the buffer that holds the currentConnections. - * The buffer is allocated internally by the function and returned to the caller via an output parameter. + * + * The required buffers are managed by TransportConfigurationStorage, the delegate function is expected to populate the vector + * correctly. */ virtual CHIP_ERROR LoadCurrentConnections(std::vector & currentConnections) = 0; From 281c6ffce4ce20459696daed593cc2fbb5a162b6 Mon Sep 17 00:00:00 2001 From: Sayon Deep Date: Wed, 28 May 2025 15:14:42 +0530 Subject: [PATCH 20/22] Address review comments --- .../push-av-stream-transport-delegate-impl.h | 2 +- ...push-av-stream-transport-delegate-impl.cpp | 3 +- .../push-av-stream-transport-server.cpp | 590 +++++++++++++++--- .../push-av-stream-transport-server.h | 260 ++++++-- 4 files changed, 746 insertions(+), 109 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h b/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h index 574b07a4ef59a4..18d799efdf64ca 100644 --- a/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h +++ b/examples/all-clusters-app/all-clusters-common/include/push-av-stream-transport-delegate-impl.h @@ -45,7 +45,7 @@ class PushAvStreamTransportManager : public PushAvStreamTransportDelegate const uint16_t connectionID); Protocols::InteractionModel::Status DeallocatePushTransport(const uint16_t connectionID); Protocols::InteractionModel::Status ModifyPushTransport(const uint16_t connectionID, - const TransportOptionsStruct & transportOptions); + const Structs::TransportOptionsStruct::DecodableType transportOptions); Protocols::InteractionModel::Status SetTransportStatus(const std::vector connectionIDList, TransportStatusEnum transportStatus); diff --git a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp index 7687fb24b8727b..33a834724489d2 100644 --- a/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/push-av-stream-transport-delegate-impl.cpp @@ -57,7 +57,8 @@ Protocols::InteractionModel::Status PushAvStreamTransportManager::DeallocatePush } Protocols::InteractionModel::Status -PushAvStreamTransportManager::ModifyPushTransport(const uint16_t connectionID, const TransportOptionsStruct & transportOptions) +PushAvStreamTransportManager::ModifyPushTransport(const uint16_t connectionID, + const Structs::TransportOptionsStruct::DecodableType transportOptions) { for (PushAvStream & stream : pushavStreams) { diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp index f61045c1976b57..111cc6d9f6d469 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -49,7 +50,10 @@ PushAvStreamTransportServer::PushAvStreamTransportServer(PushAvStreamTransportDe AttributeAccessInterface(MakeOptional(aEndpointId), PushAvStreamTransport::Id), CommandHandlerInterface(MakeOptional(aEndpointId), PushAvStreamTransport::Id), mDelegate(aDelegate), mFeatures(aFeatures), mSupportedFormats{ SupportedFormatStruct{ ContainerFormatEnum::kCmaf, IngestMethodsEnum::kCMAFIngest } } -{} +{ + /* set the base class delegates endpointId */ + mDelegate.SetEndpointId(aEndpointId); +} PushAvStreamTransportServer::~PushAvStreamTransportServer() { @@ -274,18 +278,236 @@ uint16_t PushAvStreamTransportServer::GenerateConnectionID() return kMaxConnectionId; // All 0 to 65534 IDs are in use } +void PushAvStreamTransportServer::PushAVStreamTransportDeallocateCallback(System::Layer *, void * callbackContext) +{ + PushAVStreamTransportDeallocateCallbackContext * transportDeallocateContext = + static_cast((callbackContext)); + + uint16_t connectionID = transportDeallocateContext->connectionID; + + // Call the delegate + auto delegateStatus = Protocols::InteractionModel::ClusterStatusCode( + transportDeallocateContext->instance->mDelegate.DeallocatePushTransport(connectionID)); + + if (delegateStatus.IsSuccess() == true) + { + ChipLogProgress(Zcl, "Push AV Stream Transport Deallocate timer expired. %s", "Deallocating"); + + // Remove connection from CurrentConnections + transportDeallocateContext->instance->RemoveStreamTransportConnection(connectionID); + } + else + { + ChipLogError(Zcl, "Push AV Stream Transport Deallocate timer expired. %s", "Deallocation Failed"); + } + + delete transportDeallocateContext; +} + +void PushAvStreamTransportServer::ScheduleTransportDeallocate(uint16_t connectionID, uint32_t timeoutSec) +{ + uint32_t timeoutMs = timeoutSec * MILLISECOND_TICKS_PER_SECOND; + + PushAVStreamTransportDeallocateCallbackContext * transportDeallocateContext = + new (std::nothrow) PushAVStreamTransportDeallocateCallbackContext{ this, connectionID }; + + if (transportDeallocateContext == nullptr) + { + ChipLogError(Zcl, "Failed to allocate memory for deallocate context"); + return; + } + + CHIP_ERROR err = DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Milliseconds32(timeoutMs), + PushAVStreamTransportDeallocateCallback, + static_cast(transportDeallocateContext)); + + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "Failed to schedule deallocate: timeout=%" PRIu32 ", status=%" CHIP_ERROR_FORMAT, timeoutSec, + err.Format()); + } +} + void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & ctx, const Commands::AllocatePushTransport::DecodableType & commandData) { Commands::AllocatePushTransportResponse::Type response; auto & transportOptions = commandData.transportOptions; + // Contraints check on incoming transport Options + + VerifyOrReturn(transportOptions.streamUsage != StreamUsageEnum::kUnknownEnumValue, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Invalid streamUsage ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + + VerifyOrReturn(transportOptions.videoStreamID.HasValue() || transportOptions.audioStreamID.HasValue(), { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing videoStreamID and audioStreamID", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + + VerifyOrReturn(transportOptions.url.size() <= 2000, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing videoStreamID and audioStreamID", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + }); + + auto & triggerOptions = transportOptions.triggerOptions; + + VerifyOrReturn(triggerOptions.triggerType != TransportTriggerTypeEnum::kUnknownEnumValue, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Invalid triggerType ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + + if (triggerOptions.triggerType == TransportTriggerTypeEnum::kMotion) + { + VerifyOrReturn(triggerOptions.motionZones.HasValue(), { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing motion zones ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + + if (triggerOptions.motionZones.Value().IsNull() == false) + { + auto & motionZonesList = triggerOptions.motionZones; + auto iter = motionZonesList.Value().Value().begin(); + + while (iter.Next()) + { + auto & transportZoneOption = iter.GetValue(); + + if (mFeatures.Has(Feature::kPerZoneSensitivity)) + { + VerifyOrReturn(transportZoneOption.sensitivity.HasValue(), { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing Zone Sensitivity ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + + VerifyOrReturn(transportZoneOption.sensitivity.Value() >= 1 && transportZoneOption.sensitivity.Value() <= 10, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Zone Sensitivity Constraint Error", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + }); + } + } + } + + if (mFeatures.Has(Feature::kPerZoneSensitivity) == false) + { + VerifyOrReturn(triggerOptions.motionSensitivity.HasValue(), { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing Motion Sensitivity ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + VerifyOrReturn( + triggerOptions.motionSensitivity.Value().Value() >= 1 && triggerOptions.motionSensitivity.Value().Value() <= 10, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Motion Sensitivity Constraint Error", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + }); + } + + VerifyOrReturn(triggerOptions.motionTimeControl.HasValue(), { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing Motion Time Control ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + + VerifyOrReturn(triggerOptions.motionTimeControl.Value().initialDuration >= 1, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Motion Time Control (InitialDuration) Constraint Error", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + }); + + VerifyOrReturn(triggerOptions.motionTimeControl.Value().maxDuration >= 1, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Motion Time Control (MaxDuration) Constraint Error", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + }); + } + + if (triggerOptions.triggerType == TransportTriggerTypeEnum::kMotion || + triggerOptions.triggerType == TransportTriggerTypeEnum::kCommand) + { + VerifyOrReturn(triggerOptions.maxPreRollLen.HasValue(), { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing Max Pre Roll Len field ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + } + + VerifyOrReturn(transportOptions.ingestMethod != IngestMethodsEnum::kUnknownEnumValue, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Invalid Ingest Method ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + // Todo: TLSEndpointID Validation - bool isFormatSupported = false; - IngestMethodsEnum ingestMethod = commandData.transportOptions.ingestMethod; + IngestMethodsEnum ingestMethod = commandData.transportOptions.ingestMethod; + + VerifyOrReturn(transportOptions.ingestMethod != IngestMethodsEnum::kUnknownEnumValue, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Invalid Ingest Method ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + ContainerOptionsStruct containerOptions = commandData.transportOptions.containerOptions; + VerifyOrReturn(containerOptions.containerType != ContainerFormatEnum::kUnknownEnumValue, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Invalid Container Format ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + + if (containerOptions.containerType == ContainerFormatEnum::kCmaf) + { + VerifyOrReturn(containerOptions.CMAFContainerOptions.HasValue(), { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing CMAF Container Options ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + + if (containerOptions.CMAFContainerOptions.Value().CENCKey.HasValue()) + { + VerifyOrReturn(containerOptions.CMAFContainerOptions.Value().CENCKey.Value().size() <= kMaxCENCKeyLength, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: CMAF Container Options CENC Key constraint Error", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + }); + } + + if (mFeatures.Has(Feature::kMetadata)) + { + VerifyOrReturn(containerOptions.CMAFContainerOptions.Value().metadataEnabled.HasValue(), { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing CMAF Container Options MetadataEnabled ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + } + + if (containerOptions.CMAFContainerOptions.Value().CENCKey.HasValue()) + { + VerifyOrReturn(containerOptions.CMAFContainerOptions.Value().CENCKeyID.HasValue(), { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing CMAF Container Options CENC Key ID ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + + VerifyOrReturn(containerOptions.CMAFContainerOptions.Value().CENCKeyID.Value().size() <= kMaxCENCKeyIDLength, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: CMAF Container Options CENC Key ID constraint Error", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + }); + } + } + + bool isFormatSupported = false; + for (auto & supportsFormat : mSupportedFormats) { if ((supportsFormat.ingestMethod == ingestMethod) && (supportsFormat.containerFormat == containerOptions.containerType)) @@ -297,7 +519,11 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c if (isFormatSupported == false) { auto status = to_underlying(StatusCodeEnum::kInvalidCombination); - ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid Format Combination"); + ChipLogError(Zcl, + "HandleAllocatePushTransport[ep=%d]: Invalid Ingest Method and Container Format Combination : (Ingest Method: " + "%02X and Container Format: %02X)", + AttributeAccessInterface::GetEndpointId().Value(), static_cast(ingestMethod), + static_cast(containerOptions.containerType)); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); return; } @@ -307,26 +533,30 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c if (isValidUrl == false) { auto status = to_underlying(StatusCodeEnum::kInvalidURL); - ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid Url"); + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Invalid Url", AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); return; } + /*Spec issue for invalid Trigger Type: https://github.com/CHIP-Specifications/connectedhomeip-spec/issues/11701*/ if (transportOptions.triggerOptions.triggerType == TransportTriggerTypeEnum::kUnknownEnumValue) { auto status = to_underlying(StatusCodeEnum::kInvalidTriggerType); - ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid Trigger type"); + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Invalid Trigger type", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); return; } - // Todo: Validate MotionZones list in the TransportTriggerOptionsStruct field + // Validate ZoneId + // Validate Bandwidth Requirement CHIP_ERROR err = mDelegate.ValidateBandwidthLimit(transportOptions.streamUsage, transportOptions.videoStreamID, transportOptions.audioStreamID); if (err != CHIP_NO_ERROR) { - ChipLogError(Zcl, "HandleAllocatePushTransport: Resource Exhausted"); + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Resource Exhausted", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ResourceExhausted); return; } @@ -337,7 +567,7 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c if (err != CHIP_NO_ERROR) { auto status = to_underlying(StatusCodeEnum::kInvalidStream); - ChipLogError(Zcl, "HandleAllocatePushTransport: Invalid Stream"); + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Invalid Stream", AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, status); return; } @@ -346,13 +576,21 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c if (connectionID == kMaxConnectionId) { - ChipLogError(Zcl, "HandleAllocatePushTransport: Max Connections Exhausted"); + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Max Connections Exhausted", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ResourceExhausted); return; } - std::shared_ptr transportOptionsPtr = - std::make_shared(transportOptions, mFeatures); + std::shared_ptr transportOptionsPtr{ new (std::nothrow) TransportOptionsStorage(transportOptions) }; + + if (transportOptionsPtr == nullptr) + { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Memory Allocation failed for transportOptions", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ResourceExhausted); + return; + } TransportConfigurationStorage outTransportConfiguration(connectionID, transportOptionsPtr); @@ -368,6 +606,12 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c UpsertStreamTransportConnection(transportConfiguration); response.transportConfiguration = outTransportConfiguration; + // ExpiryTime Handling + if (transportOptions.expiryTime.HasValue()) + { + ScheduleTransportDeallocate(connectionID, transportOptions.expiryTime.Value()); + } + ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); } else @@ -379,31 +623,34 @@ void PushAvStreamTransportServer::HandleAllocatePushTransport(HandlerContext & c void PushAvStreamTransportServer::HandleDeallocatePushTransport( HandlerContext & ctx, const Commands::DeallocatePushTransport::DecodableType & commandData) { - Status status = Status::Success; uint16_t connectionID = commandData.connectionID; TransportConfigurationStorageWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID); if (transportConfiguration == nullptr) { - ChipLogError(Zcl, "HandleDeallocatePushTransport: ConnectionID Not Found."); + ChipLogError(Zcl, "HandleDeallocatePushTransport[ep=%d]: ConnectionID Not Found.", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } if (transportConfiguration->fabricIndex != ctx.mCommandHandler.GetAccessingFabricIndex()) { - ChipLogError(Zcl, "HandleDeallocatePushTransport: ConnectionID Not Found."); + ChipLogError(Zcl, "HandleDeallocatePushTransport[ep=%d]: ConnectionID Not Found.", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } // Call the delegate - status = mDelegate.DeallocatePushTransport(connectionID); + auto delegateStatus = Protocols::InteractionModel::ClusterStatusCode(mDelegate.DeallocatePushTransport(connectionID)); - if (status == Status::Success) - // Remove connection form CurrentConnections + if (delegateStatus.IsSuccess() == true) + { + // Remove connection from CurrentConnections RemoveStreamTransportConnection(connectionID); + } - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, delegateStatus); } void PushAvStreamTransportServer::HandleModifyPushTransport(HandlerContext & ctx, @@ -413,54 +660,159 @@ void PushAvStreamTransportServer::HandleModifyPushTransport(HandlerContext & ctx uint16_t connectionID = commandData.connectionID; auto & transportOptions = commandData.transportOptions; + // Contraints check on incoming transport Options + + VerifyOrReturn(transportOptions.streamUsage != StreamUsageEnum::kUnknownEnumValue, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Invalid streamUsage ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + + VerifyOrReturn(transportOptions.videoStreamID.HasValue() || transportOptions.audioStreamID.HasValue(), { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing videoStreamID and audioStreamID", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + + VerifyOrReturn(transportOptions.url.size() <= 2000, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing videoStreamID and audioStreamID", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + }); + + auto & triggerOptions = transportOptions.triggerOptions; + + VerifyOrReturn(triggerOptions.triggerType != TransportTriggerTypeEnum::kUnknownEnumValue, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Invalid triggerType ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + + if (triggerOptions.triggerType == TransportTriggerTypeEnum::kMotion) + { + VerifyOrReturn(triggerOptions.motionZones.HasValue(), { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing motion zones ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + + if (triggerOptions.motionZones.Value().IsNull() == false) + { + auto & motionZonesList = triggerOptions.motionZones; + auto iter = motionZonesList.Value().Value().begin(); + + while (iter.Next()) + { + auto & transportZoneOption = iter.GetValue(); + + if (mFeatures.Has(Feature::kPerZoneSensitivity)) + { + VerifyOrReturn(transportZoneOption.sensitivity.HasValue(), { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing Zone Sensitivity ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + + VerifyOrReturn(transportZoneOption.sensitivity.Value() >= 1 && transportZoneOption.sensitivity.Value() <= 10, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Zone Sensitivity Constraint Error", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + }); + } + } + } + + if (mFeatures.Has(Feature::kPerZoneSensitivity) == false) + { + VerifyOrReturn(triggerOptions.motionSensitivity.HasValue(), { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing Motion Sensitivity ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + VerifyOrReturn( + triggerOptions.motionSensitivity.Value().Value() >= 1 && triggerOptions.motionSensitivity.Value().Value() <= 10, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Motion Sensitivity Constraint Error", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + }); + } + + VerifyOrReturn(triggerOptions.motionTimeControl.HasValue(), { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing Motion Time Control ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + + VerifyOrReturn(triggerOptions.motionTimeControl.Value().initialDuration >= 1, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Motion Time Control (InitialDuration) Constraint Error", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + }); + + VerifyOrReturn(triggerOptions.motionTimeControl.Value().maxDuration >= 1, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Motion Time Control (MaxDuration) Constraint Error", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + }); + } + + if (triggerOptions.triggerType == TransportTriggerTypeEnum::kMotion || + triggerOptions.triggerType == TransportTriggerTypeEnum::kCommand) + { + VerifyOrReturn(triggerOptions.maxPreRollLen.HasValue(), { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Missing Max Pre Roll Len field ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + } + + VerifyOrReturn(transportOptions.ingestMethod != IngestMethodsEnum::kUnknownEnumValue, { + ChipLogError(Zcl, "HandleAllocatePushTransport[ep=%d]: Invalid Ingest Method ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + TransportConfigurationStorageWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID); if (transportConfiguration == nullptr) { - ChipLogError(Zcl, "HandleModifyPushTransport: ConnectionID Not Found."); + ChipLogError(Zcl, "HandleModifyPushTransport[ep=%d]: ConnectionID Not Found.", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } if (transportConfiguration->fabricIndex != ctx.mCommandHandler.GetAccessingFabricIndex()) { - ChipLogError(Zcl, "HandleModifyPushTransport: ConnectionID Not Found."); + ChipLogError(Zcl, "HandleModifyPushTransport[ep=%d]: ConnectionID Not Found.", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } if (mDelegate.GetTransportStatus(connectionID) == PushAvStreamTransportStatusEnum::kBusy) { - ChipLogError(Zcl, "HandleModifyPushTransport: Connection is Busy"); + ChipLogError(Zcl, "HandleModifyPushTransport[ep=%d]: Connection is Busy", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Busy); return; } - TransportOptionsStruct transportOptionArgs; - transportOptionArgs.streamUsage = transportOptions.streamUsage; - transportOptionArgs.videoStreamID = transportOptions.videoStreamID; - transportOptionArgs.audioStreamID = transportOptions.audioStreamID; - transportOptionArgs.endpointID = transportOptions.endpointID; - transportOptionArgs.url = transportOptions.url; - transportOptionArgs.triggerOptions.triggerType = transportOptions.triggerOptions.triggerType; - // Todo: copy motion zones - transportOptionArgs.triggerOptions.motionSensitivity = transportOptions.triggerOptions.motionSensitivity; - transportOptionArgs.triggerOptions.motionTimeControl = transportOptions.triggerOptions.motionTimeControl; - transportOptionArgs.triggerOptions.maxPreRollLen = transportOptions.triggerOptions.maxPreRollLen; - transportOptionArgs.ingestMethod = transportOptions.ingestMethod; - transportOptionArgs.containerOptions = transportOptions.containerOptions; - transportOptionArgs.expiryTime = transportOptions.expiryTime; + std::shared_ptr transportOptionsPtr{ new (std::nothrow) TransportOptionsStorage(transportOptions) }; + if (transportOptionsPtr == nullptr) + { + ChipLogError(Zcl, "HandleModifyPushTransport[ep=%d]: Memory Allocation failed for transportOptions", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ResourceExhausted); + return; + } // Call the delegate - status = mDelegate.ModifyPushTransport(connectionID, transportOptionArgs); + status = mDelegate.ModifyPushTransport(connectionID, transportOptions); if (status == Status::Success) { - if (transportConfiguration->transportConfiguration.transportOptions.HasValue()) - { - transportConfiguration->transportConfiguration.transportOptions = - static_cast>(transportOptionArgs); - } + transportConfiguration->transportConfiguration.SetTransportOptionsPtr(transportOptionsPtr); } ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); @@ -480,7 +832,6 @@ void PushAvStreamTransportServer::HandleSetTransportStatus(HandlerContext & ctx, { if (transportConnection.fabricIndex == ctx.mCommandHandler.GetAccessingFabricIndex()) { - transportConnection.transportConfiguration.transportStatus = transportStatus; connectionIDList.push_back(transportConnection.transportConfiguration.connectionID); } } @@ -490,22 +841,35 @@ void PushAvStreamTransportServer::HandleSetTransportStatus(HandlerContext & ctx, TransportConfigurationStorageWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID.Value()); if (transportConfiguration == nullptr) { - ChipLogError(Zcl, "HandleSetTransportStatus: ConnectionID Not Found."); + ChipLogError(Zcl, "HandleSetTransportStatus[ep=%d]: ConnectionID Not Found.", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } if (transportConfiguration->fabricIndex != ctx.mCommandHandler.GetAccessingFabricIndex()) { - ChipLogError(Zcl, "HandleSetTransportStatus: ConnectionID Not Found."); + ChipLogError(Zcl, "HandleSetTransportStatus[ep=%d]: ConnectionID Not Found.", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } - - transportConfiguration->transportConfiguration.transportStatus = transportStatus; connectionIDList.push_back(connectionID.Value()); } // Call the delegate status = mDelegate.SetTransportStatus(connectionIDList, transportStatus); + if (status == Status::Success) + { + for (auto & connID : connectionIDList) + { + for (auto & transportConnection : mCurrentConnections) + { + if (transportConnection.transportConfiguration.connectionID == connID) + { + transportConnection.transportConfiguration.transportStatus = transportStatus; + } + } + } + } ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } @@ -515,27 +879,52 @@ void PushAvStreamTransportServer::HandleManuallyTriggerTransport( Status status = Status::Success; uint16_t connectionID = commandData.connectionID; auto & activationReason = commandData.activationReason; - auto & timeControl = commandData.timeControl; + + VerifyOrReturn(activationReason != TriggerActivationReasonEnum::kUnknownEnumValue, { + ChipLogError(Zcl, "HandleManuallyTriggerTransport[ep=%d]: Invalid Activation Reason ", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); + }); + + Optional timeControl = commandData.timeControl; + + if (timeControl.HasValue()) + { + VerifyOrReturn(timeControl.Value().initialDuration >= 1, { + ChipLogError(Zcl, "HandleManuallyTriggerTransport[ep=%d]: Motion Time Control (InitialDuration) Constraint Error", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + }); + + VerifyOrReturn(timeControl.Value().maxDuration >= 1, { + ChipLogError(Zcl, "HandleManuallyTriggerTransport[ep=%d]: Motion Time Control (MaxDuration) Constraint Error", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + }); + } TransportConfigurationStorageWithFabricIndex * transportConfiguration = FindStreamTransportConnection(connectionID); if (transportConfiguration == nullptr) { - ChipLogError(Zcl, "HandleManuallyTriggerTransport: ConnectionID Not Found."); + ChipLogError(Zcl, "HandleManuallyTriggerTransport[ep=%d]: ConnectionID Not Found.", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } if (transportConfiguration->fabricIndex != ctx.mCommandHandler.GetAccessingFabricIndex()) { - ChipLogError(Zcl, "HandleManuallyTriggerTransport: ConnectionID Not Found."); + ChipLogError(Zcl, "HandleManuallyTriggerTransport[ep=%d]: ConnectionID Not Found.", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } if (mDelegate.GetTransportStatus(connectionID) == PushAvStreamTransportStatusEnum::kBusy) { - ChipLogError(Zcl, "HandleManuallyTriggerTransport: Connection is Busy"); + ChipLogError(Zcl, "HandleManuallyTriggerTransport[ep=%d]: Connection is Busy", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::Busy); return; } @@ -543,7 +932,8 @@ void PushAvStreamTransportServer::HandleManuallyTriggerTransport( if (transportConfiguration->transportConfiguration.transportStatus == TransportStatusEnum::kInactive) { auto clusterStatus = to_underlying(StatusCodeEnum::kInvalidTransportStatus); - ChipLogError(Zcl, "HandleManuallyTriggerTransport: Invalid Transport status"); + ChipLogError(Zcl, "HandleManuallyTriggerTransport[ep=%d]: Invalid Transport status", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, clusterStatus); return; } @@ -554,23 +944,37 @@ void PushAvStreamTransportServer::HandleManuallyTriggerTransport( { auto clusterStatus = to_underlying(StatusCodeEnum::kInvalidTriggerType); - ChipLogError(Zcl, "HandleManuallyTriggerTransport: Invalid Trigger type"); + ChipLogError(Zcl, "HandleManuallyTriggerTransport[ep=%d]: Invalid Trigger type", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddClusterSpecificFailure(ctx.mRequestPath, clusterStatus); return; } if (transportConfiguration->transportConfiguration.transportOptions.Value().triggerOptions.triggerType == TransportTriggerTypeEnum::kCommand && - !timeControl.HasValue()) + timeControl.HasValue() == false) { - ChipLogError(Zcl, "HandleManuallyTriggerTransport: Time control field not present"); - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError); + ChipLogError(Zcl, "HandleManuallyTriggerTransport[ep=%d]: Time control field not present", + AttributeAccessInterface::GetEndpointId().Value()); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::DynamicConstraintError); return; } } + // When trigger type is motion in the allocated transport but triggering it manually + if (timeControl.HasValue() == false) + { + timeControl = transportConfiguration->transportConfiguration.transportOptions.Value().triggerOptions.motionTimeControl; + } + // Call the delegate status = mDelegate.ManuallyTriggerTransport(connectionID, activationReason, timeControl); + + if (status == Status::Success) + { + mDelegate.GeneratePushTransportBeginEvent(connectionID, TransportTriggerTypeEnum::kCommand, MakeOptional(activationReason)); + } + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); } @@ -581,21 +985,14 @@ void PushAvStreamTransportServer::HandleFindTransport(HandlerContext & ctx, Optional> connectionID = commandData.connectionID; - size_t count = 0; - size_t bufferSize = mCurrentConnections.size(); - - Platform::ScopedMemoryBuffer transportConfigurations; - if (!transportConfigurations.Calloc(bufferSize)) - { - ChipLogError(Zcl, "Memory allocation failed for forecast buffer"); - return; - } + std::vector transportConfigurations; if ((connectionID.HasValue() == false) || connectionID.Value().IsNull()) { if (mCurrentConnections.size() == 0) { - ChipLogError(Zcl, "HandleFindTransport: ConnectionID not found"); + ChipLogError(Zcl, "HandleFindTransport[ep=%d]: ConnectionID not found", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } @@ -604,7 +1001,7 @@ void PushAvStreamTransportServer::HandleFindTransport(HandlerContext & ctx, { if (connection.fabricIndex == ctx.mCommandHandler.GetAccessingFabricIndex()) { - transportConfigurations[count++] = connection.transportConfiguration; + transportConfigurations.push_back(connection.transportConfiguration); } } } @@ -614,25 +1011,74 @@ void PushAvStreamTransportServer::HandleFindTransport(HandlerContext & ctx, FindStreamTransportConnection(connectionID.Value().Value()); if (transportConfiguration == nullptr) { - ChipLogError(Zcl, "HandleFindTransport: ConnectionID not found"); + ChipLogError(Zcl, "HandleFindTransport[ep=%d]: ConnectionID not found", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } if (transportConfiguration->fabricIndex != ctx.mCommandHandler.GetAccessingFabricIndex()) { - ChipLogError(Zcl, "HandleFindTransport: ConnectionID Not Found."); + ChipLogError(Zcl, "HandleFindTransport[ep=%d]: ConnectionID Not Found.", + AttributeAccessInterface::GetEndpointId().Value()); ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); return; } - transportConfigurations[count++] = transportConfiguration->transportConfiguration; + transportConfigurations.push_back(transportConfiguration->transportConfiguration); + } + + if (transportConfigurations.size() == 0) + { + ctx.mCommandHandler.AddResponse(ctx.mRequestPath, Status::NotFound); } - response.transportConfigurations = DataModel::List( - Span(transportConfigurations.Get(), count)); + response.transportConfigurations = + DataModel::List(transportConfigurations.data(), transportConfigurations.size()); ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); } +Status PushAvStreamTransportDelegate::GeneratePushTransportBeginEvent(const uint16_t connectionID, + const TransportTriggerTypeEnum triggerType, + const Optional activationReason) +{ + Events::PushTransportBegin::Type event; + EventNumber eventNumber; + + event.connectionID = connectionID; + event.triggerType = triggerType; + event.activationReason = activationReason; + + CHIP_ERROR err = LogEvent(event, mEndpointId, eventNumber); + if (CHIP_NO_ERROR != err) + { + ChipLogError(AppServer, "Endpoint %d - Unable to generate PushAVTransportBegin event: %" CHIP_ERROR_FORMAT, mEndpointId, + err.Format()); + return Status::Failure; + } + return Status::Success; +} + +Status PushAvStreamTransportDelegate::GeneratePushTransportEndEvent(const uint16_t connectionID, + const TransportTriggerTypeEnum triggerType, + const Optional activationReason) +{ + Events::PushTransportEnd::Type event; + EventNumber eventNumber; + + event.connectionID = connectionID; + event.triggerType = triggerType; + event.activationReason = activationReason; + + CHIP_ERROR err = LogEvent(event, mEndpointId, eventNumber); + if (CHIP_NO_ERROR != err) + { + ChipLogError(AppServer, "Endpoint %d - Unable to generate PushAVTransportEnd event: %" CHIP_ERROR_FORMAT, mEndpointId, + err.Format()); + return Status::Failure; + } + return Status::Success; +} + } // namespace PushAvStreamTransport } // namespace Clusters } // namespace app diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h index c66e620cfb22fe..5e422139802564 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h @@ -29,7 +29,9 @@ namespace app { namespace Clusters { namespace PushAvStreamTransport { -static constexpr size_t kMaxUrlLength = 2000u; +static constexpr size_t kMaxUrlLength = 2000u; +static constexpr size_t kMaxCENCKeyLength = 16u; +static constexpr size_t kMaxCENCKeyIDLength = 16u; using SupportedFormatStruct = Structs::SupportedFormatStruct::Type; using CMAFContainerOptionsStruct = Structs::CMAFContainerOptionsStruct::Type; @@ -51,8 +53,36 @@ struct TransportTriggerOptionsStorage : public TransportTriggerOptionsStruct { TransportTriggerOptionsStorage() {}; - TransportTriggerOptionsStorage(Structs::TransportTriggerOptionsStruct::DecodableType triggerOptions, - const BitFlags features) + TransportTriggerOptionsStorage(const TransportTriggerOptionsStorage & aTransportTriggerOptionsStorage) + { + *this = aTransportTriggerOptionsStorage; + } + + TransportTriggerOptionsStorage & operator=(const TransportTriggerOptionsStorage & aTransportTriggerOptionsStorage) + { + triggerType = aTransportTriggerOptionsStorage.triggerType; + + mTransportZoneOptions = aTransportTriggerOptionsStorage.mTransportZoneOptions; + + // Rebind motionZones to point to the copied vector if it was set + if (aTransportTriggerOptionsStorage.motionZones.HasValue() && !aTransportTriggerOptionsStorage.motionZones.Value().IsNull()) + { + motionZones.SetValue(DataModel::Nullable>( + Span(mTransportZoneOptions.data(), mTransportZoneOptions.size()))); + } + else + { + motionZones.Missing(); + } + + motionSensitivity = aTransportTriggerOptionsStorage.motionSensitivity; + motionTimeControl = aTransportTriggerOptionsStorage.motionTimeControl; + maxPreRollLen = aTransportTriggerOptionsStorage.maxPreRollLen; + + return *this; + } + + TransportTriggerOptionsStorage(Structs::TransportTriggerOptionsStruct::DecodableType triggerOptions) { triggerType = triggerOptions.triggerType; @@ -91,8 +121,43 @@ struct CMAFContainerOptionsStorage : public CMAFContainerOptionsStruct { CMAFContainerOptionsStorage() {}; - CMAFContainerOptionsStorage(Optional CMAFContainerOptions, - const BitFlags features) + CMAFContainerOptionsStorage(const CMAFContainerOptionsStorage & aCMAFContainerOptionsStorage) + { + *this = aCMAFContainerOptionsStorage; + } + + CMAFContainerOptionsStorage & operator=(const CMAFContainerOptionsStorage & aCMAFContainerOptionsStorage) + { + chunkDuration = aCMAFContainerOptionsStorage.chunkDuration; + + std::memcpy(mCENCKeyBuffer, aCMAFContainerOptionsStorage.mCENCKeyBuffer, sizeof(mCENCKeyBuffer)); + + std::memcpy(mCENCKeyIDBuffer, aCMAFContainerOptionsStorage.mCENCKeyIDBuffer, sizeof(mCENCKeyIDBuffer)); + + if (aCMAFContainerOptionsStorage.CENCKey.HasValue()) + { + CENCKey.SetValue(ByteSpan(mCENCKeyBuffer, aCMAFContainerOptionsStorage.CENCKey.Value().size())); + } + else + { + CENCKey.Missing(); + } + + metadataEnabled = aCMAFContainerOptionsStorage.metadataEnabled; + + if (aCMAFContainerOptionsStorage.CENCKeyID.HasValue()) + { + CENCKeyID.SetValue(ByteSpan(mCENCKeyIDBuffer, aCMAFContainerOptionsStorage.CENCKeyID.Value().size())); + } + else + { + CENCKeyID.Missing(); + } + + return *this; + } + + CMAFContainerOptionsStorage(Optional CMAFContainerOptions) { if (CMAFContainerOptions.HasValue() == true) { @@ -104,41 +169,55 @@ struct CMAFContainerOptionsStorage : public CMAFContainerOptionsStruct CopySpanToMutableSpan(CMAFContainerOptions.Value().CENCKey.Value(), CENCKeyBuffer); CENCKey.SetValue(CENCKeyBuffer); } - - if (features.Has(Feature::kMetadata) && CMAFContainerOptions.HasValue()) - { - metadataEnabled = CMAFContainerOptions.Value().metadataEnabled; - } else { - metadataEnabled.Missing(); + CENCKey.Missing(); } + metadataEnabled = CMAFContainerOptions.Value().metadataEnabled; + if (CMAFContainerOptions.Value().CENCKey.HasValue()) { MutableByteSpan CENCKeyIDBuffer(mCENCKeyIDBuffer); CopySpanToMutableSpan(CMAFContainerOptions.Value().CENCKeyID.Value(), CENCKeyIDBuffer); CENCKeyID.SetValue(CENCKeyIDBuffer); } + else + { + CENCKeyID.Missing(); + } } } private: - uint8_t mCENCKeyBuffer[16]; - uint8_t mCENCKeyIDBuffer[16]; + uint8_t mCENCKeyBuffer[kMaxCENCKeyLength]; + uint8_t mCENCKeyIDBuffer[kMaxCENCKeyIDLength]; }; struct ContainerOptionsStorage : public ContainerOptionsStruct { ContainerOptionsStorage() {}; - ContainerOptionsStorage(Structs::ContainerOptionsStruct::DecodableType containerOptions, const BitFlags features) + ContainerOptionsStorage(const ContainerOptionsStorage & aContainerOptionsStorage) { *this = aContainerOptionsStorage; } + + ContainerOptionsStorage & operator=(const ContainerOptionsStorage & aContainerOptionsStorage) + { + containerType = aContainerOptionsStorage.containerType; + + mCMAFContainerStorage = aContainerOptionsStorage.mCMAFContainerStorage; + + CMAFContainerOptions.SetValue(mCMAFContainerStorage); + + return *this; + } + + ContainerOptionsStorage(Structs::ContainerOptionsStruct::DecodableType containerOptions) { containerType = containerOptions.containerType; if (containerType == ContainerFormatEnum::kCmaf) { - mCMAFContainerStorage = CMAFContainerOptionsStorage(containerOptions.CMAFContainerOptions, features); + mCMAFContainerStorage = CMAFContainerOptionsStorage(containerOptions.CMAFContainerOptions); CMAFContainerOptions.SetValue(mCMAFContainerStorage); } else @@ -155,7 +234,34 @@ struct TransportOptionsStorage : public TransportOptionsStruct { TransportOptionsStorage() {}; - TransportOptionsStorage(Structs::TransportOptionsStruct::DecodableType transportOptions, const BitFlags features) + TransportOptionsStorage(const TransportOptionsStorage & aTransportOptionsStorage) { *this = aTransportOptionsStorage; } + + TransportOptionsStorage & operator=(const TransportOptionsStorage & aTransportOptionsStorage) + { + streamUsage = aTransportOptionsStorage.streamUsage; + videoStreamID = aTransportOptionsStorage.videoStreamID; + audioStreamID = aTransportOptionsStorage.audioStreamID; + endpointID = aTransportOptionsStorage.endpointID; + + // Deep copy the URL buffer + std::memcpy(mUrlBuffer, aTransportOptionsStorage.mUrlBuffer, kMaxUrlLength); + url = MutableCharSpan(mUrlBuffer, aTransportOptionsStorage.url.size()); + + // Copy internal storage objects + mTriggerOptionsStorage = aTransportOptionsStorage.mTriggerOptionsStorage; + triggerOptions = mTriggerOptionsStorage; + + ingestMethod = aTransportOptionsStorage.ingestMethod; + + mContainerOptionsStorage = aTransportOptionsStorage.mContainerOptionsStorage; + containerOptions = mContainerOptionsStorage; + + expiryTime = aTransportOptionsStorage.expiryTime; + + return *this; + } + + TransportOptionsStorage(Structs::TransportOptionsStruct::DecodableType transportOptions) { streamUsage = transportOptions.streamUsage; videoStreamID = transportOptions.videoStreamID; @@ -166,12 +272,12 @@ struct TransportOptionsStorage : public TransportOptionsStruct CopyCharSpanToMutableCharSpanWithTruncation(transportOptions.url, urlBuffer); url = urlBuffer; - mTriggerOptionsStorage = TransportTriggerOptionsStorage(transportOptions.triggerOptions, features); + mTriggerOptionsStorage = TransportTriggerOptionsStorage(transportOptions.triggerOptions); triggerOptions = mTriggerOptionsStorage; ingestMethod = transportOptions.ingestMethod; - mContainerOptionsStorage = ContainerOptionsStorage(transportOptions.containerOptions, features); + mContainerOptionsStorage = ContainerOptionsStorage(transportOptions.containerOptions); containerOptions = mContainerOptionsStorage; expiryTime = transportOptions.expiryTime; @@ -187,6 +293,30 @@ struct TransportConfigurationStorage : public TransportConfigurationStruct { TransportConfigurationStorage() {} + TransportConfigurationStorage(const TransportConfigurationStorage & aTransportConfigurationStorage) + { + *this = aTransportConfigurationStorage; + } + + TransportConfigurationStorage & operator=(const TransportConfigurationStorage & aTransportConfigurationStorage) + { + connectionID = aTransportConfigurationStorage.connectionID; + transportStatus = aTransportConfigurationStorage.transportStatus; + + mTransportOptionsPtr = aTransportConfigurationStorage.mTransportOptionsPtr; + + if (mTransportOptionsPtr) + { + transportOptions.SetValue(*mTransportOptionsPtr); + } + else + { + transportOptions.Missing(); + } + + return *this; + } + TransportConfigurationStorage(const uint16_t aConnectionID, std::shared_ptr aTransportOptionsPtr) { connectionID = aConnectionID; @@ -194,9 +324,28 @@ struct TransportConfigurationStorage : public TransportConfigurationStruct /*Store the pointer to keep buffer alive*/ mTransportOptionsPtr = aTransportOptionsPtr; /*Convert Storage type to base type*/ - transportOptions.SetValue(*aTransportOptionsPtr); + if (mTransportOptionsPtr) + { + transportOptions.SetValue(*mTransportOptionsPtr); + } + else + { + transportOptions.Missing(); + } } std::shared_ptr GetTransportOptionsPtr() const { return mTransportOptionsPtr; } + void SetTransportOptionsPtr(std::shared_ptr aTransportOptionsPtr) + { + mTransportOptionsPtr = aTransportOptionsPtr; + if (mTransportOptionsPtr) + { + transportOptions.SetValue(*mTransportOptionsPtr); + } + else + { + transportOptions.Missing(); + } + } private: std::shared_ptr mTransportOptionsPtr; @@ -219,6 +368,8 @@ class PushAvStreamTransportDelegate virtual ~PushAvStreamTransportDelegate() = default; + void SetEndpointId(EndpointId aEndpoint) { mEndpointId = aEndpoint; } + /** * @brief Handle Command Delegate for stream transport allocation with the provided transport configuration option. * @@ -227,8 +378,14 @@ class PushAvStreamTransportDelegate * @param connectionID[in] Indicates the connectionID to allocate. * * @return Success if the allocation is successful and a PushTransportConnectionID was produced; otherwise, the command SHALL - * be rejected with an appropriate error. The delegate is expected to process the transport options, allocate the transport - * and map it to the connectionID. On Success TransportConfigurationStruct is sent as response by the server. + * be rejected with Failure. + * + * The buffers storing URL, Trigger Options, Motion Zones, Container Options is owned by the PushAVStreamTransport Server. + * The buffers are allocated on success of AllocatePushTransport and deallocated on success of DeallocatePushTransport + * command. The delegate is expected to process the transport following transport options: URL : Validate the URL + * StreamUsage,VideoStreamID,AudioStreamID for selection of Stream. + * Allocate the transport and map it to the connectionID. + * On Success TransportConfigurationStruct is sent as response by the server. */ virtual Protocols::InteractionModel::Status AllocatePushTransport(const TransportOptionsStruct & transportOptions, const uint16_t connectionID) = 0; @@ -238,8 +395,8 @@ class PushAvStreamTransportDelegate * * @param connectionID[in] Indicates the connectionID to deallocate. * - * @return Success if the transport deallocation is successful; otherwise, the command SHALL be rejected with an appropriate - * error. + * @return Success if the transport deallocation is successful; otherwise, the delegate is expected to return status code BUSY + * if the transport is currently uploading. * */ virtual Protocols::InteractionModel::Status DeallocatePushTransport(const uint16_t connectionID) = 0; @@ -248,13 +405,16 @@ class PushAvStreamTransportDelegate * * @param connectionID [in] Indicates the connectionID of the stream transport to modify. * - * @param transportOptions [out] represents the Trigger Options to modify. + * @param transportOptions [out] represents the Transport Options to modify. + * + * The buffers storing URL, Trigger Options, Motion Zones, Container Options is owned by the PushAVStreamTransport Server. + * The allocated buffers are cleared and reassigned on success of ModifyPushTransport and deallocated on success of + * DeallocatePushTransport. * - * @return Success if the stream transport modification is successful; otherwise, the command SHALL be rejected with an - * appropriate error. + * @return Success if the stream transport modification is successful; otherwise, the command SHALL be rejected with Failure. */ - virtual Protocols::InteractionModel::Status ModifyPushTransport(const uint16_t connectionID, - const TransportOptionsStruct & transportOptions) = 0; + virtual Protocols::InteractionModel::Status + ModifyPushTransport(const uint16_t connectionID, const Structs::TransportOptionsStruct::DecodableType transportOptions) = 0; /** * @brief Handle Command Delegate for Stream transport modification. @@ -262,8 +422,7 @@ class PushAvStreamTransportDelegate * @param connectionIDList [in] represent the list of connectionIDs for which new transport status to apply. * @param transportStatus [in] represents the updated status of the connection(s). * - * @return Success if the stream transport status is successfully set; otherwise, the command SHALL be rejected with an - * appropriate error. + * @return Success if the stream transport status is successfully set; otherwise, the command SHALL be rejected with Failure. */ virtual Protocols::InteractionModel::Status SetTransportStatus(const std::vector connectionIDList, TransportStatusEnum transportStatus) = 0; @@ -276,9 +435,13 @@ class PushAvStreamTransportDelegate * * @param timeControl [in] Configuration to control the life cycle of a triggered transport. * - * @return Success if the stream transport trigger is successful; otherwise, the command SHALL be rejected with an -appropriate - * error. + * The delegate is expected to begin transmission using the timeControl values. + * + * Emitting of PushTransportBegin event is handled by the server when delegate returns success. + * + * The delegate should emit PushTransportEnd Event using GeneratePushTransportEndEvent() API when timeControl values when +transmission ends. + * @return Success if the stream transport trigger is successful; otherwise, the command SHALL be rejected with Failure. */ virtual Protocols::InteractionModel::Status ManuallyTriggerTransport(const uint16_t connectionID, TriggerActivationReasonEnum activationReason, @@ -333,7 +496,7 @@ appropriate * * @param[in] connectionID Indicates the connectionID of the stream transport to check status * - * @return busy if transport is active else idle + * @return busy if transport is uploading else idle */ virtual PushAvStreamTransportStatusEnum GetTransportStatus(const uint16_t connectionID) = 0; @@ -363,6 +526,17 @@ appropriate * the Cluster have been loaded from Storage. */ virtual CHIP_ERROR PersistentAttributesLoadedCallback() = 0; + + // Send Push AV Stream Transport events + Protocols::InteractionModel::Status + GeneratePushTransportBeginEvent(const uint16_t connectionID, const TransportTriggerTypeEnum triggerType, + const Optional activationReason); + Protocols::InteractionModel::Status GeneratePushTransportEndEvent(const uint16_t connectionID, + const TransportTriggerTypeEnum triggerType, + const Optional activationReason); + +protected: + EndpointId mEndpointId = 0; }; class PushAvStreamTransportServer : public AttributeAccessInterface, public CommandHandlerInterface @@ -397,7 +571,7 @@ class PushAvStreamTransportServer : public AttributeAccessInterface, public Comm bool HasFeature(Feature feature) const; - // Attribute Getters + static void PushAVStreamTransportDeallocateCallback(chip::System::Layer *, void * callbackContext); private: enum class UpsertResultEnum : uint8_t @@ -406,6 +580,12 @@ class PushAvStreamTransportServer : public AttributeAccessInterface, public Comm kUpdated = 0x01, }; + struct PushAVStreamTransportDeallocateCallbackContext + { + PushAvStreamTransportServer * instance; + uint16_t connectionID; + }; + PushAvStreamTransportDelegate & mDelegate; const BitFlags mFeatures; @@ -434,12 +614,22 @@ class PushAvStreamTransportServer : public AttributeAccessInterface, public Comm // Helper functions uint16_t GenerateConnectionID(); + TransportConfigurationStorageWithFabricIndex * FindStreamTransportConnection(const uint16_t connectionID); + // Add/Remove Management functions for transport UpsertResultEnum UpsertStreamTransportConnection(const TransportConfigurationStorageWithFabricIndex & transportConfiguration); void RemoveStreamTransportConnection(const uint16_t connectionID); + /** + * @brief Schedule deallocate with a given timeout + * + * @param endpointId endpoint where DoorLockServer is running + * @param timeoutSec timeout in seconds + */ + void ScheduleTransportDeallocate(chip::EndpointId endpointId, uint32_t timeoutSec); + /** * @brief Inherited from CommandHandlerInterface */ From a459df797198ac3f830683a0346a5dc173feeef0 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Wed, 28 May 2025 09:47:33 +0000 Subject: [PATCH 21/22] Restyled by clang-format --- .../push-av-stream-transport-server.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h index 5e422139802564..98d2e7f89ea341 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h @@ -51,7 +51,7 @@ enum class PushAvStreamTransportStatusEnum : uint8_t struct TransportTriggerOptionsStorage : public TransportTriggerOptionsStruct { - TransportTriggerOptionsStorage() {}; + TransportTriggerOptionsStorage(){}; TransportTriggerOptionsStorage(const TransportTriggerOptionsStorage & aTransportTriggerOptionsStorage) { @@ -119,7 +119,7 @@ struct TransportTriggerOptionsStorage : public TransportTriggerOptionsStruct struct CMAFContainerOptionsStorage : public CMAFContainerOptionsStruct { - CMAFContainerOptionsStorage() {}; + CMAFContainerOptionsStorage(){}; CMAFContainerOptionsStorage(const CMAFContainerOptionsStorage & aCMAFContainerOptionsStorage) { @@ -196,7 +196,7 @@ struct CMAFContainerOptionsStorage : public CMAFContainerOptionsStruct struct ContainerOptionsStorage : public ContainerOptionsStruct { - ContainerOptionsStorage() {}; + ContainerOptionsStorage(){}; ContainerOptionsStorage(const ContainerOptionsStorage & aContainerOptionsStorage) { *this = aContainerOptionsStorage; } @@ -232,7 +232,7 @@ struct ContainerOptionsStorage : public ContainerOptionsStruct struct TransportOptionsStorage : public TransportOptionsStruct { - TransportOptionsStorage() {}; + TransportOptionsStorage(){}; TransportOptionsStorage(const TransportOptionsStorage & aTransportOptionsStorage) { *this = aTransportOptionsStorage; } From 890e11fdee1c23287ade98c4497ba275593b3b06 Mon Sep 17 00:00:00 2001 From: Sayon Deep Date: Wed, 28 May 2025 15:52:11 +0530 Subject: [PATCH 22/22] update all-cluster-app.matter --- .../all-clusters-common/all-clusters-app.matter | 14 -------------- .../push-av-stream-transport-server.cpp | 2 +- .../push-av-stream-transport-server.h | 1 + 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index 08ebe8d7bf26b2..9f2a2ca9a68c8e 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -7425,13 +7425,6 @@ provisional cluster PushAvStreamTransport = 1365 { kInvalidTransportStatus = 8; } - shared enum StreamUsageEnum : enum8 { - kInternal = 0; - kRecording = 1; - kAnalysis = 2; - kLiveView = 3; - } - enum TransportStatusEnum : enum8 { kActive = 0; kInactive = 1; @@ -7601,13 +7594,6 @@ provisional cluster PushAvStreamTransport = 1365 { kInvalidTransportStatus = 8; } - shared enum StreamUsageEnum : enum8 { - kInternal = 0; - kRecording = 1; - kAnalysis = 2; - kLiveView = 3; - } - enum TransportStatusEnum : enum8 { kActive = 0; kInactive = 1; diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp index 111cc6d9f6d469..ce5bac4c3e8014 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.cpp @@ -1028,7 +1028,7 @@ void PushAvStreamTransportServer::HandleFindTransport(HandlerContext & ctx, if (transportConfigurations.size() == 0) { - ctx.mCommandHandler.AddResponse(ctx.mRequestPath, Status::NotFound); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::NotFound); } response.transportConfigurations = diff --git a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h index 98d2e7f89ea341..6eb4c3074e4a5a 100644 --- a/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h +++ b/src/app/clusters/push-av-stream-transport-server/push-av-stream-transport-server.h @@ -41,6 +41,7 @@ using TransportTriggerOptionsStruct = Structs::TransportTriggerOptions using TransportMotionTriggerTimeControlStruct = Structs::TransportMotionTriggerTimeControlStruct::Type; using TransportOptionsStruct = Structs::TransportOptionsStruct::Type; using TransportConfigurationStruct = Structs::TransportConfigurationStruct::Type; +using StreamUsageEnum = chip::app::Clusters::Globals::StreamUsageEnum; enum class PushAvStreamTransportStatusEnum : uint8_t {