Skip to content

Commit a073055

Browse files
tv-casting-app cancel connection upon CancelPasscode CDC message from TV (#35331)
* tv-casting-app cancel connection upon CancelPasscode CDC message from TV * Addressed comments by sharadb-amazon * Fix iOS app crash due to null cpp cluster
1 parent 3621c43 commit a073055

13 files changed

+199
-47
lines changed

examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/MCEndpoint.mm

+56-16
Original file line numberDiff line numberDiff line change
@@ -90,27 +90,67 @@ - (MCCastingPlayer * _Nonnull)castingPlayer
9090
- (MCCluster * _Nullable)clusterForType:(MCEndpointClusterType)type
9191
{
9292
switch (type) {
93-
case MCEndpointClusterTypeApplicationBasic:
94-
return [[MCApplicationBasicCluster alloc] initWithCppCluster:_cppEndpoint->GetCluster<matter::casting::clusters::application_basic::ApplicationBasicCluster>()];
95-
96-
case MCEndpointClusterTypeApplicationLauncher:
97-
return [[MCApplicationLauncherCluster alloc] initWithCppCluster:_cppEndpoint->GetCluster<matter::casting::clusters::application_launcher::ApplicationLauncherCluster>()];
98-
99-
case MCEndpointClusterTypeContentLauncher:
100-
return [[MCContentLauncherCluster alloc] initWithCppCluster:_cppEndpoint->GetCluster<matter::casting::clusters::content_launcher::ContentLauncherCluster>()];
93+
case MCEndpointClusterTypeApplicationBasic: {
94+
auto cppCluster = _cppEndpoint->GetCluster<matter::casting::clusters::application_basic::ApplicationBasicCluster>();
95+
if (cppCluster == nullptr) {
96+
ChipLogError(AppServer, "MCEndpoint::clusterForType() MCEndpointClusterTypeApplicationBasic, GetCluster() returned nullptr");
97+
return nil;
98+
}
99+
return [[MCApplicationBasicCluster alloc] initWithCppCluster:cppCluster];
100+
}
101101

102-
case MCEndpointClusterTypeKeypadInput:
103-
return [[MCKeypadInputCluster alloc] initWithCppCluster:_cppEndpoint->GetCluster<matter::casting::clusters::keypad_input::KeypadInputCluster>()];
102+
case MCEndpointClusterTypeApplicationLauncher: {
103+
auto cppCluster = _cppEndpoint->GetCluster<matter::casting::clusters::application_launcher::ApplicationLauncherCluster>();
104+
if (cppCluster == nullptr) {
105+
ChipLogError(AppServer, "MCEndpoint::clusterForType() MCEndpointClusterTypeApplicationLauncher GetCluster() returned nullptr");
106+
return nil;
107+
}
108+
return [[MCApplicationLauncherCluster alloc] initWithCppCluster:cppCluster];
109+
}
104110

105-
case MCEndpointClusterTypeMediaPlayback:
106-
return [[MCMediaPlaybackCluster alloc] initWithCppCluster:_cppEndpoint->GetCluster<matter::casting::clusters::media_playback::MediaPlaybackCluster>()];
111+
case MCEndpointClusterTypeContentLauncher: {
112+
auto cppCluster = _cppEndpoint->GetCluster<matter::casting::clusters::content_launcher::ContentLauncherCluster>();
113+
if (cppCluster == nullptr) {
114+
ChipLogError(AppServer, "MCEndpoint::clusterForType() MCEndpointClusterTypeContentLauncher GetCluster() returned nullptr");
115+
return nil;
116+
}
117+
return [[MCContentLauncherCluster alloc] initWithCppCluster:cppCluster];
118+
}
107119

108-
case MCEndpointClusterTypeOnOff:
109-
return [[MCOnOffCluster alloc] initWithCppCluster:_cppEndpoint->GetCluster<matter::casting::clusters::on_off::OnOffCluster>()];
120+
case MCEndpointClusterTypeKeypadInput: {
121+
auto cppCluster = _cppEndpoint->GetCluster<matter::casting::clusters::keypad_input::KeypadInputCluster>();
122+
if (cppCluster == nullptr) {
123+
ChipLogError(AppServer, "MCEndpoint::clusterForType() MCEndpointClusterTypeKeypadInput GetCluster() returned nullptr");
124+
return nil;
125+
}
126+
return [[MCKeypadInputCluster alloc] initWithCppCluster:cppCluster];
127+
}
110128

111-
case MCEndpointClusterTypeTargetNavigator:
112-
return [[MCTargetNavigatorCluster alloc] initWithCppCluster:_cppEndpoint->GetCluster<matter::casting::clusters::target_navigator::TargetNavigatorCluster>()];
129+
case MCEndpointClusterTypeMediaPlayback: {
130+
auto cppCluster = _cppEndpoint->GetCluster<matter::casting::clusters::media_playback::MediaPlaybackCluster>();
131+
if (cppCluster == nullptr) {
132+
ChipLogError(AppServer, "MCEndpoint::clusterForType() MCEndpointClusterTypeMediaPlayback GetCluster() returned nullptr");
133+
return nil;
134+
}
135+
return [[MCMediaPlaybackCluster alloc] initWithCppCluster:cppCluster];
136+
}
113137

138+
case MCEndpointClusterTypeOnOff: {
139+
auto cppCluster = _cppEndpoint->GetCluster<matter::casting::clusters::on_off::OnOffCluster>();
140+
if (cppCluster == nullptr) {
141+
ChipLogError(AppServer, "MCEndpoint::clusterForType() MCEndpointClusterTypeOnOff GetCluster() returned nullptr");
142+
return nil;
143+
}
144+
return [[MCOnOffCluster alloc] initWithCppCluster:cppCluster];
145+
}
146+
case MCEndpointClusterTypeTargetNavigator: {
147+
auto cppCluster = _cppEndpoint->GetCluster<matter::casting::clusters::target_navigator::TargetNavigatorCluster>();
148+
if (cppCluster == nullptr) {
149+
ChipLogError(AppServer, "MCEndpoint::clusterForType() MCEndpointClusterTypeTargetNavigator GetCluster() returned nullptr");
150+
return nil;
151+
}
152+
return [[MCTargetNavigatorCluster alloc] initWithCppCluster:cppCluster];
153+
}
114154
default:
115155
ChipLogError(AppServer, "MCEndpointClusterType not found");
116156
break;

examples/tv-casting-app/darwin/TvCasting/TvCasting/MCApplicationBasicReadVendorIDExampleViewModel.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class MCApplicationBasicReadVendorIDExampleViewModel: ObservableObject {
4747
// validate that the selected endpoint supports the ApplicationBasic cluster
4848
if(!endpoint.hasCluster(MCEndpointClusterTypeApplicationBasic))
4949
{
50-
self.Log.error("No ApplicationBasic cluster supporting endpoint found")
50+
self.Log.error("MCApplicationBasicReadVendorIDExampleViewModel.read() No ApplicationBasic cluster supporting endpoint found")
5151
DispatchQueue.main.async
5252
{
5353
self.status = "No ApplicationBasic cluster supporting endpoint found"

examples/tv-casting-app/darwin/TvCasting/TvCasting/MCContentLauncherLaunchURLExampleViewModel.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class MCContentLauncherLaunchURLExampleViewModel: ObservableObject {
4747
// validate that the selected endpoint supports the ContentLauncher cluster
4848
if(!endpoint.hasCluster(MCEndpointClusterTypeContentLauncher))
4949
{
50-
self.Log.error("No ContentLauncher cluster supporting endpoint found")
50+
self.Log.error("MCContentLauncherLaunchURLExampleViewModel.invokeCommand() No ContentLauncher cluster supporting endpoint found")
5151
DispatchQueue.main.async
5252
{
5353
self.status = "No ContentLauncher cluster supporting endpoint found"

examples/tv-casting-app/darwin/TvCasting/TvCasting/MCMediaPlaybackSubscribeToCurrentStateExampleViewModel.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class MCMediaPlaybackSubscribeToCurrentStateExampleViewModel: ObservableObject {
4747
// validate that the selected endpoint supports the MediaPlayback cluster
4848
if(!endpoint.hasCluster(MCEndpointClusterTypeMediaPlayback))
4949
{
50-
self.Log.error("No MediaPlayback cluster supporting endpoint found")
50+
self.Log.error("MCMediaPlaybackSubscribeToCurrentStateExampleViewModel.subscribe() No MediaPlayback cluster supporting endpoint found")
5151
DispatchQueue.main.async
5252
{
5353
self.status = "No MediaPlayback cluster supporting endpoint found"

examples/tv-casting-app/linux/simple-app-helper.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ void ConnectionHandler(CHIP_ERROR err, matter::casting::core::CastingPlayer * ca
267267
// For a connection failure, called back with an error and nullptr.
268268
VerifyOrReturn(
269269
err == CHIP_NO_ERROR,
270-
ChipLogProgress(
270+
ChipLogError(
271271
AppServer,
272272
"simple-app-helper.cpp::ConnectionHandler(): Failed to connect to CastingPlayer (ID: %s) with err %" CHIP_ERROR_FORMAT,
273273
targetCastingPlayer->GetId(), err.Format()));

examples/tv-casting-app/tv-casting-common/core/BaseCluster.h

+18-2
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,28 @@ class BaseCluster
5858
/**
5959
* @return Pointer to the Attribute registered in this cluster, corresponding to attributeId
6060
*/
61-
void * GetAttribute(const chip::AttributeId attributeId) { return mAttributes[attributeId]; }
61+
void * GetAttribute(const chip::AttributeId attributeId)
62+
{
63+
if (mAttributes.empty())
64+
{
65+
ChipLogError(AppServer, "BaseCluster::GetAttribute() mAttributes is empty");
66+
return nullptr;
67+
}
68+
return mAttributes[attributeId];
69+
}
6270

6371
/**
6472
* @return Pointer to the Command registered in this cluster, corresponding to commandId
6573
*/
66-
void * GetCommand(const chip::CommandId commandId) { return mCommands[commandId]; }
74+
void * GetCommand(const chip::CommandId commandId)
75+
{
76+
if (mCommands.empty())
77+
{
78+
ChipLogError(AppServer, "BaseCluster::GetCommand() mCommands is empty");
79+
return nullptr;
80+
}
81+
return mCommands[commandId];
82+
}
6783

6884
protected:
6985
/**

examples/tv-casting-app/tv-casting-common/core/CastingPlayer.cpp

+28-7
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,14 @@ void CastingPlayer::VerifyOrEstablishConnection(ConnectionCallbacks connectionCa
6868
// Set the callback for handling CommissionerDeclaration messages.
6969
matter::casting::core::CommissionerDeclarationHandler::GetInstance()->SetCommissionerDeclarationCallback(
7070
connectionCallbacks.mCommissionerDeclarationCallback);
71+
mClientProvidedCommissionerDeclarationCallback = true;
7172
}
7273
else
7374
{
7475
ChipLogProgress(
7576
AppServer,
7677
"CastingPlayer::VerifyOrEstablishConnection() CommissionerDeclarationCallback not provided in ConnectionCallbacks");
78+
mClientProvidedCommissionerDeclarationCallback = false;
7779
}
7880

7981
ChipLogProgress(AppServer, "CastingPlayer::VerifyOrEstablishConnection() verifying User Directed Commissioning (UDC) state");
@@ -107,6 +109,7 @@ void CastingPlayer::VerifyOrEstablishConnection(ConnectionCallbacks connectionCa
107109
// found the CastingPlayer in cache
108110
if (it != cachedCastingPlayers.end())
109111
{
112+
ChipLogProgress(AppServer, "CastingPlayer::VerifyOrEstablishConnection() found this CastingPlayer in app cache");
110113
unsigned index = (unsigned int) std::distance(cachedCastingPlayers.begin(), it);
111114
if (ContainsDesiredTargetApp(&cachedCastingPlayers[index], idOptions.getTargetAppInfoList()))
112115
{
@@ -225,16 +228,24 @@ CHIP_ERROR CastingPlayer::ContinueConnecting()
225228

226229
CHIP_ERROR CastingPlayer::StopConnecting()
227230
{
228-
ChipLogProgress(AppServer, "CastingPlayer::StopConnecting() called, while ChipDeviceEventHandler.sUdcInProgress: %s",
229-
support::ChipDeviceEventHandler::isUdcInProgress() ? "true" : "false");
230-
VerifyOrReturnValue(mConnectionState == CASTING_PLAYER_CONNECTING, CHIP_ERROR_INCORRECT_STATE,
231-
ChipLogError(AppServer, "CastingPlayer::StopConnecting() called while not in connecting state"););
232231
VerifyOrReturnValue(
233232
mIdOptions.mCommissionerPasscode, CHIP_ERROR_INCORRECT_STATE,
234233
ChipLogError(AppServer,
235234
"CastingPlayer::StopConnecting() mIdOptions.mCommissionerPasscode == false, ContinueConnecting() should only "
236235
"be called when the CastingPlayer/Commissioner-Generated passcode commissioning flow is in progress."););
236+
// Calling the internal StopConnecting() API with the shouldSendIdentificationDeclarationMessage set to true to notify the
237+
// CastingPlayer/Commissioner that the commissioning session was cancelled by the Casting Client/Commissionee user. This will
238+
// result in the Casting Client/Commissionee sending a CancelPasscode IdentificationDeclaration message to the CastingPlayer.
239+
// shouldSendIdentificationDeclarationMessage is true when StopConnecting() is called by the Client.
240+
return this->StopConnecting(true);
241+
}
237242

243+
CHIP_ERROR CastingPlayer::StopConnecting(bool shouldSendIdentificationDeclarationMessage)
244+
{
245+
ChipLogProgress(AppServer, "CastingPlayer::StopConnecting() called, while ChipDeviceEventHandler.sUdcInProgress: %s",
246+
support::ChipDeviceEventHandler::isUdcInProgress() ? "true" : "false");
247+
VerifyOrReturnValue(mConnectionState == CASTING_PLAYER_CONNECTING, CHIP_ERROR_INCORRECT_STATE,
248+
ChipLogError(AppServer, "CastingPlayer::StopConnecting() called while not in connecting state"););
238249
CHIP_ERROR err = CHIP_NO_ERROR;
239250
mIdOptions.resetState();
240251
mIdOptions.mCancelPasscode = true;
@@ -243,6 +254,16 @@ CHIP_ERROR CastingPlayer::StopConnecting()
243254
mTargetCastingPlayer.reset();
244255
CastingPlayerDiscovery::GetInstance()->ClearCastingPlayersInternal();
245256

257+
if (!shouldSendIdentificationDeclarationMessage)
258+
{
259+
ChipLogProgress(AppServer,
260+
"CastingPlayer::StopConnecting() shouldSendIdentificationDeclarationMessage: %d, User Directed "
261+
"Commissioning aborted by the CastingPlayer/Commissioner user.",
262+
shouldSendIdentificationDeclarationMessage);
263+
resetState(CHIP_ERROR_CONNECTION_ABORTED);
264+
return err;
265+
}
266+
246267
// If a CastingPlayer::ContinueConnecting() error occurs, StopConnecting() can be called while sUdcInProgress == true.
247268
// sUdcInProgress should be set to false before sending the CancelPasscode IdentificationDeclaration message to the
248269
// CastingPlayer/Commissioner.
@@ -251,9 +272,9 @@ CHIP_ERROR CastingPlayer::StopConnecting()
251272
support::ChipDeviceEventHandler::SetUdcStatus(false);
252273
}
253274

254-
ChipLogProgress(
255-
AppServer,
256-
"CastingPlayer::StopConnecting() calling SendUserDirectedCommissioningRequest() to indicate user canceled passcode entry");
275+
ChipLogProgress(AppServer,
276+
"CastingPlayer::StopConnecting() calling SendUserDirectedCommissioningRequest() to indicate "
277+
"Client/Commissionee user canceled passcode entry");
257278
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
258279
err = SendUserDirectedCommissioningRequest();
259280
if (err != CHIP_NO_ERROR)

examples/tv-casting-app/tv-casting-common/core/CastingPlayer.h

+31-11
Original file line numberDiff line numberDiff line change
@@ -102,16 +102,11 @@ class CastingPlayer : public std::enable_shared_from_this<CastingPlayer>
102102
*/
103103
static CastingPlayer * GetTargetCastingPlayer()
104104
{
105-
ChipLogProgress(AppServer, "CastingPlayer::GetTargetCastingPlayer() called");
106105
std::shared_ptr<CastingPlayer> sharedPtr = mTargetCastingPlayer.lock();
107106
CastingPlayer * rawPtr = nullptr;
108107
if (sharedPtr)
109108
{
110109
rawPtr = sharedPtr.get();
111-
ChipLogProgress(
112-
AppServer,
113-
"CastingPlayer::GetTargetCastingPlayer() Got rawPtr from mTargetCastingPlayer, sharedPtr reference count: %lu",
114-
sharedPtr.use_count());
115110
sharedPtr.reset();
116111
}
117112
else
@@ -207,12 +202,14 @@ class CastingPlayer : public std::enable_shared_from_this<CastingPlayer>
207202
/**
208203
* @brief This cancels the CastingPlayer/Commissioner-Generated passcode commissioning flow started via the
209204
* VerifyOrEstablishConnection() API above. It constructs and sends an IdentificationDeclaration message to the
210-
* CastingPlayer/Commissioner containing CancelPasscode set to true. It is used to indicate that the user, and thus the
211-
* Client/Commissionee, have cancelled the commissioning process. This indicates that the CastingPlayer/Commissioner can dismiss
212-
* any dialogs corresponding to commissioning, such as a Passcode input dialog or a Passcode display dialog.
213-
* Note: stopConnecting() does not call the ConnectCallback() callback passed to the VerifyOrEstablishConnection() API above
214-
* since no connection is established.
215-
* @return CHIP_NO_ERROR if this function was called with the CastingPlayer in the correct state and an error otherwise.
205+
* CastingPlayer/Commissioner containing CancelPasscode set to true. It is used to indicate that the Client/Commissionee user
206+
* has cancelled the commissioning process. This indicates that the CastingPlayer/Commissioner can dismiss any dialogs
207+
* corresponding to commissioning, such as a Passcode input dialog or a Passcode display dialog. Note: StopConnecting() does not
208+
* call the ConnectCallback() callback passed to the VerifyOrEstablishConnection() API above since no connection is established.
209+
* @return CHIP_NO_ERROR if this function was called with the CastingPlayer in the correct state and CHIP_ERROR_INCORRECT_STATE.
210+
* otherwise. StopConnecting() can only be called by the client during the CastingPlayer/Commissioner-Generated passcode
211+
* commissioning flow. Calling StopConnecting() during the Client/Commissionee-Generated commissioning flow will return a
212+
* CHIP_ERROR_INCORRECT_STATE error.
216213
*/
217214
CHIP_ERROR StopConnecting();
218215

@@ -295,6 +292,28 @@ class CastingPlayer : public std::enable_shared_from_this<CastingPlayer>
295292
static memory::Weak<CastingPlayer> mTargetCastingPlayer;
296293
uint16_t mCommissioningWindowTimeoutSec = kCommissioningWindowTimeoutSec;
297294
ConnectCallback mOnCompleted = {};
295+
bool mClientProvidedCommissionerDeclarationCallback;
296+
297+
/**
298+
* @brief This internal version of the StopConnecting API cancels the Client/Commissionee-Generated passcode or the
299+
* CastingPlayer/Commissioner-Generated passcode commissioning flow started via the VerifyOrEstablishConnection() API above.
300+
* Furthermore, StopConnecting operates in two ways as governed by the shouldSendIdentificationDeclarationMessage flag:
301+
* 1. If shouldSendIdentificationDeclarationMessage is true. StopConnecting constructs and sends an IdentificationDeclaration
302+
* message to the CastingPlayer/Commissioner containing CancelPasscode set to true. The CancelPasscode flag set to true conveys
303+
* that the Client/Commissionee user has cancelled the commissioning session. This indicates that the CastingPlayer/Commissioner
304+
* can dismiss any dialogs corresponding to commissioning, such as a Passcode input dialog or a Passcode display dialog. In this
305+
* case, since StopConnecting was called by the Client/Commissionee, StopConnecting() does not call the ConnectCallback()
306+
* callback passed to the VerifyOrEstablishConnection().
307+
* 2. If shouldSendIdentificationDeclarationMessage is false. StopConnecting does not send an IdentificationDeclaration message
308+
* to the CastingPlayer/Commissioner since the CastingPlayer/Commissioner notified the Client/Commissionee that the connection
309+
* is aborted. If the (Optional) ConnectionCallbacks mCommissionerDeclarationCallback is not set, it calls ConnectionCallbacks
310+
* mOnConnectionComplete callback with CHIP_ERROR_CONNECTION_ABORTED.
311+
* @param shouldSendIdentificationDeclarationMessage if true, send the IdentificationDeclaration message to the CastingPlayer
312+
* with CancelPasscode set to true. If false, only call the ConnectionCallbacks mCommissionerDeclarationCallback callback passed
313+
* to the VerifyOrEstablishConnection() API above, without sending the IdentificationDeclaration message.
314+
* @return CHIP_NO_ERROR if this function was called with the CastingPlayer in the correct state and an error otherwise.
315+
*/
316+
CHIP_ERROR StopConnecting(bool shouldSendIdentificationDeclarationMessage);
298317

299318
/**
300319
* @brief resets this CastingPlayer's state and calls mOnCompleted with the CHIP_ERROR. Also, after calling mOnCompleted, it
@@ -329,6 +348,7 @@ class CastingPlayer : public std::enable_shared_from_this<CastingPlayer>
329348
// and connect to a CastingPlayer
330349
friend class support::ChipDeviceEventHandler;
331350

351+
friend class CommissionerDeclarationHandler;
332352
friend class ConnectionContext;
333353
friend class support::EndpointListLoader;
334354
};

0 commit comments

Comments
 (0)