Skip to content

Commit

Permalink
Linux tv-casting-app: simplified CastingPlayer.VerifyOrEstablishConne…
Browse files Browse the repository at this point in the history
…ction API
  • Loading branch information
sharadb-amazon authored and pull[bot] committed Nov 2, 2023
1 parent 13f7924 commit 1941919
Show file tree
Hide file tree
Showing 16 changed files with 1,466 additions and 131 deletions.
35 changes: 33 additions & 2 deletions examples/tv-casting-app/APIs.md
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ func initialize() -> MatterError {

### Discover Casting Players

_{Complete Discovery examples: [Linux](linux/simple-app.cpp)}_
_{Complete Discovery examples: [Linux](linux/simple-app-helper.cpp)}_

The Casting Client discovers `CastingPlayers` using Matter Commissioner
discovery over DNS-SD by listening for `CastingPlayer` events as they are
Expand Down Expand Up @@ -444,12 +444,14 @@ singleton instance. Then, call `StartDiscovery` by optionally specifying the
`kTargetPlayerDeviceType` to filter results by.

```c
const uint64_t kTargetPlayerDeviceType = 35; // 35 represents device type of Matter Video Player
...
...
DiscoveryDelegateImpl delegate;
CastingPlayerDiscovery::GetInstance()->SetDelegate(&delegate);
VerifyOrReturnValue(err == CHIP_NO_ERROR, 0,
ChipLogError(AppServer, "CastingPlayerDiscovery::SetDelegate failed %" CHIP_ERROR_FORMAT, err.Format()));

const uint64_t kTargetPlayerDeviceType = 35; // 35 represents device type of Matter Video Player
err = CastingPlayerDiscovery::GetInstance()->StartDiscovery(kTargetPlayerDeviceType);
VerifyOrReturnValue(err == CHIP_NO_ERROR, 0,
ChipLogError(AppServer, "CastingPlayerDiscovery::StartDiscovery failed %" CHIP_ERROR_FORMAT, err.Format()));
Expand All @@ -459,6 +461,35 @@ chip::DeviceLayer::PlatformMgr().RunEventLoop();

### Connect to a Casting Player

_{Complete Connection examples: [Linux](linux/simple-app-helper.cpp)}_

Each `CastingPlayer` object created during
[Discovery](#discover-casting-players) contains information such as
`deviceName`, `vendorId`, `productId`, etc. which can help the user pick the
right `CastingPlayer`. A Casting Client can attempt to connect to the
`selectedCastingPlayer` using
[Matter User Directed Commissioning (UDC)](https://github.com/CHIP-Specifications/connectedhomeip-spec/blob/master/src/rendezvous/UserDirectedCommissioning.adoc).
The Matter TV Casting library locally caches information required to reconnect
to a `CastingPlayer`, once the Casting client has been commissioned by it. After
that, the Casting client is able to skip the full UDC process by establishing
CASE with the `CastingPlayer` directly. Once connected, the `CastingPlayer`
object will contain the list of available Endpoints on that `CastingPlayer`.

On Linux, the Casting Client can connect to a `CastingPlayer` by successfully
calling `VerifyOrEstablishConnection` on it.

```c
void ConnectionHandler(CHIP_ERROR err, matter::casting::core::CastingPlayer * castingPlayer)
{
ChipLogProgress(AppServer, "ConnectionHandler called with %" CHIP_ERROR_FORMAT, err.Format());
}

...
// targetCastingPlayer is a discovered CastingPlayer
targetCastingPlayer->VerifyOrEstablishConnection(ConnectionHandler);
...
```

### Select an Endpoint on the Casting Player

## Interacting with a Casting Endpoint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
#include "../JNIDACProvider.h"
#include "../support/ErrorConverter-JNI.h"
#include "../support/RotatingDeviceIdUniqueIdProvider-JNI.h"
#include "core/CastingApp.h" // from tv-casting-common

// from tv-casting-common
#include "core/CastingApp.h"
#include "support/ChipDeviceEventHandler.h"

#include <app/clusters/bindings/BindingManager.h>
#include <app/server/Server.h>
Expand Down Expand Up @@ -79,20 +82,25 @@ JNI_METHOD(jobject, finishStartup)(JNIEnv *, jobject)
{
chip::DeviceLayer::StackLock lock;
ChipLogProgress(AppServer, "JNI_METHOD CastingAppJNI.finishStartup called");
auto & server = chip::Server::GetInstance();

CHIP_ERROR err = CHIP_NO_ERROR;
auto & server = chip::Server::GetInstance();

// TODO: Set AppDelegate
// &server.GetCommissioningWindowManager().SetAppDelegate(??);

// Initialize binding handlers
chip::BindingManager::GetInstance().Init(
err = chip::BindingManager::GetInstance().Init(
{ &server.GetFabricTable(), server.GetCASESessionManager(), &server.GetPersistentStorage() });
VerifyOrReturnValue(err == CHIP_NO_ERROR, support::createJMatterError(err),
ChipLogError(AppServer, "Failed to init BindingManager %" CHIP_ERROR_FORMAT, err.Format()));

// TODO: Set FabricDelegate
// chip::Server::GetInstance().GetFabricTable().AddFabricDelegate(&mPersistenceManager);

// TODO: Add DeviceEvent Handler
// ReturnErrorOnFailure(DeviceLayer::PlatformMgrImpl().AddEventHandler(DeviceEventCallback, 0));
err = chip::DeviceLayer::PlatformMgrImpl().AddEventHandler(support::ChipDeviceEventHandler::Handle, 0);
VerifyOrReturnValue(err == CHIP_NO_ERROR, support::createJMatterError(err),
ChipLogError(AppServer, "Failed to register ChipDeviceEventHandler %" CHIP_ERROR_FORMAT, err.Format()));

return support::createJMatterError(CHIP_NO_ERROR);
}
Expand Down
2 changes: 2 additions & 0 deletions examples/tv-casting-app/linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ executable("chip-tv-casting-app") {
if (chip_casting_simplified) {
sources = [
"${chip_root}/examples/tv-casting-app/tv-casting-common/include/CHIPProjectAppConfig.h",
"simple-app-helper.cpp",
"simple-app-helper.h",
"simple-app.cpp",
]
} else {
Expand Down
177 changes: 177 additions & 0 deletions examples/tv-casting-app/linux/simple-app-helper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/*
*
* Copyright (c) 2023 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.
*/
#include "simple-app-helper.h"

#include "app/clusters/bindings/BindingManager.h"
#include <inttypes.h>
#include <lib/core/CHIPCore.h>
#include <lib/shell/Commands.h>
#include <lib/shell/Engine.h>
#include <lib/shell/commands/Help.h>
#include <lib/support/CHIPArgParser.hpp>
#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>
#include <platform/CHIPDeviceLayer.h>

DiscoveryDelegateImpl * DiscoveryDelegateImpl::_discoveryDelegateImpl = nullptr;

DiscoveryDelegateImpl * DiscoveryDelegateImpl::GetInstance()
{
if (_discoveryDelegateImpl == nullptr)
{
_discoveryDelegateImpl = new DiscoveryDelegateImpl();
}
return _discoveryDelegateImpl;
}

void DiscoveryDelegateImpl::HandleOnAdded(matter::casting::memory::Strong<matter::casting::core::CastingPlayer> player)
{
if (commissionersCount == 0)
{
ChipLogProgress(AppServer, "Select discovered Casting Player (start index = 0) to request commissioning");

ChipLogProgress(AppServer, "Example: cast request 0");
}
ChipLogProgress(AppServer, "Discovered CastingPlayer #%d", commissionersCount);
++commissionersCount;
player->LogDetail();
}

void DiscoveryDelegateImpl::HandleOnUpdated(matter::casting::memory::Strong<matter::casting::core::CastingPlayer> player)
{
ChipLogProgress(AppServer, "Updated CastingPlayer with ID: %s", player->GetId());
}

void ConnectionHandler(CHIP_ERROR err, matter::casting::core::CastingPlayer * castingPlayer)
{
ChipLogProgress(AppServer, "ConnectionHandler called with %" CHIP_ERROR_FORMAT, err.Format());
}

#if defined(ENABLE_CHIP_SHELL)
void RegisterCommands()
{
static const chip::Shell::shell_command_t sDeviceComand = { &CommandHandler, "cast",
"Casting commands. Usage: cast [command_name]" };

// Register the root `device` command with the top-level shell.
chip::Shell::Engine::Root().RegisterCommands(&sDeviceComand, 1);
}

CHIP_ERROR CommandHandler(int argc, char ** argv)
{
if (argc == 0 || strcmp(argv[0], "help") == 0)
{
return PrintAllCommands();
}
if (strcmp(argv[0], "discover") == 0)
{
ChipLogProgress(AppServer, "discover");

return matter::casting::core::CastingPlayerDiscovery::GetInstance()->StartDiscovery(kTargetPlayerDeviceType);
}
if (strcmp(argv[0], "stop-discovery") == 0)
{
ChipLogProgress(AppServer, "stop-discovery");
return matter::casting::core::CastingPlayerDiscovery::GetInstance()->StopDiscovery();
}
if (strcmp(argv[0], "request") == 0)
{
ChipLogProgress(AppServer, "request");
if (argc < 2)
{
return PrintAllCommands();
}
char * eptr;
unsigned long index = static_cast<unsigned long>(strtol(argv[1], &eptr, 10));
std::vector<matter::casting::memory::Strong<matter::casting::core::CastingPlayer>> castingPlayers =
matter::casting::core::CastingPlayerDiscovery::GetInstance()->GetCastingPlayers();
VerifyOrReturnValue(0 <= index && index < castingPlayers.size(), CHIP_ERROR_INVALID_ARGUMENT,
ChipLogError(AppServer, "Invalid casting player index provided: %lu", index));
std::shared_ptr<matter::casting::core::CastingPlayer> targetCastingPlayer = castingPlayers.at(index);
targetCastingPlayer->VerifyOrEstablishConnection(ConnectionHandler);
return CHIP_NO_ERROR;
}
if (strcmp(argv[0], "print-bindings") == 0)
{
PrintBindings();
return CHIP_NO_ERROR;
}
if (strcmp(argv[0], "print-fabrics") == 0)
{
PrintFabrics();
return CHIP_NO_ERROR;
}
if (strcmp(argv[0], "delete-fabric") == 0)
{
char * eptr;
chip::FabricIndex fabricIndex = (chip::FabricIndex) strtol(argv[1], &eptr, 10);
chip::Server::GetInstance().GetFabricTable().Delete(fabricIndex);
return CHIP_NO_ERROR;
}
return CHIP_ERROR_INVALID_ARGUMENT;
}

CHIP_ERROR PrintAllCommands()
{
chip::Shell::streamer_t * sout = chip::Shell::streamer_get();
streamer_printf(sout, " help Usage: cast <subcommand>\r\n");
streamer_printf(sout, " print-bindings Usage: cast print-bindings\r\n");
streamer_printf(sout, " print-fabrics Usage: cast print-fabrics\r\n");
streamer_printf(
sout,
" delete-fabric <index> 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 <index> Request connecting to discovered Casting Player with [index]. Usage: cast request 0\r\n");
streamer_printf(sout, "\r\n");

return CHIP_NO_ERROR;
}

void PrintBindings()
{
for (const auto & binding : chip::BindingTable::GetInstance())
{
ChipLogProgress(AppServer,
"Binding type=%d fab=%d nodeId=0x" ChipLogFormatX64
" groupId=%d local endpoint=%d remote endpoint=%d cluster=" ChipLogFormatMEI,
binding.type, binding.fabricIndex, ChipLogValueX64(binding.nodeId), binding.groupId, binding.local,
binding.remote, ChipLogValueMEI(binding.clusterId.ValueOr(0)));
}
}

void PrintFabrics()
{
// set fabric to be the first in the list
for (const auto & fb : chip::Server::GetInstance().GetFabricTable())
{
chip::FabricIndex fabricIndex = fb.GetFabricIndex();
ChipLogError(AppServer, "Next Fabric index=%d", fabricIndex);
if (!fb.IsInitialized())
{
ChipLogError(AppServer, " -- Not initialized");
continue;
}
chip::NodeId myNodeId = fb.GetNodeId();
ChipLogProgress(AppServer,
"---- Current Fabric nodeId=0x" ChipLogFormatX64 " fabricId=0x" ChipLogFormatX64 " fabricIndex=%d",
ChipLogValueX64(myNodeId), ChipLogValueX64(fb.GetFabricId()), fabricIndex);
}
}

#endif // ENABLE_CHIP_SHELL
92 changes: 92 additions & 0 deletions examples/tv-casting-app/linux/simple-app-helper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
*
* Copyright (c) 2023 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 "core/CastingPlayer.h"
#include "core/CastingPlayerDiscovery.h"
#include "core/Types.h"

#include <platform/CHIPDeviceLayer.h>

/**
* @brief Matter deviceType that the Linux tv-casting-app will discover over Commissionable Node discovery (DNS-SD)
*
* 35 represents device type of Matter Video Player
*/
const uint64_t kTargetPlayerDeviceType = 35;

/**
* @brief Singleton that reacts to CastingPlayer discovery results
*/
class DiscoveryDelegateImpl : public matter::casting::core::DiscoveryDelegate
{
private:
DiscoveryDelegateImpl(){};
static DiscoveryDelegateImpl * _discoveryDelegateImpl;
int commissionersCount = 0;

public:
static DiscoveryDelegateImpl * GetInstance();

/**
* @brief Called when a new CastingPlayer is discovered
*
* @param player the discovered CastingPlayer
*/
void HandleOnAdded(matter::casting::memory::Strong<matter::casting::core::CastingPlayer> player) override;

/**
* @brief Called when there are updates to the Attributes of a previously discovered CastingPlayer
*
* @param player the updated CastingPlayer
*/
void HandleOnUpdated(matter::casting::memory::Strong<matter::casting::core::CastingPlayer> player) override;
};

/**
* @brief Linux tv-casting-app's onCompleted handler for CastingPlayer.VerifyOrEstablishConnection API
*/
void ConnectionHandler(CHIP_ERROR err, matter::casting::core::CastingPlayer * castingPlayer);

#if defined(ENABLE_CHIP_SHELL)
/**
* @brief Register CHIP Shell commands for the Linux tv-casting-app CLI
*/
void RegisterCommands();

/**
* @brief Top level handler that parses text entered on the Linux tv-casting-app CLI and invokes the appropriate handler
*/
CHIP_ERROR CommandHandler(int argc, char ** argv);

/**
* @brief Prints all the commands available on the Linux tv-casting-app CLI
*/
CHIP_ERROR PrintAllCommands();

/**
* @brief Implements the "print-bindings" command
*/
void PrintBindings();

/**
* @brief Implements the "print-fabrics" command
*/
void PrintFabrics();
#endif
Loading

0 comments on commit 1941919

Please sign in to comment.