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 committed Oct 19, 2023
1 parent 71ef633 commit 666427f
Show file tree
Hide file tree
Showing 16 changed files with 1,465 additions and 131 deletions.
34 changes: 32 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,34 @@ chip::DeviceLayer::PlatformMgr().RunEventLoop();

### Connect to a Casting Player

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

Each CastingPlayer object created during [Discovery](#discovery) 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 666427f

Please sign in to comment.