blob: b00f9f1bf7a1ab84b9795f872b606dcc0b00c208 [file] [log] [blame]
/*
*
* 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