From 96e1100c8ccd4d0a2dbb971c696a8c13569f667e Mon Sep 17 00:00:00 2001 From: Philip Gregor Date: Mon, 13 Jan 2025 14:01:25 -0800 Subject: [PATCH] tv-casting-app fix double call to OnCompleted() on connection success Fixing spelling Fixing CI build documentation error Fixing CI build documentation error2 Fixing CI build documentation error3 Fixing CI build documentation error4 --- examples/tv-casting-app/APIs.md | 11 ++++- .../casting/ConnectionExampleFragment.java | 2 +- examples/tv-casting-app/android/README.md | 44 ++++++++++++++++++- .../tv-casting-app/darwin/TvCasting/README.md | 17 +++++++ examples/tv-casting-app/linux/README.md | 20 +++++++-- .../linux/simple-app-helper.cpp | 3 ++ .../support/ChipDeviceEventHandler.cpp | 6 ++- .../support/EndpointListLoader.cpp | 25 +++++++++-- 8 files changed, 114 insertions(+), 14 deletions(-) diff --git a/examples/tv-casting-app/APIs.md b/examples/tv-casting-app/APIs.md index 75c63eb2379eac..90b3b0e118aea0 100644 --- a/examples/tv-casting-app/APIs.md +++ b/examples/tv-casting-app/APIs.md @@ -71,14 +71,21 @@ In order to illustrate these steps, refer to the figure below The Casting Client is expected to consume the Matter TV Casting library built for its respective platform which implements the APIs described in this document. Refer to the tv-casting-app READMEs for [Linux](linux/README.md), -Android and [iOS](darwin/TvCasting/README.md) to understand how to build and -consume each platform's specific libraries. The libraries MUST be built with the +[Android](https://github.com/project-chip/connectedhomeip/blob/master/examples/tv-casting-app/android/README.md) +and [iOS](darwin/TvCasting/README.md) to understand how to build and consume +each platform's specific libraries. The libraries MUST be built with the client's specific values for `CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID` and `CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID` updated in the [CHIPProjectAppConfig.h](tv-casting-common/include/CHIPProjectAppConfig.h) file. Other values like the `CHIP_DEVICE_CONFIG_DEVICE_NAME` may be updated as well to correspond to the client being built. +`CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID` and `CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID` +can be obtained during the CSA certification of your mobile app. The Matter SDK +has pre-configured sample/test values for them in the +[CHIPDeviceConfig.h](https://github.com/project-chip/connectedhomeip/blob/master/src/include/platform/CHIPDeviceConfig.h) +file. + ### Initialize the Casting Client _{Complete Initialization examples: [Linux](linux/simple-app.cpp) | diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ConnectionExampleFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ConnectionExampleFragment.java index f711096a22f79f..dcc148357ebe26 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ConnectionExampleFragment.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/matter/casting/ConnectionExampleFragment.java @@ -211,7 +211,7 @@ public void handle(CommissionerDeclaration cd) { FragmentActivity activity = getActivity(); // Prevent possible NullPointerException. This callback could be called when - // this Fragment is not attached to its host activity or when the fragment's + // this fragment is not attached to its host activity or when the fragment's // lifecycle is not in a valid state for interacting with the activity. if (activity != null && !activity.isFinishing()) { activity.runOnUiThread( diff --git a/examples/tv-casting-app/android/README.md b/examples/tv-casting-app/android/README.md index 047f960f817600..c4de0f921d6d35 100644 --- a/examples/tv-casting-app/android/README.md +++ b/examples/tv-casting-app/android/README.md @@ -7,6 +7,10 @@ commissioning mode, advertises itself as a Commissionable Node and gets commissioned. Then it allows the user to send Matter ContentLauncher commands to the TV. +Refer to the +[Matter Casting APIs documentation](https://project-chip.github.io/connectedhomeip-doc/examples/tv-casting-app/APIs.html) +to build the Matter “Casting Client” into your consumer-facing mobile app. +
- [Matter TV Casting Android App Example](#matter-tv-casting-android-app-example) @@ -15,6 +19,8 @@ the TV. - [Gradle \& JDK Version](#gradle--jdk-version) - [Preparing for build](#preparing-for-build) - [Building \& Installing the app](#building--installing-the-app) + - [Common build environment issues](#common-build-environment-issues) + - [Running the app](#running-the-app)
@@ -50,10 +56,24 @@ We are using Gradle 7.1.1 for all android project which does not support Java 17 (https://docs.gradle.org/current/userguide/compatibility.html) while the default JDK version on MacOS for Apple Silicon is 'openjdk 17.0.1' or above. -Using JDK bundled with Android Studio will help with that. +If you attempt to build with an incompatible Java version, you may encounter the +following error: + +```text +Unsupported class file major version XX +``` + +This error occurs when the Java version being used is not compatible with the +Gradle version in your project. + +See the +[Building Android](../../../docs/platforms/android/android_building.md#gradle--jdk-version) +guide for more info about the supported Gradle & JDK Version. + +You can verify your current Java version by running: ```shell -export JAVA_HOME=/Applications/Android\ Studio.app/Contents/jre/Contents/Home/ +java -version ```
@@ -107,3 +127,23 @@ adb install out/android-$TARGET_CPU-tv-casting-app/outputs/apk/debug/app-debug.a You can use Android Studio to edit the Android app itself and run it after build_examples.py, but you will not be able to edit Matter Android code from `src/controller/java`, or other Matter C++ code within Android Studio. + +## Common build environment issues + +1. If you see an error like `kotlinc: command not found`, install the Kotlin in + your build environment. Eg. on MacOS, this can be done with the command: + +```shell +brew install kotlin +``` + +## Running the app + +This example Matter TV Casting Android app can be tested with the following +video players: + +1. With the + [example Matter tv-app](https://github.com/project-chip/connectedhomeip/tree/master/examples/tv-app) + running on a Raspberry Pi - works out of the box. +2. With a FireTV device - requires your Amazon Customer ID to be allow-listed + first. diff --git a/examples/tv-casting-app/darwin/TvCasting/README.md b/examples/tv-casting-app/darwin/TvCasting/README.md index cb9a04dda120a2..904d6728cf799d 100644 --- a/examples/tv-casting-app/darwin/TvCasting/README.md +++ b/examples/tv-casting-app/darwin/TvCasting/README.md @@ -7,6 +7,10 @@ commissioning mode, advertises itself as a Commissionable Node and gets commissioned. Then it allows the user to send Matter ContentLauncher commands to the TV. +Refer to the +[Matter Casting APIs documentation](https://project-chip.github.io/connectedhomeip-doc/examples/tv-casting-app/APIs.html) +to build the Matter “Casting Client” into your consumer-facing mobile app. + --- - [Matter TV Casting iOS App Example](#matter-tv-casting-ios-app-example) @@ -14,6 +18,8 @@ the TV. - [Building through command line](#building-through-command-line) - [Compilation Fixes](#compilation-fixes) - [Installing the Application](#installing-the-application) + - [Debugging](#debugging) + - [Running the Application](#running-the-application) --- @@ -98,3 +104,14 @@ the run button once more. Use the "TvCasting" scheme when building to enable debugging. If you wish to build the app without any debugging symbols, use the "TvCasting Release" scheme. + +## Running the Application + +This example Matter TV Casting iOS application can be tested with the following +video players: + +1. With the + [example Matter tv-app](https://github.com/project-chip/connectedhomeip/tree/master/examples/tv-app) + running on a Raspberry Pi - works out of the box. +2. With a FireTV device - requires your Amazon Customer ID to be allow-listed + first. diff --git a/examples/tv-casting-app/linux/README.md b/examples/tv-casting-app/linux/README.md index 19b75b87034bdb..877505680fd770 100644 --- a/examples/tv-casting-app/linux/README.md +++ b/examples/tv-casting-app/linux/README.md @@ -6,6 +6,10 @@ select one, sends the TV a User Directed Commissioning request, enters commissioning mode, advertises itself as a Commissionable Node and gets commissioned. Then it allows the user to send CHIP commands to the TV. +Refer to the +[Matter Casting APIs documentation](https://project-chip.github.io/connectedhomeip-doc/examples/tv-casting-app/APIs.html) +to build the Matter “Casting Client” into your consumer-facing mobile app. +
- [CHIP TV Casting App Example](#chip-tv-casting-app-example) @@ -63,10 +67,15 @@ commissioned. Then it allows the user to send CHIP commands to the TV. ### Commissioning the tv-casting-app -The tv-casting-app will automatically discover video players and print these out -upon startup. The user-directed-commissioning (UDC) process can be initiated -using the shell by specifying the index of the discovered video player in the -printed list. +This example Matter TV Casting iOS application can be tested with the following +video players: + +1. With the + [example Matter tv-app](https://github.com/project-chip/connectedhomeip/tree/master/examples/tv-app) + running on a Raspberry Pi - works out of the box. The tv-casting-app will + automatically discover video players and print these out upon startup. The + user-directed-commissioning (UDC) process can be initiated using the shell by + specifying the index of the discovered video player in the printed list. - Initiate UDC for the discovered video player with index 0 @@ -81,6 +90,9 @@ printed list. tv-casting-app> cast discover +2. With a FireTV device - requires your Amazon Customer ID to be allow-listed + first. + ### Re-Running the Example on Linux with Cached Fabrics After successfully commissioning the tv-casting-app onto a fabric the app can be diff --git a/examples/tv-casting-app/linux/simple-app-helper.cpp b/examples/tv-casting-app/linux/simple-app-helper.cpp index f354aa094f7da5..0109fa819d1f1d 100644 --- a/examples/tv-casting-app/linux/simple-app-helper.cpp +++ b/examples/tv-casting-app/linux/simple-app-helper.cpp @@ -318,12 +318,15 @@ void ConnectionHandler(CHIP_ERROR err, matter::casting::core::CastingPlayer * ca castingPlayer->GetId(), endpoints[index]->GetId()); // demonstrate invoking a command + ChipLogProgress(AppServer, "simple-app-helper.cpp::ConnectionHandler() calling InvokeContentLauncherLaunchURL()"); InvokeContentLauncherLaunchURL(endpoints[index]); // demonstrate reading an attribute + ChipLogProgress(AppServer, "simple-app-helper.cpp::ConnectionHandler() calling ReadApplicationBasicVendorID()"); ReadApplicationBasicVendorID(endpoints[index]); // demonstrate subscribing to an attribute + ChipLogProgress(AppServer, "simple-app-helper.cpp::ConnectionHandler() calling SubscribeToMediaPlaybackCurrentState()"); SubscribeToMediaPlaybackCurrentState(endpoints[index]); } else diff --git a/examples/tv-casting-app/tv-casting-common/support/ChipDeviceEventHandler.cpp b/examples/tv-casting-app/tv-casting-common/support/ChipDeviceEventHandler.cpp index f027c8d1c477df..91c0da0173e693 100644 --- a/examples/tv-casting-app/tv-casting-common/support/ChipDeviceEventHandler.cpp +++ b/examples/tv-casting-app/tv-casting-common/support/ChipDeviceEventHandler.cpp @@ -44,6 +44,7 @@ void ChipDeviceEventHandler::Handle(const chip::DeviceLayer::ChipDeviceEvent * e if (event->Type == chip::DeviceLayer::DeviceEventType::kFailSafeTimerExpired && CastingPlayer::GetTargetCastingPlayer()->mConnectionState == CASTING_PLAYER_CONNECTING) { + ChipLogProgress(AppServer, "ChipDeviceEventHandler::Handle() event kFailSafeTimerExpired"); HandleFailSafeTimerExpired(); } else if (event->Type == chip::DeviceLayer::DeviceEventType::kBindingsChangedViaCluster && @@ -53,16 +54,19 @@ void ChipDeviceEventHandler::Handle(const chip::DeviceLayer::ChipDeviceEvent * e } else if (event->Type == chip::DeviceLayer::DeviceEventType::kCommissioningComplete) { + // True when device completes initial commissioning (PASE). + // Note: Not triggered for subsequent CASE sessions established via CastingPlayer::FindOrEstablishSession() HandleCommissioningComplete(event, arg, runPostCommissioning, targetNodeId, targetFabricIndex); } + // Run post commissioing for kBindingsChangedViaCluster and kCommissioningComplete events. if (runPostCommissioning) { sUdcInProgress = false; CastingPlayer::GetTargetCastingPlayer()->SetNodeId(targetNodeId); CastingPlayer::GetTargetCastingPlayer()->SetFabricIndex(targetFabricIndex); - ChipLogProgress(AppServer, "ChipDeviceEventHandler::Handle() calling FindOrEstablishSession()"); + ChipLogProgress(AppServer, "ChipDeviceEventHandler::Handle() calling CastingPlayer FindOrEstablishSession()"); CastingPlayer::GetTargetCastingPlayer()->FindOrEstablishSession( nullptr, [](void * context, chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle) { diff --git a/examples/tv-casting-app/tv-casting-common/support/EndpointListLoader.cpp b/examples/tv-casting-app/tv-casting-common/support/EndpointListLoader.cpp index a54c4ddc59debf..2399627a87884e 100644 --- a/examples/tv-casting-app/tv-casting-common/support/EndpointListLoader.cpp +++ b/examples/tv-casting-app/tv-casting-common/support/EndpointListLoader.cpp @@ -130,7 +130,8 @@ CHIP_ERROR EndpointListLoader::Load() if (!isLoadingRequired) { - ChipLogProgress(AppServer, "EndpointListLoader::Load found no new endpoints to load"); + ChipLogProgress(AppServer, + "EndpointListLoader::Load() found no new endpoints to load. Calling EndpointListLoader::Complete()"); mPendingAttributeReads = 0; Complete(); } @@ -172,16 +173,32 @@ void EndpointListLoader::Complete() mNewEndpointsToLoad = 0; // done loading endpoints, store TargetCastingPlayer + ChipLogProgress(AppServer, "EndpointListLoader::Complete() Calling CastingStore::AddOrUpdate()"); CHIP_ERROR err = support::CastingStore::GetInstance()->AddOrUpdate(*CastingPlayer::GetTargetCastingPlayer()); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "CastingStore::AddOrUpdate() failed. Err: %" CHIP_ERROR_FORMAT, err.Format()); } - // callback client OnCompleted + // Only trigger OnCompleted callback for target CastingPlayer when it has loaded endpoints (count >= 1) + // Note: After initial commissioning (kCommissioningComplete event), endpoints will be 0. + // CastingPlayer Endpoints are populated later, after receiving the kBindingsChangedViaCluster device event. VerifyOrReturn(CastingPlayer::GetTargetCastingPlayer()->mOnCompleted, - ChipLogError(AppServer, "EndpointListLoader::Complete() mOnCompleted() not found")); - CastingPlayer::GetTargetCastingPlayer()->mOnCompleted(CHIP_NO_ERROR, CastingPlayer::GetTargetCastingPlayer()); + ChipLogError(AppServer, "EndpointListLoader::Complete() OnCompleted() not found")); + + std::vector> endpoints = + CastingPlayer::GetTargetCastingPlayer()->GetEndpoints(); + if (endpoints.size() > 0) + { + ChipLogProgress(AppServer, + "EndpointListLoader::Complete() Target CastingPlayer endpoints: %d, calling client's OnCompleted()", + static_cast(endpoints.size())); + CastingPlayer::GetTargetCastingPlayer()->mOnCompleted(CHIP_NO_ERROR, CastingPlayer::GetTargetCastingPlayer()); + } + else + { + ChipLogProgress(AppServer, "EndpointListLoader::Complete() Target CastingPlayer endpoints pending setup."); + } } }