From 87938704ed93dde93e960605ae6a714923efa2e0 Mon Sep 17 00:00:00 2001 From: chrisdecenzo <61757564+chrisdecenzo@users.noreply.github.com> Date: Mon, 18 Apr 2022 18:59:53 -0700 Subject: [PATCH] enable content app platform on android (#17302) * enable content app platform on android * Fix CI * Fix CI * fix restyle * address comments * add casting init shell command --- examples/platform/linux/AppMain.cpp | 324 +------------ examples/platform/linux/BUILD.gn | 33 ++ .../linux/CommissioneeShellCommands.cpp | 9 +- examples/platform/linux/CommissionerMain.cpp | 385 ++++++++++++++++ examples/platform/linux/CommissionerMain.h | 43 ++ .../tv/server/service/MatterServant.java | 7 +- examples/tv-app/android/BUILD.gn | 5 + .../account-login/AccountLoginManager.cpp | 28 +- .../account-login/AccountLoginManager.h | 11 +- .../ApplicationBasicManager.cpp | 11 +- .../ApplicationBasicManager.h | 40 +- .../ApplicationLauncherManager.cpp | 13 +- .../ApplicationLauncherManager.h | 3 + .../audio-output/AudioOutputManager.cpp | 52 ++- .../include/audio-output/AudioOutputManager.h | 11 + .../AppContentLauncherManager.cpp | 79 ++++ .../AppContentLauncherManager.h | 52 +++ .../TargetNavigatorManager.cpp | 33 +- .../target-navigator/TargetNavigatorManager.h | 9 + examples/tv-app/android/java/AppImpl.cpp | 428 ++++++++++++++++++ examples/tv-app/android/java/AppImpl.h | 140 ++++++ examples/tv-app/android/java/TVApp-JNI.cpp | 21 +- .../java/src/com/tcl/chip/tvapp/TvApp.java | 7 +- examples/tv-app/linux/AppImpl.cpp | 92 +++- examples/tv-app/linux/AppImpl.h | 3 + examples/tv-app/linux/main.cpp | 92 +--- examples/tv-casting-app/linux/Casting.h | 1 + .../linux/CastingShellCommands.cpp | 14 +- examples/tv-casting-app/linux/main.cpp | 41 +- 29 files changed, 1510 insertions(+), 477 deletions(-) create mode 100644 examples/platform/linux/CommissionerMain.cpp create mode 100644 examples/platform/linux/CommissionerMain.h create mode 100644 examples/tv-app/android/include/content-launcher/AppContentLauncherManager.cpp create mode 100644 examples/tv-app/android/include/content-launcher/AppContentLauncherManager.h create mode 100644 examples/tv-app/android/java/AppImpl.cpp create mode 100644 examples/tv-app/android/java/AppImpl.h diff --git a/examples/platform/linux/AppMain.cpp b/examples/platform/linux/AppMain.cpp index b4d91babf35fb1..ccb7ae524659d2 100644 --- a/examples/platform/linux/AppMain.cpp +++ b/examples/platform/linux/AppMain.cpp @@ -44,6 +44,7 @@ #include #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE +#include "CommissionerMain.h" #include #include #include @@ -388,326 +389,6 @@ int ChipLinuxAppInit(int argc, char ** argv, OptionSet * customOptions) return 0; } -#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE - -using namespace ::chip; -using namespace ::chip::Inet; -using namespace ::chip::Transport; -using namespace ::chip::Credentials; -using namespace ::chip::DeviceLayer; -using namespace ::chip::Messaging; -using namespace ::chip::Controller; - -class MyServerStorageDelegate : public PersistentStorageDelegate -{ - CHIP_ERROR SyncGetKeyValue(const char * key, void * buffer, uint16_t & size) override - { - ChipLogProgress(AppServer, "Retrieving value from server storage."); - size_t bytesRead = 0; - CHIP_ERROR err = PersistedStorage::KeyValueStoreMgr().Get(key, buffer, size, &bytesRead); - - if (err == CHIP_NO_ERROR) - { - ChipLogProgress(AppServer, "Retrieved value from server storage."); - } - size = static_cast(bytesRead); - return err; - } - - CHIP_ERROR SyncSetKeyValue(const char * key, const void * value, uint16_t size) override - { - ChipLogProgress(AppServer, "Stored value in server storage"); - return PersistedStorage::KeyValueStoreMgr().Put(key, value, size); - } - - CHIP_ERROR SyncDeleteKeyValue(const char * key) override - { - ChipLogProgress(AppServer, "Delete value in server storage"); - return PersistedStorage::KeyValueStoreMgr().Delete(key); - } -}; - -class MyCommissionerCallback : public CommissionerCallback -{ - void ReadyForCommissioning(uint32_t pincode, uint16_t longDiscriminator, PeerAddress peerAddress) override - { - CommissionerPairOnNetwork(pincode, longDiscriminator, peerAddress); - } -}; - -DeviceCommissioner gCommissioner; -CommissionerDiscoveryController gCommissionerDiscoveryController; -MyCommissionerCallback gCommissionerCallback; -MyServerStorageDelegate gServerStorage; -ExampleOperationalCredentialsIssuer gOpCredsIssuer; -NodeId gLocalId = kMaxOperationalNodeId; -Credentials::GroupDataProviderImpl gGroupDataProvider; - -CHIP_ERROR InitCommissioner() -{ - Controller::FactoryInitParams factoryParams; - Controller::SetupParams params; - - // use a different listen port for the commissioner than the default used by chip-tool. - factoryParams.listenPort = LinuxDeviceOptions::GetInstance().securedCommissionerPort + 10; - factoryParams.fabricIndependentStorage = &gServerStorage; - - gGroupDataProvider.SetStorageDelegate(&gServerStorage); - ReturnErrorOnFailure(gGroupDataProvider.Init()); - factoryParams.groupDataProvider = &gGroupDataProvider; - - params.operationalCredentialsDelegate = &gOpCredsIssuer; - - ReturnErrorOnFailure(gOpCredsIssuer.Initialize(gServerStorage)); - - // No need to explicitly set the UDC port since we will use default - ReturnErrorOnFailure(gCommissioner.SetUdcListenPort(LinuxDeviceOptions::GetInstance().unsecuredCommissionerPort)); - - // Initialize device attestation verifier - // TODO: Replace testingRootStore with a AttestationTrustStore that has the necessary official PAA roots available - const Credentials::AttestationTrustStore * testingRootStore = Credentials::GetTestAttestationTrustStore(); - SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore)); - - Platform::ScopedMemoryBuffer noc; - VerifyOrReturnError(noc.Alloc(Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY); - MutableByteSpan nocSpan(noc.Get(), Controller::kMaxCHIPDERCertLength); - - Platform::ScopedMemoryBuffer icac; - VerifyOrReturnError(icac.Alloc(Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY); - MutableByteSpan icacSpan(icac.Get(), Controller::kMaxCHIPDERCertLength); - - Platform::ScopedMemoryBuffer rcac; - VerifyOrReturnError(rcac.Alloc(Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY); - MutableByteSpan rcacSpan(rcac.Get(), Controller::kMaxCHIPDERCertLength); - - Crypto::P256Keypair ephemeralKey; - ReturnErrorOnFailure(ephemeralKey.Initialize()); - - ReturnErrorOnFailure(gOpCredsIssuer.GenerateNOCChainAfterValidation(gLocalId, /* fabricId = */ 1, chip::kUndefinedCATs, - ephemeralKey.Pubkey(), rcacSpan, icacSpan, nocSpan)); - - params.operationalKeypair = &ephemeralKey; - params.controllerRCAC = rcacSpan; - params.controllerICAC = icacSpan; - params.controllerNOC = nocSpan; - - auto & factory = Controller::DeviceControllerFactory::GetInstance(); - ReturnErrorOnFailure(factory.Init(factoryParams)); - ReturnErrorOnFailure(factory.SetupCommissioner(params, gCommissioner)); - - chip::FabricInfo * fabricInfo = gCommissioner.GetFabricInfo(); - VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_INTERNAL); - - uint8_t compressedFabricId[sizeof(uint64_t)] = { 0 }; - MutableByteSpan compressedFabricIdSpan(compressedFabricId); - ReturnErrorOnFailure(fabricInfo->GetCompressedId(compressedFabricIdSpan)); - ChipLogProgress(Support, "Setting up group data for Fabric Index %u with Compressed Fabric ID:", - static_cast(fabricInfo->GetFabricIndex())); - ChipLogByteSpan(Support, compressedFabricIdSpan); - - // TODO: Once ExampleOperationalCredentialsIssuer has support, set default IPK on it as well so - // that commissioned devices get the IPK set from real values rather than "test-only" internal hookups. - ByteSpan defaultIpk = chip::GroupTesting::DefaultIpkValue::GetDefaultIpk(); - ReturnLogErrorOnFailure(chip::Credentials::SetSingleIpkEpochKey(&gGroupDataProvider, fabricInfo->GetFabricIndex(), defaultIpk, - compressedFabricIdSpan)); - - gCommissionerDiscoveryController.SetUserDirectedCommissioningServer(gCommissioner.GetUserDirectedCommissioningServer()); - gCommissionerDiscoveryController.SetCommissionerCallback(&gCommissionerCallback); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR ShutdownCommissioner() -{ - UserDirectedCommissioningServer * udcServer = gCommissioner.GetUserDirectedCommissioningServer(); - if (udcServer != nullptr) - { - udcServer->SetUserConfirmationProvider(nullptr); - } - - gCommissioner.Shutdown(); - return CHIP_NO_ERROR; -} - -class PairingCommand : public Controller::DevicePairingDelegate -{ -public: - PairingCommand() : - mOnDeviceConnectedCallback(OnDeviceConnectedFn, this), - mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this){}; - - /////////// DevicePairingDelegate Interface ///////// - void OnStatusUpdate(Controller::DevicePairingDelegate::Status status) override; - void OnPairingComplete(CHIP_ERROR error) override; - void OnPairingDeleted(CHIP_ERROR error) override; - void OnCommissioningComplete(NodeId deviceId, CHIP_ERROR error) override; - - CHIP_ERROR UpdateNetworkAddress(); - -private: -#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - static void OnDeviceConnectedFn(void * context, chip::OperationalDeviceProxy * device); - static void OnDeviceConnectionFailureFn(void * context, PeerId peerId, CHIP_ERROR error); - - chip::Callback::Callback mOnDeviceConnectedCallback; - chip::Callback::Callback mOnDeviceConnectionFailureCallback; -#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED -}; - -PairingCommand gPairingCommand; -NodeId gRemoteId = kTestDeviceNodeId; - -CHIP_ERROR PairingCommand::UpdateNetworkAddress() -{ - ChipLogProgress(AppServer, "Mdns: Updating NodeId: %" PRIx64 " ...", gRemoteId); - return gCommissioner.UpdateDevice(gRemoteId); -} - -void PairingCommand::OnStatusUpdate(DevicePairingDelegate::Status status) -{ - switch (status) - { - case DevicePairingDelegate::Status::SecurePairingSuccess: - ChipLogProgress(AppServer, "Secure Pairing Success"); - break; - case DevicePairingDelegate::Status::SecurePairingFailed: - ChipLogError(AppServer, "Secure Pairing Failed"); - break; - } -} - -void PairingCommand::OnPairingComplete(CHIP_ERROR err) -{ - if (err == CHIP_NO_ERROR) - { - ChipLogProgress(AppServer, "Pairing Success"); - } - else - { - ChipLogProgress(AppServer, "Pairing Failure: %s", ErrorStr(err)); - // For some devices, it may take more time to appear on the network and become discoverable - // over DNS-SD, so don't give up on failure and restart the address update. Note that this - // will not be repeated endlessly as each chip-tool command has a timeout (in the case of - // the `pairing` command it equals 120s). - // UpdateNetworkAddress(); - } -} - -void PairingCommand::OnPairingDeleted(CHIP_ERROR err) -{ - if (err == CHIP_NO_ERROR) - { - ChipLogProgress(AppServer, "Pairing Deleted Success"); - } - else - { - ChipLogProgress(AppServer, "Pairing Deleted Failure: %s", ErrorStr(err)); - } -} - -void PairingCommand::OnCommissioningComplete(NodeId nodeId, CHIP_ERROR err) -{ - if (err == CHIP_NO_ERROR) - { -#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - ChipLogProgress(AppServer, "Device commissioning completed with success - getting OperationalDeviceProxy"); - - gCommissioner.GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback); -#else // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - ChipLogProgress(AppServer, "Device commissioning completed with success"); -#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - } - else - { - ChipLogProgress(AppServer, "Device commissioning Failure: %s", ErrorStr(err)); -#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); - if (cdc != nullptr) - { - cdc->CommissioningFailed(err); - } -#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - } -} - -#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - -void PairingCommand::OnDeviceConnectedFn(void * context, chip::OperationalDeviceProxy * device) -{ - ChipLogProgress(Controller, "OnDeviceConnectedFn"); - CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); - - if (device == nullptr) - { - ChipLogProgress(AppServer, "No OperationalDeviceProxy returned from OnDeviceConnectedFn"); - if (cdc != nullptr) - { - cdc->CommissioningFailed(CHIP_ERROR_INCORRECT_STATE); - } - return; - } - - if (cdc != nullptr) - { - // TODO: get from DAC! - UDCClientState * udc = cdc->GetUDCClientState(); - uint16_t vendorId = (udc == nullptr ? 0 : udc->GetVendorId()); - uint16_t productId = (udc == nullptr ? 0 : udc->GetProductId()); - cdc->CommissioningSucceeded(vendorId, productId, gRemoteId, device); - } -} - -void PairingCommand::OnDeviceConnectionFailureFn(void * context, PeerId peerId, CHIP_ERROR err) -{ - ChipLogProgress(Controller, "OnDeviceConnectionFailureFn - attempt to get OperationalDeviceProxy failed"); - CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); - { - cdc->CommissioningFailed(err); - } -} - -#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - -CHIP_ERROR CommissionerPairOnNetwork(uint32_t pincode, uint16_t disc, Transport::PeerAddress address) -{ - RendezvousParameters params = RendezvousParameters().SetSetupPINCode(pincode).SetDiscriminator(disc).SetPeerAddress(address); - - gCommissioner.RegisterPairingDelegate(&gPairingCommand); - gCommissioner.PairDevice(gRemoteId, params); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR CommissionerPairUDC(uint32_t pincode, size_t index) -{ - UDCClientState * state = gCommissioner.GetUserDirectedCommissioningServer()->GetUDCClients().GetUDCClientState(index); - if (state == nullptr) - { - ChipLogProgress(AppServer, "udc client[%ld] null \r\n", index); - return CHIP_ERROR_KEY_NOT_FOUND; - } - else - { - Transport::PeerAddress peerAddress = state->GetPeerAddress(); - - state->SetUDCClientProcessingState(UDCClientProcessingState::kCommissioningNode); - - return CommissionerPairOnNetwork(pincode, state->GetLongDiscriminator(), peerAddress); - } -} - -DeviceCommissioner * GetDeviceCommissioner() -{ - return &gCommissioner; -} - -CommissionerDiscoveryController * GetCommissionerDiscoveryController() -{ - return &gCommissionerDiscoveryController; -} - -#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE - void ChipLinuxAppMainLoop(DeviceAttestationCredentialsProvider * dacProvider) { static chip::CommonCaseDeviceServerInitParams initParams; @@ -745,7 +426,8 @@ void ChipLinuxAppMainLoop(DeviceAttestationCredentialsProvider * dacProvider) #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE ChipLogProgress(AppServer, "Starting commissioner"); - VerifyOrReturn(InitCommissioner() == CHIP_NO_ERROR); + VerifyOrReturn(InitCommissioner(LinuxDeviceOptions::GetInstance().securedCommissionerPort + 10, + LinuxDeviceOptions::GetInstance().unsecuredCommissionerPort) == CHIP_NO_ERROR); ChipLogProgress(AppServer, "Started commissioner"); #if defined(ENABLE_CHIP_SHELL) Shell::RegisterControllerCommands(); diff --git a/examples/platform/linux/BUILD.gn b/examples/platform/linux/BUILD.gn index 1db7f364e8ba4d..4cb3655e74ee51 100644 --- a/examples/platform/linux/BUILD.gn +++ b/examples/platform/linux/BUILD.gn @@ -29,6 +29,8 @@ source_set("app-main") { "AppMain.h", "CommissioneeShellCommands.cpp", "CommissioneeShellCommands.h", + "CommissionerMain.cpp", + "CommissionerMain.h", "ControllerShellCommands.cpp", "ControllerShellCommands.h", "LinuxCommissionableDataProvider.cpp", @@ -60,3 +62,34 @@ source_set("app-main") { public_configs = [ ":app-main-config" ] } + +source_set("commissioner-main") { + defines = [] + sources = [ + "CommissionerMain.cpp", + "CommissionerMain.h", + ] + + defines = [] + + if (chip_enable_pw_rpc) { + defines += [ "PW_RPC_ENABLED" ] + } + if (chip_build_libshell) { + defines += [ "ENABLE_CHIP_SHELL" ] + } + + public_deps = [ + "${chip_root}/src/app/server", + "${chip_root}/src/credentials:default_attestation_verifier", + "${chip_root}/src/lib", + "${chip_root}/src/lib/shell", + "${chip_root}/src/lib/shell:shell_core", + ] + + if (chip_enable_transport_trace) { + public_deps += [ "${chip_root}/examples/common/tracing:trace_handlers" ] + } + + public_configs = [ ":app-main-config" ] +} diff --git a/examples/platform/linux/CommissioneeShellCommands.cpp b/examples/platform/linux/CommissioneeShellCommands.cpp index a07a6bb4e31489..73cc376bd8db7e 100644 --- a/examples/platform/linux/CommissioneeShellCommands.cpp +++ b/examples/platform/linux/CommissioneeShellCommands.cpp @@ -72,6 +72,7 @@ static CHIP_ERROR PrintAllCommands() " restartmdns (disabled|enabled_basic|enabled_enhanced) Start Mdns with given " "settings. Usage: commissionee " "restartmdns enabled_basic\r\n"); + streamer_printf(sout, " startbcm Start basic commissioning mode. Usage: commissionee startbcm\r\n"); streamer_printf(sout, "\r\n"); return CHIP_NO_ERROR; @@ -84,7 +85,7 @@ static CHIP_ERROR CommissioneeHandler(int argc, char ** argv) return PrintAllCommands(); } #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT - else if (strcmp(argv[0], "sendudc") == 0) + if (strcmp(argv[0], "sendudc") == 0) { char * eptr; chip::Inet::IPAddress commissioner; @@ -132,7 +133,11 @@ static CHIP_ERROR CommissioneeHandler(int argc, char ** argv) } return PrintAllCommands(); } - + if (strcmp(argv[0], "startbcm") == 0) + { + Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow(); + return CHIP_NO_ERROR; + } return CHIP_ERROR_INVALID_ARGUMENT; } diff --git a/examples/platform/linux/CommissionerMain.cpp b/examples/platform/linux/CommissionerMain.cpp new file mode 100644 index 00000000000000..e26e18b5ad1eb7 --- /dev/null +++ b/examples/platform/linux/CommissionerMain.cpp @@ -0,0 +1,385 @@ +/* + * + * Copyright (c) 2021-2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#if defined(PW_RPC_ENABLED) +#include +#endif + +#if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED +#include "TraceHandlers.h" +#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED + +#include + +#include "CommissionerMain.h" + +using namespace chip; +using namespace chip::Credentials; +using namespace chip::DeviceLayer; +using namespace chip::Inet; +using namespace chip::Transport; +using namespace chip::app::Clusters; + +using namespace ::chip::Messaging; +using namespace ::chip::Controller; + +class MyServerStorageDelegate : public PersistentStorageDelegate +{ + CHIP_ERROR SyncGetKeyValue(const char * key, void * buffer, uint16_t & size) override + { + ChipLogProgress(AppServer, "Retrieving value from server storage."); + size_t bytesRead = 0; + CHIP_ERROR err = PersistedStorage::KeyValueStoreMgr().Get(key, buffer, size, &bytesRead); + + if (err == CHIP_NO_ERROR) + { + ChipLogProgress(AppServer, "Retrieved value from server storage."); + } + size = static_cast(bytesRead); + return err; + } + + CHIP_ERROR SyncSetKeyValue(const char * key, const void * value, uint16_t size) override + { + ChipLogProgress(AppServer, "Stored value in server storage"); + return PersistedStorage::KeyValueStoreMgr().Put(key, value, size); + } + + CHIP_ERROR SyncDeleteKeyValue(const char * key) override + { + ChipLogProgress(AppServer, "Delete value in server storage"); + return PersistedStorage::KeyValueStoreMgr().Delete(key); + } +}; + +class MyCommissionerCallback : public CommissionerCallback +{ + void ReadyForCommissioning(uint32_t pincode, uint16_t longDiscriminator, PeerAddress peerAddress) override + { + CommissionerPairOnNetwork(pincode, longDiscriminator, peerAddress); + } +}; + +DeviceCommissioner gCommissioner; +CommissionerDiscoveryController gCommissionerDiscoveryController; +MyCommissionerCallback gCommissionerCallback; +MyServerStorageDelegate gServerStorage; +ExampleOperationalCredentialsIssuer gOpCredsIssuer; +NodeId gLocalId = kMaxOperationalNodeId; +Credentials::GroupDataProviderImpl gGroupDataProvider; + +CHIP_ERROR InitCommissioner(uint16_t commissionerPort, uint16_t udcListenPort) +{ + Controller::FactoryInitParams factoryParams; + Controller::SetupParams params; + + // use a different listen port for the commissioner than the default used by chip-tool. + factoryParams.listenPort = commissionerPort; + factoryParams.fabricIndependentStorage = &gServerStorage; + + gGroupDataProvider.SetStorageDelegate(&gServerStorage); + ReturnErrorOnFailure(gGroupDataProvider.Init()); + factoryParams.groupDataProvider = &gGroupDataProvider; + + params.operationalCredentialsDelegate = &gOpCredsIssuer; + + ReturnErrorOnFailure(gOpCredsIssuer.Initialize(gServerStorage)); + + // No need to explicitly set the UDC port since we will use default + ReturnErrorOnFailure(gCommissioner.SetUdcListenPort(udcListenPort)); + + // Initialize device attestation verifier + // TODO: Replace testingRootStore with a AttestationTrustStore that has the necessary official PAA roots available + const Credentials::AttestationTrustStore * testingRootStore = Credentials::GetTestAttestationTrustStore(); + SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore)); + + Platform::ScopedMemoryBuffer noc; + VerifyOrReturnError(noc.Alloc(Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY); + MutableByteSpan nocSpan(noc.Get(), Controller::kMaxCHIPDERCertLength); + + Platform::ScopedMemoryBuffer icac; + VerifyOrReturnError(icac.Alloc(Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY); + MutableByteSpan icacSpan(icac.Get(), Controller::kMaxCHIPDERCertLength); + + Platform::ScopedMemoryBuffer rcac; + VerifyOrReturnError(rcac.Alloc(Controller::kMaxCHIPDERCertLength), CHIP_ERROR_NO_MEMORY); + MutableByteSpan rcacSpan(rcac.Get(), Controller::kMaxCHIPDERCertLength); + + Crypto::P256Keypair ephemeralKey; + ReturnErrorOnFailure(ephemeralKey.Initialize()); + + ReturnErrorOnFailure(gOpCredsIssuer.GenerateNOCChainAfterValidation(gLocalId, /* fabricId = */ 1, chip::kUndefinedCATs, + ephemeralKey.Pubkey(), rcacSpan, icacSpan, nocSpan)); + + params.operationalKeypair = &ephemeralKey; + params.controllerRCAC = rcacSpan; + params.controllerICAC = icacSpan; + params.controllerNOC = nocSpan; + + auto & factory = Controller::DeviceControllerFactory::GetInstance(); + ReturnErrorOnFailure(factory.Init(factoryParams)); + ReturnErrorOnFailure(factory.SetupCommissioner(params, gCommissioner)); + + chip::FabricInfo * fabricInfo = gCommissioner.GetFabricInfo(); + VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_INTERNAL); + + uint8_t compressedFabricId[sizeof(uint64_t)] = { 0 }; + MutableByteSpan compressedFabricIdSpan(compressedFabricId); + ReturnErrorOnFailure(fabricInfo->GetCompressedId(compressedFabricIdSpan)); + ChipLogProgress(Support, "Setting up group data for Fabric Index %u with Compressed Fabric ID:", + static_cast(fabricInfo->GetFabricIndex())); + ChipLogByteSpan(Support, compressedFabricIdSpan); + + // TODO: Once ExampleOperationalCredentialsIssuer has support, set default IPK on it as well so + // that commissioned devices get the IPK set from real values rather than "test-only" internal hookups. + ByteSpan defaultIpk = chip::GroupTesting::DefaultIpkValue::GetDefaultIpk(); + ReturnLogErrorOnFailure(chip::Credentials::SetSingleIpkEpochKey(&gGroupDataProvider, fabricInfo->GetFabricIndex(), defaultIpk, + compressedFabricIdSpan)); + + gCommissionerDiscoveryController.SetUserDirectedCommissioningServer(gCommissioner.GetUserDirectedCommissioningServer()); + gCommissionerDiscoveryController.SetCommissionerCallback(&gCommissionerCallback); + + ChipLogProgress(Support, "InitCommissioner nodeId=0x" ChipLogFormatX64 " fabricIndex=%d", + ChipLogValueX64(gCommissioner.GetNodeId()), fabricInfo->GetFabricIndex()); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ShutdownCommissioner() +{ + UserDirectedCommissioningServer * udcServer = gCommissioner.GetUserDirectedCommissioningServer(); + if (udcServer != nullptr) + { + udcServer->SetUserConfirmationProvider(nullptr); + } + + gCommissioner.Shutdown(); + return CHIP_NO_ERROR; +} + +class PairingCommand : public Controller::DevicePairingDelegate +{ +public: + PairingCommand() : + mOnDeviceConnectedCallback(OnDeviceConnectedFn, this), + mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this){}; + + /////////// DevicePairingDelegate Interface ///////// + void OnStatusUpdate(Controller::DevicePairingDelegate::Status status) override; + void OnPairingComplete(CHIP_ERROR error) override; + void OnPairingDeleted(CHIP_ERROR error) override; + void OnCommissioningComplete(NodeId deviceId, CHIP_ERROR error) override; + + CHIP_ERROR UpdateNetworkAddress(); + +private: +#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + static void OnDeviceConnectedFn(void * context, chip::OperationalDeviceProxy * device); + static void OnDeviceConnectionFailureFn(void * context, PeerId peerId, CHIP_ERROR error); + + chip::Callback::Callback mOnDeviceConnectedCallback; + chip::Callback::Callback mOnDeviceConnectionFailureCallback; +#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED +}; + +PairingCommand gPairingCommand; +NodeId gRemoteId = kTestDeviceNodeId; + +CHIP_ERROR PairingCommand::UpdateNetworkAddress() +{ + ChipLogProgress(AppServer, "Mdns: Updating NodeId: %" PRIx64 " ...", gRemoteId); + return gCommissioner.UpdateDevice(gRemoteId); +} + +void PairingCommand::OnStatusUpdate(DevicePairingDelegate::Status status) +{ + switch (status) + { + case DevicePairingDelegate::Status::SecurePairingSuccess: + ChipLogProgress(AppServer, "Secure Pairing Success"); + break; + case DevicePairingDelegate::Status::SecurePairingFailed: + ChipLogError(AppServer, "Secure Pairing Failed"); + break; + } +} + +void PairingCommand::OnPairingComplete(CHIP_ERROR err) +{ + if (err == CHIP_NO_ERROR) + { + ChipLogProgress(AppServer, "Pairing Success"); + } + else + { + ChipLogProgress(AppServer, "Pairing Failure: %s", ErrorStr(err)); + // For some devices, it may take more time to appear on the network and become discoverable + // over DNS-SD, so don't give up on failure and restart the address update. Note that this + // will not be repeated endlessly as each chip-tool command has a timeout (in the case of + // the `pairing` command it equals 120s). + // UpdateNetworkAddress(); + } +} + +void PairingCommand::OnPairingDeleted(CHIP_ERROR err) +{ + if (err == CHIP_NO_ERROR) + { + ChipLogProgress(AppServer, "Pairing Deleted Success"); + } + else + { + ChipLogProgress(AppServer, "Pairing Deleted Failure: %s", ErrorStr(err)); + } +} + +void PairingCommand::OnCommissioningComplete(NodeId nodeId, CHIP_ERROR err) +{ + if (err == CHIP_NO_ERROR) + { +#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + ChipLogProgress(AppServer, "Device commissioning completed with success - getting OperationalDeviceProxy"); + + gCommissioner.GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback); +#else // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + ChipLogProgress(AppServer, "Device commissioning completed with success"); +#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + } + else + { + ChipLogProgress(AppServer, "Device commissioning Failure: %s", ErrorStr(err)); +#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); + if (cdc != nullptr) + { + cdc->CommissioningFailed(err); + } +#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + } +} + +#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + +void PairingCommand::OnDeviceConnectedFn(void * context, chip::OperationalDeviceProxy * device) +{ + ChipLogProgress(Controller, "OnDeviceConnectedFn"); + CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); + + if (device == nullptr) + { + ChipLogProgress(AppServer, "No OperationalDeviceProxy returned from OnDeviceConnectedFn"); + if (cdc != nullptr) + { + cdc->CommissioningFailed(CHIP_ERROR_INCORRECT_STATE); + } + return; + } + + if (cdc != nullptr) + { + // TODO: get from DAC! + UDCClientState * udc = cdc->GetUDCClientState(); + uint16_t vendorId = (udc == nullptr ? 0 : udc->GetVendorId()); + uint16_t productId = (udc == nullptr ? 0 : udc->GetProductId()); + cdc->CommissioningSucceeded(vendorId, productId, gRemoteId, device); + } +} + +void PairingCommand::OnDeviceConnectionFailureFn(void * context, PeerId peerId, CHIP_ERROR err) +{ + ChipLogProgress(Controller, "OnDeviceConnectionFailureFn - attempt to get OperationalDeviceProxy failed"); + CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); + { + cdc->CommissioningFailed(err); + } +} + +#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + +CHIP_ERROR CommissionerPairOnNetwork(uint32_t pincode, uint16_t disc, Transport::PeerAddress address) +{ + RendezvousParameters params = RendezvousParameters().SetSetupPINCode(pincode).SetDiscriminator(disc).SetPeerAddress(address); + + gCommissioner.RegisterPairingDelegate(&gPairingCommand); + gCommissioner.PairDevice(gRemoteId, params); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR CommissionerPairUDC(uint32_t pincode, size_t index) +{ + UDCClientState * state = gCommissioner.GetUserDirectedCommissioningServer()->GetUDCClients().GetUDCClientState(index); + if (state == nullptr) + { + ChipLogProgress(AppServer, "udc client[%ld] null \r\n", static_cast(index)); + return CHIP_ERROR_KEY_NOT_FOUND; + } + else + { + Transport::PeerAddress peerAddress = state->GetPeerAddress(); + + state->SetUDCClientProcessingState(UDCClientProcessingState::kCommissioningNode); + + return CommissionerPairOnNetwork(pincode, state->GetLongDiscriminator(), peerAddress); + } +} + +DeviceCommissioner * GetDeviceCommissioner() +{ + return &gCommissioner; +} + +CommissionerDiscoveryController * GetCommissionerDiscoveryController() +{ + return &gCommissionerDiscoveryController; +} + +#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE diff --git a/examples/platform/linux/CommissionerMain.h b/examples/platform/linux/CommissionerMain.h new file mode 100644 index 00000000000000..73141c335ed8ae --- /dev/null +++ b/examples/platform/linux/CommissionerMain.h @@ -0,0 +1,43 @@ +/* + * + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE + +using chip::Controller::DeviceCommissioner; +using chip::Transport::PeerAddress; + +CHIP_ERROR CommissionerPairOnNetwork(uint32_t pincode, uint16_t disc, PeerAddress address); +CHIP_ERROR CommissionerPairUDC(uint32_t pincode, size_t index); + +CHIP_ERROR InitCommissioner(uint16_t commissionerPort, uint16_t udcListenPort); +CHIP_ERROR ShutdownCommissioner(); + +DeviceCommissioner * GetDeviceCommissioner(); +CommissionerDiscoveryController * GetCommissionerDiscoveryController(); + +#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE diff --git a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java index bf1e85019931dc..904cf4251c22fd 100644 --- a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java +++ b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java @@ -65,8 +65,9 @@ public void init(@NonNull Context context) { // The order is important, must // first new TvApp to load dynamic library // then chipPlatform to prepare platform - // then TvApp.postInit to init app which needs platform + // then TvApp.preServerInit to initialize any server configuration // then start ChipAppServer + // then TvApp.postServerInit to init app platform mTvApp = new TvApp( (app, clusterId, endpoint) -> { @@ -117,10 +118,12 @@ public void init(@NonNull Context context) { chipPlatform.updateCommissionableDataProviderData( null, null, 0, testSetupPasscode, testDiscriminator); - mTvApp.postInit(); + mTvApp.preServerInit(); chipAppServer = new ChipAppServer(); chipAppServer.startApp(); + + mTvApp.postServerInit(); } public void restart() { diff --git a/examples/tv-app/android/BUILD.gn b/examples/tv-app/android/BUILD.gn index 7f7b1b1c689df8..d354573bbd622b 100644 --- a/examples/tv-app/android/BUILD.gn +++ b/examples/tv-app/android/BUILD.gn @@ -33,10 +33,14 @@ shared_library("jni") { "include/audio-output/AudioOutputManager.cpp", "include/audio-output/AudioOutputManager.h", "include/cluster-init.cpp", + "include/content-launcher/AppContentLauncherManager.cpp", + "include/content-launcher/AppContentLauncherManager.h", "include/endpoint-configuration/EndpointConfigurationStorage.cpp", "include/endpoint-configuration/EndpointConfigurationStorage.h", "include/target-navigator/TargetNavigatorManager.cpp", "include/target-navigator/TargetNavigatorManager.h", + "java/AppImpl.cpp", + "java/AppImpl.h", "java/ChannelManager.cpp", "java/ChannelManager.h", "java/ClusterChangeAttribute.cpp", @@ -62,6 +66,7 @@ shared_library("jni") { ] deps = [ + "${chip_root}/examples/platform/linux:commissioner-main", "${chip_root}/examples/tv-app/tv-common", "${chip_root}/src/app/server/java:jni", "${chip_root}/src/lib", diff --git a/examples/tv-app/android/include/account-login/AccountLoginManager.cpp b/examples/tv-app/android/include/account-login/AccountLoginManager.cpp index 1d2ae613d56cd2..edf79a5367ed91 100644 --- a/examples/tv-app/android/include/account-login/AccountLoginManager.cpp +++ b/examples/tv-app/android/include/account-login/AccountLoginManager.cpp @@ -23,15 +23,28 @@ using namespace std; using namespace chip::app::Clusters::AccountLogin; -bool AccountLoginManager::HandleLogin(const chip::CharSpan & tempAccountIdentifier, const chip::CharSpan & setupPin) +AccountLoginManager::AccountLoginManager(const char * setupPin) +{ + CopyString(mSetupPin, sizeof(mSetupPin), setupPin); +} + +bool AccountLoginManager::HandleLogin(const CharSpan & tempAccountIdentifier, const CharSpan & setupPin) { string tempAccountIdentifierString(tempAccountIdentifier.data(), tempAccountIdentifier.size()); string setupPinString(setupPin.data(), setupPin.size()); ChipLogProgress(Zcl, "temporary account id: %s", tempAccountIdentifierString.c_str()); ChipLogProgress(Zcl, "setup pin %s", setupPinString.c_str()); - // TODO: Insert your code here to handle login request - return true; + if (strcmp(mSetupPin, setupPinString.c_str()) == 0) + { + ChipLogProgress(Zcl, "AccountLoginManager::HandleLogin success"); + return true; + } + else + { + ChipLogProgress(Zcl, "AccountLoginManager::HandleLogin failed expected pin %s", mSetupPin); + return false; + } } bool AccountLoginManager::HandleLogout() @@ -44,9 +57,10 @@ void AccountLoginManager::HandleGetSetupPin(CommandResponseHelper +using chip::CharSpan; using chip::app::AttributeValueEncoder; +using chip::Platform::CopyString; using ApplicationBasicDelegate = chip::app::Clusters::ApplicationBasic::Delegate; class ApplicationBasicManager : public ApplicationBasicDelegate { public: + ApplicationBasicManager() : + ApplicationBasicManager(123, "applicationId", "exampleVendorName1", 1, "exampleName1", 1, "exampleVersion"){}; + ApplicationBasicManager(uint16_t szCatalogVendorId, const char * szApplicationId, const char * szVendorName, uint16_t vendorId, + const char * szApplicationName, uint16_t productId, const char * szApplicationVersion) : + ApplicationBasicDelegate(szCatalogVendorId, szApplicationId) + { + + ChipLogProgress(DeviceLayer, "ApplicationBasic[%s]: Application Name=\"%s\"", szApplicationId, szApplicationName); + + CopyString(mApplicationName, sizeof(mApplicationName), szApplicationName); + CopyString(mVendorName, sizeof(mVendorName), szVendorName); + mVendorId = vendorId; + CopyString(mApplicationVersion, sizeof(mApplicationVersion), szApplicationVersion); + mProductId = productId; + static const uint16_t kTestVendorId = 456; // CI test cases require this vendor id + mAllowedVendorList.push_back(vendorId); + mAllowedVendorList.push_back(kTestVendorId); + }; + virtual ~ApplicationBasicManager(){}; + CHIP_ERROR HandleGetVendorName(AttributeValueEncoder & aEncoder) override; uint16_t HandleGetVendorId() override; CHIP_ERROR HandleGetApplicationName(AttributeValueEncoder & aEncoder) override; @@ -33,9 +55,17 @@ class ApplicationBasicManager : public ApplicationBasicDelegate CHIP_ERROR HandleGetApplicationVersion(AttributeValueEncoder & aEncoder) override; CHIP_ERROR HandleGetAllowedVendorList(AttributeValueEncoder & aEncoder) override; - std::list GetAllowedVendorList() override - { - static const uint16_t kTestVendorId = 456; // CI test cases require this vendor id - return { HandleGetVendorId(), kTestVendorId }; - }; + std::list GetAllowedVendorList() override { return mAllowedVendorList; }; + +protected: + static const int kVendorNameSize = 32; + static const int kApplicationNameSize = 32; + static const int kApplicationVersionSize = 32; + + char mVendorName[kVendorNameSize]; + uint16_t mVendorId; + char mApplicationName[kApplicationNameSize]; + uint16_t mProductId; + char mApplicationVersion[kApplicationVersionSize]; + std::list mAllowedVendorList = {}; }; diff --git a/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.cpp b/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.cpp index 20340e478cbae1..f8b5043d5dac56 100644 --- a/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.cpp +++ b/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.cpp @@ -20,6 +20,7 @@ using namespace std; using namespace chip::app; +using namespace chip::app::Clusters; using namespace chip::app::Clusters::ApplicationLauncher; using namespace chip::Uint8; @@ -38,8 +39,10 @@ CHIP_ERROR ApplicationLauncherManager::HandleGetCatalogList(AttributeValueEncode void ApplicationLauncherManager::HandleLaunchApp(CommandResponseHelper & helper, const ByteSpan & data, const ApplicationType & application) { + ChipLogProgress(Zcl, "ApplicationLauncherManager::HandleLaunchApp"); + // TODO: Insert code here - Commands::LauncherResponse::Type response; + LauncherResponseType response; const char * buf = "data"; response.data = ByteSpan(from_const_char(buf), strlen(buf)); response.status = StatusEnum::kSuccess; @@ -49,8 +52,10 @@ void ApplicationLauncherManager::HandleLaunchApp(CommandResponseHelper & helper, const ApplicationType & application) { + ChipLogProgress(Zcl, "ApplicationLauncherManager::HandleStopApp"); + // TODO: Insert code here - Commands::LauncherResponse::Type response; + LauncherResponseType response; const char * buf = "data"; response.data = ByteSpan(from_const_char(buf), strlen(buf)); response.status = StatusEnum::kSuccess; @@ -60,8 +65,10 @@ void ApplicationLauncherManager::HandleStopApp(CommandResponseHelper & helper, const ApplicationType & application) { + ChipLogProgress(Zcl, "ApplicationLauncherManager::HandleHideApp"); + // TODO: Insert code here - Commands::LauncherResponse::Type response; + LauncherResponseType response; const char * buf = "data"; response.data = ByteSpan(from_const_char(buf), strlen(buf)); response.status = StatusEnum::kSuccess; diff --git a/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.h b/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.h index 84c65e7508aed7..073c20c9831eb3 100644 --- a/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.h +++ b/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.h @@ -31,6 +31,9 @@ using LauncherResponseType = chip::app::Clusters::ApplicationLauncher::Co class ApplicationLauncherManager : public ApplicationLauncherDelegate { public: + ApplicationLauncherManager() : ApplicationLauncherDelegate(){}; + ApplicationLauncherManager(bool featureMapContentPlatform) : ApplicationLauncherDelegate(featureMapContentPlatform){}; + CHIP_ERROR HandleGetCatalogList(AttributeValueEncoder & aEncoder) override; void HandleLaunchApp(CommandResponseHelper & helper, const ByteSpan & data, diff --git a/examples/tv-app/android/include/audio-output/AudioOutputManager.cpp b/examples/tv-app/android/include/audio-output/AudioOutputManager.cpp index c0d806994549ec..1b8a6a36c84912 100644 --- a/examples/tv-app/android/include/audio-output/AudioOutputManager.cpp +++ b/examples/tv-app/android/include/audio-output/AudioOutputManager.cpp @@ -22,22 +22,32 @@ using namespace std; using namespace chip::app; using namespace chip::app::Clusters::AudioOutput; +AudioOutputManager::AudioOutputManager() +{ + mCurrentOutput = 1; + + for (int i = 1; i < 4; ++i) + { + OutputInfoType outputInfo; + outputInfo.outputType = chip::app::Clusters::AudioOutput::OutputTypeEnum::kHdmi; + // note: safe only because of use of string literal + outputInfo.name = chip::CharSpan::fromCharString("HDMI"); + outputInfo.index = static_cast(i); + mOutputs.push_back(outputInfo); + } +} + uint8_t AudioOutputManager::HandleGetCurrentOutput() { - return 0; + return mCurrentOutput; } CHIP_ERROR AudioOutputManager::HandleGetOutputList(AttributeValueEncoder & aEncoder) { // TODO: Insert code here - return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { - int maximumVectorSize = 3; - for (int i = 0; i < maximumVectorSize; ++i) + return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { + for (auto const & outputInfo : this->mOutputs) { - chip::app::Clusters::AudioOutput::Structs::OutputInfo::Type outputInfo; - outputInfo.outputType = chip::app::Clusters::AudioOutput::OutputTypeEnum::kHdmi; - outputInfo.name = chip::CharSpan::fromCharString("exampleName"); - outputInfo.index = static_cast(1 + i); ReturnErrorOnFailure(encoder.Encode(outputInfo)); } return CHIP_NO_ERROR; @@ -47,11 +57,33 @@ CHIP_ERROR AudioOutputManager::HandleGetOutputList(AttributeValueEncoder & aEnco bool AudioOutputManager::HandleRenameOutput(const uint8_t & index, const chip::CharSpan & name) { // TODO: Insert code here - return true; + bool audioOutputRenamed = false; + + for (OutputInfoType & output : mOutputs) + { + if (output.index == index) + { + audioOutputRenamed = true; + memcpy(this->Data(index), name.data(), name.size()); + output.name = chip::CharSpan(this->Data(index), name.size()); + } + } + + return audioOutputRenamed; } bool AudioOutputManager::HandleSelectOutput(const uint8_t & index) { // TODO: Insert code here - return true; + bool audioOutputSelected = false; + for (OutputInfoType & output : mOutputs) + { + if (output.index == index) + { + audioOutputSelected = true; + mCurrentOutput = index; + } + } + + return audioOutputSelected; } diff --git a/examples/tv-app/android/include/audio-output/AudioOutputManager.h b/examples/tv-app/android/include/audio-output/AudioOutputManager.h index 44359fa75c8e1f..3ede64310157af 100644 --- a/examples/tv-app/android/include/audio-output/AudioOutputManager.h +++ b/examples/tv-app/android/include/audio-output/AudioOutputManager.h @@ -19,15 +19,26 @@ #pragma once #include +#include using chip::app::AttributeValueEncoder; using AudioOutputDelegate = chip::app::Clusters::AudioOutput::Delegate; +using OutputInfoType = chip::app::Clusters::AudioOutput::Structs::OutputInfo::Type; class AudioOutputManager : public AudioOutputDelegate { public: + AudioOutputManager(); + uint8_t HandleGetCurrentOutput() override; CHIP_ERROR HandleGetOutputList(AttributeValueEncoder & aEncoder) override; bool HandleRenameOutput(const uint8_t & index, const chip::CharSpan & name) override; bool HandleSelectOutput(const uint8_t & index) override; + char * Data(uint8_t index) { return mCharDataBuffer[index]; } + +protected: + uint8_t mCurrentOutput; + std::vector mOutputs; + // Magic numbers are here on purpose, please allocate memory + char mCharDataBuffer[10][32]; }; diff --git a/examples/tv-app/android/include/content-launcher/AppContentLauncherManager.cpp b/examples/tv-app/android/include/content-launcher/AppContentLauncherManager.cpp new file mode 100644 index 00000000000000..1b1deb54eb5771 --- /dev/null +++ b/examples/tv-app/android/include/content-launcher/AppContentLauncherManager.cpp @@ -0,0 +1,79 @@ +/* + * + * 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. + */ + +#include "AppContentLauncherManager.h" + +using namespace std; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::DataModel; +using namespace chip::app::Clusters::ContentLauncher; + +AppContentLauncherManager::AppContentLauncherManager(list acceptHeaderList, uint32_t supportedStreamingProtocols) +{ + mAcceptHeaderList = acceptHeaderList; + mSupportedStreamingProtocols = supportedStreamingProtocols; +} + +void AppContentLauncherManager::HandleLaunchContent(CommandResponseHelper & helper, + const DecodableList & parameterList, bool autoplay, + const CharSpan & data) +{ + ChipLogProgress(Zcl, "AppContentLauncherManager::HandleLaunchContent for endpoint %d", mEndpointId); + string dataString(data.data(), data.size()); + + LaunchResponseType response; + // TODO: Insert code here + response.data = chip::MakeOptional(CharSpan::fromCharString("exampleData")); + response.status = ContentLauncher::StatusEnum::kSuccess; + helper.Success(response); +} + +void AppContentLauncherManager::HandleLaunchUrl(CommandResponseHelper & helper, const CharSpan & contentUrl, + const CharSpan & displayString, const BrandingInformationType & brandingInformation) +{ + ChipLogProgress(Zcl, "AppContentLauncherManager::HandleLaunchUrl"); + + string contentUrlString(contentUrl.data(), contentUrl.size()); + string displayStringString(displayString.data(), displayString.size()); + + // TODO: Insert code here + LaunchResponseType response; + response.data = chip::MakeOptional(CharSpan::fromCharString("exampleData")); + response.status = ContentLauncher::StatusEnum::kSuccess; + helper.Success(response); +} + +CHIP_ERROR AppContentLauncherManager::HandleGetAcceptHeaderList(AttributeValueEncoder & aEncoder) +{ + ChipLogProgress(Zcl, "AppContentLauncherManager::HandleGetAcceptHeaderList"); + return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { + for (std::string & entry : mAcceptHeaderList) + { + CharSpan data = CharSpan::fromCharString(entry.c_str()); + ReturnErrorOnFailure(encoder.Encode(data)); + } + return CHIP_NO_ERROR; + }); +} + +uint32_t AppContentLauncherManager::HandleGetSupportedStreamingProtocols() +{ + ChipLogProgress(Zcl, "AppContentLauncherManager::HandleGetSupportedStreamingProtocols"); + return mSupportedStreamingProtocols; +} diff --git a/examples/tv-app/android/include/content-launcher/AppContentLauncherManager.h b/examples/tv-app/android/include/content-launcher/AppContentLauncherManager.h new file mode 100644 index 00000000000000..223ca948a47752 --- /dev/null +++ b/examples/tv-app/android/include/content-launcher/AppContentLauncherManager.h @@ -0,0 +1,52 @@ +/* + * + * 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. + */ + +#pragma once + +#include + +using chip::CharSpan; +using chip::EndpointId; +using chip::app::AttributeValueEncoder; +using chip::app::CommandResponseHelper; +using ContentLauncherDelegate = chip::app::Clusters::ContentLauncher::Delegate; +using LaunchResponseType = chip::app::Clusters::ContentLauncher::Commands::LaunchResponse::Type; +using ParameterType = chip::app::Clusters::ContentLauncher::Structs::Parameter::DecodableType; +using BrandingInformationType = chip::app::Clusters::ContentLauncher::Structs::BrandingInformation::Type; + +class AppContentLauncherManager : public ContentLauncherDelegate +{ +public: + AppContentLauncherManager() : AppContentLauncherManager({ "example", "example" }, 0){}; + AppContentLauncherManager(std::list acceptHeaderList, uint32_t supportedStreamingProtocols); + + void HandleLaunchContent(CommandResponseHelper & helper, + const chip::app::DataModel::DecodableList & parameterList, bool autoplay, + const CharSpan & data) override; + void HandleLaunchUrl(CommandResponseHelper & helper, const CharSpan & contentUrl, + const CharSpan & displayString, const BrandingInformationType & brandingInformation) override; + CHIP_ERROR HandleGetAcceptHeaderList(AttributeValueEncoder & aEncoder) override; + uint32_t HandleGetSupportedStreamingProtocols() override; + +protected: + std::list mAcceptHeaderList; + uint32_t mSupportedStreamingProtocols; + +private: + EndpointId mEndpointId; +}; diff --git a/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.cpp b/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.cpp index 5b8a0ad46d2109..d0ae459e56fc07 100644 --- a/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.cpp +++ b/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.cpp @@ -21,17 +21,24 @@ using namespace std; using namespace chip::app; using namespace chip::app::Clusters::TargetNavigator; +TargetNavigatorManager::TargetNavigatorManager(std::list targets, uint8_t currentTarget) +{ + mTargets = targets; + mCurrentTarget = currentTarget; +} + CHIP_ERROR TargetNavigatorManager::HandleGetTargetList(AttributeValueEncoder & aEncoder) { // NOTE: the ids for each target start at 1 so that we can reserve 0 as "no current target" - return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { - int maximumVectorSize = 2; - for (int i = 0; i < maximumVectorSize; ++i) + return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { + int i = 0; + for (std::string & entry : mTargets) { Structs::TargetInfo::Type outputInfo; outputInfo.identifier = static_cast(i + 1); - outputInfo.name = chip::CharSpan::fromCharString("exampleName"); + outputInfo.name = CharSpan::fromCharString(entry.c_str()); ReturnErrorOnFailure(encoder.Encode(outputInfo)); + i++; } return CHIP_NO_ERROR; }); @@ -39,15 +46,23 @@ CHIP_ERROR TargetNavigatorManager::HandleGetTargetList(AttributeValueEncoder & a uint8_t TargetNavigatorManager::HandleGetCurrentTarget() { - return 0; + return mCurrentTarget; } void TargetNavigatorManager::HandleNavigateTarget(CommandResponseHelper & helper, const uint64_t & target, const CharSpan & data) { - // TODO: Insert code here - Commands::NavigateTargetResponse::Type response; - response.data = chip::Optional(chip::CharSpan::fromCharString("data response")); - response.status = chip::app::Clusters::TargetNavigator::StatusEnum::kSuccess; + NavigateTargetResponseType response; + if (target == kNoCurrentTarget || target > mTargets.size()) + { + response.data = chip::MakeOptional(CharSpan::fromCharString("error")); + response.status = StatusEnum::kTargetNotFound; + helper.Success(response); + return; + } + mCurrentTarget = static_cast(target); + + response.data = chip::MakeOptional(CharSpan::fromCharString("data response")); + response.status = StatusEnum::kSuccess; helper.Success(response); } diff --git a/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.h b/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.h index b09b2775adbe91..f4cb0b372bc7e3 100644 --- a/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.h +++ b/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.h @@ -29,8 +29,17 @@ using NavigateTargetResponseType = chip::app::Clusters::TargetNavigator::Command class TargetNavigatorManager : public TargetNavigatorDelegate { public: + TargetNavigatorManager() : TargetNavigatorManager({ "exampleName", "exampleName" }, kNoCurrentTarget){}; + TargetNavigatorManager(std::list targets, uint8_t currentTarget); + CHIP_ERROR HandleGetTargetList(AttributeValueEncoder & aEncoder) override; uint8_t HandleGetCurrentTarget() override; void HandleNavigateTarget(CommandResponseHelper & responser, const uint64_t & target, const CharSpan & data) override; + +protected: + // NOTE: the ids for each target start at 1 so that we can reserve 0 as "no current target" + static const uint8_t kNoCurrentTarget = 0; + std::list mTargets; + uint8_t mCurrentTarget; }; diff --git a/examples/tv-app/android/java/AppImpl.cpp b/examples/tv-app/android/java/AppImpl.cpp new file mode 100644 index 00000000000000..cc7444ab0c1882 --- /dev/null +++ b/examples/tv-app/android/java/AppImpl.cpp @@ -0,0 +1,428 @@ +/* + * + * Copyright (c) 2021 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. + */ + +/** + * @file Contains Implementation of the ContentApp and the ContentAppPlatform. + */ + +#include "AppImpl.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::AppPlatform; + +#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE +class MyUserPrompter : public UserPrompter +{ + // tv should override this with a dialog prompt + inline void PromptForCommissionOKPermission(uint16_t vendorId, uint16_t productId, const char * commissioneeName) override + { + /* + * Called to prompt the user for consent to allow the given commissioneeName/vendorId/productId to be commissioned. + * For example "[commissioneeName] is requesting permission to cast to this TV, approve?" + * + * If user responds with OK then implementor should call CommissionerRespondOk(); + * If user responds with Cancel then implementor should call CommissionerRespondCancel(); + * + */ + GetCommissionerDiscoveryController()->Ok(); + + /** + * For Demo: Launch Prime Video App + */ + return; + } + + // tv should override this with a dialog prompt + inline void PromptForCommissionPincode(uint16_t vendorId, uint16_t productId, const char * commissioneeName) override + { + /* + * Called to prompt the user to enter the setup pincode displayed by the given commissioneeName/vendorId/productId to be + * commissioned. For example "Please enter pin displayed in casting app." + * + * If user enters with pin then implementor should call CommissionerRespondPincode(uint32_t pincode); + * If user responds with Cancel then implementor should call CommissionerRespondCancel(); + */ + + GetCommissionerDiscoveryController()->CommissionWithPincode(20202021); // dummy pin code + + /** + * For Demo: Launch Prime Video App + */ + return; + } + + // tv should override this with a dialog prompt + inline void PromptCommissioningSucceeded(uint16_t vendorId, uint16_t productId, const char * commissioneeName) override + { + return; + } + + // tv should override this with a dialog prompt + inline void PromptCommissioningFailed(const char * commissioneeName, CHIP_ERROR error) override { return; } +}; + +MyUserPrompter gMyUserPrompter; +#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE + +#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED +class MyPincodeService : public PincodeService +{ + uint32_t FetchCommissionPincodeFromContentApp(uint16_t vendorId, uint16_t productId, CharSpan rotatingId) override + { + return ContentAppPlatform::GetInstance().GetPincodeFromContentApp(vendorId, productId, rotatingId); + } +}; +MyPincodeService gMyPincodeService; + +class MyPostCommissioningListener : public PostCommissioningListener +{ + void CommissioningCompleted(uint16_t vendorId, uint16_t productId, NodeId nodeId, OperationalDeviceProxy * device) override + { + + ContentAppPlatform::GetInstance().ManageClientAccess(device, vendorId, GetDeviceCommissioner()->GetNodeId(), + OnSuccessResponse, OnFailureResponse); + } + + /* Callback when command results in success */ + static void OnSuccessResponse(void * context) + { + ChipLogProgress(Controller, "OnSuccessResponse - Binding Add Successfully"); + CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); + if (cdc != nullptr) + { + cdc->PostCommissioningSucceeded(); + } + } + + /* Callback when command results in failure */ + static void OnFailureResponse(void * context, CHIP_ERROR error) + { + ChipLogProgress(Controller, "OnFailureResponse - Binding Add Failed"); + CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); + if (cdc != nullptr) + { + cdc->PostCommissioningFailed(error); + } + } +}; + +MyPostCommissioningListener gMyPostCommissioningListener; +ContentAppFactoryImpl gFactory; + +namespace chip { +namespace AppPlatform { + +// BEGIN DYNAMIC ENDPOINTS +// ================================================================================= + +static const int kNameSize = 32; + +// Current ZCL implementation of Struct uses a max-size array of 254 bytes +static const int kDescriptorAttributeArraySize = 254; + +// Device types for dynamic endpoints: TODO Need a generated file from ZAP to define these! +// (taken from chip-devices.xml) +#define DEVICE_TYPE_CONTENT_APP 0x0024 + +// --------------------------------------------------------------------------- +// +// CONTENT APP ENDPOINT: contains the following clusters: +// - Descriptor +// - Application Basic + +// Declare Descriptor cluster attributes +DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(descriptorAttrs) +DECLARE_DYNAMIC_ATTRIBUTE(ZCL_DEVICE_LIST_ATTRIBUTE_ID, ARRAY, kDescriptorAttributeArraySize, 0), /* device list */ + DECLARE_DYNAMIC_ATTRIBUTE(ZCL_SERVER_LIST_ATTRIBUTE_ID, ARRAY, kDescriptorAttributeArraySize, 0), /* server list */ + DECLARE_DYNAMIC_ATTRIBUTE(ZCL_CLIENT_LIST_ATTRIBUTE_ID, ARRAY, kDescriptorAttributeArraySize, 0), /* client list */ + DECLARE_DYNAMIC_ATTRIBUTE(ZCL_PARTS_LIST_ATTRIBUTE_ID, ARRAY, kDescriptorAttributeArraySize, 0), /* parts list */ + DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); + +// Declare Application Basic information cluster attributes +// TODO: add missing attributes once schema is updated +DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(applicationBasicAttrs) +DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_VENDOR_NAME_ATTRIBUTE_ID, CHAR_STRING, kNameSize, 0), /* VendorName */ + DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_VENDOR_ID_ATTRIBUTE_ID, INT16U, 1, 0), /* VendorID */ + DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_NAME_ATTRIBUTE_ID, CHAR_STRING, kNameSize, 0), /* ApplicationName */ + DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_PRODUCT_ID_ATTRIBUTE_ID, INT16U, 1, 0), /* ProductID */ + DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_STATUS_ATTRIBUTE_ID, INT8U, 1, 0), /* ApplicationStatus */ + DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); + +// Declare Keypad Input cluster attributes +DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(keypadInputAttrs) +DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); + +// Declare Application Launcher cluster attributes +// TODO: add missing attributes once schema is updated +DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(applicationLauncherAttrs) +DECLARE_DYNAMIC_ATTRIBUTE(ZCL_APPLICATION_LAUNCHER_LIST_ATTRIBUTE_ID, ARRAY, kDescriptorAttributeArraySize, 0), /* catalog list */ + DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); + +// Declare Account Login cluster attributes +DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(accountLoginAttrs) +DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); + +// Declare Content Launcher cluster attributes +DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(contentLauncherAttrs) +DECLARE_DYNAMIC_ATTRIBUTE(ZCL_CONTENT_LAUNCHER_ACCEPT_HEADER_ATTRIBUTE_ID, ARRAY, kDescriptorAttributeArraySize, + 0), /* accept header list */ + DECLARE_DYNAMIC_ATTRIBUTE(ZCL_CONTENT_LAUNCHER_SUPPORTED_STREAMING_PROTOCOLS_ATTRIBUTE_ID, BITMAP32, 1, + 0), /* streaming protocols */ + DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); + +// Declare Media Playback cluster attributes +// TODO: add missing attributes once schema is updated +DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(mediaPlaybackAttrs) +DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_STATE_ATTRIBUTE_ID, ENUM8, 1, 0), /* current state */ + DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_START_TIME_ATTRIBUTE_ID, EPOCH_US, 1, 0), /* start time */ + DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_DURATION_ATTRIBUTE_ID, INT64U, 1, 0), /* duration */ + DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_PLAYBACK_SPEED_ATTRIBUTE_ID, SINGLE, 1, 0), /* playback speed */ + DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_PLAYBACK_SEEK_RANGE_END_ATTRIBUTE_ID, INT64U, 1, 0), /* seek range end */ + DECLARE_DYNAMIC_ATTRIBUTE(ZCL_MEDIA_PLAYBACK_PLAYBACK_SEEK_RANGE_START_ATTRIBUTE_ID, INT64U, 1, 0), /* seek range start */ + DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); + +// Declare Target Navigator cluster attributes +DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(targetNavigatorAttrs) +DECLARE_DYNAMIC_ATTRIBUTE(ZCL_TARGET_NAVIGATOR_LIST_ATTRIBUTE_ID, ARRAY, kDescriptorAttributeArraySize, 0), /* target list */ + DECLARE_DYNAMIC_ATTRIBUTE(ZCL_TARGET_NAVIGATOR_CURRENT_TARGET_ATTRIBUTE_ID, INT8U, 1, 0), /* current target */ + DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); + +// Declare Channel cluster attributes +DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(channelAttrs) +DECLARE_DYNAMIC_ATTRIBUTE(ZCL_CHANNEL_LIST_ATTRIBUTE_ID, ARRAY, kDescriptorAttributeArraySize, 0), /* channel list */ + DECLARE_DYNAMIC_ATTRIBUTE(ZCL_CHANNEL_LINEUP_ATTRIBUTE_ID, STRUCT, 1, 0), /* lineup */ + DECLARE_DYNAMIC_ATTRIBUTE(ZCL_CHANNEL_CURRENT_CHANNEL_ATTRIBUTE_ID, STRUCT, 1, 0), /* current channel */ + DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); + +constexpr CommandId keypadInputIncomingCommands[] = { + app::Clusters::KeypadInput::Commands::SendKey::Id, + kInvalidCommandId, +}; +constexpr CommandId keypadInputOutgoingCommands[] = { + app::Clusters::KeypadInput::Commands::SendKeyResponse::Id, + kInvalidCommandId, +}; +constexpr CommandId applicationLauncherIncomingCommands[] = { + app::Clusters::ApplicationLauncher::Commands::LaunchApp::Id, + app::Clusters::ApplicationLauncher::Commands::StopApp::Id, + app::Clusters::ApplicationLauncher::Commands::HideApp::Id, + kInvalidCommandId, +}; +constexpr CommandId applicationLauncherOutgoingCommands[] = { + app::Clusters::ApplicationLauncher::Commands::LauncherResponse::Id, + kInvalidCommandId, +}; +constexpr CommandId accountLoginIncomingCommands[] = { + app::Clusters::AccountLogin::Commands::GetSetupPIN::Id, + app::Clusters::AccountLogin::Commands::Login::Id, + app::Clusters::AccountLogin::Commands::Logout::Id, + kInvalidCommandId, +}; +constexpr CommandId accountLoginOutgoingCommands[] = { + app::Clusters::AccountLogin::Commands::GetSetupPINResponse::Id, + kInvalidCommandId, +}; +// TODO: Sort out when the optional commands here should be listed. +constexpr CommandId contentLauncherIncomingCommands[] = { + app::Clusters::ContentLauncher::Commands::LaunchContent::Id, + app::Clusters::ContentLauncher::Commands::LaunchURL::Id, + kInvalidCommandId, +}; +constexpr CommandId contentLauncherOutgoingCommands[] = { + app::Clusters::ContentLauncher::Commands::LaunchResponse::Id, + kInvalidCommandId, +}; +// TODO: Sort out when the optional commands here should be listed. +constexpr CommandId mediaPlaybackIncomingCommands[] = { + app::Clusters::MediaPlayback::Commands::Play::Id, app::Clusters::MediaPlayback::Commands::Pause::Id, + app::Clusters::MediaPlayback::Commands::StopPlayback::Id, app::Clusters::MediaPlayback::Commands::StartOver::Id, + app::Clusters::MediaPlayback::Commands::Previous::Id, app::Clusters::MediaPlayback::Commands::Next::Id, + app::Clusters::MediaPlayback::Commands::Rewind::Id, app::Clusters::MediaPlayback::Commands::FastForward::Id, + app::Clusters::MediaPlayback::Commands::SkipForward::Id, app::Clusters::MediaPlayback::Commands::SkipBackward::Id, + app::Clusters::MediaPlayback::Commands::Seek::Id, kInvalidCommandId, +}; +constexpr CommandId mediaPlaybackOutgoingCommands[] = { + app::Clusters::MediaPlayback::Commands::PlaybackResponse::Id, + kInvalidCommandId, +}; +constexpr CommandId targetNavigatorIncomingCommands[] = { + app::Clusters::TargetNavigator::Commands::NavigateTarget::Id, + kInvalidCommandId, +}; +constexpr CommandId targetNavigatorOutgoingCommands[] = { + app::Clusters::TargetNavigator::Commands::NavigateTargetResponse::Id, + kInvalidCommandId, +}; +// TODO: Sort out when the optional commands here should be listed. +constexpr CommandId channelIncomingCommands[] = { + app::Clusters::Channel::Commands::ChangeChannel::Id, + app::Clusters::Channel::Commands::ChangeChannelByNumber::Id, + app::Clusters::Channel::Commands::SkipChannel::Id, + kInvalidCommandId, +}; +constexpr CommandId channelOutgoingCommands[] = { + app::Clusters::Channel::Commands::ChangeChannelResponse::Id, + kInvalidCommandId, +}; +// Declare Cluster List for Content App endpoint +DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(contentAppClusters) +DECLARE_DYNAMIC_CLUSTER(ZCL_DESCRIPTOR_CLUSTER_ID, descriptorAttrs, nullptr, nullptr), + DECLARE_DYNAMIC_CLUSTER(ZCL_APPLICATION_BASIC_CLUSTER_ID, applicationBasicAttrs, nullptr, nullptr), + DECLARE_DYNAMIC_CLUSTER(ZCL_KEYPAD_INPUT_CLUSTER_ID, keypadInputAttrs, keypadInputIncomingCommands, + keypadInputOutgoingCommands), + DECLARE_DYNAMIC_CLUSTER(ZCL_APPLICATION_LAUNCHER_CLUSTER_ID, applicationLauncherAttrs, applicationLauncherIncomingCommands, + applicationLauncherOutgoingCommands), + DECLARE_DYNAMIC_CLUSTER(ZCL_ACCOUNT_LOGIN_CLUSTER_ID, accountLoginAttrs, accountLoginIncomingCommands, + accountLoginOutgoingCommands), + DECLARE_DYNAMIC_CLUSTER(ZCL_CONTENT_LAUNCH_CLUSTER_ID, contentLauncherAttrs, contentLauncherIncomingCommands, + contentLauncherOutgoingCommands), + DECLARE_DYNAMIC_CLUSTER(ZCL_MEDIA_PLAYBACK_CLUSTER_ID, mediaPlaybackAttrs, mediaPlaybackIncomingCommands, + mediaPlaybackOutgoingCommands), + DECLARE_DYNAMIC_CLUSTER(ZCL_TARGET_NAVIGATOR_CLUSTER_ID, targetNavigatorAttrs, targetNavigatorIncomingCommands, + targetNavigatorOutgoingCommands), + DECLARE_DYNAMIC_CLUSTER(ZCL_CHANNEL_CLUSTER_ID, channelAttrs, channelIncomingCommands, channelOutgoingCommands), + DECLARE_DYNAMIC_CLUSTER_LIST_END; + +// Declare Content App endpoint +DECLARE_DYNAMIC_ENDPOINT(contentAppEndpoint, contentAppClusters); + +namespace { + +DataVersion gDataVersions[APP_LIBRARY_SIZE][ArraySize(contentAppClusters)]; + +EmberAfDeviceType gContentAppDeviceType[] = { { DEVICE_TYPE_CONTENT_APP, 1 } }; + +} // anonymous namespace + +ContentAppFactoryImpl::ContentAppFactoryImpl() {} + +uint16_t ContentAppFactoryImpl::GetPlatformCatalogVendorId() +{ + return kCatalogVendorId; +} + +CHIP_ERROR ContentAppFactoryImpl::LookupCatalogVendorApp(uint16_t vendorId, uint16_t productId, CatalogVendorApp * destinationApp) +{ + std::string appId = BuildAppId(vendorId); + destinationApp->catalogVendorId = GetPlatformCatalogVendorId(); + Platform::CopyString(destinationApp->applicationId, sizeof(destinationApp->applicationId), appId.c_str()); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ContentAppFactoryImpl::ConvertToPlatformCatalogVendorApp(const CatalogVendorApp & sourceApp, + CatalogVendorApp * destinationApp) +{ + destinationApp->catalogVendorId = GetPlatformCatalogVendorId(); + std::string appId(sourceApp.applicationId); + if (appId == "applicationId") + { + // test case passes "applicationId", map this to our test suite app + Platform::CopyString(destinationApp->applicationId, sizeof(destinationApp->applicationId), "1111"); + } + else + { + // for now, just return the applicationId passed in + Platform::CopyString(destinationApp->applicationId, sizeof(destinationApp->applicationId), sourceApp.applicationId); + } + return CHIP_NO_ERROR; +} + +ContentApp * ContentAppFactoryImpl::LoadContentApp(const CatalogVendorApp & vendorApp) +{ + ChipLogProgress(DeviceLayer, "ContentAppFactoryImpl: LoadContentAppByAppId catalogVendorId=%d applicationId=%s ", + vendorApp.catalogVendorId, vendorApp.applicationId); + + for (size_t i = 0; i < ArraySize(mContentApps); ++i) + { + auto & app = mContentApps[i]; + + ChipLogProgress(DeviceLayer, " Looking next=%s ", app.GetApplicationBasicDelegate()->GetCatalogVendorApp()->applicationId); + if (app.GetApplicationBasicDelegate()->GetCatalogVendorApp()->Matches(vendorApp)) + { + ContentAppPlatform::GetInstance().AddContentApp(&app, &contentAppEndpoint, Span(gDataVersions[i]), + Span(gContentAppDeviceType)); + return &app; + } + } + ChipLogProgress(DeviceLayer, "LoadContentAppByAppId NOT FOUND catalogVendorId=%d applicationId=%s ", vendorApp.catalogVendorId, + vendorApp.applicationId); + + return nullptr; +} + +} // namespace AppPlatform +} // namespace chip + +#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + +CHIP_ERROR InitVideoPlayerPlatform() +{ +#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + ContentAppPlatform::GetInstance().SetupAppPlatform(); + ContentAppPlatform::GetInstance().SetContentAppFactory(&gFactory); +#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + +#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE + CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); + if (cdc != nullptr) + { + cdc->SetPincodeService(&gMyPincodeService); + cdc->SetUserPrompter(&gMyUserPrompter); + cdc->SetPostCommissioningListener(&gMyPostCommissioningListener); + } + + ChipLogProgress(AppServer, "Starting commissioner"); + ReturnErrorOnFailure(InitCommissioner(CHIP_PORT + 2 + 10, CHIP_UDC_PORT)); + ChipLogProgress(AppServer, "Started commissioner"); + +#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE + return CHIP_NO_ERROR; +} + +CHIP_ERROR PreServerInit() +{ + /** + * Apply any user-defined configurations prior to initializing Server. + * + * Ex. + * DnssdServer::Instance().SetExtendedDiscoveryTimeoutSecs(userTimeoutSecs); + * + */ + + return CHIP_NO_ERROR; +} diff --git a/examples/tv-app/android/java/AppImpl.h b/examples/tv-app/android/java/AppImpl.h new file mode 100644 index 00000000000000..db2f3340029cde --- /dev/null +++ b/examples/tv-app/android/java/AppImpl.h @@ -0,0 +1,140 @@ +/* + * + * 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 Manages Content Apps + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "../include/account-login/AccountLoginManager.h" +#include "../include/application-basic/ApplicationBasicManager.h" +#include "../include/application-launcher/ApplicationLauncherManager.h" +#include "../include/content-launcher/AppContentLauncherManager.h" +#include "../include/target-navigator/TargetNavigatorManager.h" +#include "ChannelManager.h" +#include "CommissionerMain.h" +#include "KeypadInputManager.h" +#include "MediaPlaybackManager.h" +#include +#include +#include +#include +#include +#include +#include +#include + +CHIP_ERROR InitVideoPlayerPlatform(); +CHIP_ERROR PreServerInit(); + +#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + +namespace chip { +namespace AppPlatform { + +using AccountLoginDelegate = app::Clusters::AccountLogin::Delegate; +using ApplicationBasicDelegate = app::Clusters::ApplicationBasic::Delegate; +using ApplicationLauncherDelegate = app::Clusters::ApplicationLauncher::Delegate; +using ChannelDelegate = app::Clusters::Channel::Delegate; +using ContentLauncherDelegate = app::Clusters::ContentLauncher::Delegate; +using KeypadInputDelegate = app::Clusters::KeypadInput::Delegate; +using MediaPlaybackDelegate = app::Clusters::MediaPlayback::Delegate; +using TargetNavigatorDelegate = app::Clusters::TargetNavigator::Delegate; +using SupportedStreamingProtocol = app::Clusters::ContentLauncher::SupportedStreamingProtocol; + +static const int kCatalogVendorId = CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID; + +// for this platform, appid is just vendor id +#define BuildAppId(vid) std::to_string(vid).c_str() + +class DLL_EXPORT ContentAppImpl : public ContentApp +{ +public: + ContentAppImpl(const char * szVendorName, uint16_t vendorId, const char * szApplicationName, uint16_t productId, + const char * szApplicationVersion, const char * setupPIN) : + mApplicationBasicDelegate(kCatalogVendorId, BuildAppId(vendorId), szVendorName, vendorId, szApplicationName, productId, + szApplicationVersion), + mAccountLoginDelegate(setupPIN), mContentLauncherDelegate({ "image/*", "video/*" }, + to_underlying(SupportedStreamingProtocol::kDash) | + to_underlying(SupportedStreamingProtocol::kHls)), + mTargetNavigatorDelegate({ "home", "search", "info", "guide", "menu" }, 0){}; + virtual ~ContentAppImpl() {} + + AccountLoginDelegate * GetAccountLoginDelegate() override { return &mAccountLoginDelegate; }; + ApplicationBasicDelegate * GetApplicationBasicDelegate() override { return &mApplicationBasicDelegate; }; + ApplicationLauncherDelegate * GetApplicationLauncherDelegate() override { return &mApplicationLauncherDelegate; }; + ChannelDelegate * GetChannelDelegate() override { return &mChannelDelegate; }; + ContentLauncherDelegate * GetContentLauncherDelegate() override { return &mContentLauncherDelegate; }; + KeypadInputDelegate * GetKeypadInputDelegate() override { return &mKeypadInputDelegate; }; + MediaPlaybackDelegate * GetMediaPlaybackDelegate() override { return &mMediaPlaybackDelegate; }; + TargetNavigatorDelegate * GetTargetNavigatorDelegate() override { return &mTargetNavigatorDelegate; }; + +protected: + ApplicationBasicManager mApplicationBasicDelegate; + AccountLoginManager mAccountLoginDelegate; + ApplicationLauncherManager mApplicationLauncherDelegate; + ChannelManager mChannelDelegate; + AppContentLauncherManager mContentLauncherDelegate; + KeypadInputManager mKeypadInputDelegate; + MediaPlaybackManager mMediaPlaybackDelegate; + TargetNavigatorManager mTargetNavigatorDelegate; +}; + +class DLL_EXPORT ContentAppFactoryImpl : public ContentAppFactory +{ +#define APP_LIBRARY_SIZE 4 +public: + ContentAppFactoryImpl(); + virtual ~ContentAppFactoryImpl() {} + + // Lookup CatalogVendor App for this client (vendor id/product id client) + // and then write it to destinationApp + // return error if not found + CHIP_ERROR LookupCatalogVendorApp(uint16_t vendorId, uint16_t productId, CatalogVendorApp * destinationApp) override; + + // Lookup ContentApp for this catalog id / app id and load it + ContentApp * LoadContentApp(const CatalogVendorApp & vendorApp) override; + + // Gets the catalog vendor ID used by this platform + uint16_t GetPlatformCatalogVendorId() override; + + // Converts application (any catalog) into the platform's catalog Vendor + // and then writes it to destinationApp + CHIP_ERROR ConvertToPlatformCatalogVendorApp(const CatalogVendorApp & sourceApp, CatalogVendorApp * destinationApp) override; + +protected: + ContentAppImpl mContentApps[APP_LIBRARY_SIZE] = { ContentAppImpl("Vendor1", 1, "App1", 11, "Version1", "34567890"), + ContentAppImpl("Vendor2", 65521, "App2", 32768, "Version2", "20202021"), + ContentAppImpl("Vendor3", 9050, "App3", 22, "Version3", "20202021"), + ContentAppImpl("TestSuiteVendor", 1111, "applicationId", 22, "v2", + "20202021") }; +}; + +} // namespace AppPlatform +} // namespace chip + +#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED diff --git a/examples/tv-app/android/java/TVApp-JNI.cpp b/examples/tv-app/android/java/TVApp-JNI.cpp index 6841c4e4d5af9e..765961a899963b 100644 --- a/examples/tv-app/android/java/TVApp-JNI.cpp +++ b/examples/tv-app/android/java/TVApp-JNI.cpp @@ -17,6 +17,7 @@ */ #include "TvApp-JNI.h" +#include "AppImpl.h" #include "ChannelManager.h" #include "ContentLauncherManager.h" #include "JNIDACProvider.h" @@ -39,10 +40,9 @@ using namespace chip; using namespace chip::app; +using namespace chip::AppPlatform; using namespace chip::Credentials; -#define EXTENDED_DISCOVERY_TIMEOUT_SEC 20 - #define JNI_METHOD(RETURN, METHOD_NAME) extern "C" JNIEXPORT RETURN JNICALL Java_com_tcl_chip_tvapp_TvApp_##METHOD_NAME TvAppJNI TvAppJNI::sInstance; @@ -140,11 +140,20 @@ JNI_METHOD(void, setDACProvider)(JNIEnv *, jobject, jobject provider) } } -JNI_METHOD(void, postInit)(JNIEnv *, jobject app) +JNI_METHOD(void, preServerInit)(JNIEnv *, jobject app) +{ + chip::DeviceLayer::StackLock lock; + ChipLogProgress(Zcl, "TvAppJNI::preServerInit"); + + PreServerInit(); +} + +JNI_METHOD(void, postServerInit)(JNIEnv *, jobject app) { -#if CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY - DnssdServer::Instance().SetExtendedDiscoveryTimeoutSecs(EXTENDED_DISCOVERY_TIMEOUT_SEC); -#endif + chip::DeviceLayer::StackLock lock; + ChipLogProgress(Zcl, "TvAppJNI::postServerInit"); + + InitVideoPlayerPlatform(); } JNI_METHOD(void, setOnOffManager)(JNIEnv *, jobject, jint endpoint, jobject manager) diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/TvApp.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/TvApp.java index a919bb8d1d8d6a..28f2f334126a0f 100644 --- a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/TvApp.java +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/TvApp.java @@ -37,8 +37,11 @@ private void postClusterInit(int clusterId, int endpoint) { public native void nativeInit(); - // post native init after platform is inited - public native void postInit(); + // called before Matter server is inited + public native void preServerInit(); + + // called after Matter server is inited + public native void postServerInit(); public native void setKeypadInputManager(int endpoint, KeypadInputManager manager); diff --git a/examples/tv-app/linux/AppImpl.cpp b/examples/tv-app/linux/AppImpl.cpp index d1f9faa49dfbf1..f80ff9d2a87bae 100644 --- a/examples/tv-app/linux/AppImpl.cpp +++ b/examples/tv-app/linux/AppImpl.cpp @@ -43,9 +43,80 @@ #include using namespace chip; +using namespace chip::AppPlatform; + +#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE +class MyUserPrompter : public UserPrompter +{ + // tv should override this with a dialog prompt + inline void PromptForCommissionOKPermission(uint16_t vendorId, uint16_t productId, const char * commissioneeName) override + { + return; + } + + // tv should override this with a dialog prompt + inline void PromptForCommissionPincode(uint16_t vendorId, uint16_t productId, const char * commissioneeName) override + { + return; + } + + // tv should override this with a dialog prompt + inline void PromptCommissioningSucceeded(uint16_t vendorId, uint16_t productId, const char * commissioneeName) override + { + return; + } + + // tv should override this with a dialog prompt + inline void PromptCommissioningFailed(const char * commissioneeName, CHIP_ERROR error) override { return; } +}; + +MyUserPrompter gMyUserPrompter; +#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED -using namespace chip::AppPlatform; +class MyPincodeService : public PincodeService +{ + uint32_t FetchCommissionPincodeFromContentApp(uint16_t vendorId, uint16_t productId, CharSpan rotatingId) override + { + return ContentAppPlatform::GetInstance().GetPincodeFromContentApp(vendorId, productId, rotatingId); + } +}; +MyPincodeService gMyPincodeService; + +class MyPostCommissioningListener : public PostCommissioningListener +{ + void CommissioningCompleted(uint16_t vendorId, uint16_t productId, NodeId nodeId, OperationalDeviceProxy * device) override + { + + ContentAppPlatform::GetInstance().ManageClientAccess(device, vendorId, GetDeviceCommissioner()->GetNodeId(), + OnSuccessResponse, OnFailureResponse); + } + + /* Callback when command results in success */ + static void OnSuccessResponse(void * context) + { + ChipLogProgress(Controller, "OnSuccessResponse - Binding Add Successfully"); + CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); + if (cdc != nullptr) + { + cdc->PostCommissioningSucceeded(); + } + } + + /* Callback when command results in failure */ + static void OnFailureResponse(void * context, CHIP_ERROR error) + { + ChipLogProgress(Controller, "OnFailureResponse - Binding Add Failed"); + CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); + if (cdc != nullptr) + { + cdc->PostCommissioningFailed(error); + } + } +}; + +MyPostCommissioningListener gMyPostCommissioningListener; +ContentAppFactoryImpl gFactory; namespace chip { namespace AppPlatform { @@ -292,3 +363,22 @@ ContentApp * ContentAppFactoryImpl::LoadContentApp(const CatalogVendorApp & vend } // namespace chip #endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + +CHIP_ERROR InitVideoPlayerPlatform() +{ +#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + ContentAppPlatform::GetInstance().SetupAppPlatform(); + ContentAppPlatform::GetInstance().SetContentAppFactory(&gFactory); +#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + +#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE + CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); + if (cdc != nullptr) + { + cdc->SetPincodeService(&gMyPincodeService); + cdc->SetUserPrompter(&gMyUserPrompter); + cdc->SetPostCommissioningListener(&gMyPostCommissioningListener); + } +#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE + return CHIP_NO_ERROR; +} diff --git a/examples/tv-app/linux/AppImpl.h b/examples/tv-app/linux/AppImpl.h index 368f84ce5ffd9c..709e1448da3019 100644 --- a/examples/tv-app/linux/AppImpl.h +++ b/examples/tv-app/linux/AppImpl.h @@ -30,6 +30,7 @@ #include #include +#include "CommissionerMain.h" #include "include/account-login/AccountLoginManager.h" #include "include/application-basic/ApplicationBasicManager.h" #include "include/application-launcher/ApplicationLauncherManager.h" @@ -47,6 +48,8 @@ #include #include +CHIP_ERROR InitVideoPlayerPlatform(); + #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED namespace chip { diff --git a/examples/tv-app/linux/main.cpp b/examples/tv-app/linux/main.cpp index 8adc45c6165ebf..2236e7bee2d192 100644 --- a/examples/tv-app/linux/main.cpp +++ b/examples/tv-app/linux/main.cpp @@ -77,102 +77,12 @@ static WakeOnLanManager wakeOnLanManager; void ApplicationInit() {} -#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE -class MyUserPrompter : public UserPrompter -{ - // tv should override this with a dialog prompt - inline void PromptForCommissionOKPermission(uint16_t vendorId, uint16_t productId, const char * commissioneeName) override - { - return; - } - - // tv should override this with a dialog prompt - inline void PromptForCommissionPincode(uint16_t vendorId, uint16_t productId, const char * commissioneeName) override - { - return; - } - - // tv should override this with a dialog prompt - inline void PromptCommissioningSucceeded(uint16_t vendorId, uint16_t productId, const char * commissioneeName) override - { - return; - } - - // tv should override this with a dialog prompt - inline void PromptCommissioningFailed(const char * commissioneeName, CHIP_ERROR error) override { return; } -}; - -MyUserPrompter gMyUserPrompter; -#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE - -#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED -class MyPincodeService : public PincodeService -{ - uint32_t FetchCommissionPincodeFromContentApp(uint16_t vendorId, uint16_t productId, CharSpan rotatingId) override - { - return ContentAppPlatform::GetInstance().GetPincodeFromContentApp(vendorId, productId, rotatingId); - } -}; -MyPincodeService gMyPincodeService; - -class MyPostCommissioningListener : public PostCommissioningListener -{ - void CommissioningCompleted(uint16_t vendorId, uint16_t productId, NodeId nodeId, OperationalDeviceProxy * device) override - { - - ContentAppPlatform::GetInstance().ManageClientAccess(device, vendorId, GetDeviceCommissioner()->GetNodeId(), - OnSuccessResponse, OnFailureResponse); - } - - /* Callback when command results in success */ - static void OnSuccessResponse(void * context) - { - ChipLogProgress(Controller, "OnSuccessResponse - Binding Add Successfully"); - CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); - if (cdc != nullptr) - { - cdc->PostCommissioningSucceeded(); - } - } - - /* Callback when command results in failure */ - static void OnFailureResponse(void * context, CHIP_ERROR error) - { - ChipLogProgress(Controller, "OnFailureResponse - Binding Add Failed"); - CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); - if (cdc != nullptr) - { - cdc->PostCommissioningFailed(error); - } - } -}; - -MyPostCommissioningListener gMyPostCommissioningListener; - -#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - int main(int argc, char * argv[]) { -#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - ContentAppFactoryImpl factory; -#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - VerifyOrDie(ChipLinuxAppInit(argc, argv) == 0); -#if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - ContentAppPlatform::GetInstance().SetupAppPlatform(); - ContentAppPlatform::GetInstance().SetContentAppFactory(&factory); -#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE - CommissionerDiscoveryController * cdc = GetCommissionerDiscoveryController(); - if (cdc != nullptr) - { - cdc->SetPincodeService(&gMyPincodeService); - cdc->SetUserPrompter(&gMyUserPrompter); - cdc->SetPostCommissioningListener(&gMyPostCommissioningListener); - } -#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE -#endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED + InitVideoPlayerPlatform(); #if defined(ENABLE_CHIP_SHELL) #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED diff --git a/examples/tv-casting-app/linux/Casting.h b/examples/tv-casting-app/linux/Casting.h index bb48763acb8fba..3808727f437e8e 100644 --- a/examples/tv-casting-app/linux/Casting.h +++ b/examples/tv-casting-app/linux/Casting.h @@ -23,6 +23,7 @@ #include #include +CHIP_ERROR TargetVideoPlayerInfoInit(chip::NodeId nodeId, chip::FabricIndex fabricIndex); CHIP_ERROR DiscoverCommissioners(); CHIP_ERROR RequestCommissioning(int index); void ReadServerClustersForNode(chip::NodeId nodeId); diff --git a/examples/tv-casting-app/linux/CastingShellCommands.cpp b/examples/tv-casting-app/linux/CastingShellCommands.cpp index 5e61dae4a845eb..502f5e580361ff 100644 --- a/examples/tv-casting-app/linux/CastingShellCommands.cpp +++ b/examples/tv-casting-app/linux/CastingShellCommands.cpp @@ -38,10 +38,13 @@ static CHIP_ERROR PrintAllCommands() { streamer_t * sout = streamer_get(); streamer_printf(sout, " help Usage: app \r\n"); + streamer_printf(sout, + " init Initialize casting app using given nodeid and index from previous " + "commissioning. Usage: init 18446744004990074879 2\r\n"); streamer_printf(sout, " discover Discover commissioners. Usage: cast discover\r\n"); streamer_printf( sout, " request Request commissioning from discovered commissioner with [index]. Usage: cast request 0\r\n"); - streamer_printf(sout, " launch Launch content. Usage: cast launc https://www.yahoo.com Hello\r\n"); + streamer_printf(sout, " launch Launch content. Usage: cast launch https://www.yahoo.com Hello\r\n"); streamer_printf( sout, " access Read and display clusters on each endpoint for . Usage: cast access 0xFFFFFFEFFFFFFFFF\r\n"); @@ -57,6 +60,15 @@ static CHIP_ERROR CastingHandler(int argc, char ** argv) { return PrintAllCommands(); } + if (strcmp(argv[0], "init") == 0) + { + ChipLogProgress(DeviceLayer, "init"); + + char * eptr; + chip::NodeId nodeId = (chip::NodeId) strtoull(argv[1], &eptr, 10); + chip::FabricIndex fabricIndex = (chip::FabricIndex) strtol(argv[2], &eptr, 10); + return TargetVideoPlayerInfoInit(nodeId, fabricIndex); + } if (strcmp(argv[0], "discover") == 0) { ChipLogProgress(DeviceLayer, "discover"); diff --git a/examples/tv-casting-app/linux/main.cpp b/examples/tv-casting-app/linux/main.cpp index 2c5815069fec16..40bf40ede18347 100644 --- a/examples/tv-casting-app/linux/main.cpp +++ b/examples/tv-casting-app/linux/main.cpp @@ -81,6 +81,7 @@ constexpr EndpointId kTvEndpoint = 1; CommissionableNodeController gCommissionableNodeController; chip::System::SocketWatchToken gToken; Dnssd::DiscoveryFilter gDiscoveryFilter = Dnssd::DiscoveryFilter(); +bool gInited = false; CASEClientPool gCASEClientPool; @@ -150,13 +151,12 @@ void HandleUDCSendExpiration(System::Layer * aSystemLayer, void * context) } #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT -/** - * Enters commissioning mode, opens commissioning window, logs onboarding payload. - * If non-null selectedCommissioner is provided, sends user directed commissioning - * request to the selectedCommissioner and advertises self as commissionable node over DNS-SD - */ -void PrepareForCommissioning(const Dnssd::DiscoveredNodeData * selectedCommissioner = nullptr) +void InitServer() { + if (gInited) + { + return; + } // DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().Init("/tmp/chip_tv_casting_kvs"); DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().Init(CHIP_CONFIG_KVS_PATH); @@ -165,6 +165,21 @@ void PrepareForCommissioning(const Dnssd::DiscoveredNodeData * selectedCommissio (void) initParams.InitializeStaticResourcesBeforeServerInit(); chip::Server::GetInstance().Init(initParams); + // Initialize binding handlers + ReturnOnFailure(InitBindingHandlers()); + + gInited = true; +} + +/** + * Enters commissioning mode, opens commissioning window, logs onboarding payload. + * If non-null selectedCommissioner is provided, sends user directed commissioning + * request to the selectedCommissioner and advertises self as commissionable node over DNS-SD + */ +void PrepareForCommissioning(const Dnssd::DiscoveredNodeData * selectedCommissioner = nullptr) +{ + InitServer(); + Server::GetInstance().GetFabricTable().DeleteAllFabrics(); ReturnOnFailure( Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow(kCommissioningWindowTimeout)); @@ -172,9 +187,6 @@ void PrepareForCommissioning(const Dnssd::DiscoveredNodeData * selectedCommissio // Display onboarding payload chip::DeviceLayer::ConfigurationMgr().LogDeviceConfig(); - // Initialize binding handlers - ReturnOnFailure(InitBindingHandlers()); - #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT if (selectedCommissioner != nullptr) { @@ -340,6 +352,8 @@ class TargetVideoPlayerInfo CHIP_ERROR Initialize(NodeId nodeId, FabricIndex fabricIndex) { + ChipLogProgress(NotSpecified, "TargetVideoPlayerInfo nodeId=0x" ChipLogFormatX64 " fabricIndex=%d", ChipLogValueX64(nodeId), + fabricIndex); mNodeId = nodeId; mFabricIndex = fabricIndex; for (auto & endpointInfo : mEndpoints) @@ -387,6 +401,7 @@ class TargetVideoPlayerInfo ChipLogError(AppServer, "Failed to find an existing instance of OperationalDeviceProxy to the peer"); return CHIP_ERROR_INVALID_ARGUMENT; } + ChipLogProgress(AppServer, "Created an instance of OperationalDeviceProxy"); mInitialized = true; return CHIP_NO_ERROR; @@ -468,6 +483,8 @@ class TargetVideoPlayerInfo { TargetVideoPlayerInfo * _this = static_cast(context); _this->mOperationalDeviceProxy = device; + _this->mInitialized = true; + ChipLogProgress(AppServer, "HandleDeviceConnected created an instance of OperationalDeviceProxy"); } static void HandleDeviceConnectionFailure(void * context, PeerId peerId, CHIP_ERROR error) @@ -591,6 +608,12 @@ CHIP_ERROR ContentLauncherLaunchURL(const char * contentUrl, const char * conten return CHIP_NO_ERROR; } +CHIP_ERROR TargetVideoPlayerInfoInit(NodeId nodeId, FabricIndex fabricIndex) +{ + InitServer(); + return gTargetVideoPlayerInfo.Initialize(nodeId, fabricIndex); +} + void DeviceEventCallback(const DeviceLayer::ChipDeviceEvent * event, intptr_t arg) { if (event->Type == DeviceLayer::DeviceEventType::kBindingsChangedViaCluster)