Skip to content

Commit

Permalink
Linux tv-casting-app v1.3 Commissioner-Generated passcode follow up (#…
Browse files Browse the repository at this point in the history
…33525)

* Linux tv-casting-app v1.3 Commissioner-Generated passcode follow up

* Addressed comments by andy31415 and sharadb-amazon

* Fixed Linux Test build error in CastingPlayer.cpp

* Addressed comment by andy31415, added constant
  • Loading branch information
pgregorr-amazon authored May 22, 2024
1 parent eb515e1 commit bbb4196
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,8 @@ JNI_METHOD(jobject, verifyOrEstablishConnection)
matter::casting::core::ConnectionCallbacks connectionCallbacks;
connectionCallbacks.mOnConnectionComplete = connectCallback;

// TODO: Verify why commissioningWindowTimeoutSec is a "unsigned long long int" type. Seems too big.
castingPlayer->VerifyOrEstablishConnection(connectionCallbacks,
static_cast<unsigned long long int>(commissioningWindowTimeoutSec), idOptions);
castingPlayer->VerifyOrEstablishConnection(connectionCallbacks, static_cast<uint16_t>(commissioningWindowTimeoutSec),
idOptions);
return support::convertMatterErrorFromCppToJava(CHIP_NO_ERROR);
}

Expand Down
80 changes: 66 additions & 14 deletions examples/tv-casting-app/linux/simple-app-helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@

// VendorId of the Endpoint on the CastingPlayer that the CastingApp desires to interact with after connection
const uint16_t kDesiredEndpointVendorId = 65521;
// EndpointId of the Endpoint on the CastingPlayer that the CastingApp desires to interact with after connection using the
// Commissioner-Generated passcode commissioning flow
const uint8_t kDesiredEndpointId = 1;
// Indicates that the Commissioner-Generated passcode commissioning flow is in progress.
bool gCommissionerGeneratedPasscodeFlowRunning = false;

DiscoveryDelegateImpl * DiscoveryDelegateImpl::_discoveryDelegateImpl = nullptr;
bool gAwaitingCommissionerPasscodeInput = false;
Expand Down Expand Up @@ -244,6 +249,16 @@ CHIP_ERROR InitCommissionableDataProvider(LinuxCommissionableDataProvider & prov
options.payload.discriminator.GetLongValue());
}

void LogEndpointsDetails(const std::vector<matter::casting::memory::Strong<matter::casting::core::Endpoint>> & endpoints)
{
ChipLogProgress(AppServer, "simple-app-helper.cpp::LogEndpointsDetails() Number of Endpoints: %d",
static_cast<int>(endpoints.size()));
for (const auto & endpoint : endpoints)
{
endpoint->LogDetail();
}
}

void ConnectionHandler(CHIP_ERROR err, matter::casting::core::CastingPlayer * castingPlayer)
{
ChipLogProgress(AppServer, "simple-app-helper.cpp::ConnectionHandler()");
Expand All @@ -256,23 +271,51 @@ void ConnectionHandler(CHIP_ERROR err, matter::casting::core::CastingPlayer * ca
"simple-app-helper.cpp::ConnectionHandler(): Failed to connect to CastingPlayer (ID: %s) with err %" CHIP_ERROR_FORMAT,
targetCastingPlayer->GetId(), err.Format()));

ChipLogProgress(AppServer, "simple-app-helper.cpp::ConnectionHandler(): Successfully connected to CastingPlayer (ID: %s)",
castingPlayer->GetId());
ChipLogProgress(AppServer,
"simple-app-helper.cpp::ConnectionHandler(): Triggering demo interactions with CastingPlayer (ID: %s)",
castingPlayer->GetId());
if (gCommissionerGeneratedPasscodeFlowRunning)
{
ChipLogProgress(AppServer,
"simple-app-helper.cpp::ConnectionHandler(): Successfully connected to CastingPlayer (ID: %s) using "
"Commissioner-Generated passcode",
castingPlayer->GetId());
ChipLogProgress(AppServer, "simple-app-helper.cpp::ConnectionHandler(): Desired Endpoint ID for demo interactions: 1");
}
else
{
ChipLogProgress(AppServer, "simple-app-helper.cpp::ConnectionHandler(): Successfully connected to CastingPlayer (ID: %s)",
castingPlayer->GetId());
ChipLogProgress(AppServer,
"simple-app-helper.cpp::ConnectionHandler(): Desired Endpoint Vendor ID for demo interactions: %d",
kDesiredEndpointVendorId);
}

ChipLogProgress(AppServer, "simple-app-helper.cpp::ConnectionHandler(): Getting endpoints avaiable for demo interactions");
std::vector<matter::casting::memory::Strong<matter::casting::core::Endpoint>> endpoints = castingPlayer->GetEndpoints();
LogEndpointsDetails(endpoints);

// Find the desired Endpoint and auto-trigger some Matter Casting demo interactions
auto it = std::find_if(endpoints.begin(), endpoints.end(),
[](const matter::casting::memory::Strong<matter::casting::core::Endpoint> & endpoint) {
if (gCommissionerGeneratedPasscodeFlowRunning)
{
// For the example Commissioner-Generated passcode commissioning flow, run demo interactions with
// the Endpoint with ID 1. For this flow, we commissioned with the Target Content Application
// with Vendor ID 1111. Since this target content application does not report its Endpoint's
// Vendor IDs, we find the desired endpoint based on the Endpoint ID. See
// connectedhomeip/examples/tv-app/tv-common/include/AppTv.h.
return endpoint->GetId() == kDesiredEndpointId;
}
return endpoint->GetVendorId() == kDesiredEndpointVendorId;
});
if (it != endpoints.end())
{
// The desired endpoint is endpoints[index]
unsigned index = (unsigned int) std::distance(endpoints.begin(), it);

ChipLogProgress(
AppServer,
"simple-app-helper.cpp::ConnectionHandler(): Triggering demo interactions with CastingPlayer (ID: %s). Endpoint ID: %d",
castingPlayer->GetId(), endpoints[index]->GetId());

// demonstrate invoking a command
InvokeContentLauncherLaunchURL(endpoints[index]);

Expand All @@ -286,8 +329,8 @@ void ConnectionHandler(CHIP_ERROR err, matter::casting::core::CastingPlayer * ca
{
ChipLogError(
AppServer,
"simple-app-helper.cpp::ConnectionHandler():Desired Endpoint Vendor Id (%d) not found on the CastingPlayer (ID: %s)",
kDesiredEndpointVendorId, castingPlayer->GetId());
"simple-app-helper.cpp::ConnectionHandler():Desired Endpoint Vendor ID not found on the CastingPlayer (ID: %s)",
castingPlayer->GetId());
}
}

Expand Down Expand Up @@ -350,9 +393,14 @@ CHIP_ERROR CommandHandler(int argc, char ** argv)
ChipLogError(AppServer, "Invalid casting player index provided: %lu", index));
targetCastingPlayer = castingPlayers.at(index);

gCommissionerGeneratedPasscodeFlowRunning = false;
matter::casting::core::IdentificationDeclarationOptions idOptions;
chip::Protocols::UserDirectedCommissioning::TargetAppInfo targetAppInfo;
targetAppInfo.vendorId = kDesiredEndpointVendorId;

if (argc == 3)
{

if (strcmp(argv[2], "commissioner-generated-passcode") == 0)
{
// Attempt Commissioner-Generated Passcode (commissioner-generated-passcode) commissioning flow only if the
Expand All @@ -364,6 +412,14 @@ CHIP_ERROR CommandHandler(int argc, char ** argv)
"Commissioner-Generated Passcode commissioning flow",
index);
idOptions.mCommissionerPasscode = true;

// For the example Commissioner-Generated passcode commissioning flow, override the default Target Content
// Application Vendor ID, which is configured on the tv-app. This Target Content Application Vendor ID (1111),
// does not implement the AccountLogin cluster, which would otherwise auto commission using the
// Commissionee-Generated passcode upon recieving the IdentificationDeclaration Message. See
// connectedhomeip/examples/tv-app/tv-common/include/AppTv.h.
targetAppInfo.vendorId = 1111;
gCommissionerGeneratedPasscodeFlowRunning = true;
}
else
{
Expand All @@ -374,9 +430,8 @@ CHIP_ERROR CommandHandler(int argc, char ** argv)
}
}
}
chip::Protocols::UserDirectedCommissioning::TargetAppInfo targetAppInfo;
targetAppInfo.vendorId = kDesiredEndpointVendorId;
CHIP_ERROR result = idOptions.addTargetAppInfo(targetAppInfo);

CHIP_ERROR result = idOptions.addTargetAppInfo(targetAppInfo);
if (result != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "CommandHandler() request, failed to add targetAppInfo: %" CHIP_ERROR_FORMAT, result.Format());
Expand Down Expand Up @@ -430,11 +485,8 @@ CHIP_ERROR CommandHandler(int argc, char ** argv)
err.Format());
}

matter::casting::core::ConnectionCallbacks connectionCallbacks;
connectionCallbacks.mOnConnectionComplete = ConnectionHandler;

// Continue Connecting to the target CastingPlayer with the user entered Commissioner-generated Passcode.
targetCastingPlayer->ContinueConnecting(connectionCallbacks, matter::casting::core::kCommissioningWindowTimeoutSec);
targetCastingPlayer->ContinueConnecting();
}
else
{
Expand Down
102 changes: 55 additions & 47 deletions examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ namespace core {

CastingPlayer * CastingPlayer::mTargetCastingPlayer = nullptr;

// TODO: Verify why commissioningWindowTimeoutSec is a "unsigned long long int" type. Seems too big.
void CastingPlayer::VerifyOrEstablishConnection(ConnectionCallbacks connectionCallbacks,
unsigned long long int commissioningWindowTimeoutSec,
void CastingPlayer::VerifyOrEstablishConnection(ConnectionCallbacks connectionCallbacks, uint16_t commissioningWindowTimeoutSec,
IdentificationDeclarationOptions idOptions)
{
ChipLogProgress(AppServer, "CastingPlayer::VerifyOrEstablishConnection() called");
Expand Down Expand Up @@ -72,6 +70,25 @@ void CastingPlayer::VerifyOrEstablishConnection(ConnectionCallbacks connectionCa
"CastingPlayer::VerifyOrEstablishConnection() CommissionerDeclarationCallback not provided in ConnectionCallbacks");
}

ChipLogProgress(AppServer, "CastingPlayer::VerifyOrEstablishConnection() verifying User Directed Commissioning (UDC) state");
mIdOptions.LogDetail();
if (!GetSupportsCommissionerGeneratedPasscode() && mIdOptions.mCommissionerPasscode)
{
ChipLogError(AppServer,
"CastingPlayer::VerifyOrEstablishConnection() the target CastingPlayer doesn't support Commissioner-Generated "
"passcode yet IdentificationDeclarationOptions.mCommissionerPasscode is set to true");
SuccessOrExit(err = CHIP_ERROR_INVALID_ARGUMENT);
}
if (!matter::casting::core::CommissionerDeclarationHandler::GetInstance()->HasCommissionerDeclarationCallback() &&
mIdOptions.mCommissionerPasscode)
{
ChipLogError(
AppServer,
"CastingPlayer::VerifyOrEstablishConnection() the CommissionerDeclarationHandler CommissionerDeclaration message "
"callback has not been set, yet IdentificationDeclarationOptions.mCommissionerPasscode is set to true");
SuccessOrExit(err = CHIP_ERROR_INVALID_ARGUMENT);
}

// 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 IdentificationDeclarationOptions.mTargetAppInfos, simply Find or Re-establish the CASE session and return early.
Expand Down Expand Up @@ -138,28 +155,11 @@ void CastingPlayer::VerifyOrEstablishConnection(ConnectionCallbacks connectionCa
}
else
{
ChipLogProgress(AppServer,
"CastingPlayer::VerifyOrEstablishConnection() verifying User Directed Commissioning (UDC) state");
mIdOptions.LogDetail();
SuccessOrExit(err = support::ChipDeviceEventHandler::SetUdcStatus(true));

if (!GetSupportsCommissionerGeneratedPasscode() && mIdOptions.mCommissionerPasscode)
{
ChipLogError(
AppServer,
"CastingPlayer::VerifyOrEstablishConnection() the target CastingPlayer doesn't support Commissioner-Generated "
"passcode yet IdentificationDeclarationOptions.mCommissionerPasscode is set to true");
SuccessOrExit(err = CHIP_ERROR_INVALID_ARGUMENT);
}
if (!matter::casting::core::CommissionerDeclarationHandler::GetInstance()->HasCommissionerDeclarationCallback() &&
mIdOptions.mCommissionerPasscode)
{
ChipLogError(AppServer,
"CastingPlayer::VerifyOrEstablishConnection() the CommissionerDeclaration message callback has not been "
"set yet IdentificationDeclarationOptions.mCommissionerPasscode is set to true");
SuccessOrExit(err = CHIP_ERROR_INVALID_ARGUMENT);
}

// We need to call OpenBasicCommissioningWindow() for both Commissionee-Generated passcode commissioning flow and
// Commissioner-Generated passcode commissioning flow. Per the Matter spec (UserDirectedCommissioning), even if the
// Commissionee sends an IdentificationDeclaration with CommissionerPasscode set to true, the Commissioner will first
// attempt to use AccountLogin in order to obtain Passcode using rotatingID. If no Passcode is obtained, Commissioner
// displays a Passcode.
ChipLogProgress(AppServer, "CastingPlayer::VerifyOrEstablishConnection() calling OpenBasicCommissioningWindow()");
SuccessOrExit(err = chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow(
chip::System::Clock::Seconds16(mCommissioningWindowTimeoutSec)));
Expand All @@ -178,33 +178,19 @@ void CastingPlayer::VerifyOrEstablishConnection(ConnectionCallbacks connectionCa
}
}

void CastingPlayer::ContinueConnecting(ConnectionCallbacks connectionCallbacks,
unsigned long long int commissioningWindowTimeoutSec)
void CastingPlayer::ContinueConnecting()
{
ChipLogProgress(AppServer, "CastingPlayer::ContinueConnecting()");
CHIP_ERROR err = CHIP_NO_ERROR;
SuccessOrExit(err = support::ChipDeviceEventHandler::SetUdcStatus(true));
VerifyOrExit(
connectionCallbacks.mOnConnectionComplete != nullptr,
ChipLogError(AppServer, "CastingPlayer::ContinueConnecting() ConnectionCallbacks.mOnConnectionComplete was not provided"));
mConnectionState = CASTING_PLAYER_CONNECTING;
mOnCompleted = connectionCallbacks.mOnConnectionComplete;
mCommissioningWindowTimeoutSec = commissioningWindowTimeoutSec;
mTargetCastingPlayer = this;

// Register the handler for Commissioner's CommissionerDeclaration messages. The CommissionerDeclaration messages provide
// information indicating the Commissioner's pre-commissioning state.
if (connectionCallbacks.mCommissionerDeclarationCallback != nullptr)
{
matter::casting::core::CommissionerDeclarationHandler::GetInstance()->SetCommissionerDeclarationCallback(
connectionCallbacks.mCommissionerDeclarationCallback);
}
else
// Verify that mOnCompleted is not nullptr.
VerifyOrExit(mOnCompleted != nullptr, ChipLogError(AppServer, "CastingPlayer::ContinueConnecting() mOnCompleted == nullptr"));
if (!matter::casting::core::CommissionerDeclarationHandler::GetInstance()->HasCommissionerDeclarationCallback())
{
ChipLogProgress(
AppServer,
"CastingPlayer::VerifyOrEstablishConnection() CommissionerDeclarationCallback not provided in ConnectionCallbacks");
ChipLogProgress(AppServer,
"CastingPlayer::ContinueConnecting() CommissionerDeclaration message callback has not been set.");
}
mConnectionState = CASTING_PLAYER_CONNECTING;
mTargetCastingPlayer = this;

ChipLogProgress(AppServer, "CastingPlayer::ContinueConnecting() calling OpenBasicCommissioningWindow()");
SuccessOrExit(err = chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow(
Expand Down Expand Up @@ -272,6 +258,8 @@ CHIP_ERROR CastingPlayer::SendUserDirectedCommissioningRequest()

chip::Protocols::UserDirectedCommissioning::IdentificationDeclaration id = mIdOptions.buildIdentificationDeclarationMessage();

ReturnErrorOnFailure(support::ChipDeviceEventHandler::SetUdcStatus(true));

ReturnErrorOnFailure(chip::Server::GetInstance().SendUserDirectedCommissioningRequest(
chip::Transport::PeerAddress::UDP(*ipAddressToUse, mAttributes.port, mAttributes.interfaceId), id));

Expand Down Expand Up @@ -401,6 +389,26 @@ void CastingPlayer::LogDetail() const
}
}

CastingPlayer::CastingPlayer(const CastingPlayer & other) :
std::enable_shared_from_this<CastingPlayer>(other), mEndpoints(other.mEndpoints), mConnectionState(other.mConnectionState),
mAttributes(other.mAttributes), mIdOptions(other.mIdOptions),
mCommissioningWindowTimeoutSec(other.mCommissioningWindowTimeoutSec), mOnCompleted(other.mOnCompleted)
{}

CastingPlayer & CastingPlayer::operator=(const CastingPlayer & other)
{
if (this != &other)
{
mAttributes = other.mAttributes;
mEndpoints = other.mEndpoints;
mConnectionState = other.mConnectionState;
mIdOptions = other.mIdOptions;
mCommissioningWindowTimeoutSec = other.mCommissioningWindowTimeoutSec;
mOnCompleted = other.mOnCompleted;
}
return *this;
}

ConnectionContext::ConnectionContext(void * clientContext, core::CastingPlayer * targetCastingPlayer,
chip::OnDeviceConnected onDeviceConnectedFn,
chip::OnDeviceConnectionFailure onDeviceConnectionFailureFn)
Expand Down
Loading

0 comments on commit bbb4196

Please sign in to comment.