Skip to content

Commit

Permalink
Fixes in tv-casting-app to allow setting custom Setup Passcodes and b…
Browse files Browse the repository at this point in the history
…ackgrounding the app on iOS (#24046)

* tv-casting-app: Making getDiscoveredCommissioner API synchronous

* iOS MatterTvCastingBridge: Generate spake2pSalt (and verifier) if required in CommissionableDataProviderImpl

* tv-casting-app/darwin: Stopping/restarting Matter server when app becomes inactive/active. Also, disabling BLE

* Addressing cliffamzn@'s feedback
  • Loading branch information
sharadb-amazon authored Dec 23, 2022
1 parent 63803aa commit 19c8ea4
Show file tree
Hide file tree
Showing 10 changed files with 405 additions and 176 deletions.
2 changes: 2 additions & 0 deletions examples/tv-casting-app/android/args.gni
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ chip_build_libshell = true
chip_enable_additional_data_advertising = true

chip_enable_rotating_device_id = true

chip_config_network_layer_ble = false
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
3CCB8742286A593700771BAD /* ConversionUtils.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3CCB873C286A593700771BAD /* ConversionUtils.hpp */; };
3CCB8743286A593700771BAD /* CastingServerBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CCB873D286A593700771BAD /* CastingServerBridge.mm */; };
3CCB8744286A593700771BAD /* ConversionUtils.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CCB873E286A593700771BAD /* ConversionUtils.mm */; };
3CE868F42946D76200FCB92B /* CommissionableDataProviderImpl.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CE868F32946D76200FCB92B /* CommissionableDataProviderImpl.mm */; };
3CF8532728E37F1000F07B9F /* MatterError.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CF8532628E37F1000F07B9F /* MatterError.mm */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -59,6 +60,7 @@
3CCB873C286A593700771BAD /* ConversionUtils.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ConversionUtils.hpp; sourceTree = "<group>"; };
3CCB873D286A593700771BAD /* CastingServerBridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CastingServerBridge.mm; sourceTree = "<group>"; };
3CCB873E286A593700771BAD /* ConversionUtils.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ConversionUtils.mm; sourceTree = "<group>"; };
3CE868F32946D76200FCB92B /* CommissionableDataProviderImpl.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CommissionableDataProviderImpl.mm; sourceTree = "<group>"; };
3CF8532528E37ED800F07B9F /* MatterError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MatterError.h; sourceTree = "<group>"; };
3CF8532628E37F1000F07B9F /* MatterError.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MatterError.mm; sourceTree = "<group>"; };
/* End PBXFileReference section */
Expand Down Expand Up @@ -125,6 +127,7 @@
3C26AC8B2926FE0C00BA6881 /* DeviceAttestationCredentialsProviderImpl.hpp */,
3C26AC8F2927008900BA6881 /* DeviceAttestationCredentialsProviderImpl.mm */,
3C0D9CDF2920A30C00D3332B /* CommissionableDataProviderImpl.hpp */,
3CE868F32946D76200FCB92B /* CommissionableDataProviderImpl.mm */,
);
path = MatterTvCastingBridge;
sourceTree = "<group>";
Expand Down Expand Up @@ -241,6 +244,7 @@
3CCB8744286A593700771BAD /* ConversionUtils.mm in Sources */,
3C4E53B028E4F28100F293E8 /* MediaPlaybackTypes.mm in Sources */,
3C66FBFC290327BB00B63FE7 /* AppParameters.mm in Sources */,
3CE868F42946D76200FCB92B /* CommissionableDataProviderImpl.mm in Sources */,
3C26AC9329282B8100BA6881 /* DeviceAttestationCredentialsHolder.m in Sources */,
3C26AC902927008900BA6881 /* DeviceAttestationCredentialsProviderImpl.mm in Sources */,
3CCB873F286A593700771BAD /* DiscoveredNodeData.mm in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@

@property uint32_t spake2pIterationCount;

@property NSData * spake2pSalt;
@property NSData * spake2pSaltBase64;

@property NSData * spake2pVerifier;
@property NSData * spake2pVerifierBase64;

@property DeviceAttestationCredentialsHolder * deviceAttestationCredentials;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
@param clientQueue Queue to dispatch the call to the discoveredCommissionerHandler on
@param discoveredCommissionerHandler Handler to call after a discovered commissioner has been retrieved
@param discoveredCommissionerHandler Handler called synchronously after a discovered commissioner has been retrieved
*/
- (void)getDiscoveredCommissioner:(int)index
clientQueue:(dispatch_queue_t _Nonnull)clientQueue
Expand Down Expand Up @@ -184,6 +184,16 @@
*/
- (void)disconnect:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(nullable void (^)())requestSentHandler;

/**
@brief Start the Matter server and reconnect to a previously connected Video Player (if any)
*/
- (void)startMatterServer;

/**
@brief Stop the Matter server
*/
- (void)stopMatterServer;

/*!
@brief Send a ContentLauncher:LaunchURL request to a TV
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,14 @@ @interface CastingServerBridge ()

@property OnboardingPayload * _Nonnull onboardingPayload;

@property chip::DeviceLayer::CommissionableDataProviderImpl * commissionableDataProvider;
@property CommissionableDataProviderImpl * commissionableDataProvider;

@property chip::Credentials::DeviceAttestationCredentialsProvider * deviceAttestationCredentialsProvider;

@property chip::CommonCaseDeviceServerInitParams * serverInitParams;

@property TargetVideoPlayerInfo * previouslyConnectedVideoPlayer;

// queue used to serialize all work performed by the CastingServerBridge
@property (atomic) dispatch_queue_t chipWorkQueue;

Expand Down Expand Up @@ -111,10 +115,15 @@ - (void)initApp:(AppParameters * _Nullable)appParameters
ChipLogProgress(AppServer, "CastingServerBridge().initApp() called");

CHIP_ERROR err = CHIP_NO_ERROR;
_commissionableDataProvider = new chip::DeviceLayer::CommissionableDataProviderImpl();
_commissionableDataProvider = new CommissionableDataProviderImpl();
_deviceAttestationCredentialsProvider = chip::Credentials::Examples::GetExampleDACProvider();

_appParameters = appParameters;
AppParams cppAppParams;
uint32_t setupPasscode = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE;
uint16_t setupDiscriminator = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR;
uint32_t spake2pIterationCount;
chip::ByteSpan spake2pSaltSpan, spake2pVerifierSpan;
if (_appParameters != nil) {
err = [ConversionUtils convertToCppAppParamsInfoFrom:_appParameters outAppParams:cppAppParams];
if (err != CHIP_NO_ERROR) {
Expand All @@ -123,22 +132,31 @@ - (void)initApp:(AppParameters * _Nullable)appParameters
}

// set fields in commissionableDataProvider
_commissionableDataProvider->SetSpake2pIterationCount(_appParameters.spake2pIterationCount);
if (_appParameters.spake2pSalt != nil) {
chip::ByteSpan spake2pSaltSpan
= chip::ByteSpan(static_cast<const uint8_t *>(_appParameters.spake2pSalt.bytes), _appParameters.spake2pSalt.length);
_commissionableDataProvider->SetSpake2pSalt(spake2pSaltSpan);
if (_appParameters.onboardingPayload != nil) {
setupPasscode = _appParameters.onboardingPayload.setupPasscode > 0 ? _appParameters.onboardingPayload.setupPasscode
: CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE;
setupDiscriminator = _appParameters.onboardingPayload.setupDiscriminator > 0
? _appParameters.onboardingPayload.setupDiscriminator
: CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR;
}
spake2pIterationCount = _appParameters.spake2pIterationCount;
if (_appParameters.spake2pSaltBase64 != nil) {
spake2pSaltSpan = chip::ByteSpan(
static_cast<const uint8_t *>(_appParameters.spake2pSaltBase64.bytes), _appParameters.spake2pSaltBase64.length);
}

if (_appParameters.spake2pVerifier != nil) {
chip::ByteSpan spake2pVerifierSpan = chip::ByteSpan(
static_cast<const uint8_t *>(_appParameters.spake2pVerifier.bytes), _appParameters.spake2pVerifier.length);
_commissionableDataProvider->SetSpake2pSalt(spake2pVerifierSpan);
if (_appParameters.spake2pVerifierBase64 != nil) {
chip::ByteSpan spake2pVerifierSpan
= chip::ByteSpan(static_cast<const uint8_t *>(_appParameters.spake2pVerifierBase64.bytes),
_appParameters.spake2pVerifierBase64.length);
}

if (_appParameters.onboardingPayload != nil) {
_commissionableDataProvider->SetSetupPasscode(_appParameters.onboardingPayload.setupPasscode);
_commissionableDataProvider->SetSetupDiscriminator(_appParameters.onboardingPayload.setupDiscriminator);
err = _commissionableDataProvider->Initialize(_appParameters.spake2pVerifierBase64 != nil ? &spake2pVerifierSpan : nil,
_appParameters.spake2pSaltBase64 != nil ? &spake2pSaltSpan : nil, spake2pIterationCount, setupPasscode,
setupDiscriminator);
if (err != CHIP_NO_ERROR) {
ChipLogError(AppServer, "Failed to initialize CommissionableDataProvider: %s", ErrorStr(err));
return;
}

if (_appParameters.deviceAttestationCredentials != nil) {
Expand Down Expand Up @@ -182,8 +200,6 @@ - (void)initApp:(AppParameters * _Nullable)appParameters
}
chip::DeviceLayer::SetCommissionableDataProvider(_commissionableDataProvider);

uint32_t setupPasscode = 0;
uint16_t setupDiscriminator = 0;
_commissionableDataProvider->GetSetupPasscode(setupPasscode);
_commissionableDataProvider->GetSetupDiscriminator(setupDiscriminator);
_onboardingPayload = [[OnboardingPayload alloc] initWithSetupPasscode:setupPasscode setupDiscriminator:setupDiscriminator];
Expand All @@ -199,14 +215,14 @@ - (void)initApp:(AppParameters * _Nullable)appParameters
}

// init app Server
static chip::CommonCaseDeviceServerInitParams initParams;
err = initParams.InitializeStaticResourcesBeforeServerInit();
_serverInitParams = new chip::CommonCaseDeviceServerInitParams();
err = _serverInitParams->InitializeStaticResourcesBeforeServerInit();
if (err != CHIP_NO_ERROR) {
ChipLogError(AppServer, "InitializeStaticResourcesBeforeServerInit failed: %s", ErrorStr(err));
return;
}

err = chip::Server::GetInstance().Init(initParams);
err = chip::Server::GetInstance().Init(*_serverInitParams);
if (err != CHIP_NO_ERROR) {
ChipLogError(AppServer, "chip::Server init failed: %s", ErrorStr(err));
return;
Expand Down Expand Up @@ -261,7 +277,7 @@ - (void)getDiscoveredCommissioner:(int)index
{
ChipLogProgress(AppServer, "CastingServerBridge().getDiscoveredCommissioner() called");

dispatch_async(_chipWorkQueue, ^{
dispatch_sync(_chipWorkQueue, ^{
chip::Optional<TargetVideoPlayerInfo *> associatedConnectableVideoPlayer;
DiscoveredNodeData * commissioner = nil;
const chip::Dnssd::DiscoveredNodeData * cppDiscoveredNodeData
Expand All @@ -275,7 +291,7 @@ - (void)getDiscoveredCommissioner:(int)index
}
}

dispatch_async(clientQueue, ^{
dispatch_sync(clientQueue, ^{
discoveredCommissionerHandler(commissioner);
});
});
Expand Down Expand Up @@ -407,10 +423,9 @@ - (void)getActiveTargetVideoPlayers:(dispatch_queue_t _Nonnull)clientQueue
ChipLogProgress(AppServer, "CastingServerBridge().getActiveTargetVideoPlayers() called");

dispatch_async(_chipWorkQueue, ^{
NSMutableArray * videoPlayers = nil;
NSMutableArray * videoPlayers = [NSMutableArray new];
TargetVideoPlayerInfo * cppTargetVideoPlayerInfo = CastingServer::GetInstance()->GetActiveTargetVideoPlayer();
if (cppTargetVideoPlayerInfo != nullptr) {
videoPlayers = [NSMutableArray new];
if (cppTargetVideoPlayerInfo != nullptr && cppTargetVideoPlayerInfo->IsInitialized()) {
videoPlayers[0] = [ConversionUtils convertToObjCVideoPlayerFrom:cppTargetVideoPlayerInfo];
}

Expand Down Expand Up @@ -495,6 +510,79 @@ - (void)shutdownAllSubscriptions:(dispatch_queue_t _Nonnull)clientQueue requestS
});
}

- (void)startMatterServer
{
ChipLogProgress(AppServer, "CastingServerBridge().startMatterServer() called");

dispatch_sync(_chipWorkQueue, ^{
// Initialize the Matter server
CHIP_ERROR err = chip::Server::GetInstance().Init(*self->_serverInitParams);
if (err != CHIP_NO_ERROR) {
ChipLogError(AppServer, "chip::Server init failed: %s", ErrorStr(err));
return;
}

// Now reconnect to the VideoPlayer the casting app was previously connected to (if any)
if (self->_previouslyConnectedVideoPlayer != nil) {
ChipLogProgress(
AppServer, "CastingServerBridge().startMatterServer() reconnecting to previously connected VideoPlayer...");
err = CastingServer::GetInstance()->VerifyOrEstablishConnection(
*(self->_previouslyConnectedVideoPlayer), [](TargetVideoPlayerInfo * cppTargetVideoPlayerInfo) {},
[](CHIP_ERROR err) {}, [](TargetEndpointInfo * cppTargetEndpointInfo) {});
}
});
}

- (void)stopMatterServer
{
ChipLogProgress(AppServer, "CastingServerBridge().stopMatterServer() called");

dispatch_sync(_chipWorkQueue, ^{
// capture pointer to previouslyConnectedVideoPlayer, to be deleted
TargetVideoPlayerInfo * videoPlayerForDeletion
= self->_previouslyConnectedVideoPlayer == nil ? nil : self->_previouslyConnectedVideoPlayer;

// On shutting down the Matter server, the casting app will be automatically disconnected from any Video Players it was
// connected to. Save the VideoPlayer that the casting app was targetting and connected to, so we can reconnect to it on
// re-starting the Matter server.
TargetVideoPlayerInfo * currentTargetVideoPlayerInfo = CastingServer::GetInstance()->GetActiveTargetVideoPlayer();
if (currentTargetVideoPlayerInfo != nil && currentTargetVideoPlayerInfo->IsInitialized()
&& currentTargetVideoPlayerInfo->GetOperationalDeviceProxy() != nil) {
self->_previouslyConnectedVideoPlayer = new TargetVideoPlayerInfo();
self->_previouslyConnectedVideoPlayer->Initialize(currentTargetVideoPlayerInfo->GetNodeId(),
currentTargetVideoPlayerInfo->GetFabricIndex(), nullptr, nullptr, currentTargetVideoPlayerInfo->GetVendorId(),
currentTargetVideoPlayerInfo->GetProductId(), currentTargetVideoPlayerInfo->GetDeviceType(),
currentTargetVideoPlayerInfo->GetDeviceName(), currentTargetVideoPlayerInfo->GetNumIPs(),
const_cast<chip::Inet::IPAddress *>(currentTargetVideoPlayerInfo->GetIpAddresses()));

TargetEndpointInfo * prevEndpoints = self->_previouslyConnectedVideoPlayer->GetEndpoints();
if (prevEndpoints != nullptr) {
for (size_t i = 0; i < kMaxNumberOfEndpoints; i++) {
prevEndpoints[i].Reset();
}
}
TargetEndpointInfo * currentEndpoints = currentTargetVideoPlayerInfo->GetEndpoints();
for (size_t i = 0; i < kMaxNumberOfEndpoints && currentEndpoints[i].IsInitialized(); i++) {
prevEndpoints[i].Initialize(currentEndpoints[i].GetEndpointId());
chip::ClusterId * currentClusters = currentEndpoints[i].GetClusters();
for (size_t j = 0; j < kMaxNumberOfClustersPerEndpoint && currentClusters[j] != chip::kInvalidClusterId; j++) {
prevEndpoints[i].AddCluster(currentClusters[j]);
}
}
} else {
self->_previouslyConnectedVideoPlayer = nil;
}

// Now shutdown the Matter server
chip::Server::GetInstance().Shutdown();

// Delete the old previouslyConnectedVideoPlayer, if non-nil
if (videoPlayerForDeletion != nil) {
delete videoPlayerForDeletion;
}
});
}

- (void)disconnect:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(nullable void (^)())requestSentHandler
{
ChipLogProgress(AppServer, "CastingServerBridge().disconnect() called");
Expand Down
Loading

0 comments on commit 19c8ea4

Please sign in to comment.