diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/DiscoveryExampleFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/DiscoveryExampleFragment.java index a706780c5be3b4..65d670584971aa 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/DiscoveryExampleFragment.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/DiscoveryExampleFragment.java @@ -327,8 +327,9 @@ public View getView(int i, View view, ViewGroup viewGroup) { TAG, "OnClickListener.onClick() called for CastingPlayer with deviceId: " + castingPlayer.getDeviceId()); - DiscoveryExampleFragment.Callback callback1 = (DiscoveryExampleFragment.Callback) context; - callback1.handleConnectionButtonClicked(castingPlayer); + DiscoveryExampleFragment.Callback onClickCallback = + (DiscoveryExampleFragment.Callback) context; + onClickCallback.handleConnectionButtonClicked(castingPlayer); }; playerDescription.setOnClickListener(clickListener); return view; diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterCastingPlayer-JNI.cpp b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterCastingPlayer-JNI.cpp index caa64b4ac8d717..1c4a949c9f7cc5 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterCastingPlayer-JNI.cpp +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/core/MatterCastingPlayer-JNI.cpp @@ -53,9 +53,14 @@ JNI_METHOD(jobject, verifyOrEstablishConnection) CastingPlayer * castingPlayer = support::convertCastingPlayerFromJavaToCpp(thiz); VerifyOrReturnValue(castingPlayer != nullptr, support::convertMatterErrorFromCppToJava(CHIP_ERROR_INVALID_ARGUMENT)); + matter::casting::core::IdentificationDeclarationOptions idOptions; + + // TODO: In the following PRs. Replace EndpointFilter Java class with IdentificationDeclarationOptions Java class. matter::casting::core::EndpointFilter desiredEndpointFilter; if (desiredEndpointFilterJavaObject != nullptr) { + chip::Protocols::UserDirectedCommissioning::TargetAppInfo targetAppInfo; + // Convert the EndpointFilter Java class to a C++ EndpointFilter jclass endpointFilterJavaClass = env->GetObjectClass(desiredEndpointFilterJavaObject); jfieldID vendorIdFieldId = env->GetFieldID(endpointFilterJavaClass, "vendorId", "Ljava/lang/Integer;"); @@ -66,20 +71,28 @@ JNI_METHOD(jobject, verifyOrEstablishConnection) // "Ljava/util/List;"); // Value of 0 means unspecified - desiredEndpointFilter.vendorId = vendorIdIntegerObject != nullptr + targetAppInfo.vendorId = vendorIdIntegerObject != nullptr ? static_cast(env->CallIntMethod( vendorIdIntegerObject, env->GetMethodID(env->GetObjectClass(vendorIdIntegerObject), "intValue", "()I"))) : 0; - desiredEndpointFilter.productId = productIdIntegerObject != nullptr + targetAppInfo.productId = productIdIntegerObject != nullptr ? static_cast(env->CallIntMethod( productIdIntegerObject, env->GetMethodID(env->GetObjectClass(productIdIntegerObject), "intValue", "()I"))) : 0; - // TODO: In following PRs. Translate the Java requiredDeviceTypes list to a C++ requiredDeviceTypes vector. For now we're - // passing an empty list of DeviceTypeStruct. + + CHIP_ERROR result = idOptions.addTargetAppInfo(targetAppInfo); + if (result != CHIP_NO_ERROR) + { + ChipLogError(AppServer, + "MatterCastingPlayer-JNI::verifyOrEstablishConnection() failed to add targetAppInfo: %" CHIP_ERROR_FORMAT, + result.Format()); + } } MatterCastingPlayerJNIMgr().mConnectionSuccessHandler.SetUp(env, jSuccessCallback); MatterCastingPlayerJNIMgr().mConnectionFailureHandler.SetUp(env, jFailureCallback); + + // TODO: In the following PRs. Add optional CommissionerDeclarationHandler callback parameter. castingPlayer->VerifyOrEstablishConnection( [](CHIP_ERROR err, CastingPlayer * playerPtr) { ChipLogProgress(AppServer, "MatterCastingPlayer-JNI::verifyOrEstablishConnection() ConnectCallback called"); @@ -96,7 +109,7 @@ JNI_METHOD(jobject, verifyOrEstablishConnection) MatterCastingPlayerJNIMgr().mConnectionFailureHandler.Handle(err); } }, - static_cast(commissioningWindowTimeoutSec), desiredEndpointFilter); + static_cast(commissioningWindowTimeoutSec), idOptions); return support::convertMatterErrorFromCppToJava(CHIP_NO_ERROR); } diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/MCCastingPlayer.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/MCCastingPlayer.mm index b69bbfb99f9bd7..3bc72235a86c72 100644 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/MCCastingPlayer.mm +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/MCCastingPlayer.mm @@ -52,19 +52,29 @@ - (void)verifyOrEstablishConnectionWithCompletionBlock:(void (^_Nonnull)(NSError dispatch_queue_t workQueue = [[MCCastingApp getSharedInstance] getWorkQueue]; dispatch_sync(workQueue, ^{ + matter::casting::core::IdentificationDeclarationOptions idOptions; + + // TODO: In the following PRs. Replace EndpointFilter objC class with IdentificationDeclarationOptions objC class. __block matter::casting::core::EndpointFilter cppDesiredEndpointFilter; if (desiredEndpointFilter != nil) { - cppDesiredEndpointFilter.vendorId = desiredEndpointFilter.vendorId; - cppDesiredEndpointFilter.productId = desiredEndpointFilter.productId; + chip::Protocols::UserDirectedCommissioning::TargetAppInfo targetAppInfo; + targetAppInfo.vendorId = desiredEndpointFilter.vendorId; + targetAppInfo.productId = desiredEndpointFilter.productId; + + CHIP_ERROR result = idOptions.addTargetAppInfo(targetAppInfo); + if (result != CHIP_NO_ERROR) { + ChipLogError(AppServer, "MCCastingPlayer.verifyOrEstablishConnectionWithCompletionBlock failed to add targetAppInfo: %" CHIP_ERROR_FORMAT, result.Format()); + } } + // TODO: In the following PRs. Add optional CommissionerDeclarationHandler callback parameter. _cppCastingPlayer->VerifyOrEstablishConnection( [completion](CHIP_ERROR err, matter::casting::core::CastingPlayer * castingPlayer) { dispatch_queue_t clientQueue = [[MCCastingApp getSharedInstance] getClientQueue]; dispatch_async(clientQueue, ^{ completion(err == CHIP_NO_ERROR ? nil : [MCErrorUtils NSErrorFromChipError:err]); }); - }, timeout, cppDesiredEndpointFilter); + }, timeout, idOptions); }); } diff --git a/examples/tv-casting-app/linux/simple-app-helper.cpp b/examples/tv-casting-app/linux/simple-app-helper.cpp index de8c255366cd37..ceb66233a7bc6d 100644 --- a/examples/tv-casting-app/linux/simple-app-helper.cpp +++ b/examples/tv-casting-app/linux/simple-app-helper.cpp @@ -49,8 +49,10 @@ void DiscoveryDelegateImpl::HandleOnAdded(matter::casting::memory::StrongGetId(), err.Format())); - ChipLogProgress(AppServer, "ConnectionHandler: Successfully connected to CastingPlayer(ID: %s)", castingPlayer->GetId()); + ChipLogProgress(AppServer, "ConnectionHandler(): Successfully connected to CastingPlayer(ID: %s)", castingPlayer->GetId()); + ChipLogProgress(AppServer, "ConnectionHandler(): Triggering demo interactions with CastingPlayer(ID: %s)", + castingPlayer->GetId()); std::vector> endpoints = castingPlayer->GetEndpoints(); // Find the desired Endpoint and auto-trigger some Matter Casting demo interactions @@ -219,18 +223,18 @@ CHIP_ERROR CommandHandler(int argc, char ** argv) } if (strcmp(argv[0], "discover") == 0) { - ChipLogProgress(AppServer, "discover"); + ChipLogProgress(AppServer, "CommandHandler() discover"); return matter::casting::core::CastingPlayerDiscovery::GetInstance()->StartDiscovery(kTargetPlayerDeviceType); } if (strcmp(argv[0], "stop-discovery") == 0) { - ChipLogProgress(AppServer, "stop-discovery"); + ChipLogProgress(AppServer, "CommandHandler() stop-discovery"); return matter::casting::core::CastingPlayerDiscovery::GetInstance()->StopDiscovery(); } if (strcmp(argv[0], "request") == 0) { - ChipLogProgress(AppServer, "request"); + ChipLogProgress(AppServer, "CommandHandler() request"); if (argc < 2) { return PrintAllCommands(); @@ -243,10 +247,40 @@ CHIP_ERROR CommandHandler(int argc, char ** argv) ChipLogError(AppServer, "Invalid casting player index provided: %lu", index)); std::shared_ptr targetCastingPlayer = castingPlayers.at(index); - matter::casting::core::EndpointFilter desiredEndpointFilter; - desiredEndpointFilter.vendorId = kDesiredEndpointVendorId; + matter::casting::core::IdentificationDeclarationOptions idOptions; + if (argc == 3) + { + if (strcmp(argv[2], "cgp") == 0) + { + // Attempt Commissioner-Generated Passcode (cgp) commissioning flow only if the CastingPlayer indicates support for + // it. + if (targetCastingPlayer->GetSupportsCommissionerGeneratedPasscode()) + { + ChipLogProgress( + AppServer, + "CommandHandler() request %lu cgp. Attempting the Commissioner-Generated Passcode commissioning flow", + index); + idOptions.mCommissionerPasscode = true; + } + else + { + ChipLogError(AppServer, + "CommandHandler() request %lu cgp. Selected CastingPLayer does not support the " + "Commissioner-Generated Passcode commissioning flow", + index); + } + } + } + chip::Protocols::UserDirectedCommissioning::TargetAppInfo targetAppInfo; + targetAppInfo.vendorId = kDesiredEndpointVendorId; + CHIP_ERROR result = idOptions.addTargetAppInfo(targetAppInfo); + if (result != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "CommandHandler() request, failed to add targetAppInfo: %" CHIP_ERROR_FORMAT, result.Format()); + } + targetCastingPlayer->VerifyOrEstablishConnection(ConnectionHandler, matter::casting::core::kCommissioningWindowTimeoutSec, - desiredEndpointFilter); + idOptions); return CHIP_NO_ERROR; } if (strcmp(argv[0], "print-bindings") == 0) @@ -280,8 +314,12 @@ CHIP_ERROR PrintAllCommands() " delete-fabric Delete a fabric from the casting client's fabric store. Usage: cast delete-fabric 1\r\n"); streamer_printf(sout, " discover Discover Casting Players. Usage: cast discover\r\n"); streamer_printf(sout, " stop-discovery Stop Discovery of Casting Players. Usage: cast stop-discovery\r\n"); - streamer_printf( - sout, " request Request connecting to discovered Casting Player with [index]. Usage: cast request 0\r\n"); + streamer_printf(sout, + " request Request connecting to discovered Casting Player with [index] using the " + "Commissionee-Generated Passcode commissioning flow. Usage: cast request 0\r\n"); + streamer_printf(sout, + " request cgp Request connecting to discovered Casting Player with [index] using the " + "Commissioner-Generated Passcode commissioning flow. Usage: cast request 0 cgp\r\n"); streamer_printf(sout, "\r\n"); return CHIP_NO_ERROR; diff --git a/examples/tv-casting-app/linux/simple-app-helper.h b/examples/tv-casting-app/linux/simple-app-helper.h index b1dbbe60cf04b3..f8826b5dfe021f 100644 --- a/examples/tv-casting-app/linux/simple-app-helper.h +++ b/examples/tv-casting-app/linux/simple-app-helper.h @@ -20,6 +20,7 @@ #include "core/CastingPlayer.h" #include "core/CastingPlayerDiscovery.h" +#include "core/IdentificationDeclarationOptions.h" #include "core/Types.h" #include diff --git a/examples/tv-casting-app/tv-casting-common/BUILD.gn b/examples/tv-casting-app/tv-casting-common/BUILD.gn index 72f14fb7bffeee..a58d272abe88bf 100644 --- a/examples/tv-casting-app/tv-casting-common/BUILD.gn +++ b/examples/tv-casting-app/tv-casting-common/BUILD.gn @@ -106,6 +106,7 @@ chip_data_model("tv-casting-common") { "core/CastingPlayerDiscovery.cpp", "core/CastingPlayerDiscovery.h", "core/Command.h", + "core/CommissionerDeclarationHandler.cpp", "core/Endpoint.cpp", "core/Endpoint.h", "core/Types.h", diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingApp.cpp b/examples/tv-casting-app/tv-casting-common/core/CastingApp.cpp index f7865910832ec9..7e000134190daf 100644 --- a/examples/tv-casting-app/tv-casting-common/core/CastingApp.cpp +++ b/examples/tv-casting-app/tv-casting-common/core/CastingApp.cpp @@ -18,6 +18,7 @@ #include "CastingApp.h" +#include "CommissionerDeclarationHandler.h" #include "support/CastingStore.h" #include "support/ChipDeviceEventHandler.h" @@ -100,6 +101,9 @@ CHIP_ERROR CastingApp::Start() // reconnect (or verify connection) to the CastingPlayer that the app was connected to before being stopped, if any if (CastingPlayer::GetTargetCastingPlayer() != nullptr) { + ChipLogProgress( + Discovery, + "CastingApp::Start() calling VerifyOrEstablishConnection() to reconnect (or verify connection) to a CastingPlayer"); CastingPlayer::GetTargetCastingPlayer()->VerifyOrEstablishConnection( [](CHIP_ERROR err, matter::casting::core::CastingPlayer * castingPlayer) { if (err != CHIP_NO_ERROR) @@ -136,6 +140,12 @@ CHIP_ERROR CastingApp::PostStartRegistrations() // Register DeviceEvent Handler ReturnErrorOnFailure(chip::DeviceLayer::PlatformMgrImpl().AddEventHandler(ChipDeviceEventHandler::Handle, 0)); +#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT + // Set a handler for Commissioner's CommissionerDeclaration messages. + chip::Server::GetInstance().GetUserDirectedCommissioningClient()->SetCommissionerDeclarationHandler( + CommissionerDeclarationHandler::GetInstance()); +#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT + mState = CASTING_APP_RUNNING; // CastingApp started successfully, set state to RUNNING return CHIP_NO_ERROR; } @@ -145,6 +155,11 @@ CHIP_ERROR CastingApp::Stop() ChipLogProgress(Discovery, "CastingApp::Stop() called"); VerifyOrReturnError(mState == CASTING_APP_RUNNING, CHIP_ERROR_INCORRECT_STATE); +#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT + // Remove the handler previously set for Commissioner's CommissionerDeclaration messages. + chip::Server::GetInstance().GetUserDirectedCommissioningClient()->SetCommissionerDeclarationHandler(nullptr); +#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT + // Shutdown the Matter server chip::Server::GetInstance().Shutdown(); diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp index c9f938dbc695c7..0f455d6b4c9a44 100644 --- a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp +++ b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp @@ -30,7 +30,7 @@ namespace core { CastingPlayer * CastingPlayer::mTargetCastingPlayer = nullptr; void CastingPlayer::VerifyOrEstablishConnection(ConnectCallback onCompleted, unsigned long long int commissioningWindowTimeoutSec, - EndpointFilter desiredEndpointFilter) + IdentificationDeclarationOptions idOptions) { ChipLogProgress(AppServer, "CastingPlayer::VerifyOrEstablishConnection() called"); @@ -50,12 +50,14 @@ void CastingPlayer::VerifyOrEstablishConnection(ConnectCallback onCompleted, uns mOnCompleted = onCompleted; mCommissioningWindowTimeoutSec = commissioningWindowTimeoutSec; mTargetCastingPlayer = this; + mIdOptions = idOptions; // If *this* CastingPlayer was previously connected to, its nodeId, fabricIndex and other attributes should be present // in the CastingStore cache. If that is the case, AND, the cached data contains the endpoint desired by the client, if any, - // as per desiredEndpointFilter, simply Find or Re-establish the CASE session and return early + // as per IdentificationDeclarationOptions.mTargetAppInfos, simply Find or Re-establish the CASE session and return early. if (cachedCastingPlayers.size() != 0) { + ChipLogProgress(AppServer, "CastingPlayer::VerifyOrEstablishConnection() Re-establishing CASE with cached CastingPlayer"); it = std::find_if(cachedCastingPlayers.begin(), cachedCastingPlayers.end(), [this](const core::CastingPlayer & castingPlayerParam) { return castingPlayerParam == *this; }); @@ -63,7 +65,7 @@ void CastingPlayer::VerifyOrEstablishConnection(ConnectCallback onCompleted, uns if (it != cachedCastingPlayers.end()) { unsigned index = (unsigned int) std::distance(cachedCastingPlayers.begin(), it); - if (ContainsDesiredEndpoint(&cachedCastingPlayers[index], desiredEndpointFilter)) + if (ContainsDesiredTargetApp(&cachedCastingPlayers[index], idOptions.getTargetAppInfoList())) { ChipLogProgress( AppServer, @@ -163,14 +165,15 @@ void CastingPlayer::RegisterEndpoint(const memory::Strong endpoint) #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT CHIP_ERROR CastingPlayer::SendUserDirectedCommissioningRequest() { + ChipLogProgress(AppServer, "CastingPlayer::SendUserDirectedCommissioningRequest()"); chip::Inet::IPAddress * ipAddressToUse = GetIpAddressForUDCRequest(); VerifyOrReturnValue(ipAddressToUse != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(AppServer, "No IP Address found to send UDC request to")); ReturnErrorOnFailure(support::ChipDeviceEventHandler::SetUdcStatus(true)); - // TODO: expose options to the higher layer - chip::Protocols::UserDirectedCommissioning::IdentificationDeclaration id; + chip::Protocols::UserDirectedCommissioning::IdentificationDeclaration id = mIdOptions.buildIdentificationDeclarationMessage(); + ReturnErrorOnFailure(chip::Server::GetInstance().SendUserDirectedCommissioningRequest( chip::Transport::PeerAddress::UDP(*ipAddressToUse, mAttributes.port, mAttributes.interfaceId), id)); @@ -216,21 +219,27 @@ void CastingPlayer::FindOrEstablishSession(void * clientContext, chip::OnDeviceC connectionContext->mOnConnectionFailureCallback); } -bool CastingPlayer::ContainsDesiredEndpoint(core::CastingPlayer * cachedCastingPlayer, EndpointFilter desiredEndpointFilter) +bool CastingPlayer::ContainsDesiredTargetApp( + core::CastingPlayer * cachedCastingPlayer, + std::vector desiredTargetApps) { std::vector> cachedEndpoints = cachedCastingPlayer->GetEndpoints(); - for (const auto & cachedEndpoint : cachedEndpoints) + for (size_t i = 0; i < desiredTargetApps.size(); i++) { - bool match = true; - match = match && (desiredEndpointFilter.vendorId == 0 || cachedEndpoint->GetVendorId() == desiredEndpointFilter.vendorId); - match = - match && (desiredEndpointFilter.productId == 0 || cachedEndpoint->GetProductId() == desiredEndpointFilter.productId); - // TODO: check deviceTypeList - if (match) + for (const auto & cachedEndpoint : cachedEndpoints) { - return true; + bool match = true; + match = match && (desiredTargetApps[i].vendorId == 0 || cachedEndpoint->GetVendorId() == desiredTargetApps[i].vendorId); + match = + match && (desiredTargetApps[i].productId == 0 || cachedEndpoint->GetProductId() == desiredTargetApps[i].productId); + if (match) + { + ChipLogProgress(AppServer, "CastingPlayer::ContainsDesiredTargetApp() matching cached CastingPlayer found"); + return true; + } } } + ChipLogProgress(AppServer, "CastingPlayer::ContainsDesiredTargetApp() matching cached CastingPlayer not found"); return false; } diff --git a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h index 783d50f60af390..2748eafc22cc7e 100644 --- a/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h +++ b/examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h @@ -18,7 +18,9 @@ #pragma once +#include "CommissionerDeclarationHandler.h" #include "Endpoint.h" +#include "IdentificationDeclarationOptions.h" #include "Types.h" #include "support/ChipDeviceEventHandler.h" #include "support/EndpointListLoader.h" @@ -123,13 +125,15 @@ class CastingPlayer : public std::enable_shared_from_this * For failure - called back with an error and nullptr. * @param commissioningWindowTimeoutSec (Optional) time (in sec) to keep the commissioning window open, if commissioning is * required. Needs to be >= kCommissioningWindowTimeoutSec. - * @param desiredEndpointFilter (Optional) Attributes (such as VendorId) describing an Endpoint that the client wants to - * interact with after commissioning. If this value is passed in, the VerifyOrEstablishConnection will force User Directed - * Commissioning, in case the desired Endpoint is not found in the on device CastingStore. + * @param idOptions (Optional) Parameters in the IdentificationDeclaration message sent by the Commissionee to the Commissioner. + * These parameters specify the information relating to the requested commissioning session. + * Furthermore, attributes (such as VendorId) describe the TargetApp that the client wants to interact with after commissioning. + * If this value is passed in, VerifyOrEstablishConnection() will force User Directed Commissioning, in case the desired + * TargetApp is not found in the on-device CastingStore. */ void VerifyOrEstablishConnection(ConnectCallback onCompleted, unsigned long long int commissioningWindowTimeoutSec = kCommissioningWindowTimeoutSec, - EndpointFilter desiredEndpointFilter = EndpointFilter()); + IdentificationDeclarationOptions idOptions = IdentificationDeclarationOptions()); /** * @brief Sets the internal connection state of this CastingPlayer to "disconnected" @@ -197,6 +201,7 @@ class CastingPlayer : public std::enable_shared_from_this std::vector> mEndpoints; ConnectionState mConnectionState = CASTING_PLAYER_NOT_CONNECTED; CastingPlayerAttributes mAttributes; + IdentificationDeclarationOptions mIdOptions; static CastingPlayer * mTargetCastingPlayer; unsigned long long int mCommissioningWindowTimeoutSec = kCommissioningWindowTimeoutSec; ConnectCallback mOnCompleted = {}; @@ -217,12 +222,12 @@ class CastingPlayer : public std::enable_shared_from_this #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT /** - * @brief Checks if the cachedCastingPlayer contains an Endpoint that matches the description of the desiredEndpointFilter - * - * @return true - cachedCastingPlayer contains at least one endpoint that matches all the (non-default) values in - * desiredEndpointFilter, false otherwise + * @brief Checks if the cachedCastingPlayer contains at least one Endpoint/TargetApp described in the desiredTargetApps list. + * @return true - cachedCastingPlayer contains at least one endpoints with matching (non-default) values for vendorID and + * productID as described in the desiredTargetApps list, false otherwise. */ - bool ContainsDesiredEndpoint(core::CastingPlayer * cachedCastingPlayer, EndpointFilter desiredEndpointFilter); + bool ContainsDesiredTargetApp(core::CastingPlayer * cachedCastingPlayer, + std::vector desiredTargetApps); // ChipDeviceEventHandler handles chip::DeviceLayer::ChipDeviceEvent events and helps the CastingPlayer class commission with // and connect to a CastingPlayer diff --git a/examples/tv-casting-app/tv-casting-common/core/CommissionerDeclarationHandler.cpp b/examples/tv-casting-app/tv-casting-common/core/CommissionerDeclarationHandler.cpp new file mode 100644 index 00000000000000..1bedc6ce316a39 --- /dev/null +++ b/examples/tv-casting-app/tv-casting-common/core/CommissionerDeclarationHandler.cpp @@ -0,0 +1,49 @@ +/* + * + * Copyright (c) 2024 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 "CommissionerDeclarationHandler.h" + +#include "Types.h" + +namespace matter { +namespace casting { +namespace core { + +CommissionerDeclarationHandler * CommissionerDeclarationHandler::sCommissionerDeclarationHandler_ = nullptr; + +CommissionerDeclarationHandler * CommissionerDeclarationHandler::GetInstance() +{ + if (sCommissionerDeclarationHandler_ == nullptr) + { + sCommissionerDeclarationHandler_ = new CommissionerDeclarationHandler(); + } + return sCommissionerDeclarationHandler_; +} + +// TODO: In the following PRs. Implement setHandler() for CommissionerDeclaration messages and expose messages to higher layers for +// Linux, Android and iOS. +void CommissionerDeclarationHandler::OnCommissionerDeclarationMessage( + const chip::Transport::PeerAddress & source, chip::Protocols::UserDirectedCommissioning::CommissionerDeclaration cd) +{ + ChipLogProgress(AppServer, "CommissionerDeclarationHandler::OnCommissionerDeclarationMessage() called TODO: handle message"); + cd.DebugLog(); +} + +}; // namespace core +}; // namespace casting +}; // namespace matter diff --git a/examples/tv-casting-app/tv-casting-common/core/CommissionerDeclarationHandler.h b/examples/tv-casting-app/tv-casting-common/core/CommissionerDeclarationHandler.h new file mode 100644 index 00000000000000..e84ca59a59e23d --- /dev/null +++ b/examples/tv-casting-app/tv-casting-common/core/CommissionerDeclarationHandler.h @@ -0,0 +1,49 @@ +/* + * + * Copyright (c) 2024 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 "Types.h" + +namespace matter { +namespace casting { +namespace core { + +/** + * @brief React to the Commissioner's CommissionerDeclaration messages with this singleton. + */ +class CommissionerDeclarationHandler : public chip::Protocols::UserDirectedCommissioning::CommissionerDeclarationHandler +{ +public: + CommissionerDeclarationHandler(const CommissionerDeclarationHandler &) = delete; + void operator=(const CommissionerDeclarationHandler &) = delete; + + static CommissionerDeclarationHandler * GetInstance(); + + void OnCommissionerDeclarationMessage(const chip::Transport::PeerAddress & source, + chip::Protocols::UserDirectedCommissioning::CommissionerDeclaration cd) override; + +private: + static CommissionerDeclarationHandler * sCommissionerDeclarationHandler_; + CommissionerDeclarationHandler() {} + ~CommissionerDeclarationHandler() {} +}; + +}; // namespace core +}; // namespace casting +}; // namespace matter diff --git a/examples/tv-casting-app/tv-casting-common/core/IdentificationDeclarationOptions.h b/examples/tv-casting-app/tv-casting-common/core/IdentificationDeclarationOptions.h new file mode 100644 index 00000000000000..af1ae2aaa79d62 --- /dev/null +++ b/examples/tv-casting-app/tv-casting-common/core/IdentificationDeclarationOptions.h @@ -0,0 +1,126 @@ +/* + * + * Copyright (c) 2024 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 "Types.h" +#include + +namespace matter { +namespace casting { +namespace core { + +/** + * This class contains the optional parameters used in the IdentificationDeclaration Message, sent by the Commissionee to the + * Commissioner. The options specify information relating to the requested UDC commissioning session. + */ +class IdentificationDeclarationOptions +{ +public: + /** + * Feature: Target Content Application + * Flag to instruct the Commissioner not to display a Passcode input dialog, and instead send a CommissionerDeclaration message + * if a commissioning Passcode is needed. + */ + bool mNoPasscode = false; + /** + * Feature: Coordinate Passcode Dialogs + * Flag to instruct the Commissioner to send a CommissionerDeclaration message when the Passcode input dialog on the + * Commissioner has been shown to the user. + */ + bool mCdUponPasscodeDialog = false; + /** + * Feature: Commissioner-Generated Passcode + * Flag to instruct the Commissioner to use the Commissioner-generated Passcode for commissioning. + */ + bool mCommissionerPasscode = false; + /** + * Feature: Commissioner-Generated Passcode + * Flag to indicate whether or not the Commissionee has obtained the Commissioner Passcode from the user and is therefore ready + * for commissioning. + */ + bool mCommissionerPasscodeReady = false; + /** + * Feature: Coordinate Passcode Dialogs + * Flag to indicate when the Commissionee user has decided to exit the commissioning process. + */ + bool mCancelPasscode = false; + + CHIP_ERROR addTargetAppInfo(const chip::Protocols::UserDirectedCommissioning::TargetAppInfo & targetAppInfo) + { + if (mTargetAppInfos.size() >= CHIP_DEVICE_CONFIG_UDC_MAX_TARGET_APPS) + { + ChipLogError(AppServer, + "IdentificationDeclarationOptions::addTargetAppInfo() failed to add TargetAppInfo, max vector size is %d", + CHIP_DEVICE_CONFIG_UDC_MAX_TARGET_APPS); + return CHIP_ERROR_NO_MEMORY; + } + + mTargetAppInfos.push_back(targetAppInfo); + return CHIP_NO_ERROR; + } + + std::vector getTargetAppInfoList() const { return mTargetAppInfos; } + + /** + * @brief Builds an IdentificationDeclaration message to be sent to a CastingPlayer, given the options state specified in this + * object. + */ + chip::Protocols::UserDirectedCommissioning::IdentificationDeclaration buildIdentificationDeclarationMessage() + { + ChipLogProgress(AppServer, "IdentificationDeclarationOptions::buildIdentificationDeclarationMessage()"); + chip::Protocols::UserDirectedCommissioning::IdentificationDeclaration id; + + std::vector targetAppInfos = getTargetAppInfoList(); + for (size_t i = 0; i < targetAppInfos.size(); i++) + { + id.AddTargetAppInfo(targetAppInfos[i]); + } + id.SetNoPasscode(mNoPasscode); + id.SetCdUponPasscodeDialog(mCdUponPasscodeDialog); + id.SetCancelPasscode(mCancelPasscode); + + ChipLogProgress(AppServer, + "IdentificationDeclarationOptions::buildIdentificationDeclarationMessage() mCommissionerPasscode: %s", + mCommissionerPasscode ? "true" : "false"); + id.SetCommissionerPasscode(mCommissionerPasscode); + + ChipLogProgress(AppServer, + "IdentificationDeclarationOptions::buildIdentificationDeclarationMessage() mCommissionerPasscodeReady: %s", + mCommissionerPasscodeReady ? "true" : "false"); + if (mCommissionerPasscodeReady) + { + id.SetCommissionerPasscodeReady(true); + mCommissionerPasscodeReady = false; + } + return id; + } + +private: + /** + * Feature: Target Content Application + * The set of content app Vendor IDs (and optionally, Product IDs) that can be used for authentication. + * Also, if TargetAppInfo is passed in, VerifyOrEstablishConnection() will force User Directed Commissioning, in case the + * desired TargetApp is not found in the on-device CastingStore. + */ + std::vector mTargetAppInfos; +}; + +}; // namespace core +}; // namespace casting +}; // namespace matter diff --git a/examples/tv-casting-app/tv-casting-common/include/CHIPProjectAppConfig.h b/examples/tv-casting-app/tv-casting-common/include/CHIPProjectAppConfig.h index 74926b00489703..f5887bc3828b08 100644 --- a/examples/tv-casting-app/tv-casting-common/include/CHIPProjectAppConfig.h +++ b/examples/tv-casting-app/tv-casting-common/include/CHIPProjectAppConfig.h @@ -53,6 +53,10 @@ #define CHIP_DEVICE_CONFIG_ENABLE_PAIRING_AUTOSTART 0 +// TVs can handle the memory impact of supporting a larger list of target apps. See +// examples/tv-app/tv-common/include/CHIPProjectAppConfig.h +#define CHIP_DEVICE_CONFIG_UDC_MAX_TARGET_APPS 10 + // For casting, we need to allow more ACL entries, and more complex entries #define CHIP_CONFIG_EXAMPLE_ACCESS_CONTROL_MAX_TARGETS_PER_ENTRY 20 #define CHIP_CONFIG_EXAMPLE_ACCESS_CONTROL_MAX_SUBJECTS_PER_ENTRY 20 diff --git a/examples/tv-casting-app/tv-casting-common/support/AppParameters.h b/examples/tv-casting-app/tv-casting-common/support/AppParameters.h index 9539a2919a81f5..080011f8953c37 100644 --- a/examples/tv-casting-app/tv-casting-common/support/AppParameters.h +++ b/examples/tv-casting-app/tv-casting-common/support/AppParameters.h @@ -42,6 +42,7 @@ class AppParameters chip::Credentials::DeviceAttestationCredentialsProvider * deviceAttestationCredentialsProvider, chip::Credentials::DeviceAttestationVerifier * deviceAttestationVerifier, ServerInitParamsProvider * serverInitParamsProvider) + // TODO: In the following PRs. Add CommissionerDeclarationHandler. { VerifyOrReturnError(commissionableDataProvider != nullptr, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(deviceAttestationCredentialsProvider != nullptr, CHIP_ERROR_INVALID_ARGUMENT); diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp index 1ad98d271262da..ad085d52be8a22 100644 --- a/src/app/server/Server.cpp +++ b/src/app/server/Server.cpp @@ -621,7 +621,7 @@ void Server::Shutdown() CHIP_ERROR Server::SendUserDirectedCommissioningRequest(chip::Transport::PeerAddress commissioner, Protocols::UserDirectedCommissioning::IdentificationDeclaration & id) { - ChipLogDetail(AppServer, "SendUserDirectedCommissioningRequest2"); + ChipLogDetail(AppServer, "Server::SendUserDirectedCommissioningRequest()"); CHIP_ERROR err; diff --git a/src/protocols/user_directed_commissioning/UserDirectedCommissioningServer.cpp b/src/protocols/user_directed_commissioning/UserDirectedCommissioningServer.cpp index a06bffcec62b3a..fb31049d1d99a9 100644 --- a/src/protocols/user_directed_commissioning/UserDirectedCommissioningServer.cpp +++ b/src/protocols/user_directed_commissioning/UserDirectedCommissioningServer.cpp @@ -367,6 +367,7 @@ CHIP_ERROR IdentificationDeclaration::ReadPayload(uint8_t * udcPayload, size_t p { ChipLogProgress(AppServer, "TLV end of array"); ReturnErrorOnFailure(reader.ExitContainer(listContainerType)); + err = CHIP_NO_ERROR; } } break;