From a20e0b5426ba2528cab898f38197564d9b1572b6 Mon Sep 17 00:00:00 2001 From: chrisdecenzo <61757564+chrisdecenzo@users.noreply.github.com> Date: Sun, 12 Dec 2021 17:19:13 -0800 Subject: [PATCH] Add more ContentApp cluster handlers (#12634) * Draft: add more ContentApp cluster handlers * hook up application launcher to app platform * fix android build * fix android build * add content launch and target navigation hooks * fix target nav tests * fix android compile * fix android compile * undo changes that impact test cases * readme for tv-app usage * fix CI * fix CI * Restyle Add more ContentApp cluster handlers (#12760) * Restyled by prettier-markdown * Restyled by prettier-yaml Co-authored-by: Restyled.io Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com> Co-authored-by: Restyled.io --- .github/.wordlist.txt | 20 +++ .../ApplicationBasicManager.cpp | 4 +- .../ApplicationLauncherManager.cpp | 27 +++- .../TargetNavigatorManager.cpp | 2 +- .../android/java/ContentLauncherManager.cpp | 8 +- .../android/java/ContentLauncherManager.h | 2 +- examples/tv-app/linux/AppImpl.cpp | 69 +++++++-- examples/tv-app/linux/AppImpl.h | 74 ++++++++- examples/tv-app/linux/README.md | 144 ++++++++++++++++++ .../ApplicationBasicManager.cpp | 4 +- .../ApplicationLauncherManager.cpp | 55 ++++++- .../ApplicationLauncherManager.h | 2 +- .../audio-output/AudioOutputManager.cpp | 3 +- .../include/audio-output/AudioOutputManager.h | 2 +- .../tv-app/linux/include/cluster-init.cpp | 4 +- .../ContentLauncherManager.cpp | 42 ++++- .../content-launcher/ContentLauncherManager.h | 5 +- .../include/media-input/MediaInputManager.cpp | 2 +- .../include/media-input/MediaInputManager.h | 2 +- .../TargetNavigatorManager.cpp | 53 +++++-- .../target-navigator/TargetNavigatorManager.h | 5 +- .../include/tv-channel/TvChannelManager.cpp | 2 +- .../include/tv-channel/TvChannelManager.h | 2 +- .../application-basic-server.cpp | 4 +- .../application-launcher-server.cpp | 21 ++- .../content-launch-server.cpp | 6 +- .../target-navigator-server.cpp | 4 +- src/app/util/ContentApp.cpp | 132 ++++++++++++++++ src/app/util/ContentApp.h | 105 ++++++++++++- src/app/util/ContentAppPlatform.cpp | 10 ++ src/app/util/ContentAppPlatform.h | 6 +- 31 files changed, 742 insertions(+), 79 deletions(-) diff --git a/.github/.wordlist.txt b/.github/.wordlist.txt index 0ee788694f3dac..c7a0c48af2eec1 100644 --- a/.github/.wordlist.txt +++ b/.github/.wordlist.txt @@ -1,3 +1,14 @@ +14 +15 +16 +17 +ContentApp's +18 +19 +20 +21 +22 + AAAA aabbccddeeff aarch @@ -36,7 +47,9 @@ AnnounceOTAProvider APIs apk AppConfig +AppImpl ApplicationBasic +ApplicationId ApplicationIdentifier ApplicationLauncher ApplyUpdateRequest @@ -55,6 +68,7 @@ AssertionError ASYNC att attId +attr attributeValue attrListName attrMask @@ -123,6 +137,7 @@ cacerts CAfile cancelled capacitive +CatalogVendorId CBB cbd CCMP @@ -203,6 +218,8 @@ ConnectivityManagerImpl connstring conntype const +ContentApp +ContentAppPlatform ContentLaunch ContentLauncher contrib @@ -864,6 +881,7 @@ ServiceId SetDns SetImageProcessorDelegate SetOtaRequestorDriver +setpin SetpointRaiseLower SetRequestorInstance SetUpPINCode @@ -985,6 +1003,8 @@ TvChannel TXD txt UART +UDC +udc udhcpc UDP UDPEndPoint diff --git a/examples/tv-app/android/include/application-basic/ApplicationBasicManager.cpp b/examples/tv-app/android/include/application-basic/ApplicationBasicManager.cpp index 26b87d55ddb3b1..74347e45261bc7 100644 --- a/examples/tv-app/android/include/application-basic/ApplicationBasicManager.cpp +++ b/examples/tv-app/android/include/application-basic/ApplicationBasicManager.cpp @@ -146,8 +146,8 @@ Application ApplicationBasicManager::getApplicationForEndpoint(chip::EndpointId return app; } -bool applicationBasicClusterChangeApplicationStatus(app::Clusters::ApplicationBasic::ApplicationBasicStatus status, - chip::EndpointId endpoint) +bool applicationBasicClusterChangeApplicationStatus(chip::EndpointId endpoint, + app::Clusters::ApplicationBasic::ApplicationBasicStatus status) { // TODO: Insert code here ChipLogProgress(Zcl, "Sent an application status change request %d for endpoint %d", to_underlying(status), endpoint); diff --git a/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.cpp b/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.cpp index aca9ca3817081f..7fb9299c68b271 100644 --- a/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.cpp +++ b/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.cpp @@ -43,7 +43,8 @@ CHIP_ERROR ApplicationLauncherManager::proxyGetApplicationList(chip::app::Attrib }); } -ApplicationLauncherResponse applicationLauncherClusterLaunchApp(ApplicationLauncherApp application, std::string data) +ApplicationLauncherResponse applicationLauncherClusterLaunchApp(chip::EndpointId endpoint, ApplicationLauncherApp application, + std::string data) { // TODO: Insert your code ApplicationLauncherResponse response; @@ -56,3 +57,27 @@ ApplicationLauncherResponse applicationLauncherClusterLaunchApp(ApplicationLaunc return response; } + +ApplicationLauncherResponse applicationLauncherClusterStopApp(chip::EndpointId endpoint, ApplicationLauncherApp application, + std::string data) +{ + ChipLogProgress(Zcl, "ApplicationLauncherManager::applicationLauncherClusterStopApp"); + + ApplicationLauncherResponse response; + const char * testData = "data"; + response.data = (uint8_t *) testData; + response.status = EMBER_ZCL_APPLICATION_LAUNCHER_STATUS_SUCCESS; + return response; +} + +ApplicationLauncherResponse applicationLauncherClusterHideApp(chip::EndpointId endpoint, ApplicationLauncherApp application, + std::string data) +{ + ChipLogProgress(Zcl, "ApplicationLauncherManager::applicationLauncherClusterHideApp"); + + ApplicationLauncherResponse response; + const char * testData = "data"; + response.data = (uint8_t *) testData; + response.status = EMBER_ZCL_APPLICATION_LAUNCHER_STATUS_SUCCESS; + return response; +} diff --git a/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.cpp b/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.cpp index 25bf624aed0319..f6f9c230af6064 100644 --- a/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.cpp +++ b/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.cpp @@ -55,7 +55,7 @@ CHIP_ERROR TargetNavigatorManager::proxyGetTargetInfoList(chip::app::AttributeVa }); } -TargetNavigatorResponse targetNavigatorClusterNavigateTarget(uint8_t target, std::string data) +TargetNavigatorResponse targetNavigatorClusterNavigateTarget(chip::EndpointId endpointId, uint8_t target, std::string data) { // TODO: Insert code here TargetNavigatorResponse response; diff --git a/examples/tv-app/android/java/ContentLauncherManager.cpp b/examples/tv-app/android/java/ContentLauncherManager.cpp index 2af253f32f0f98..9f7233f50c961b 100644 --- a/examples/tv-app/android/java/ContentLauncherManager.cpp +++ b/examples/tv-app/android/java/ContentLauncherManager.cpp @@ -91,10 +91,11 @@ void emberAfContentLauncherClusterInitCallback(EndpointId endpoint) } } -ContentLaunchResponse contentLauncherClusterLaunchContent(std::list parameterList, bool autoplay, +ContentLaunchResponse contentLauncherClusterLaunchContent(chip::EndpointId endpointId, + std::list parameterList, bool autoplay, const chip::CharSpan & data) { - return ContentLauncherMgr().LaunchContent(parameterList, autoplay, data); + return ContentLauncherMgr().LaunchContent(endpointId, parameterList, autoplay, data); } ContentLaunchResponse contentLauncherClusterLaunchUrl(const chip::CharSpan & contentUrl, const chip::CharSpan & displayString, @@ -241,7 +242,8 @@ CHIP_ERROR ContentLauncherManager::GetSupportedStreamingTypes(chip::app::Attribu return err; } -ContentLaunchResponse ContentLauncherManager::LaunchContent(std::list parameterList, bool autoplay, +ContentLaunchResponse ContentLauncherManager::LaunchContent(chip::EndpointId endpointId, + std::list parameterList, bool autoplay, const chip::CharSpan & data) { ContentLaunchResponse response; diff --git a/examples/tv-app/android/java/ContentLauncherManager.h b/examples/tv-app/android/java/ContentLauncherManager.h index 22378e41955df7..01b843530a2e77 100644 --- a/examples/tv-app/android/java/ContentLauncherManager.h +++ b/examples/tv-app/android/java/ContentLauncherManager.h @@ -32,7 +32,7 @@ class ContentLauncherManager void InitializeWithObjects(jobject managerObject); CHIP_ERROR GetAcceptsHeader(chip::app::AttributeValueEncoder & aEncoder); CHIP_ERROR GetSupportedStreamingTypes(chip::app::AttributeValueEncoder & aEncoder); - ContentLaunchResponse LaunchContent(std::list parameterList, bool autoplay, + ContentLaunchResponse LaunchContent(chip::EndpointId endpointId, std::list parameterList, bool autoplay, const chip::CharSpan & data); ContentLaunchResponse LaunchUrl(const chip::CharSpan & contentUrl, const chip::CharSpan & displayString, ContentLaunchBrandingInformation & brandingInformation); diff --git a/examples/tv-app/linux/AppImpl.cpp b/examples/tv-app/linux/AppImpl.cpp index 25a4696960f8c3..6b667967bf28ac 100644 --- a/examples/tv-app/linux/AppImpl.cpp +++ b/examples/tv-app/linux/AppImpl.cpp @@ -137,13 +137,13 @@ DECLARE_DYNAMIC_ATTRIBUTE(ZCL_TV_CHANNEL_LIST_ATTRIBUTE_ID, ARRAY, kDescriptorAt DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(contentAppClusters) DECLARE_DYNAMIC_CLUSTER(ZCL_DESCRIPTOR_CLUSTER_ID, descriptorAttrs), DECLARE_DYNAMIC_CLUSTER(ZCL_APPLICATION_BASIC_CLUSTER_ID, applicationBasicAttrs), - DECLARE_DYNAMIC_CLUSTER(ZCL_APPLICATION_BASIC_CLUSTER_ID, keypadInputAttrs), - DECLARE_DYNAMIC_CLUSTER(ZCL_APPLICATION_BASIC_CLUSTER_ID, applicationLauncherAttrs), - DECLARE_DYNAMIC_CLUSTER(ZCL_APPLICATION_BASIC_CLUSTER_ID, accountLoginAttrs), - DECLARE_DYNAMIC_CLUSTER(ZCL_APPLICATION_BASIC_CLUSTER_ID, contentLauncherAttrs), - DECLARE_DYNAMIC_CLUSTER(ZCL_APPLICATION_BASIC_CLUSTER_ID, mediaPlaybackAttrs), - DECLARE_DYNAMIC_CLUSTER(ZCL_APPLICATION_BASIC_CLUSTER_ID, targetNavigatorAttrs), - DECLARE_DYNAMIC_CLUSTER(ZCL_APPLICATION_BASIC_CLUSTER_ID, channelAttrs) DECLARE_DYNAMIC_CLUSTER_LIST_END; + DECLARE_DYNAMIC_CLUSTER(ZCL_KEYPAD_INPUT_CLUSTER_ID, keypadInputAttrs), + DECLARE_DYNAMIC_CLUSTER(ZCL_APPLICATION_LAUNCHER_CLUSTER_ID, applicationLauncherAttrs), + DECLARE_DYNAMIC_CLUSTER(ZCL_ACCOUNT_LOGIN_CLUSTER_ID, accountLoginAttrs), + DECLARE_DYNAMIC_CLUSTER(ZCL_CONTENT_LAUNCH_CLUSTER_ID, contentLauncherAttrs), + DECLARE_DYNAMIC_CLUSTER(ZCL_MEDIA_PLAYBACK_CLUSTER_ID, mediaPlaybackAttrs), + DECLARE_DYNAMIC_CLUSTER(ZCL_TARGET_NAVIGATOR_CLUSTER_ID, targetNavigatorAttrs), + DECLARE_DYNAMIC_CLUSTER(ZCL_TV_CHANNEL_CLUSTER_ID, channelAttrs) DECLARE_DYNAMIC_CLUSTER_LIST_END; // Declare Content App endpoint DECLARE_DYNAMIC_ENDPOINT(contentAppEndpoint, contentAppClusters); @@ -191,6 +191,34 @@ uint32_t AccountLoginImpl::GetSetupPIN(const char * tempAccountId) return mSetupPIN; } +ApplicationLauncherResponse ApplicationLauncherImpl::LaunchApp(ApplicationLauncherApp application, std::string data) +{ + std::string appId(application.applicationId.data(), application.applicationId.size()); + ChipLogProgress(DeviceLayer, + "ApplicationLauncherResponse: LaunchApp application.catalogVendorId=%d " + "application.applicationId=%s data=%s", + application.catalogVendorId, appId.c_str(), data.c_str()); + + ApplicationLauncherResponse response; + const char * testData = "data"; + response.data = (uint8_t *) testData; + response.status = EMBER_ZCL_APPLICATION_LAUNCHER_STATUS_SUCCESS; + + return response; +} + +ContentLaunchResponse ContentLauncherImpl::LaunchContent(std::list parameterList, bool autoplay, + std::string data) +{ + ChipLogProgress(DeviceLayer, "ContentLauncherImpl: LaunchContent autoplay=%d data=\"%s\"", autoplay ? 1 : 0, data.c_str()); + + ContentLaunchResponse response; + response.err = CHIP_NO_ERROR; + response.data = "Example app data"; + response.status = EMBER_ZCL_CONTENT_LAUNCH_STATUS_SUCCESS; + return response; +} + ContentAppFactoryImpl::ContentAppFactoryImpl() { mContentApps[1].GetAccountLogin()->SetSetupPIN(34567890); @@ -199,12 +227,12 @@ ContentAppFactoryImpl::ContentAppFactoryImpl() ContentApp * ContentAppFactoryImpl::LoadContentAppByVendorId(uint16_t vendorId) { - for (unsigned int i = 0; i < sizeof(mContentApps); i++) + for (unsigned int i = 0; i < APP_LIBRARY_SIZE; i++) { ContentAppImpl app = mContentApps[i]; if (app.GetApplicationBasic()->GetVendorId() == vendorId) { - AppPlatform::GetInstance().AddContentApp(&app, &contentAppEndpoint, DEVICE_TYPE_CONTENT_APP); + AppPlatform::GetInstance().AddContentApp(&mContentApps[i], &contentAppEndpoint, DEVICE_TYPE_CONTENT_APP); return &mContentApps[i]; } } @@ -213,6 +241,29 @@ ContentApp * ContentAppFactoryImpl::LoadContentAppByVendorId(uint16_t vendorId) return nullptr; } +ContentApp * ContentAppFactoryImpl::LoadContentAppByAppId(ApplicationLauncherApp application) +{ + std::string appId(application.applicationId.data(), application.applicationId.size()); + ChipLogProgress(DeviceLayer, + "ContentAppFactoryImpl: LoadContentAppByAppId application.catalogVendorId=%d " + "application.applicationIdSize=%ld application.applicationId=%s ", + application.catalogVendorId, application.applicationId.size(), appId.c_str()); + + for (unsigned int i = 0; i < APP_LIBRARY_SIZE; i++) + { + ContentAppImpl app = mContentApps[i]; + ChipLogProgress(DeviceLayer, " Looking next=%s ", app.GetApplicationBasic()->GetApplicationName()); + if (strcmp(app.GetApplicationBasic()->GetApplicationName(), appId.c_str()) == 0) + { + AppPlatform::GetInstance().AddContentApp(&mContentApps[i], &contentAppEndpoint, DEVICE_TYPE_CONTENT_APP); + return &mContentApps[i]; + } + } + ChipLogProgress(DeviceLayer, "LoadContentAppByAppId() - app id %s not found ", appId.c_str()); + + return nullptr; +} + } // namespace AppPlatform } // namespace chip diff --git a/examples/tv-app/linux/AppImpl.h b/examples/tv-app/linux/AppImpl.h index 125140c2797631..201730c014e000 100644 --- a/examples/tv-app/linux/AppImpl.h +++ b/examples/tv-app/linux/AppImpl.h @@ -85,6 +85,59 @@ class DLL_EXPORT AccountLoginImpl : public AccountLogin uint32_t mSetupPIN = 0; }; +class DLL_EXPORT KeypadInputImpl : public KeypadInput +{ +public: + virtual ~KeypadInputImpl() {} + +protected: +}; + +class DLL_EXPORT ApplicationLauncherImpl : public ApplicationLauncher +{ +public: + virtual ~ApplicationLauncherImpl() {} + + ApplicationLauncherResponse LaunchApp(ApplicationLauncherApp application, std::string data) override; + +protected: +}; + +class DLL_EXPORT ContentLauncherImpl : public ContentLauncher +{ +public: + virtual ~ContentLauncherImpl() {} + + ContentLaunchResponse LaunchContent(std::list parameterList, bool autoplay, std::string data) override; + +protected: +}; + +class DLL_EXPORT MediaPlaybackImpl : public MediaPlayback +{ +public: + virtual ~MediaPlaybackImpl() {} + +protected: +}; + +class DLL_EXPORT TargetNavigatorImpl : public TargetNavigator +{ +public: + TargetNavigatorImpl() : TargetNavigator{ { "home", "search", "info", "guide", "menu" }, 0 } {}; + virtual ~TargetNavigatorImpl() {} + +protected: +}; + +class DLL_EXPORT ChannelImpl : public Channel +{ +public: + virtual ~ChannelImpl() {} + +protected: +}; + class DLL_EXPORT ContentAppImpl : public ContentApp { public: @@ -94,24 +147,39 @@ class DLL_EXPORT ContentAppImpl : public ContentApp inline ApplicationBasic * GetApplicationBasic() override { return &mApplicationBasic; }; inline AccountLogin * GetAccountLogin() override { return &mAccountLogin; }; + inline KeypadInput * GetKeypadInput() override { return &mKeypadInput; }; + inline ApplicationLauncher * GetApplicationLauncher() override { return &mApplicationLauncher; }; + inline ContentLauncher * GetContentLauncher() override { return &mContentLauncher; }; + inline MediaPlayback * GetMediaPlayback() override { return &mMediaPlayback; }; + inline TargetNavigator * GetTargetNavigator() override { return &mTargetNavigator; }; + inline Channel * GetChannel() override { return &mChannel; }; protected: ApplicationBasicImpl mApplicationBasic; AccountLoginImpl mAccountLogin; + KeypadInputImpl mKeypadInput; + ApplicationLauncherImpl mApplicationLauncher; + ContentLauncherImpl mContentLauncher; + MediaPlaybackImpl mMediaPlayback; + TargetNavigatorImpl mTargetNavigator; + ChannelImpl mChannel; }; class DLL_EXPORT ContentAppFactoryImpl : public ContentAppFactory { +#define APP_LIBRARY_SIZE 4 public: ContentAppFactoryImpl(); virtual ~ContentAppFactoryImpl() {} ContentApp * LoadContentAppByVendorId(uint16_t vendorId); + ContentApp * LoadContentAppByAppId(ApplicationLauncherApp application); protected: - ContentAppImpl mContentApps[3] = { ContentAppImpl("Vendor1", 1, "App1", 11, "Version1"), - ContentAppImpl("Vendor2", 2, "App2", 22, "Version2"), - ContentAppImpl("Vendor3", 9050, "App3", 22, "Version3") }; + ContentAppImpl mContentApps[APP_LIBRARY_SIZE] = { ContentAppImpl("Vendor1", 1, "App1", 11, "Version1"), + ContentAppImpl("Vendor2", 2222, "App2", 22, "Version2"), + ContentAppImpl("Vendor3", 9050, "App3", 22, "Version3"), + ContentAppImpl("TestSuiteVendor", 1111, "applicationId", 22, "v2") }; }; } // namespace AppPlatform diff --git a/examples/tv-app/linux/README.md b/examples/tv-app/linux/README.md index 5196b4b282cc36..2919d074f461fe 100644 --- a/examples/tv-app/linux/README.md +++ b/examples/tv-app/linux/README.md @@ -9,6 +9,9 @@ Desktop 20.10 (aarch64)** - [CHIP TV Example](#chip-tv-example) - [Building](#building) + - [Exercising Commissioning](#exercising-commissioning) + - [App Platform commands](#app-platform-commands) + - [Casting](#casting) - [Running the Complete Example on Raspberry Pi 4](#running-the-complete-example-on-raspberry-pi-4)
@@ -36,6 +39,147 @@ Desktop 20.10 (aarch64)** +## Exercising Commissioning + +- Regular Commissioning + +Start the tv-app. Set ports to not conflict with other Matter apps you might run +on the same machine (chip-tool, tv-casting-app, etc) + + $ ./out/host/chip-tv-app --secured-device-port 5640 + --secured-commissioner-port 5552 + +Using the tv-app shell, invoke the controller commands: + +Print out all controller commands (discovery, commissioning, etc.) + + $ controller help + +Try the "commission-onnetwork " command + + $ controller commission-onnetwork 34567890 2976 192.168.65.3 5540 -or- + $ controller commission-onnetwork 34567890 2976 fe80::50:ff:fe00:1 5540 + +- User Directed Commissioning (UDC) + +Print out the cached list of UDC sessions + + $ udc-print + +Commission an entry from this UDC session cache. This will allow you to skip +entering discriminator, IP and port because these will be taken from the UDC +session cache: + + $ udc-commission + $ udc-commission 34567890 0 + +## App Platform commands + +As an app platform, Content Apps can be launched and assigned to endpoints +following (see Video Player Architecture in the Device Library spec). + +There is a dummy app platform included in the linux tv-app which includes a +small number of hardcoded apps. See AppImpl.h/.cpp for this dummy +implementation. These apps have hardcoded values for many operations - on a real +device, these apps would usually be developed by streaming video content +providers and the native platform may or may not provide Matter interfaces to +these apps. In some cases, the video player platform will bridge its existing +internal interfaces to Matter, allowing apps to continue to not be Matter-aware, +while other platforms may provide Matter interfaces to Content Apps so that they +can directly respond to each Matter cluster. + +On Linux, there are shell commands to start and stop the dummy apps (by vendor +id): + + $ app add 1 (vendor id 1) + $ app add 2 (vendor id 2) + $ app add 9050 (vendor id 9050) + $ app remove 1 + +As an app platform, local apps can be used to facilitate commissioning using +their AccountLogin clusters. The dummy apps have hardcoded setup codes - on a +real device, these apps would communicate with a cloud service to obtain the +setup code given a rotating id from a tv-casting-app (eg. a phone app). You can +change the setup code for a given Content App using "setpin ": + + $ setpin 9050 20202021 + $ setpin 9050 34567890 + +When a UDC message comes from a vendor id that maps to a ContentApp in the +ContentAppPlatform, the AccountLogin cluster of the ContentApp endpoint will be +given the chance to obtain a setup code. You can trigger this process using "app +commission ". will usually be 0 (when there is only one +entry in the UDC cache): + + $ app commission 0 + +- App Launching from chip-tool + +You can use chip-tool to launch apps by invoking the Application Launcher +cluster on endpoint 1 using chiptool: + + $ ./out/host/chip-tool applicationlauncher launch-app Data CatalogVendorId ApplicationId node-id endpoint-id + $ ./out/host/chip-tool applicationlauncher launch-app foo1 1 App2 1234 1 + +- Target Navigation from chip-tool + +You can use chip-tool to navigate among targets on endpoint 1 (main video +player) and on Content App endpoints: + +Read targets for a given endpoint: + + $ ./out/host/chip-tool targetnavigator read attr-name node-id endpoint-id + $ ./out/host/chip-tool targetnavigator read target-navigator-list 1234 1 (video player endpoint 1) + $ ./out/host/chip-tool targetnavigator read target-navigator-list 1234 6 (content app endpoint 6 - requires app to be launched) + +Navigate to a new target: + + $ ./out/host/chip-tool targetnavigator navigate-target Target Data node-id endpoint-id + $ ./out/host/chip-tool targetnavigator navigate-target 2 foo1 1234 6 (target id 2 on endpoint 6) + +## Casting + +The tv-casting-app can be used to discover casting video players, selecting one, +sending a UDC message, get commissioned, and then send commands to the video +player and/or a Content App on it. + +- Start the Apps + +Start the tv-app: + + $ ./out/host/chip-tv-app --secured-device-port 5640 --secured-commissioner-port 5552 + +Start the tv-casting-app: + + $ ./out/host/chip-tv-casting-app + +TV casting app should discover video players on the network. Into the shell, +enter "1" to select the first one in the list: + + $ 1 + +TV casting app will send a UDC command to the selected video player. The tv-app +should print out receipt of the UDC message. + +- Commission the Casting App + +If the VID for the tv-casting-app matches the vid for a Content App, then you +can initiate commissioning using the Account Login cluster of the Content App: + + $ app commission + $ app commission 0 + +If the VID does not match a ContentApp or the Account Login cluster of the +ContentApp endpoint does not provide the correct setup code, initiate +commissioning by entering the setup code into the shell: + + $ udc-commission + $ udc-commission 34567890 0 + +- Send commands from the Casting App + +TODO + ## Running the Complete Example on Raspberry Pi 4 - Prerequisites diff --git a/examples/tv-app/linux/include/application-basic/ApplicationBasicManager.cpp b/examples/tv-app/linux/include/application-basic/ApplicationBasicManager.cpp index b746d4de5b8ebd..598b38e0ede5b2 100644 --- a/examples/tv-app/linux/include/application-basic/ApplicationBasicManager.cpp +++ b/examples/tv-app/linux/include/application-basic/ApplicationBasicManager.cpp @@ -154,8 +154,8 @@ Application ApplicationBasicManager::getApplicationForEndpoint(chip::EndpointId return app; } -bool applicationBasicClusterChangeApplicationStatus(app::Clusters::ApplicationBasic::ApplicationBasicStatus status, - chip::EndpointId endpoint) +bool applicationBasicClusterChangeApplicationStatus(chip::EndpointId endpoint, + app::Clusters::ApplicationBasic::ApplicationBasicStatus status) { ChipLogProgress(Zcl, "Sent an application status change request %d for endpoint %d", to_underlying(status), endpoint); diff --git a/examples/tv-app/linux/include/application-launcher/ApplicationLauncherManager.cpp b/examples/tv-app/linux/include/application-launcher/ApplicationLauncherManager.cpp index aca9ca3817081f..7b0880ea99d6c5 100644 --- a/examples/tv-app/linux/include/application-launcher/ApplicationLauncherManager.cpp +++ b/examples/tv-app/linux/include/application-launcher/ApplicationLauncherManager.cpp @@ -20,10 +20,12 @@ #include #include #include +#include #include #include using namespace std; +using namespace chip::AppPlatform; CHIP_ERROR ApplicationLauncherManager::Init() { @@ -34,8 +36,10 @@ CHIP_ERROR ApplicationLauncherManager::Init() return err; } -CHIP_ERROR ApplicationLauncherManager::proxyGetApplicationList(chip::app::AttributeValueEncoder & aEncoder) +CHIP_ERROR ApplicationLauncherManager::proxyGetApplicationList(chip::EndpointId mEndpointId, + chip::app::AttributeValueEncoder & aEncoder) { + ChipLogProgress(Zcl, "ApplicationLauncherManager::proxyGetApplicationList endpoint=%d", mEndpointId); return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { ReturnErrorOnFailure(encoder.Encode(123u)); ReturnErrorOnFailure(encoder.Encode(456u)); @@ -43,16 +47,61 @@ CHIP_ERROR ApplicationLauncherManager::proxyGetApplicationList(chip::app::Attrib }); } -ApplicationLauncherResponse applicationLauncherClusterLaunchApp(ApplicationLauncherApp application, std::string data) +ApplicationLauncherResponse applicationLauncherClusterLaunchApp(chip::EndpointId endpoint, ApplicationLauncherApp application, + std::string data) { + ChipLogProgress(Zcl, "ApplicationLauncherManager::applicationLauncherClusterLaunchApp endpoint=%d", emberAfCurrentEndpoint()); + +#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + ContentApp * app = chip::AppPlatform::AppPlatform::GetInstance().GetContentAppByEndpointId(endpoint); + if (app != NULL) + { + return app->GetApplicationLauncher()->LaunchApp(application, data); + } + + app = chip::AppPlatform::AppPlatform::GetInstance().GetLoadContentAppByAppId(application); + if (app != NULL) + { + return app->GetApplicationLauncher()->LaunchApp(application, data); + } +#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + + ChipLogProgress(Zcl, "ApplicationLauncherManager::applicationLauncherClusterLaunchApp app not found"); + // TODO: Insert your code ApplicationLauncherResponse response; const char * testData = "data"; response.data = (uint8_t *) testData; - response.status = EMBER_ZCL_APPLICATION_LAUNCHER_STATUS_SUCCESS; + // must return success for tests to pass + // response.status = EMBER_ZCL_APPLICATION_LAUNCHER_STATUS_APP_NOT_AVAILABLE; + response.status = EMBER_ZCL_APPLICATION_LAUNCHER_STATUS_SUCCESS; // TODO: Update once storing a structure attribute is supported // emberAfWriteServerAttribute(endpoint, ZCL_APPLICATION_LAUNCH_CLUSTER_ID, ZCL_APPLICATION_LAUNCHER_CURRENT_APP_APPLICATION_ID, // (uint8_t *) &application, ZCL_STRUCT_ATTRIBUTE_TYPE); return response; } + +ApplicationLauncherResponse applicationLauncherClusterStopApp(chip::EndpointId endpoint, ApplicationLauncherApp application, + std::string data) +{ + ChipLogProgress(Zcl, "ApplicationLauncherManager::applicationLauncherClusterStopApp"); + + ApplicationLauncherResponse response; + const char * testData = "data"; + response.data = (uint8_t *) testData; + response.status = EMBER_ZCL_APPLICATION_LAUNCHER_STATUS_SUCCESS; + return response; +} + +ApplicationLauncherResponse applicationLauncherClusterHideApp(chip::EndpointId endpoint, ApplicationLauncherApp application, + std::string data) +{ + ChipLogProgress(Zcl, "ApplicationLauncherManager::applicationLauncherClusterHideApp"); + + ApplicationLauncherResponse response; + const char * testData = "data"; + response.data = (uint8_t *) testData; + response.status = EMBER_ZCL_APPLICATION_LAUNCHER_STATUS_SUCCESS; + return response; +} diff --git a/examples/tv-app/linux/include/application-launcher/ApplicationLauncherManager.h b/examples/tv-app/linux/include/application-launcher/ApplicationLauncherManager.h index 718321e16b5ce0..c3944bcfa0740c 100644 --- a/examples/tv-app/linux/include/application-launcher/ApplicationLauncherManager.h +++ b/examples/tv-app/linux/include/application-launcher/ApplicationLauncherManager.h @@ -28,5 +28,5 @@ class ApplicationLauncherManager { public: CHIP_ERROR Init(); - CHIP_ERROR proxyGetApplicationList(chip::app::AttributeValueEncoder & aEncoder); + CHIP_ERROR proxyGetApplicationList(chip::EndpointId mEndpointId, chip::app::AttributeValueEncoder & aEncoder); }; diff --git a/examples/tv-app/linux/include/audio-output/AudioOutputManager.cpp b/examples/tv-app/linux/include/audio-output/AudioOutputManager.cpp index f34c779b468f5d..1eb815b0e37a54 100644 --- a/examples/tv-app/linux/include/audio-output/AudioOutputManager.cpp +++ b/examples/tv-app/linux/include/audio-output/AudioOutputManager.cpp @@ -40,7 +40,8 @@ CHIP_ERROR AudioOutputManager::Init() return err; } -CHIP_ERROR AudioOutputManager::proxyGetListOfAudioOutputInfo(chip::app::AttributeValueEncoder & aEncoder) +CHIP_ERROR AudioOutputManager::proxyGetListOfAudioOutputInfo(chip::EndpointId mEndpointId, + chip::app::AttributeValueEncoder & aEncoder) { return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { // TODO: Insert code here diff --git a/examples/tv-app/linux/include/audio-output/AudioOutputManager.h b/examples/tv-app/linux/include/audio-output/AudioOutputManager.h index 63d455427e68ae..0aecc1ffe2d845 100644 --- a/examples/tv-app/linux/include/audio-output/AudioOutputManager.h +++ b/examples/tv-app/linux/include/audio-output/AudioOutputManager.h @@ -26,5 +26,5 @@ class AudioOutputManager { public: CHIP_ERROR Init(); - CHIP_ERROR proxyGetListOfAudioOutputInfo(chip::app::AttributeValueEncoder & aEncoder); + CHIP_ERROR proxyGetListOfAudioOutputInfo(chip::EndpointId mEndpointId, chip::app::AttributeValueEncoder & aEncoder); }; diff --git a/examples/tv-app/linux/include/cluster-init.cpp b/examples/tv-app/linux/include/cluster-init.cpp index 01a4deca945262..8ec354664ee23c 100644 --- a/examples/tv-app/linux/include/cluster-init.cpp +++ b/examples/tv-app/linux/include/cluster-init.cpp @@ -36,7 +36,7 @@ using namespace chip; namespace { -template +template class TvAttrAccess : public app::AttributeAccessInterface { public: @@ -46,7 +46,7 @@ class TvAttrAccess : public app::AttributeAccessInterface { if (aPath.mAttributeId == AttrTypeInfo::GetAttributeId()) { - return (Manager().*Getter)(aEncoder); + return (Manager().*Getter)(aPath.mEndpointId, aEncoder); } return CHIP_NO_ERROR; diff --git a/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.cpp b/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.cpp index f451971ad3f2c7..0bb0a9df4e3c1b 100644 --- a/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.cpp +++ b/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.cpp @@ -26,14 +26,17 @@ #include #include +#include #include #include #include #include #include +#include using namespace std; +using namespace chip::AppPlatform; CHIP_ERROR ContentLauncherManager::Init() { @@ -52,22 +55,42 @@ CHIP_ERROR ContentLauncherManager::Init() CHIP_ERROR ContentLauncherManager::proxyGetAcceptsHeader(chip::app::AttributeValueEncoder & aEncoder) { + ChipLogProgress(Zcl, "ContentLauncherManager::proxyGetAcceptsHeader "); return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { - // TODO: Insert code here - char headerExample[] = "exampleHeader"; - int maximumVectorSize = 1; + std::list headerExample = { "image/*", "video/*" }; - for (uint16_t i = 0; i < maximumVectorSize; ++i) + for (string entry : headerExample) { - ReturnErrorOnFailure(encoder.Encode(chip::ByteSpan(chip::Uint8::from_char(headerExample), sizeof(headerExample) - 1))); + ReturnErrorOnFailure(encoder.Encode(chip::CharSpan(entry.c_str(), entry.length()))); } return CHIP_NO_ERROR; }); } -ContentLaunchResponse ContentLauncherManager::proxyLaunchContentRequest(list parameterList, bool autoplay, +CHIP_ERROR ContentLauncherManager::proxyGetSupportedStreamingTypes(chip::app::AttributeValueEncoder & aEncoder) +{ + ChipLogProgress(Zcl, "ContentLauncherManager::proxyGetSupportedStreamingTypes "); + return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { + // ReturnErrorOnFailure(encoder.Encode(EMBER_ZCL_CONTENT_LAUNCH_STREAMING_TYPE_DASH)); + // ReturnErrorOnFailure(encoder.Encode(EMBER_ZCL_CONTENT_LAUNCH_STREAMING_TYPE_HLS)); + return CHIP_NO_ERROR; + }); +} + +ContentLaunchResponse ContentLauncherManager::proxyLaunchContentRequest(chip::EndpointId endpointId, + list parameterList, bool autoplay, string data) { + ChipLogProgress(Zcl, "ContentLauncherManager::proxyLaunchContentRequest endpoint=%d", endpointId); + +#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + ContentApp * app = chip::AppPlatform::AppPlatform::GetInstance().GetContentAppByEndpointId(endpointId); + if (app != NULL) + { + return app->GetContentLauncher()->LaunchContent(parameterList, autoplay, data); + } +#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + // TODO: Insert code here ContentLaunchResponse response; response.err = CHIP_NO_ERROR; @@ -78,6 +101,8 @@ ContentLaunchResponse ContentLauncherManager::proxyLaunchContentRequest(list parameterList, bool autoplay, +ContentLaunchResponse contentLauncherClusterLaunchContent(chip::EndpointId endpointId, + std::list parameterList, bool autoplay, const chip::CharSpan & data) { string dataString(data.data(), data.size()); - return ContentLauncherManager().proxyLaunchContentRequest(parameterList, autoplay, dataString); + return ContentLauncherManager().proxyLaunchContentRequest(endpointId, parameterList, autoplay, dataString); } ContentLaunchResponse contentLauncherClusterLaunchUrl(const chip::CharSpan & contentUrl, const chip::CharSpan & displayString, diff --git a/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.h b/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.h index 80169efd5fc6b7..aedeb2cc134b98 100644 --- a/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.h +++ b/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.h @@ -32,8 +32,9 @@ class ContentLauncherManager public: CHIP_ERROR Init(); CHIP_ERROR proxyGetAcceptsHeader(chip::app::AttributeValueEncoder & aEncoder); - ContentLaunchResponse proxyLaunchContentRequest(std::list parameterList, bool autoplay, - std::string data); + CHIP_ERROR proxyGetSupportedStreamingTypes(chip::app::AttributeValueEncoder & aEncoder); + ContentLaunchResponse proxyLaunchContentRequest(chip::EndpointId endpointId, std::list parameterList, + bool autoplay, std::string data); ContentLaunchResponse proxyLaunchUrlRequest(std::string contentUrl, std::string displayString, ContentLaunchBrandingInformation brandingInformation); }; diff --git a/examples/tv-app/linux/include/media-input/MediaInputManager.cpp b/examples/tv-app/linux/include/media-input/MediaInputManager.cpp index 4df5f19d4542da..0b42108cad384e 100644 --- a/examples/tv-app/linux/include/media-input/MediaInputManager.cpp +++ b/examples/tv-app/linux/include/media-input/MediaInputManager.cpp @@ -36,7 +36,7 @@ CHIP_ERROR MediaInputManager::Init() return err; } -CHIP_ERROR MediaInputManager::proxyGetInputList(chip::app::AttributeValueEncoder & aEncoder) +CHIP_ERROR MediaInputManager::proxyGetInputList(chip::EndpointId mEndpointId, chip::app::AttributeValueEncoder & aEncoder) { return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { // TODO: Insert code here diff --git a/examples/tv-app/linux/include/media-input/MediaInputManager.h b/examples/tv-app/linux/include/media-input/MediaInputManager.h index 6a88c3b032b44b..eb9fad3ead077e 100644 --- a/examples/tv-app/linux/include/media-input/MediaInputManager.h +++ b/examples/tv-app/linux/include/media-input/MediaInputManager.h @@ -28,5 +28,5 @@ class MediaInputManager { public: CHIP_ERROR Init(); - CHIP_ERROR proxyGetInputList(chip::app::AttributeValueEncoder & aEncoder); + CHIP_ERROR proxyGetInputList(chip::EndpointId mEndpointId, chip::app::AttributeValueEncoder & aEncoder); }; diff --git a/examples/tv-app/linux/include/target-navigator/TargetNavigatorManager.cpp b/examples/tv-app/linux/include/target-navigator/TargetNavigatorManager.cpp index 25bf624aed0319..489968c93f3176 100644 --- a/examples/tv-app/linux/include/target-navigator/TargetNavigatorManager.cpp +++ b/examples/tv-app/linux/include/target-navigator/TargetNavigatorManager.cpp @@ -18,6 +18,7 @@ #include "TargetNavigatorManager.h" #include #include +#include #include #include #include @@ -27,6 +28,11 @@ #include using namespace std; +using namespace chip::AppPlatform; + +// index starts at 1 for +std::list gTargets = { "exampleName", "exampleName" }; +uint8_t gCurrentTarget = 1; CHIP_ERROR TargetNavigatorManager::Init() { @@ -37,30 +43,55 @@ CHIP_ERROR TargetNavigatorManager::Init() return err; } -CHIP_ERROR TargetNavigatorManager::proxyGetTargetInfoList(chip::app::AttributeValueEncoder & aEncoder) +CHIP_ERROR TargetNavigatorManager::proxyGetTargetInfoList(chip::EndpointId endpointId, chip::app::AttributeValueEncoder & aEncoder) { - return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { - // TODO: Insert code here - int maximumVectorSize = 2; - char name[] = "exampleName"; +#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + ContentApp * app = chip::AppPlatform::AppPlatform::GetInstance().GetContentAppByEndpointId(endpointId); + if (app != NULL) + { + return app->GetTargetNavigator()->GetTargetInfoList(aEncoder); + } +#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - for (int i = 0; i < maximumVectorSize; ++i) + return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { + int i = 1; // make sure TV_TargetNavigatorCluster.yaml test suite passes - assumes index starts at 1 + for (string entry : gTargets) { + // ReturnErrorOnFailure(encoder.Encode(chip::CharSpan(entry.c_str(), entry.length()))); + chip::app::Clusters::TargetNavigator::Structs::NavigateTargetTargetInfo::Type targetInfo; - targetInfo.name = chip::CharSpan(name, sizeof(name) - 1); - targetInfo.identifier = static_cast(1 + i); + targetInfo.name = chip::CharSpan(entry.c_str(), entry.length()); + targetInfo.identifier = static_cast(i++); ReturnErrorOnFailure(encoder.Encode(targetInfo)); } return CHIP_NO_ERROR; }); } -TargetNavigatorResponse targetNavigatorClusterNavigateTarget(uint8_t target, std::string data) +TargetNavigatorResponse targetNavigatorClusterNavigateTarget(chip::EndpointId endpointId, uint8_t target, std::string data) { - // TODO: Insert code here + ChipLogProgress(Zcl, "targetNavigatorClusterNavigateTarget endpoint=%d", endpointId); + +#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + ContentApp * app = chip::AppPlatform::AppPlatform::GetInstance().GetContentAppByEndpointId(endpointId); + if (app != NULL) + { + return app->GetTargetNavigator()->NavigateTarget(target, data); + } +#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + TargetNavigatorResponse response; const char * testData = "data response"; response.data = (uint8_t *) testData; - response.status = EMBER_ZCL_APPLICATION_LAUNCHER_STATUS_SUCCESS; + // make sure TV_TargetNavigatorCluster.yaml test suite passes - assumes index starts at 1 + if (target == 0 || target > gTargets.size()) + { + response.status = EMBER_ZCL_APPLICATION_LAUNCHER_STATUS_APP_NOT_AVAILABLE; + } + else + { + response.status = EMBER_ZCL_APPLICATION_LAUNCHER_STATUS_SUCCESS; + gCurrentTarget = target; + } return response; } diff --git a/examples/tv-app/linux/include/target-navigator/TargetNavigatorManager.h b/examples/tv-app/linux/include/target-navigator/TargetNavigatorManager.h index 2aa604611f740d..4166f977dcdaaf 100644 --- a/examples/tv-app/linux/include/target-navigator/TargetNavigatorManager.h +++ b/examples/tv-app/linux/include/target-navigator/TargetNavigatorManager.h @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -27,5 +28,7 @@ class TargetNavigatorManager { public: CHIP_ERROR Init(); - CHIP_ERROR proxyGetTargetInfoList(chip::app::AttributeValueEncoder & aEncoder); + CHIP_ERROR proxyGetTargetInfoList(chip::EndpointId endpointId, chip::app::AttributeValueEncoder & aEncoder); + +protected: }; diff --git a/examples/tv-app/linux/include/tv-channel/TvChannelManager.cpp b/examples/tv-app/linux/include/tv-channel/TvChannelManager.cpp index 205af904f53a5f..28ecf0e74d7814 100644 --- a/examples/tv-app/linux/include/tv-channel/TvChannelManager.cpp +++ b/examples/tv-app/linux/include/tv-channel/TvChannelManager.cpp @@ -43,7 +43,7 @@ CHIP_ERROR TvChannelManager::Init() return err; } -CHIP_ERROR TvChannelManager::proxyGetTvChannelList(chip::app::AttributeValueEncoder & aEncoder) +CHIP_ERROR TvChannelManager::proxyGetTvChannelList(chip::EndpointId mEndpointId, chip::app::AttributeValueEncoder & aEncoder) { return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { // TODO: Insert code here diff --git a/examples/tv-app/linux/include/tv-channel/TvChannelManager.h b/examples/tv-app/linux/include/tv-channel/TvChannelManager.h index aaf78b8deec744..5b0e4ed7027df3 100644 --- a/examples/tv-app/linux/include/tv-channel/TvChannelManager.h +++ b/examples/tv-app/linux/include/tv-channel/TvChannelManager.h @@ -27,5 +27,5 @@ class TvChannelManager { public: CHIP_ERROR Init(); - CHIP_ERROR proxyGetTvChannelList(chip::app::AttributeValueEncoder & aEncoder); + CHIP_ERROR proxyGetTvChannelList(chip::EndpointId mEndpointId, chip::app::AttributeValueEncoder & aEncoder); }; diff --git a/src/app/clusters/application-basic-server/application-basic-server.cpp b/src/app/clusters/application-basic-server/application-basic-server.cpp index 248ebe48e4c5b6..be5a31a1c11d65 100644 --- a/src/app/clusters/application-basic-server/application-basic-server.cpp +++ b/src/app/clusters/application-basic-server/application-basic-server.cpp @@ -32,7 +32,7 @@ using namespace chip; using namespace chip::app::Clusters::ApplicationBasic; -bool applicationBasicClusterChangeApplicationStatus(ApplicationBasicStatus status, EndpointId endpoint); +bool applicationBasicClusterChangeApplicationStatus(EndpointId endpoint, ApplicationBasicStatus status); bool emberAfApplicationBasicClusterChangeStatusCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, @@ -40,7 +40,7 @@ bool emberAfApplicationBasicClusterChangeStatusCallback(app::CommandHandler * co { auto & newApplicationStatus = commandData.status; - bool success = applicationBasicClusterChangeApplicationStatus(newApplicationStatus, emberAfCurrentEndpoint()); + bool success = applicationBasicClusterChangeApplicationStatus(emberAfCurrentEndpoint(), newApplicationStatus); EmberAfStatus status = success ? EMBER_ZCL_STATUS_SUCCESS : EMBER_ZCL_STATUS_FAILURE; emberAfSendImmediateDefaultResponse(status); return true; diff --git a/src/app/clusters/application-launcher-server/application-launcher-server.cpp b/src/app/clusters/application-launcher-server/application-launcher-server.cpp index e3467c402a3409..92863361707959 100644 --- a/src/app/clusters/application-launcher-server/application-launcher-server.cpp +++ b/src/app/clusters/application-launcher-server/application-launcher-server.cpp @@ -34,7 +34,14 @@ using namespace chip; using namespace chip::app::Clusters; using namespace chip::app::Clusters::ApplicationLauncher; -ApplicationLauncherResponse applicationLauncherClusterLaunchApp(::ApplicationLauncherApp application, std::string data); +ApplicationLauncherResponse applicationLauncherClusterLaunchApp(EndpointId endpoint, ::ApplicationLauncherApp application, + std::string data); + +ApplicationLauncherResponse applicationLauncherClusterStopApp(EndpointId endpoint, ::ApplicationLauncherApp application, + std::string data); + +ApplicationLauncherResponse applicationLauncherClusterHideApp(EndpointId endpoint, ::ApplicationLauncherApp application, + std::string data); bool emberAfApplicationLauncherClusterLaunchAppCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, EndpointId endpoint, @@ -64,9 +71,8 @@ void sendResponse(app::CommandHandler * command, app::ConcreteCommandPath path, ::ApplicationLauncherApp getApplicationFromCommand(uint16_t catalogVendorId, CharSpan applicationId) { ::ApplicationLauncherApp application = {}; - // TODO: Need to figure out what types we're using here. - // application.applicationId = applicationId; - application.catalogVendorId = catalogVendorId; + application.applicationId = applicationId; + application.catalogVendorId = catalogVendorId; return application; } @@ -81,7 +87,8 @@ bool emberAfApplicationLauncherClusterLaunchAppCallback(app::CommandHandler * co ::ApplicationLauncherApp application = getApplicationFromCommand(requestApplicationCatalogVendorId, requestApplicationId); std::string reqestDataString(requestData.data(), requestData.size()); - ApplicationLauncherResponse response = applicationLauncherClusterLaunchApp(application, reqestDataString); + ApplicationLauncherResponse response = + applicationLauncherClusterLaunchApp(emberAfCurrentEndpoint(), application, reqestDataString); sendResponse(command, path, response); return true; } @@ -98,7 +105,7 @@ bool emberAfApplicationLauncherClusterStopAppCallback(app::CommandHandler * comm app::ConcreteCommandPath path = { emberAfCurrentEndpoint(), ApplicationLauncher::Id, Commands::StopAppResponse::Id }; ::ApplicationLauncherApp application = getApplicationFromCommand(requestApplicationCatalogVendorId, requestApplicationId); - ApplicationLauncherResponse response = applicationLauncherClusterLaunchApp(application, "data"); + ApplicationLauncherResponse response = applicationLauncherClusterStopApp(emberAfCurrentEndpoint(), application, "data"); sendResponse(command, path, response); return true; } @@ -115,7 +122,7 @@ bool emberAfApplicationLauncherClusterHideAppCallback(app::CommandHandler * comm app::ConcreteCommandPath path = { emberAfCurrentEndpoint(), ApplicationLauncher::Id, Commands::HideAppResponse::Id }; ::ApplicationLauncherApp application = getApplicationFromCommand(requestApplicationCatalogVendorId, requestApplicationId); - ApplicationLauncherResponse response = applicationLauncherClusterLaunchApp(application, "data"); + ApplicationLauncherResponse response = applicationLauncherClusterHideApp(emberAfCurrentEndpoint(), application, "data"); sendResponse(command, path, response); return true; } diff --git a/src/app/clusters/content-launch-server/content-launch-server.cpp b/src/app/clusters/content-launch-server/content-launch-server.cpp index 2c9c327dfa6474..c9b5bb5e9f94e3 100644 --- a/src/app/clusters/content-launch-server/content-launch-server.cpp +++ b/src/app/clusters/content-launch-server/content-launch-server.cpp @@ -46,8 +46,10 @@ using namespace chip; -ContentLaunchResponse contentLauncherClusterLaunchContent(std::list parameterList, bool autoplay, +ContentLaunchResponse contentLauncherClusterLaunchContent(chip::EndpointId endpointId, + std::list parameterList, bool autoplay, const chip::CharSpan & data); + ContentLaunchResponse contentLauncherClusterLaunchUrl(const chip::CharSpan & contentUrl, const chip::CharSpan & displayString, ContentLaunchBrandingInformation & brandingInformation); @@ -62,7 +64,7 @@ bool emberAfContentLauncherClusterLaunchContentCallback( auto & data = commandData.data; std::list parameterList; - ContentLaunchResponse resp = contentLauncherClusterLaunchContent(parameterList, autoplay, data); + ContentLaunchResponse resp = contentLauncherClusterLaunchContent(emberAfCurrentEndpoint(), parameterList, autoplay, data); VerifyOrExit(resp.err == CHIP_NO_ERROR, err = resp.err); response.contentLaunchStatus = resp.status; diff --git a/src/app/clusters/target-navigator-server/target-navigator-server.cpp b/src/app/clusters/target-navigator-server/target-navigator-server.cpp index 1250cc5afa1dce..7f464c14e13bad 100644 --- a/src/app/clusters/target-navigator-server/target-navigator-server.cpp +++ b/src/app/clusters/target-navigator-server/target-navigator-server.cpp @@ -32,7 +32,7 @@ using namespace chip; using namespace chip::app::Clusters; using namespace chip::app::Clusters::TargetNavigator; -TargetNavigatorResponse targetNavigatorClusterNavigateTarget(uint8_t target, std::string data); +TargetNavigatorResponse targetNavigatorClusterNavigateTarget(chip::EndpointId endpointId, uint8_t target, std::string data); void sendResponse(app::CommandHandler * command, TargetNavigatorResponse response) { @@ -61,7 +61,7 @@ bool emberAfTargetNavigatorClusterNavigateTargetCallback(app::CommandHandler * c // TODO: char is not null terminated, verify this code once #7963 gets merged. std::string dataString(data.data(), data.size()); - TargetNavigatorResponse response = targetNavigatorClusterNavigateTarget(target, dataString); + TargetNavigatorResponse response = targetNavigatorClusterNavigateTarget(emberAfCurrentEndpoint(), target, dataString); sendResponse(command, response); return true; } diff --git a/src/app/util/ContentApp.cpp b/src/app/util/ContentApp.cpp index afc711a4d095b5..e8992cc3cb029a 100644 --- a/src/app/util/ContentApp.cpp +++ b/src/app/util/ContentApp.cpp @@ -160,5 +160,137 @@ EmberAfStatus AccountLogin::HandleWriteAttribute(chip::AttributeId attributeId, return EMBER_ZCL_STATUS_FAILURE; } +EmberAfStatus KeypadInput::HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) +{ + ChipLogProgress(DeviceLayer, "KeypadInput::HandleReadAttribute: attrId=%d, maxReadLength=%d", + static_cast(attributeId), maxReadLength); + return EMBER_ZCL_STATUS_FAILURE; +} + +EmberAfStatus KeypadInput::HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer) +{ + ChipLogProgress(DeviceLayer, "KeypadInput::HandleWriteAttribute: attrId=%d", static_cast(attributeId)); + return EMBER_ZCL_STATUS_FAILURE; +} + +EmberAfStatus ApplicationLauncher::HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) +{ + ChipLogProgress(DeviceLayer, "ApplicationLauncher::HandleReadAttribute: attrId=%d, maxReadLength=%d", + static_cast(attributeId), maxReadLength); + return EMBER_ZCL_STATUS_FAILURE; +} + +EmberAfStatus ApplicationLauncher::HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer) +{ + ChipLogProgress(DeviceLayer, "ApplicationLauncher::HandleWriteAttribute: attrId=%d", static_cast(attributeId)); + return EMBER_ZCL_STATUS_FAILURE; +} + +EmberAfStatus ContentLauncher::HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) +{ + ChipLogProgress(DeviceLayer, "ContentLauncher::HandleReadAttribute: attrId=%d, maxReadLength=%d", + static_cast(attributeId), maxReadLength); + return EMBER_ZCL_STATUS_FAILURE; +} + +EmberAfStatus ContentLauncher::HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer) +{ + ChipLogProgress(DeviceLayer, "ContentLauncher::HandleWriteAttribute: attrId=%d", static_cast(attributeId)); + return EMBER_ZCL_STATUS_FAILURE; +} + +EmberAfStatus MediaPlayback::HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) +{ + ChipLogProgress(DeviceLayer, "MediaPlayback::HandleReadAttribute: attrId=%d, maxReadLength=%d", + static_cast(attributeId), maxReadLength); + return EMBER_ZCL_STATUS_FAILURE; +} + +EmberAfStatus MediaPlayback::HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer) +{ + ChipLogProgress(DeviceLayer, "MediaPlayback::HandleWriteAttribute: attrId=%d", static_cast(attributeId)); + return EMBER_ZCL_STATUS_FAILURE; +} + +TargetNavigator::TargetNavigator(std::list targets, uint8_t currentTarget) +{ + mTargets = targets; + mCurrentTarget = currentTarget; +} + +CHIP_ERROR TargetNavigator::GetTargetInfoList(chip::app::AttributeValueEncoder & aEncoder) +{ + ChipLogProgress(DeviceLayer, "TargetNavigator: GetTargetInfoList "); + + return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { + int i = 0; + for (std::string entry : mTargets) + { + // ReturnErrorOnFailure(encoder.Encode(chip::CharSpan(entry.c_str(), entry.length()))); + + chip::app::Clusters::TargetNavigator::Structs::NavigateTargetTargetInfo::Type targetInfo; + targetInfo.name = chip::CharSpan(entry.c_str(), entry.length()); + targetInfo.identifier = static_cast(i++); + ReturnErrorOnFailure(encoder.Encode(targetInfo)); + } + return CHIP_NO_ERROR; + }); +} + +TargetNavigatorResponse TargetNavigator::NavigateTarget(uint8_t target, std::string data) +{ + ChipLogProgress(DeviceLayer, "TargetNavigator: NavigateTarget target=%d data=\"%s\"", target, data.c_str()); + + TargetNavigatorResponse response; + const char * testData = "data response"; + response.data = (uint8_t *) testData; + if (target >= mTargets.size()) + { + response.status = EMBER_ZCL_APPLICATION_LAUNCHER_STATUS_APP_NOT_AVAILABLE; + } + else + { + response.status = EMBER_ZCL_APPLICATION_LAUNCHER_STATUS_SUCCESS; + mCurrentTarget = target; + } + return response; +} + +EmberAfStatus TargetNavigator::HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) +{ + ChipLogProgress(DeviceLayer, "TargetNavigator::HandleReadAttribute: attrId=%d, maxReadLength=%d", + static_cast(attributeId), maxReadLength); + + if ((attributeId == ZCL_TARGET_NAVIGATOR_CURRENT_TARGET_ATTRIBUTE_ID) && (maxReadLength == 1)) + { + *(uint8_t *) buffer = mCurrentTarget; + } + else + { + return EMBER_ZCL_STATUS_FAILURE; + } + + return EMBER_ZCL_STATUS_SUCCESS; +} + +EmberAfStatus TargetNavigator::HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer) +{ + ChipLogProgress(DeviceLayer, "TargetNavigator::HandleWriteAttribute: attrId=%d", static_cast(attributeId)); + return EMBER_ZCL_STATUS_FAILURE; +} + +EmberAfStatus Channel::HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) +{ + ChipLogProgress(DeviceLayer, "Channel::HandleReadAttribute: attrId=%d, maxReadLength=%d", static_cast(attributeId), + maxReadLength); + return EMBER_ZCL_STATUS_FAILURE; +} + +EmberAfStatus Channel::HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer) +{ + ChipLogProgress(DeviceLayer, "Channel::HandleWriteAttribute: attrId=%d", static_cast(attributeId)); + return EMBER_ZCL_STATUS_FAILURE; +} + } // namespace AppPlatform } // namespace chip diff --git a/src/app/util/ContentApp.h b/src/app/util/ContentApp.h index 729397d12557e7..e9572c0d3dc25c 100644 --- a/src/app/util/ContentApp.h +++ b/src/app/util/ContentApp.h @@ -22,16 +22,32 @@ #pragma once +#include +#include #include +#include +#include +#include #include #include +#include #include #include +#include namespace chip { namespace AppPlatform { -class DLL_EXPORT ApplicationBasic +class DLL_EXPORT ContentAppCluster +{ +public: + virtual ~ContentAppCluster() = default; + + virtual EmberAfStatus HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) = 0; + virtual EmberAfStatus HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer) = 0; +}; + +class DLL_EXPORT ApplicationBasic : public ContentAppCluster { public: virtual ~ApplicationBasic() = default; @@ -44,11 +60,11 @@ class DLL_EXPORT ApplicationBasic virtual const char * GetApplicationVersion() = 0; virtual void SetApplicationStatus(app::Clusters::ApplicationBasic::ApplicationBasicStatus applicationStatus) = 0; - EmberAfStatus HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength); - EmberAfStatus HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer); + EmberAfStatus HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) override; + EmberAfStatus HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer) override; }; -class DLL_EXPORT AccountLogin +class DLL_EXPORT AccountLogin : public ContentAppCluster { public: virtual ~AccountLogin() = default; @@ -57,8 +73,75 @@ class DLL_EXPORT AccountLogin virtual uint32_t GetSetupPIN(const char * tempAccountId) = 0; virtual bool Login(const char * tempAccountId, uint32_t setupPin) = 0; - EmberAfStatus HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength); - EmberAfStatus HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer); + EmberAfStatus HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) override; + EmberAfStatus HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer) override; +}; + +class DLL_EXPORT KeypadInput : public ContentAppCluster +{ +public: + virtual ~KeypadInput() = default; + + EmberAfStatus HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) override; + EmberAfStatus HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer) override; +}; + +class DLL_EXPORT ApplicationLauncher : public ContentAppCluster +{ +public: + virtual ~ApplicationLauncher() = default; + + virtual ApplicationLauncherResponse LaunchApp(ApplicationLauncherApp application, std::string data) = 0; + + EmberAfStatus HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) override; + EmberAfStatus HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer) override; +}; + +class DLL_EXPORT ContentLauncher : public ContentAppCluster +{ +public: + virtual ~ContentLauncher() = default; + + virtual ContentLaunchResponse LaunchContent(std::list parameterList, bool autoplay, + std::string data) = 0; + + EmberAfStatus HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) override; + EmberAfStatus HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer) override; +}; + +class DLL_EXPORT MediaPlayback : public ContentAppCluster +{ +public: + virtual ~MediaPlayback() = default; + + EmberAfStatus HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) override; + EmberAfStatus HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer) override; +}; + +class DLL_EXPORT TargetNavigator : public ContentAppCluster +{ +public: + TargetNavigator(std::list targets, uint8_t currentTarget); + virtual ~TargetNavigator() = default; + + TargetNavigatorResponse NavigateTarget(uint8_t target, std::string data); + CHIP_ERROR GetTargetInfoList(chip::app::AttributeValueEncoder & aEncoder); + + EmberAfStatus HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) override; + EmberAfStatus HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer) override; + +protected: + std::list mTargets; + uint8_t mCurrentTarget; +}; + +class DLL_EXPORT Channel : public ContentAppCluster +{ +public: + virtual ~Channel() = default; + + EmberAfStatus HandleReadAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) override; + EmberAfStatus HandleWriteAttribute(chip::AttributeId attributeId, uint8_t * buffer) override; }; class DLL_EXPORT ContentApp @@ -69,8 +152,14 @@ class DLL_EXPORT ContentApp inline void SetEndpointId(chip::EndpointId id) { mEndpointId = id; }; inline chip::EndpointId GetEndpointId() { return mEndpointId; }; - virtual ApplicationBasic * GetApplicationBasic() = 0; - virtual AccountLogin * GetAccountLogin() = 0; + virtual ApplicationBasic * GetApplicationBasic() = 0; + virtual AccountLogin * GetAccountLogin() = 0; + virtual KeypadInput * GetKeypadInput() = 0; + virtual ApplicationLauncher * GetApplicationLauncher() = 0; + virtual ContentLauncher * GetContentLauncher() = 0; + virtual MediaPlayback * GetMediaPlayback() = 0; + virtual TargetNavigator * GetTargetNavigator() = 0; + virtual Channel * GetChannel() = 0; EmberAfStatus HandleReadAttribute(ClusterId clusterId, chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength); EmberAfStatus HandleWriteAttribute(ClusterId clusterId, chip::AttributeId attributeId, uint8_t * buffer); diff --git a/src/app/util/ContentAppPlatform.cpp b/src/app/util/ContentAppPlatform.cpp index a38e76419be029..3d2acf41d68550 100644 --- a/src/app/util/ContentAppPlatform.cpp +++ b/src/app/util/ContentAppPlatform.cpp @@ -235,6 +235,16 @@ ContentApp * AppPlatform::GetLoadContentAppByVendorId(uint16_t vendorId) return NULL; } +ContentApp * AppPlatform::GetLoadContentAppByAppId(ApplicationLauncherApp application) +{ + ChipLogProgress(DeviceLayer, "GetLoadContentAppByAppId()"); + if (mContentAppFactory != NULL) + { + return mContentAppFactory->LoadContentAppByAppId(application); + } + return NULL; +} + ContentApp * AppPlatform::GetContentAppByEndpointId(chip::EndpointId id) { uint8_t index = 0; diff --git a/src/app/util/ContentAppPlatform.h b/src/app/util/ContentAppPlatform.h index 35c876ca91e9be..0f64e9532d3298 100644 --- a/src/app/util/ContentAppPlatform.h +++ b/src/app/util/ContentAppPlatform.h @@ -37,8 +37,9 @@ namespace AppPlatform { class DLL_EXPORT ContentAppFactory { public: - virtual ~ContentAppFactory() = default; - virtual ContentApp * LoadContentAppByVendorId(uint16_t vendorId) = 0; + virtual ~ContentAppFactory() = default; + virtual ContentApp * LoadContentAppByVendorId(uint16_t vendorId) = 0; + virtual ContentApp * LoadContentAppByAppId(ApplicationLauncherApp application) = 0; }; class DLL_EXPORT AppPlatform @@ -62,6 +63,7 @@ class DLL_EXPORT AppPlatform // load and unload by vendor id void UnloadContentAppByVendorId(uint16_t vendorId); ContentApp * GetLoadContentAppByVendorId(uint16_t vendorId); + ContentApp * GetLoadContentAppByAppId(ApplicationLauncherApp application); // helpful method to get a Content App by endpoint in order to perform attribute or command ops ContentApp * GetContentAppByEndpointId(chip::EndpointId id);