| /* |
| * |
| * Copyright (c) 2021 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. |
| */ |
| |
| /** |
| * @brief classes relating to Content App platform of the Video Player. |
| */ |
| |
| #pragma once |
| |
| #include <app/OperationalSessionSetup.h> |
| #include <app/app-platform/ContentApp.h> |
| #include <app/util/attribute-storage.h> |
| #include <controller/CHIPCluster.h> |
| #include <platform/CHIPDeviceLayer.h> |
| #include <protocols/interaction_model/StatusCode.h> |
| #include <protocols/user_directed_commissioning/UserDirectedCommissioning.h> |
| |
| using chip::app::Clusters::ApplicationBasic::CatalogVendorApp; |
| using chip::Controller::CommandResponseFailureCallback; |
| using chip::Controller::CommandResponseSuccessCallback; |
| |
| using BindingListType = chip::app::Clusters::Binding::Attributes::Binding::TypeInfo::Type; |
| |
| namespace chip { |
| namespace AppPlatform { |
| |
| // The AppPlatform overrides emberAfExternalAttributeReadCallback to handle external attribute reads for ContentApps. |
| // This callback can be used to handle external attribute reads for attributes belonging to static endpoints. |
| Protocols::InteractionModel::Status AppPlatformExternalAttributeReadCallback(EndpointId endpoint, ClusterId clusterId, |
| const EmberAfAttributeMetadata * attributeMetadata, |
| uint8_t * buffer, uint16_t maxReadLength); |
| |
| // The AppPlatform overrides emberAfExternalAttributeWriteCallback to handle external attribute writes for ContentApps. |
| // This callback can be used to handle external attribute writes for attributes belonging to static endpoints. |
| Protocols::InteractionModel::Status AppPlatformExternalAttributeWriteCallback(EndpointId endpoint, ClusterId clusterId, |
| const EmberAfAttributeMetadata * attributeMetadata, |
| uint8_t * buffer); |
| |
| inline constexpr EndpointId kTargetBindingClusterEndpointId = 0; |
| inline constexpr EndpointId kLocalVideoPlayerEndpointId = 1; |
| inline constexpr EndpointId kLocalSpeakerEndpointId = 2; |
| |
| class DLL_EXPORT ContentAppFactory |
| { |
| public: |
| virtual ~ContentAppFactory() = default; |
| |
| // Lookup CatalogVendor App for this client (vendor id/product id client) |
| // and then write it to destinationApp |
| // return error if not found |
| virtual CHIP_ERROR LookupCatalogVendorApp(uint16_t vendorId, uint16_t productId, CatalogVendorApp * destinationApp) = 0; |
| |
| // Lookup ContentApp for this catalog id / app id and load it |
| virtual ContentApp * LoadContentApp(const CatalogVendorApp & vendorApp) = 0; |
| |
| // Gets the catalog vendor ID used by this platform |
| virtual uint16_t GetPlatformCatalogVendorId() = 0; |
| |
| // Converts application (any catalog) into the platform's catalog Vendor |
| // and then writes it to destinationApp |
| virtual CHIP_ERROR ConvertToPlatformCatalogVendorApp(const CatalogVendorApp & sourceApp, CatalogVendorApp * destinationApp) = 0; |
| |
| // Get the privilege this vendorId should have on endpoints 1, 2, and content app endpoints |
| // In the case of casting video clients, this should usually be Access::Privilege::kOperate |
| // and for voice agents, this may be Access::Privilege::kAdminister |
| // When a vendor has admin privileges, it will get access to all clusters on ep1 |
| virtual Access::Privilege GetVendorPrivilege(uint16_t vendorId) = 0; |
| |
| // Get the cluster list this vendorId/productId should have on static endpoints such as ep1 for casting video clients. |
| // When a vendor has admin privileges, it will get access to all clusters on ep1 |
| virtual std::list<ClusterId> GetAllowedClusterListForStaticEndpoint(EndpointId endpointId, uint16_t vendorId, |
| uint16_t productId) = 0; |
| }; |
| |
| class DLL_EXPORT ContentAppPlatform |
| { |
| public: |
| static ContentAppPlatform & GetInstance() |
| { |
| static ContentAppPlatform instance; |
| return instance; |
| } |
| |
| void SetupAppPlatform(); |
| |
| inline void SetContentAppFactory(ContentAppFactory * factory) { mContentAppFactory = factory; }; |
| |
| // add apps to the platform. |
| // This will assign the app to an endpoint (if it is not already added) and make it accessible via Matter |
| // returns the global endpoint for this app, or kNoCurrentEndpointId if an error occurred. |
| // dataVersionStorage.size() needs to be at least as big as the number of |
| // server clusters in the EmberAfEndpointType passed in. |
| EndpointId AddContentApp(ContentApp * app, EmberAfEndpointType * ep, const Span<DataVersion> & dataVersionStorage, |
| const Span<const EmberAfDeviceType> & deviceTypeList); |
| |
| // add apps to the platform. |
| // This will assign the app to the desiredEndpointId (if it is not already used) |
| // and make it accessible via Matter, return the global endpoint for this app(if app is already added) |
| // , or kNoCurrentEndpointId if an error occurred. desiredEndpointId cannot be less that Fixed endpoint count |
| // dataVersionStorage.size() needs to be at least as big as the number of |
| // server clusters in the EmberAfEndpointType passed in. |
| EndpointId AddContentApp(ContentApp * app, EmberAfEndpointType * ep, const Span<DataVersion> & dataVersionStorage, |
| const Span<const EmberAfDeviceType> & deviceTypeList, EndpointId desiredEndpointId); |
| |
| // remove app from the platform. |
| // returns the endpoint id where the app was, or 0 if app was not loaded |
| EndpointId RemoveContentApp(ContentApp * app); |
| |
| // load and unload by vendor id |
| // void UnloadContentAppByVendorId(uint16_t vendorId, uint16_t productId); |
| |
| // Lookup ContentApp for this client (vendor id/product id client) and load it |
| ContentApp * LoadContentAppByClient(uint16_t vendorId, uint16_t productId); |
| |
| // Lookup ContentApp described by this application and load it |
| ContentApp * LoadContentApp(const CatalogVendorApp & application); |
| |
| // helpful method to get a Content App by endpoint in order to perform attribute or command ops |
| ContentApp * GetContentApp(EndpointId id); |
| |
| // helpful method to get a Content App by application, does not load if not found |
| ContentApp * GetContentApp(const CatalogVendorApp & application); |
| |
| // sets the current app for this platform |
| void SetCurrentApp(ContentApp * app); |
| |
| // returns true if there is a current app for this platform |
| inline bool HasCurrentApp() { return mCurrentAppEndpointId != kNoCurrentEndpointId; } |
| |
| // returns true if the vendor/app arguments are the current app |
| bool IsCurrentApp(ContentApp * app); |
| |
| // returns the current app endpoint |
| inline EndpointId GetCurrentAppEndpointId() { return mCurrentAppEndpointId; }; |
| |
| // unset this as current app, if it is current app |
| void UnsetIfCurrentApp(ContentApp * app); |
| |
| // loads content app identified by vid/pid of client and calls HandleGetSetupPasscode. |
| // Returns 0 if passcode cannot be obtained. |
| uint32_t GetPasscodeFromContentApp(uint16_t vendorId, uint16_t productId, CharSpan rotatingId); |
| |
| // locates app identified by target info and confirms that it grants access to given vid/pid of client, |
| // loads given app and calls HandleGetSetupPasscode. Sets passcode to 0 if it cannot be obtained. |
| // return true if a matching app was found (and it granted this client access), even if a passcode was not obtained |
| bool HasTargetContentApp(uint16_t vendorId, uint16_t productId, CharSpan rotatingId, |
| Protocols::UserDirectedCommissioning::TargetAppInfo & info, uint32_t & passcode); |
| |
| // returns set of connected nodes for a given content app |
| std::set<NodeId> GetNodeIdsForContentApp(uint16_t vendorId, uint16_t productId); |
| |
| // returns set of connected nodes for a given allowed vendor id |
| std::set<NodeId> GetNodeIdsForAllowedVendorId(uint16_t vendorId); |
| |
| // store node id for content app after commissioning |
| // node id can be used later on to update ACL |
| // in case app is not installed |
| // Note: This is in memory storing, the values are deleted after reboot |
| void StoreNodeIdForContentApp(uint16_t vendorId, uint16_t productId, NodeId nodeId); |
| |
| /** |
| * @brief |
| * Add ACLs on this device for the given client, |
| * and create bindings on the given client so that it knows what it has access to. |
| * |
| * The default implementation follows the device library Video Player Architecture spec |
| * for a typical video player given assumptions like video player endpoint id is 1 and |
| * speaker endpoint id is 2. Some devices may need to override this implementation when |
| * these assumptions are not correct. |
| * |
| * @param[in] exchangeMgr Exchange manager to be used to get an exchange context. |
| * @param[in] sessionHandle Reference to an established session. |
| * @param[in] targetVendorId Vendor ID for the target device. |
| * @param[in] targetProductId Product ID for the target device. |
| * @param[in] localNodeId The NodeId for the local device. |
| * @param[in] rotatingId The rotating account ID to handle account login. |
| * @param[in] passcode The passcode to handle account login. |
| * @param[in] bindings Any additional bindings to include. This may include current bindings. |
| * @param[in] successCb The function to be called on success of adding the binding. |
| * @param[in] failureCb The function to be called on failure of adding the binding. |
| * |
| * @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error |
| */ |
| CHIP_ERROR ManageClientAccess(Messaging::ExchangeManager & exchangeMgr, SessionHandle & sessionHandle, uint16_t targetVendorId, |
| uint16_t targetProductId, NodeId localNodeId, chip::CharSpan rotatingId, uint32_t passcode, |
| std::vector<app::Clusters::Binding::Structs::TargetStruct::Type> bindings, |
| Controller::WriteResponseSuccessCallback successCb, |
| Controller::WriteResponseFailureCallback failureCb); |
| |
| protected: |
| // requires vendorApp to be in the catalog of the platform |
| ContentApp * LoadContentAppInternal(const CatalogVendorApp & vendorApp); |
| ContentApp * GetContentAppInternal(const CatalogVendorApp & vendorApp); |
| CHIP_ERROR GetACLEntryIndex(size_t * foundIndex, FabricIndex fabricIndex, NodeId subjectNodeId); |
| |
| static const int kNoCurrentEndpointId = 0; |
| EndpointId mCurrentAppEndpointId = kNoCurrentEndpointId; |
| |
| ContentAppFactory * mContentAppFactory = nullptr; |
| EndpointId mCurrentEndpointId; |
| EndpointId mFirstDynamicEndpointId; |
| ContentApp * mContentApps[CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT]; |
| // key is string -> vendorId:producTid |
| std::map<std::string, std::set<NodeId>> mConnectedContentAppNodeIds; |
| |
| private: |
| void IncrementCurrentEndpointID(); |
| }; |
| |
| } // namespace AppPlatform |
| } // namespace chip |