From 2c8e64fa09e1757096d785d70318038cf6786d8a Mon Sep 17 00:00:00 2001 From: Michael Douglas Date: Thu, 23 Feb 2023 09:56:10 -0800 Subject: [PATCH 1/3] Lock the SDK before interacting with it. [Problem] The Matter SDK assumes that the client will take a lock on the SDK prior to interacting with any APIs. There is 1 Android function and several iOS functions that do not take the lock prior to interacting with the SDK APIs. There are also some functions that invoke the Matter SDK in a way that may result in out-of-order callback invocation (e.g. the conceptual "started" callback may be invoked after the conceptual "ended" callback). [Solution] Create utility functions that help ensure that the Matter SDK is invoked safely and that callbacks are delivered in the correct order. [Testing] Performed local, manual testing with the 'tv-casting-app' example on iOS against a Raspberry Pi running the 'tv-app'. Ran the certification test in the 'tv-casting-app' on iOS against the same Raspberry Pi. --- .../app/src/main/jni/cpp/TvCastingApp-JNI.cpp | 3 + .../CastingServerBridge.mm | 881 +++++++++--------- .../CommissionerDiscoveryDelegateImpl.h | 4 +- 3 files changed, 464 insertions(+), 424 deletions(-) diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.cpp b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.cpp index 1c1906a7448aa9..6df8b3096c3f8f 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.cpp +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.cpp @@ -105,6 +105,9 @@ JNI_METHOD(jboolean, initJni)(JNIEnv *, jobject, jobject jAppParameters) JNI_METHOD(void, setDACProvider)(JNIEnv *, jobject, jobject provider) { + chip::DeviceLayer::StackLock lock; + ChipLogProgress(AppServer, "JNI_METHOD setDACProvider called"); + if (!chip::Credentials::IsDeviceAttestationCredentialsProviderSet()) { JNIDACProvider * p = new JNIDACProvider(provider); diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm index d8faa54ca83436..8c8e3e76a4e241 100644 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm @@ -1,6 +1,6 @@ /** * - * Copyright (c) 2020-2022 Project CHIP Authors + * Copyright (c) 2020-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. @@ -54,16 +54,6 @@ @interface CastingServerBridge () // queue used to serialize all work performed by the CastingServerBridge @property (atomic) dispatch_queue_t chipWorkQueue; -@property void (^_Nonnull commissioningCompleteCallback)(bool); - -@property void (^_Nonnull onConnectionSuccessCallback)(VideoPlayer *); - -@property void (^_Nonnull onConnectionFailureCallback)(MatterError *); - -@property void (^_Nonnull onNewOrUpdatedEndpointCallback)(ContentApp *); - -@property NSMutableDictionary * commandResponseCallbacks; - @property NSMutableDictionary * subscriptionEstablishedCallbacks; @property NSMutableDictionary * subscriptionReadSuccessCallbacks; @@ -100,6 +90,8 @@ - (instancetype)init return nil; } + // TODO: Constructors should not perform heavy work like initializing the Matter SDK. This should + // be moved to initializeApp or another suitable location. err = chip::DeviceLayer::PlatformMgr().InitChipStack(); if (err != CHIP_NO_ERROR) { ChipLogError(AppServer, "InitChipStack failed: %s", ErrorStr(err)); @@ -108,7 +100,6 @@ - (instancetype)init _commissionerDiscoveryDelegate = new CommissionerDiscoveryDelegateImpl(); - _commandResponseCallbacks = [NSMutableDictionary dictionary]; _subscriptionEstablishedCallbacks = [NSMutableDictionary dictionary]; _subscriptionReadSuccessCallbacks = [NSMutableDictionary dictionary]; _subscriptionReadFailureCallbacks = [NSMutableDictionary dictionary]; @@ -118,10 +109,157 @@ - (instancetype)init return self; } +/** + Dispatches the block on the Matter SDK dispatch queue. + + @param description Optional. A description of the callback to be dispatched for diagnostic purposes. + @param block The Block to be dispatched. + */ +- (void) dispatchOnMatterSDKQueue:(const NSString * _Nullable)description + block:(dispatch_block_t)block +{ + if (nil != description) { + ChipLogProgress(AppServer, "[SYNC] CastingServerBridge %s", [description UTF8String]); + } + dispatch_async(_chipWorkQueue, ^{ + // The Matter SDK is not, generally, internally thread-safe. It relies upon the client to lock + // the SDK prior to any interactions after chip::DeviceLayer::PlatformMgr().InitChipStack() + // + // Note that it is presently safe to do at this point because InitChipStack is called in the + // constructor for the CastingServerBridge. + chip::DeviceLayer::StackLock lock; + + if (nil != description) { + ChipLogProgress(AppServer, "[ASYNC (CHIP)] CastingServerBridge BEGIN %s", [description UTF8String]); + } + block(); + if (nil != description) { + ChipLogProgress(AppServer, "[ASYNC (CHIP)] CastingServerBridge END %s", [description UTF8String]); + } + }); +} + +/** + Dispatches a client callback via a `dispatch_block_t` to be run on the client's `dispatch_queue_t`. + + @param description Optional. A description of the callback to be dispatched for diagnostic purposes. + @param queue The client's Dispatch Queue. + @param block The Block to be invoked to invoke the client callback. + */ +- (void) dispatchOnClientQueue:(const NSString * _Nullable )description + queue:(dispatch_queue_t)queue + block:(dispatch_block_t)block +{ + // Within the CastingServerBridge, the usage pattern is typically to expose asynchronous public APIs that + // take a callback to indicate that the low-level SDK operation has been initiated (the "started" + // callback), and a separate set of result callbacks to be invoked when the low-level SDK operation + // has been completed (the "result" callbacks). + // + // All of the work is serialized on the _chipWorkQueue, with the started callback being invoked after the + // Matter SDK is called with the result callbacks. This poses a challenge because we don't have a strong + // guarantee that the Matter SDK will not complete its work and invoke the result callback before control + // is returning to the _chipWorkQueue thread; this can cause callbacks to be received in an unexpected + // order, where the result might arrive before the client knows that the call was started. + // + // To avoid this confusion, we perform a "double async" dispatch to ensure that events are delivered in a + // sensible order. First, we schedule the result callback to run on the _chipWorkQueue (so it *must* run + // after the end of the CastingServerBridge's wrapper logic that already started on the _chipWorkQueue) + // and then immediately, asynchronously dispatch the callback onto the provided client queue. + dispatch_async(_chipWorkQueue, ^{ + if (nil != description) { + ChipLogProgress(AppServer, "[ASYNC (CHIP)] CastingServerBridge dispatching %s", [description UTF8String]); + } + dispatch_async(queue, ^{ + if (nil != description) { + ChipLogProgress(AppServer, "[ASYNC (CLIENT)] CastingServerBridge BEGIN %s", [description UTF8String]); + } + block(); + if (nil != description) { + ChipLogProgress(AppServer, "[ASYNC (CLIENT)] CastingServerBridge END %s", [description UTF8String]); + } + }); + }); +} + +/** + A utility function that invokes an Objective C Block on the Matter Dispatch Queue in a thread-safe manner. + + The result of the Objective C Block will be relayed to the `blockCompleteCallback`. + + @param description Optional. A description of the Objective C Block to be invoked for diagnostic purposes. + @param blockCompleteCallback The callback to be invoked with the result of the Objective C Block. + @param callbackQueue The Dispatch Queue on which the callback shall be invoked. + @param block The Objective C Block to dispatch. + */ +- (void) withCastingServerInvokeBlock:(const NSString * _Nullable)description + withCompletionCallback:(void (^_Nonnull)(bool))blockCompleteCallback + onQueue:(dispatch_queue_t)callbackQueue + block:(CHIP_ERROR (^_Nonnull)(CastingServer *)) block +{ + [self dispatchOnMatterSDKQueue:description block:^{ + CastingServer * castingServer = CastingServer::GetInstance(); + const CHIP_ERROR result = block(castingServer); + dispatch_async(callbackQueue, ^{ + if (nil != description) { + ChipLogProgress(AppServer, "[ASYNC (CLIENT)] CastingServerBridge BEGIN %s Started Callback", [description UTF8String]); + } + blockCompleteCallback([[MatterError alloc] initWithCode:result.AsInteger() + message:[NSString stringWithUTF8String:result.AsString()]]); + if (nil != description) { + ChipLogProgress(AppServer, "[ASYNC (CLIENT)] CastingServerBridge END %s Started Callback", [description UTF8String]); + } + }); + }]; +} + +/** + A utility function that invokes an Objective C Block on the Matter Dispatch Queue in a thread-safe manner. + + The result of the Objective C Block will be relayed to the `blockCompleteCallback`. The response callback is expected to be called at a later time with the + asynchronous result of the Casting Server operation (by the Casting Server). + + @param description Optional. A description of the Objective C Block to be invoked for diagnostic purposes. + @param blockCompleteCallback The callback to be invoked with the result of the Objective C Block. + @param responseCallback The callback that will eventually be invoked by the Casting Server when the operation has completed on the remote end. + @param callbackQueue The Dispatch Queue on which the callbacks shall be invoked. + @param block The Objective C Block to dispatch. + */ +- (void) withCastingServerInvokeBlockWithResponse:(const NSString * _Nullable)description + withStartedCallback:(void (^_Nonnull)(bool))blockCompleteCallback + andResponseCallback:(void (^_Nonnull)(bool))responseCallback + onQueue:(dispatch_queue_t)callbackQueue + block:(CHIP_ERROR (^_Nonnull)(CastingServer *, std::function)) block +{ + [self withCastingServerInvokeBlock:description + withCompletionCallback:blockCompleteCallback + onQueue:callbackQueue + block:^(CastingServer *castingServer){ + return block( + castingServer, + [description, responseCallback, callbackQueue](CHIP_ERROR err) { + NSString * _description = description == nil + ? nil + : [NSString stringWithFormat:@"%@ Response Callback", description]; + + [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:_description + queue:callbackQueue block:^{ + responseCallback(CHIP_NO_ERROR == err); + }]; + } + ); + }]; +} + - (MatterError *)initializeApp:(AppParameters * _Nullable)appParameters clientQueue:(dispatch_queue_t _Nonnull)clientQueue initAppStatusHandler:(nullable void (^)(bool))initAppStatusHandler { + // The Matter SDK is not, generally, internally thread-safe. It relies upon the client to lock + // the SDK prior to any interactions after chip::DeviceLayer::PlatformMgr().InitChipStack() + // + // Note that it is presently safe to do at this point because InitChipStack is called in the + // constructor for the CastingServerBridge. + chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "CastingServerBridge().initApp() called"); CHIP_ERROR err = CHIP_NO_ERROR; @@ -282,8 +420,7 @@ - (void)discoverCommissioners:(dispatch_queue_t _Nonnull)clientQueue discoveryRequestSentHandler:(nullable void (^)(bool))discoveryRequestSentHandler discoveredCommissionerHandler:(nullable void (^)(DiscoveredNodeData *))discoveredCommissionerHandler { - ChipLogProgress(AppServer, "CastingServerBridge().discoverCommissioners() called"); - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"discoverCommissioners(...)" block:^{ bool discoveryRequestStatus = true; if (self->_cancelDiscoveryCommissionersWork) { dispatch_block_cancel(self->_cancelDiscoveryCommissionersWork); @@ -316,16 +453,14 @@ - (void)discoverCommissioners:(dispatch_queue_t _Nonnull)clientQueue dispatch_async(clientQueue, ^{ discoveryRequestSentHandler(discoveryRequestStatus); }); - }); + }]; } - (void)getDiscoveredCommissioner:(int)index clientQueue:(dispatch_queue_t _Nonnull)clientQueue discoveredCommissionerHandler:(nullable void (^)(DiscoveredNodeData * _Nullable))discoveredCommissionerHandler { - ChipLogProgress(AppServer, "CastingServerBridge().getDiscoveredCommissioner() called"); - - dispatch_sync(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"getDiscoveredCommissioner(...)" block:^{ chip::Optional associatedConnectableVideoPlayer; DiscoveredNodeData * commissioner = nil; const chip::Dnssd::DiscoveredNodeData * cppDiscoveredNodeData @@ -339,10 +474,10 @@ - (void)getDiscoveredCommissioner:(int)index } } - dispatch_sync(clientQueue, ^{ + dispatch_async(clientQueue, ^{ discoveredCommissionerHandler(commissioner); }); - }); + }]; } - (void)sendUserDirectedCommissioningRequest:(NSString * _Nonnull)commissionerIpAddress @@ -351,11 +486,8 @@ - (void)sendUserDirectedCommissioningRequest:(NSString * _Nonnull)commissionerIp clientQueue:(dispatch_queue_t _Nonnull)clientQueue udcRequestSentHandler:(nullable void (^)(bool))udcRequestSentHandler { - ChipLogProgress(AppServer, - "CastingServerBridge().sendUserDirectedCommissioningRequest() called with IP %s port %d platformInterface %d", - [commissionerIpAddress UTF8String], commissionerPort, platformInterface); - - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"sendUserDirectedCommissioningRequest() IP %s port %d platformInterface %d", [commissionerIpAddress UTF8String], commissionerPort, platformInterface]; + [self dispatchOnMatterSDKQueue:description block:^{ bool udcRequestStatus; chip::Inet::IPAddress commissionerAddrInet; if (chip::Inet::IPAddress::FromString([commissionerIpAddress UTF8String], commissionerAddrInet) == false) { @@ -380,20 +512,21 @@ - (void)sendUserDirectedCommissioningRequest:(NSString * _Nonnull)commissionerIp dispatch_async(clientQueue, ^{ udcRequestSentHandler(udcRequestStatus); }); - }); + }]; } - (void)sendUserDirectedCommissioningRequest:(DiscoveredNodeData * _Nonnull)commissioner clientQueue:(dispatch_queue_t _Nonnull)clientQueue udcRequestSentHandler:(nullable void (^)(bool))udcRequestSentHandler { - ChipLogProgress(AppServer, - "CastingServerBridge().sendUserDirectedCommissioningRequest() called with IP %s port %d platformInterface %d deviceName: " - "%s", - [commissioner.ipAddresses[0] UTF8String], commissioner.port, commissioner.platformInterface, - [commissioner.deviceName UTF8String]); - - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"sendUserDirectedCommissioningRequest(...) IP %s port %d platformInterface %d deviceName %s", + [commissioner.ipAddresses[0] UTF8String], + commissioner.port, + commissioner.platformInterface, + [commissioner.deviceName UTF8String] + ]; + + [self dispatchOnMatterSDKQueue:description block:^{ bool udcRequestStatus; chip::Dnssd::DiscoveredNodeData cppCommissioner; @@ -417,7 +550,7 @@ - (void)sendUserDirectedCommissioningRequest:(DiscoveredNodeData * _Nonnull)comm dispatch_async(clientQueue, ^{ udcRequestSentHandler(udcRequestStatus); }); - }); + }]; } - (OnboardingPayload *)getOnboardingPaylod @@ -432,45 +565,44 @@ - (void)openBasicCommissioningWindow:(dispatch_queue_t _Nonnull)clientQueue onConnectionFailureCallback:(void (^_Nonnull)(MatterError * _Nonnull))onConnectionFailureCallback onNewOrUpdatedEndpointCallback:(void (^_Nonnull)(ContentApp * _Nonnull))onNewOrUpdatedEndpointCallback { - ChipLogProgress(AppServer, "CastingServerBridge().openBasicCommissioningWindow() called"); - - _commissioningCompleteCallback = commissioningCompleteCallback; - _onConnectionSuccessCallback = onConnectionSuccessCallback; - _onConnectionFailureCallback = onConnectionFailureCallback; - _onNewOrUpdatedEndpointCallback = onNewOrUpdatedEndpointCallback; - - CHIP_ERROR OpenBasicCommissioningWindow(std::function commissioningCompleteCallback, - std::function onConnectionSuccess, std::function onConnectionFailure, - std::function onNewOrUpdatedEndpoint); - - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"openBasicCommissioningWindow(...)" block:^{ CHIP_ERROR err = CastingServer::GetInstance()->OpenBasicCommissioningWindow( - [](CHIP_ERROR err) { [CastingServerBridge getSharedInstance].commissioningCompleteCallback(CHIP_NO_ERROR == err); }, - [](TargetVideoPlayerInfo * cppTargetVideoPlayerInfo) { + [clientQueue, commissioningCompleteCallback](CHIP_ERROR err) { + [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:@"openBasicCommissioningWindow(...) commissioningCompleteCallback" queue:clientQueue block: ^{ + commissioningCompleteCallback(CHIP_NO_ERROR == err); + }]; + }, + [clientQueue, onConnectionSuccessCallback](TargetVideoPlayerInfo * cppTargetVideoPlayerInfo) { VideoPlayer * videoPlayer = [ConversionUtils convertToObjCVideoPlayerFrom:cppTargetVideoPlayerInfo]; - [CastingServerBridge getSharedInstance].onConnectionSuccessCallback(videoPlayer); + [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:@"openBasicCommissioningWindow(...) onConnectionSuccessCallback" queue:clientQueue block: ^{ + onConnectionSuccessCallback(videoPlayer); + }]; }, - [](CHIP_ERROR err) { - [CastingServerBridge getSharedInstance].onConnectionFailureCallback( - [[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); + [clientQueue, onConnectionFailureCallback](CHIP_ERROR err) { + [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:@"openBasicCommissioningWindow(...) onConnectionFailureCallback" queue:clientQueue block: ^{ + onConnectionFailureCallback( + [[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]] + ); + }]; }, - [](TargetEndpointInfo * cppTargetEndpointInfo) { + [clientQueue, onNewOrUpdatedEndpointCallback](TargetEndpointInfo * cppTargetEndpointInfo) { ContentApp * contentApp = [ConversionUtils convertToObjCContentAppFrom:cppTargetEndpointInfo]; - [CastingServerBridge getSharedInstance].onNewOrUpdatedEndpointCallback(contentApp); + [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:@"openBasicCommissioningWindow(...) onNewOrUpdatedEndpointCallback" queue:clientQueue block: ^{ + onNewOrUpdatedEndpointCallback(contentApp); + }]; }); dispatch_async(clientQueue, ^{ + ChipLogProgress(AppServer, "[async] Dispatching commissioningWindowRequestedHandler"); commissioningWindowRequestedHandler(CHIP_NO_ERROR == err); }); - }); + }]; } - (void)getActiveTargetVideoPlayers:(dispatch_queue_t _Nonnull)clientQueue activeTargetVideoPlayersHandler:(nullable void (^)(NSMutableArray * _Nullable))activeTargetVideoPlayersHandler { - ChipLogProgress(AppServer, "CastingServerBridge().getActiveTargetVideoPlayers() called"); - - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"getActiveTargetVideoPlayers(...)" block:^{ NSMutableArray * videoPlayers = [NSMutableArray new]; TargetVideoPlayerInfo * cppTargetVideoPlayerInfo = CastingServer::GetInstance()->GetActiveTargetVideoPlayer(); if (cppTargetVideoPlayerInfo != nullptr && cppTargetVideoPlayerInfo->IsInitialized()) { @@ -480,15 +612,13 @@ - (void)getActiveTargetVideoPlayers:(dispatch_queue_t _Nonnull)clientQueue dispatch_async(clientQueue, ^{ activeTargetVideoPlayersHandler(videoPlayers); }); - }); + }]; } - (void)readCachedVideoPlayers:(dispatch_queue_t _Nonnull)clientQueue readCachedVideoPlayersHandler:(nullable void (^)(NSMutableArray * _Nullable))readCachedVideoPlayersHandler { - ChipLogProgress(AppServer, "CastingServerBridge().readCachedVideoPlayers() called"); - - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"readCachedVideoPlayers(...)" block:^{ NSMutableArray * videoPlayers = nil; TargetVideoPlayerInfo * cppTargetVideoPlayerInfos = CastingServer::GetInstance()->ReadCachedTargetVideoPlayerInfos(); if (cppTargetVideoPlayerInfos != nullptr) { @@ -506,7 +636,7 @@ - (void)readCachedVideoPlayers:(dispatch_queue_t _Nonnull)clientQueue dispatch_async(clientQueue, ^{ readCachedVideoPlayersHandler(videoPlayers); }); - }); + }]; } - (void)verifyOrEstablishConnection:(VideoPlayer * _Nonnull)videoPlayer @@ -516,54 +646,52 @@ - (void)verifyOrEstablishConnection:(VideoPlayer * _Nonnull)videoPlayer onConnectionFailureCallback:(void (^_Nonnull)(MatterError * _Nonnull))onConnectionFailureCallback onNewOrUpdatedEndpointCallback:(void (^_Nonnull)(ContentApp * _Nonnull))onNewOrUpdatedEndpointCallback { - ChipLogProgress(AppServer, "CastingServerBridge().verifyOrEstablishConnection() called"); - _onConnectionSuccessCallback = onConnectionSuccessCallback; - _onConnectionFailureCallback = onConnectionFailureCallback; - _onNewOrUpdatedEndpointCallback = onNewOrUpdatedEndpointCallback; - - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"verifyOrEstablishConnection(...)" block:^{ TargetVideoPlayerInfo targetVideoPlayerInfo; [ConversionUtils convertToCppTargetVideoPlayerInfoFrom:videoPlayer outTargetVideoPlayerInfo:targetVideoPlayerInfo]; CHIP_ERROR err = CastingServer::GetInstance()->VerifyOrEstablishConnection( targetVideoPlayerInfo, - [](TargetVideoPlayerInfo * cppTargetVideoPlayerInfo) { + [clientQueue, onConnectionSuccessCallback](TargetVideoPlayerInfo * cppTargetVideoPlayerInfo) { VideoPlayer * videoPlayer = [ConversionUtils convertToObjCVideoPlayerFrom:cppTargetVideoPlayerInfo]; - [CastingServerBridge getSharedInstance].onConnectionSuccessCallback(videoPlayer); + [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:@"onConnectionSuccessCallback" queue:clientQueue block:^{ + onConnectionSuccessCallback(videoPlayer); + }]; }, - [](CHIP_ERROR err) { - [CastingServerBridge getSharedInstance].onConnectionFailureCallback( - [[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); + [clientQueue, onConnectionFailureCallback](CHIP_ERROR err) { + [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:@"onConnectionFailureCallback" queue:clientQueue block:^{ + onConnectionFailureCallback([[MatterError alloc] initWithCode:err.AsInteger() + message:[NSString stringWithUTF8String:err.AsString()]]); + }]; }, - [](TargetEndpointInfo * cppTargetEndpointInfo) { + [clientQueue, onNewOrUpdatedEndpointCallback](TargetEndpointInfo * cppTargetEndpointInfo) { ContentApp * contentApp = [ConversionUtils convertToObjCContentAppFrom:cppTargetEndpointInfo]; - [CastingServerBridge getSharedInstance].onNewOrUpdatedEndpointCallback(contentApp); + [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:@"onNewOrUpdatedEndpointCallback" queue:clientQueue block:^{ + onNewOrUpdatedEndpointCallback(contentApp); + }]; }); dispatch_async(clientQueue, ^{ requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)shutdownAllSubscriptions:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(nullable void (^)())requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().shutdownAllSubscriptions() called"); - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"shutdownAllSubscriptions(...)" block:^{ CastingServer::GetInstance()->ShutdownAllSubscriptions(); dispatch_async(clientQueue, ^{ requestSentHandler(); }); - }); + }]; } - (void)startMatterServer:(dispatch_queue_t _Nonnull)clientQueue startMatterServerCompletionCallback:(nullable void (^)(MatterError * _Nonnull))startMatterServerCompletionCallback { - ChipLogProgress(AppServer, "CastingServerBridge().startMatterServer() called"); - - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"startMatterServer(...)" block: ^{ // Initialize the Matter server CHIP_ERROR err = chip::Server::GetInstance().Init(*self->_serverInitParams); if (err != CHIP_NO_ERROR) { @@ -614,14 +742,12 @@ - (void)startMatterServer:(dispatch_queue_t _Nonnull)clientQueue message:[NSString stringWithUTF8String:CHIP_NO_ERROR.AsString()]]); }); } - }); + }]; } - (void)stopMatterServer { - ChipLogProgress(AppServer, "CastingServerBridge().stopMatterServer() called"); - - dispatch_sync(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"stopMatterServer(...)" block: ^{ // capture pointer to previouslyConnectedVideoPlayer, to be deleted TargetVideoPlayerInfo * videoPlayerForDeletion = self->_previouslyConnectedVideoPlayer == nil ? nil : self->_previouslyConnectedVideoPlayer; @@ -665,18 +791,17 @@ - (void)stopMatterServer if (videoPlayerForDeletion != nil) { delete videoPlayerForDeletion; } - }); + }]; } - (void)disconnect:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(nullable void (^)())requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().disconnect() called"); - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"disconnect(...)" block: ^{ CastingServer::GetInstance()->Disconnect(); dispatch_async(clientQueue, ^{ requestSentHandler(); }); - }); + }]; } - (void)contentLauncher_launchUrl:(ContentApp * _Nonnull)contentApp @@ -686,24 +811,21 @@ - (void)contentLauncher_launchUrl:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().contentLauncher_launchUrl() called on Content App with endpoint ID %d", - contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"contentLauncher_launchUrl"]; - - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err = CastingServer::GetInstance()->ContentLauncherLaunchURL( - &endpoint, [contentUrl UTF8String], [contentDisplayStr UTF8String], [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"contentLauncher_launchUrl"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->ContentLauncherLaunchURL( + &endpoint, + [contentUrl UTF8String], + [contentDisplayStr UTF8String], + responseFunction + ); + }]; } - (void)contentLauncher_launchContent:(ContentApp * _Nonnull)contentApp @@ -714,16 +836,13 @@ - (void)contentLauncher_launchContent:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().contentLauncher_launchContent() called on Content App with endpoint ID %d", - contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"contentLauncher_launchContent"]; + const NSString *description = [NSString stringWithFormat:@"contentLauncher_launchContent(...) with Content App endpoint ID %d", contentApp.endpointId]; // Make a copy of params before we go async. contentSearch = [contentSearch copy]; data = [data copy]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:description block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -771,15 +890,16 @@ - (void)contentLauncher_launchContent:(ContentApp * _Nonnull)contentApp CHIP_ERROR err = CastingServer::GetInstance()->ContentLauncher_LaunchContent(&endpoint, cppSearch, autoPlay, MakeOptional(chip::CharSpan([data UTF8String], [data lengthOfBytesUsingEncoding:NSUTF8StringEncoding])), - [](CHIP_ERROR err) { - void (^responseCallback)(bool) = [[CastingServerBridge getSharedInstance].commandResponseCallbacks - objectForKey:@"contentLauncher_launchContent"]; - responseCallback(CHIP_NO_ERROR == err); + [clientQueue, responseCallback](CHIP_ERROR err) { + [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:@"responseCallback" queue:clientQueue block:^{ + responseCallback(CHIP_NO_ERROR == err); + }]; }); + dispatch_async(clientQueue, ^{ requestSentHandler(CHIP_NO_ERROR == err); }); - }); + }]; } - (void)contentLauncher_subscribeSupportedStreamingProtocols:(ContentApp * _Nonnull)contentApp @@ -791,16 +911,8 @@ - (void)contentLauncher_subscribeSupportedStreamingProtocols:(ContentApp * _Nonn failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, - "CastingServerBridge().contentLauncher_subscribeSupportedStreamingProtocols() called on Content App with endpoint ID %d", - contentApp.endpointId); - - [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"contentLauncher_subscribeSupportedStreamingProtocols"]; - [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"contentLauncher_subscribeSupportedStreamingProtocols"]; - [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback - forKey:@"contentLauncher_subscribeSupportedStreamingProtocols"]; - - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"contentLauncher_subscribeSupportedStreamingProtocols(...) with Content App endpoint ID %d", contentApp.endpointId]; + [self dispatchOnMatterSDKQueue:description block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -828,7 +940,7 @@ - (void)contentLauncher_subscribeSupportedStreamingProtocols:(ContentApp * _Nonn requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)levelControl_step:(ContentApp * _Nonnull)contentApp @@ -841,25 +953,25 @@ - (void)levelControl_step:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress( - AppServer, "CastingServerBridge().levelControl_step() called on Content App with endpoint ID %d", contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"levelControl_step"]; - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err = CastingServer::GetInstance()->LevelControl_Step(&endpoint, - static_cast(stepMode), stepSize, transitionTime, optionMask, - optionOverride, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"levelControl_step"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->LevelControl_Step( + &endpoint, + static_cast(stepMode), + stepSize, + transitionTime, + optionMask, + optionOverride, + responseFunction + ); + }]; } - (void)levelControl_moveToLevel:(ContentApp * _Nonnull)contentApp @@ -871,24 +983,24 @@ - (void)levelControl_moveToLevel:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().levelControl_moveToLevel() called on Content App with endpoint ID %d", - contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"levelControl_moveToLevel"]; - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"levelControl_moveToLevel(...) with Content App endpoint ID %d", contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err = CastingServer::GetInstance()->LevelControl_MoveToLevel( - &endpoint, level, transitionTime, optionMask, optionOverride, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"levelControl_moveToLevel"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->LevelControl_MoveToLevel( + &endpoint, + level, + transitionTime, + optionMask, + optionOverride, + responseFunction + ); + }]; } - (void)levelControl_subscribeCurrentLevel:(ContentApp * _Nonnull)contentApp @@ -908,7 +1020,7 @@ - (void)levelControl_subscribeCurrentLevel:(ContentApp * _Nonnull)contentApp [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"levelControl_subscribeCurrentLevel"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"levelControl_subscribeCurrentLevel"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"levelControl_subscribeCurrentLevel(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -935,7 +1047,7 @@ - (void)levelControl_subscribeCurrentLevel:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)levelControl_subscribeMinLevel:(ContentApp * _Nonnull)contentApp @@ -954,7 +1066,7 @@ - (void)levelControl_subscribeMinLevel:(ContentApp * _Nonnull)contentApp [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"levelControl_subscribeMinLevel"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"levelControl_subscribeMinLevel"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"levelControl_subscribeMinLevel(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -980,7 +1092,7 @@ - (void)levelControl_subscribeMinLevel:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)levelControl_subscribeMaxLevel:(ContentApp * _Nonnull)contentApp @@ -999,7 +1111,7 @@ - (void)levelControl_subscribeMaxLevel:(ContentApp * _Nonnull)contentApp [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"levelControl_subscribeMaxLevel"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"levelControl_subscribeMaxLevel"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"levelControl_subscribeMaxLevel(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1025,7 +1137,7 @@ - (void)levelControl_subscribeMaxLevel:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)mediaPlayback_play:(ContentApp * _Nonnull)contentApp @@ -1033,23 +1145,17 @@ - (void)mediaPlayback_play:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress( - AppServer, "CastingServerBridge().mediaPlayback_play() called on Content App with endpoint ID %d", contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"mediaPlayback_play"]; - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_Play(&endpoint, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"mediaPlayback_play"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->MediaPlayback_Play(&endpoint, responseFunction); + }]; } - (void)mediaPlayback_pause:(ContentApp * _Nonnull)contentApp @@ -1057,23 +1163,17 @@ - (void)mediaPlayback_pause:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress( - AppServer, "CastingServerBridge().mediaPlayback_pause() called on Content App with endpoint ID %d", contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"mediaPlayback_pause"]; - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_Pause(&endpoint, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"mediaPlayback_pause"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->MediaPlayback_Pause(&endpoint, responseFunction); + }]; } - (void)mediaPlayback_stopPlayback:(ContentApp * _Nonnull)contentApp @@ -1081,23 +1181,17 @@ - (void)mediaPlayback_stopPlayback:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_stopPlayback() called on Content App with endpoint ID %d", - contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"mediaPlayback_stopPlayback"]; - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_StopPlayback(&endpoint, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"mediaPlayback_stopPlayback"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->MediaPlayback_StopPlayback(&endpoint, responseFunction); + }]; } - (void)mediaPlayback_next:(ContentApp * _Nonnull)contentApp @@ -1105,23 +1199,17 @@ - (void)mediaPlayback_next:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress( - AppServer, "CastingServerBridge().mediaPlayback_next() called on Content App with endpoint ID %d", contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"mediaPlayback_next"]; - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_Next(&endpoint, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"mediaPlayback_next"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->MediaPlayback_Next(&endpoint, responseFunction); + }]; } - (void)mediaPlayback_seek:(ContentApp * _Nonnull)contentApp @@ -1130,23 +1218,17 @@ - (void)mediaPlayback_seek:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress( - AppServer, "CastingServerBridge().mediaPlayback_seek() called on Content App with endpoint ID %d", contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"mediaPlayback_seek"]; - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_Seek(&endpoint, position, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"mediaPlayback_seek"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->MediaPlayback_Seek(&endpoint, position, responseFunction); + }]; } - (void)mediaPlayback_skipForward:(ContentApp * _Nonnull)contentApp @@ -1155,24 +1237,17 @@ - (void)mediaPlayback_skipForward:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_skipForward() called on Content App with endpoint ID %d", - contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"mediaPlayback_skipForward"]; - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err - = CastingServer::GetInstance()->MediaPlayback_SkipForward(&endpoint, deltaPositionMilliseconds, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"mediaPlayback_skipForward"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->MediaPlayback_SkipForward(&endpoint, deltaPositionMilliseconds, responseFunction); + }]; } - (void)mediaPlayback_skipBackward:(ContentApp * _Nonnull)contentApp @@ -1181,24 +1256,17 @@ - (void)mediaPlayback_skipBackward:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_skipBackward() called on Content App with endpoint ID %d", - contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"mediaPlayback_skipBackward"]; - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err - = CastingServer::GetInstance()->MediaPlayback_SkipBackward(&endpoint, deltaPositionMilliseconds, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"mediaPlayback_skipBackward"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->MediaPlayback_SkipBackward(&endpoint, deltaPositionMilliseconds, responseFunction); + }]; } - (void)mediaPlayback_subscribeCurrentState:(ContentApp * _Nonnull)contentApp @@ -1218,7 +1286,7 @@ - (void)mediaPlayback_subscribeCurrentState:(ContentApp * _Nonnull)contentApp [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"mediaPlayback_subscribeCurrentState"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"mediaPlayback_subscribeCurrentState"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"mediaPlayback_subscribeCurrentState(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1242,11 +1310,12 @@ - (void)mediaPlayback_subscribeCurrentState:(ContentApp * _Nonnull)contentApp objectForKey:@"mediaPlayback_subscribeCurrentState"]; callback(); }); + dispatch_async(clientQueue, ^{ requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)mediaPlayback_subscribeStartTime:(ContentApp * _Nonnull)contentApp @@ -1265,7 +1334,7 @@ - (void)mediaPlayback_subscribeStartTime:(ContentApp * _Nonnull)contentApp [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"mediaPlayback_subscribeStartTime"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"mediaPlayback_subscribeStartTime"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"mediaPlayback_subscribeStartTime(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1291,7 +1360,7 @@ - (void)mediaPlayback_subscribeStartTime:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)mediaPlayback_subscribeDuration:(ContentApp * _Nonnull)contentApp @@ -1310,7 +1379,7 @@ - (void)mediaPlayback_subscribeDuration:(ContentApp * _Nonnull)contentApp [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"mediaPlayback_subscribeDuration"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"mediaPlayback_subscribeDuration"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"mediaPlayback_subscribeDuration(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1336,7 +1405,7 @@ - (void)mediaPlayback_subscribeDuration:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)mediaPlayback_subscribeSampledPosition:(ContentApp * _Nonnull)contentApp @@ -1356,7 +1425,7 @@ - (void)mediaPlayback_subscribeSampledPosition:(ContentApp * _Nonnull)contentApp [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"mediaPlayback_subscribeSampledPosition"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"mediaPlayback_subscribeSampledPosition"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"mediaPlayback_subscribeSampledPosition(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1396,7 +1465,7 @@ - (void)mediaPlayback_subscribeSampledPosition:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)mediaPlayback_subscribePlaybackSpeed:(ContentApp * _Nonnull)contentApp @@ -1416,7 +1485,7 @@ - (void)mediaPlayback_subscribePlaybackSpeed:(ContentApp * _Nonnull)contentApp [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"mediaPlayback_subscribePlaybackSpeed"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"mediaPlayback_subscribePlaybackSpeed"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"mediaPlayback_subscribePlaybackSpeed(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1443,7 +1512,7 @@ - (void)mediaPlayback_subscribePlaybackSpeed:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)mediaPlayback_subscribeSeekRangeEnd:(ContentApp * _Nonnull)contentApp @@ -1463,7 +1532,7 @@ - (void)mediaPlayback_subscribeSeekRangeEnd:(ContentApp * _Nonnull)contentApp [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"mediaPlayback_subscribeSeekRangeEnd"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"mediaPlayback_subscribeSeekRangeEnd"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"mediaPlayback_subscribeSeekRangeEnd(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1486,11 +1555,12 @@ - (void)mediaPlayback_subscribeSeekRangeEnd:(ContentApp * _Nonnull)contentApp objectForKey:@"mediaPlayback_subscribeSeekRangeEnd"]; callback(); }); + dispatch_async(clientQueue, ^{ requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)mediaPlayback_subscribeSeekRangeStart:(ContentApp * _Nonnull)contentApp @@ -1510,7 +1580,7 @@ - (void)mediaPlayback_subscribeSeekRangeStart:(ContentApp * _Nonnull)contentApp [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"mediaPlayback_subscribeSeekRangeStart"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"mediaPlayback_subscribeSeekRangeStart"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"mediaPlayback_subscribeSeekRangeStart(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1537,7 +1607,7 @@ - (void)mediaPlayback_subscribeSeekRangeStart:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)applicationLauncher_launchApp:(ContentApp * _Nonnull)contentApp @@ -1548,29 +1618,26 @@ - (void)applicationLauncher_launchApp:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().applicationLauncher_launchApp() called on Content App with endpoint ID %d", - contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"applicationLauncher_launchApp"]; - chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application; application.catalogVendorId = catalogVendorId; application.applicationId = chip::CharSpan::fromCharString([applicationId UTF8String]); - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err = CastingServer::GetInstance()->ApplicationLauncher_LaunchApp(&endpoint, application, - chip::MakeOptional(chip::ByteSpan(static_cast(data.bytes), data.length)), [](CHIP_ERROR err) { - void (^responseCallback)(bool) = [[CastingServerBridge getSharedInstance].commandResponseCallbacks - objectForKey:@"applicationLauncher_launchApp"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->ApplicationLauncher_LaunchApp( + &endpoint, + application, + chip::MakeOptional(chip::ByteSpan(static_cast(data.bytes), data.length)), + responseFunction + ); + }]; } - (void)applicationLauncher_stopApp:(ContentApp * _Nonnull)contentApp @@ -1580,28 +1647,25 @@ - (void)applicationLauncher_stopApp:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().applicationLauncher_stopApp() called on Content App with endpoint ID %d", - contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"applicationLauncher_stopApp"]; - chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application; application.catalogVendorId = catalogVendorId; application.applicationId = chip::CharSpan::fromCharString([applicationId UTF8String]); - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err = CastingServer::GetInstance()->ApplicationLauncher_StopApp(&endpoint, application, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"applicationLauncher_stopApp"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->ApplicationLauncher_StopApp( + &endpoint, + application, + responseFunction + ); + }]; } - (void)applicationLauncher_hideApp:(ContentApp * _Nonnull)contentApp @@ -1611,28 +1675,25 @@ - (void)applicationLauncher_hideApp:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().applicationLauncher_hideApp() called on Content App with endpoint ID %d", - contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"applicationLauncher_hideApp"]; - chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application; application.catalogVendorId = catalogVendorId; application.applicationId = chip::CharSpan::fromCharString([applicationId UTF8String]); - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err = CastingServer::GetInstance()->ApplicationLauncher_HideApp(&endpoint, application, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"applicationLauncher_hideApp"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->ApplicationLauncher_HideApp( + &endpoint, + application, + responseFunction + ); + }]; } - (void)targetNavigator_navigateTarget:(ContentApp * _Nonnull)contentApp @@ -1642,25 +1703,22 @@ - (void)targetNavigator_navigateTarget:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().targetNavigator_navigateTarget() called on Content App with endpoint ID %d", - contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"targetNavigator_navigateTarget"]; - - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err = CastingServer::GetInstance()->TargetNavigator_NavigateTarget( - &endpoint, target, chip::MakeOptional(chip::CharSpan::fromCharString([data UTF8String])), [](CHIP_ERROR err) { - void (^responseCallback)(bool) = [[CastingServerBridge getSharedInstance].commandResponseCallbacks - objectForKey:@"targetNavigator_navigateTarget"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->TargetNavigator_NavigateTarget( + &endpoint, + target, + chip::MakeOptional(chip::CharSpan::fromCharString([data UTF8String])), + responseFunction + ); + }]; } - (void)targetNavigator_subscribeTargetList:(ContentApp * _Nonnull)contentApp @@ -1680,7 +1738,7 @@ - (void)targetNavigator_subscribeTargetList:(ContentApp * _Nonnull)contentApp [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"targetNavigator_subscribeTargetList"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"targetNavigator_subscribeTargetList"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"targetNavigator_subscribeTargetList(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1722,7 +1780,7 @@ - (void)targetNavigator_subscribeTargetList:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)targetNavigator_subscribeCurrentTarget:(ContentApp * _Nonnull)contentApp @@ -1742,7 +1800,7 @@ - (void)targetNavigator_subscribeCurrentTarget:(ContentApp * _Nonnull)contentApp [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"targetNavigator_subscribeCurrentTarget"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"targetNavigator_subscribeCurrentTarget"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"targetNavigator_subscribeCurrentTarget(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1769,7 +1827,7 @@ - (void)targetNavigator_subscribeCurrentTarget:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)keypadInput_sendKey:(ContentApp * _Nonnull)contentApp @@ -1778,25 +1836,21 @@ - (void)keypadInput_sendKey:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress( - AppServer, "CastingServerBridge().keypadInput_sendKey() called on Content App with endpoint ID %d", contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"keypadInput_sendKey"]; - - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err = CastingServer::GetInstance()->KeypadInput_SendKey( - &endpoint, static_cast(keyCode), [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"keypadInput_sendKey"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->KeypadInput_SendKey( + &endpoint, + static_cast(keyCode), + responseFunction + ); + }]; } - (void)applicationBasic_subscribeVendorName:(ContentApp * _Nonnull)contentApp @@ -1816,7 +1870,7 @@ - (void)applicationBasic_subscribeVendorName:(ContentApp * _Nonnull)contentApp [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"applicationBasic_subscribeVendorName"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"applicationBasic_subscribeVendorName"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"applicationBasic_subscribeVendorName(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1843,7 +1897,7 @@ - (void)applicationBasic_subscribeVendorName:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)applicationBasic_subscribeVendorID:(ContentApp * _Nonnull)contentApp @@ -1863,7 +1917,7 @@ - (void)applicationBasic_subscribeVendorID:(ContentApp * _Nonnull)contentApp [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"applicationBasic_subscribeVendorID"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"applicationBasic_subscribeVendorID"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"applicationBasic_subscribeVendorID(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1889,7 +1943,7 @@ - (void)applicationBasic_subscribeVendorID:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)applicationBasic_subscribeApplicationName:(ContentApp * _Nonnull)contentApp @@ -1910,7 +1964,7 @@ - (void)applicationBasic_subscribeApplicationName:(ContentApp * _Nonnull)content [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"applicationBasic_subscribeApplicationName"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"applicationBasic_subscribeApplicationName(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1937,7 +1991,7 @@ - (void)applicationBasic_subscribeApplicationName:(ContentApp * _Nonnull)content requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)applicationBasic_subscribeProductID:(ContentApp * _Nonnull)contentApp @@ -1957,7 +2011,7 @@ - (void)applicationBasic_subscribeProductID:(ContentApp * _Nonnull)contentApp [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"applicationBasic_subscribeProductID"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"applicationBasic_subscribeProductID"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"applicationBasic_subscribeProductID(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1983,7 +2037,7 @@ - (void)applicationBasic_subscribeProductID:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)applicationBasic_subscribeApplicationVersion:(ContentApp * _Nonnull)contentApp @@ -2004,7 +2058,7 @@ - (void)applicationBasic_subscribeApplicationVersion:(ContentApp * _Nonnull)cont [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"applicationBasic_subscribeApplicationVersion"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"applicationBasic_subscribeApplicationVersion(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -2032,7 +2086,7 @@ - (void)applicationBasic_subscribeApplicationVersion:(ContentApp * _Nonnull)cont requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)applicationBasic_readVendorName:(ContentApp * _Nonnull)contentApp @@ -2047,7 +2101,7 @@ - (void)applicationBasic_readVendorName:(ContentApp * _Nonnull)contentApp [_readSuccessCallbacks setObject:successCallback forKey:@"applicationBasic_readVendorName"]; [_readFailureCallbacks setObject:failureCallback forKey:@"applicationBasic_readVendorName"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:[NSString stringWithFormat:@"%s(...)", __func__] block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -2068,7 +2122,7 @@ - (void)applicationBasic_readVendorName:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)applicationBasic_readVendorID:(ContentApp * _Nonnull)contentApp @@ -2083,7 +2137,7 @@ - (void)applicationBasic_readVendorID:(ContentApp * _Nonnull)contentApp [_readSuccessCallbacks setObject:successCallback forKey:@"applicationBasic_readVendorID"]; [_readFailureCallbacks setObject:failureCallback forKey:@"applicationBasic_readVendorID"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"applicationBasic_readVendorID(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -2103,7 +2157,7 @@ - (void)applicationBasic_readVendorID:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)applicationBasic_readApplicationName:(ContentApp * _Nonnull)contentApp @@ -2119,7 +2173,7 @@ - (void)applicationBasic_readApplicationName:(ContentApp * _Nonnull)contentApp [_readSuccessCallbacks setObject:successCallback forKey:@"applicationBasic_readApplicationName"]; [_readFailureCallbacks setObject:failureCallback forKey:@"applicationBasic_readApplicationName"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"applicationBasic_readApplicationName(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -2140,7 +2194,7 @@ - (void)applicationBasic_readApplicationName:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)applicationBasic_readProductID:(ContentApp * _Nonnull)contentApp @@ -2155,7 +2209,7 @@ - (void)applicationBasic_readProductID:(ContentApp * _Nonnull)contentApp [_readSuccessCallbacks setObject:successCallback forKey:@"applicationBasic_readProductID"]; [_readFailureCallbacks setObject:failureCallback forKey:@"applicationBasic_readProductID"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"applicationBasic_readProductID(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -2175,7 +2229,7 @@ - (void)applicationBasic_readProductID:(ContentApp * _Nonnull)contentApp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)applicationBasic_readApplicationVersion:(ContentApp * _Nonnull)contentApp @@ -2191,7 +2245,7 @@ - (void)applicationBasic_readApplicationVersion:(ContentApp * _Nonnull)contentAp [_readSuccessCallbacks setObject:successCallback forKey:@"applicationBasic_readApplicationVersion"]; [_readFailureCallbacks setObject:failureCallback forKey:@"applicationBasic_readApplicationVersion"]; - dispatch_async(_chipWorkQueue, ^{ + [self dispatchOnMatterSDKQueue:@"applicationBasic_readApplicationVersion(...)" block: ^{ TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -2213,7 +2267,7 @@ - (void)applicationBasic_readApplicationVersion:(ContentApp * _Nonnull)contentAp requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }); - }); + }]; } - (void)onOff_on:(ContentApp * _Nonnull)contentApp @@ -2221,22 +2275,17 @@ - (void)onOff_on:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().onOff_on() called on Content App with endpoint ID %d", contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"onOff_on"]; - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err = CastingServer::GetInstance()->OnOff_On(&endpoint, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"onOff_on"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->OnOff_On(&endpoint, responseFunction); + }]; } - (void)onOff_off:(ContentApp * _Nonnull)contentApp @@ -2244,23 +2293,17 @@ - (void)onOff_off:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress( - AppServer, "CastingServerBridge().onOff_off() called on Content App with endpoint ID %d", contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"onOff_off"]; - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err = CastingServer::GetInstance()->OnOff_Off(&endpoint, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"onOff_off"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->OnOff_Off(&endpoint, responseFunction); + }]; } - (void)onOff_toggle:(ContentApp * _Nonnull)contentApp @@ -2268,22 +2311,16 @@ - (void)onOff_toggle:(ContentApp * _Nonnull)contentApp clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress( - AppServer, "CastingServerBridge().onOff_toggle() called on Content App with endpoint ID %d", contentApp.endpointId); - - [_commandResponseCallbacks setObject:responseCallback forKey:@"onOff_toggle"]; - dispatch_async(_chipWorkQueue, ^{ + const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; + [self withCastingServerInvokeBlockWithResponse:description + withStartedCallback:requestSentHandler + andResponseCallback:responseCallback + onQueue:clientQueue + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; - CHIP_ERROR err = CastingServer::GetInstance()->OnOff_Toggle(&endpoint, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"onOff_toggle"]; - responseCallback(CHIP_NO_ERROR == err); - }); - dispatch_async(clientQueue, ^{ - requestSentHandler(CHIP_NO_ERROR == err); - }); - }); + return castingServer->OnOff_Toggle(&endpoint, responseFunction); + }]; } @end diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissionerDiscoveryDelegateImpl.h b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissionerDiscoveryDelegateImpl.h index 56ac24526d831c..3d54b9acc022c6 100644 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissionerDiscoveryDelegateImpl.h +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissionerDiscoveryDelegateImpl.h @@ -26,7 +26,7 @@ class CommissionerDiscoveryDelegateImpl : public chip::Controller::DeviceDiscove public: void SetUp(dispatch_queue_t _Nonnull clientQueue, void (^_Nonnull objCDiscoveredCommissionerHandler)(DiscoveredNodeData * _Nonnull), - TargetVideoPlayerInfo * cachedTargetVideoPlayerInfos) + TargetVideoPlayerInfo * _Nullable cachedTargetVideoPlayerInfos) { mClientQueue = clientQueue; mObjCDiscoveredCommissionerHandler = objCDiscoveredCommissionerHandler; @@ -59,7 +59,7 @@ class CommissionerDiscoveryDelegateImpl : public chip::Controller::DeviceDiscove private: void (^_Nonnull mObjCDiscoveredCommissionerHandler)(DiscoveredNodeData * _Nonnull); dispatch_queue_t _Nonnull mClientQueue; - TargetVideoPlayerInfo * mCachedTargetVideoPlayerInfos; + TargetVideoPlayerInfo * _Nullable mCachedTargetVideoPlayerInfos; }; #endif /* CommissionerDiscoveryDelegateImpl_h */ From bb5f625466eda9271753427632878630acb786fe Mon Sep 17 00:00:00 2001 From: Michael Douglas Date: Tue, 28 Feb 2023 13:34:18 -0800 Subject: [PATCH 2/3] * Updating naming and parameter order for new CastingServerBridge APIs * Refactored the Certification Tests to more fully exercise threading behavior --- .../CastingServerBridge.h | 4 +- .../CastingServerBridge.mm | 260 ++++--- .../TvCasting/TvCasting/CertTestView.swift | 13 +- .../TvCasting/CertTestViewModel.swift | 692 ++++++++++-------- .../TvCasting/CommissioningView.swift | 6 +- .../TvCasting/MediaPlaybackViewModel.swift | 4 +- 6 files changed, 561 insertions(+), 418 deletions(-) diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h index 5827f63d4a2a19..f8ca7979962043 100644 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h @@ -1,6 +1,6 @@ /** * - * Copyright (c) 2020-2022 Project CHIP Authors + * Copyright (c) 2020-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. @@ -99,7 +99,7 @@ @return Onboarding payload */ -- (OnboardingPayload * _Nonnull)getOnboardingPaylod; +- (OnboardingPayload * _Nonnull)getOnboardingPayload; /*! @brief Request opening of a basic commissioning window diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm index 8c8e3e76a4e241..ea18494597f298 100644 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm @@ -146,9 +146,9 @@ - (void) dispatchOnMatterSDKQueue:(const NSString * _Nullable)description @param queue The client's Dispatch Queue. @param block The Block to be invoked to invoke the client callback. */ -- (void) dispatchOnClientQueue:(const NSString * _Nullable )description - queue:(dispatch_queue_t)queue - block:(dispatch_block_t)block +- (void) dispatchOnClientQueue:(dispatch_queue_t)queue + description:(const NSString * _Nullable )description + block:(dispatch_block_t)block { // Within the CastingServerBridge, the usage pattern is typically to expose asynchronous public APIs that // take a callback to indicate that the low-level SDK operation has been initiated (the "started" @@ -192,21 +192,25 @@ - (void) dispatchOnClientQueue:(const NSString * _Nullable )description @param block The Objective C Block to dispatch. */ - (void) withCastingServerInvokeBlock:(const NSString * _Nullable)description - withCompletionCallback:(void (^_Nonnull)(bool))blockCompleteCallback - onQueue:(dispatch_queue_t)callbackQueue + callbackQueue:(dispatch_queue_t)callbackQueue + onBlockComplete:(void (^_Nonnull)(bool))blockCompleteCallback block:(CHIP_ERROR (^_Nonnull)(CastingServer *)) block { [self dispatchOnMatterSDKQueue:description block:^{ CastingServer * castingServer = CastingServer::GetInstance(); + + // We invoke the block and capture the result on the Matter Dispatch Queue with the stack lock held, + // then use the result snapshot in the subsequent block to be asynchronously dispatched on the + // client's callback Dispatch Queue. const CHIP_ERROR result = block(castingServer); dispatch_async(callbackQueue, ^{ if (nil != description) { - ChipLogProgress(AppServer, "[ASYNC (CLIENT)] CastingServerBridge BEGIN %s Started Callback", [description UTF8String]); + ChipLogProgress(AppServer, "[ASYNC (CLIENT)] CastingServerBridge invoking %s Started Callback", [description UTF8String]); } blockCompleteCallback([[MatterError alloc] initWithCode:result.AsInteger() message:[NSString stringWithUTF8String:result.AsString()]]); if (nil != description) { - ChipLogProgress(AppServer, "[ASYNC (CLIENT)] CastingServerBridge END %s Started Callback", [description UTF8String]); + ChipLogProgress(AppServer, "[ASYNC (CLIENT)] CastingServerBridge invoked %s Started Callback", [description UTF8String]); } }); }]; @@ -224,15 +228,15 @@ asynchronous result of the Casting Server operation (by the Casting Server). @param callbackQueue The Dispatch Queue on which the callbacks shall be invoked. @param block The Objective C Block to dispatch. */ -- (void) withCastingServerInvokeBlockWithResponse:(const NSString * _Nullable)description - withStartedCallback:(void (^_Nonnull)(bool))blockCompleteCallback - andResponseCallback:(void (^_Nonnull)(bool))responseCallback - onQueue:(dispatch_queue_t)callbackQueue - block:(CHIP_ERROR (^_Nonnull)(CastingServer *, std::function)) block +- (void) withCastingServerInvokeBlock:(const NSString * _Nullable)description + callbackQueue:(dispatch_queue_t)callbackQueue + onBlockComplete:(void (^_Nonnull)(bool))blockCompleteCallback + onResponse:(void (^_Nonnull)(bool))responseCallback + block:(CHIP_ERROR (^_Nonnull)(CastingServer *, std::function)) block { [self withCastingServerInvokeBlock:description - withCompletionCallback:blockCompleteCallback - onQueue:callbackQueue + callbackQueue:callbackQueue + onBlockComplete:blockCompleteCallback block:^(CastingServer *castingServer){ return block( castingServer, @@ -241,8 +245,10 @@ - (void) withCastingServerInvokeBlockWithResponse:(const NSString * _Nullable)de ? nil : [NSString stringWithFormat:@"%@ Response Callback", description]; - [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:_description - queue:callbackQueue block:^{ + [[CastingServerBridge getSharedInstance] + dispatchOnClientQueue:callbackQueue + description:_description + block:^{ responseCallback(CHIP_NO_ERROR == err); }]; } @@ -553,7 +559,7 @@ - (void)sendUserDirectedCommissioningRequest:(DiscoveredNodeData * _Nonnull)comm }]; } -- (OnboardingPayload *)getOnboardingPaylod +- (OnboardingPayload *)getOnboardingPayload { return _onboardingPayload; } @@ -568,18 +574,27 @@ - (void)openBasicCommissioningWindow:(dispatch_queue_t _Nonnull)clientQueue [self dispatchOnMatterSDKQueue:@"openBasicCommissioningWindow(...)" block:^{ CHIP_ERROR err = CastingServer::GetInstance()->OpenBasicCommissioningWindow( [clientQueue, commissioningCompleteCallback](CHIP_ERROR err) { - [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:@"openBasicCommissioningWindow(...) commissioningCompleteCallback" queue:clientQueue block: ^{ + [[CastingServerBridge getSharedInstance] + dispatchOnClientQueue:clientQueue + description:@"openBasicCommissioningWindow(...) commissioningCompleteCallback" + block: ^{ commissioningCompleteCallback(CHIP_NO_ERROR == err); }]; }, [clientQueue, onConnectionSuccessCallback](TargetVideoPlayerInfo * cppTargetVideoPlayerInfo) { VideoPlayer * videoPlayer = [ConversionUtils convertToObjCVideoPlayerFrom:cppTargetVideoPlayerInfo]; - [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:@"openBasicCommissioningWindow(...) onConnectionSuccessCallback" queue:clientQueue block: ^{ + [[CastingServerBridge getSharedInstance] + dispatchOnClientQueue:clientQueue + description:@"openBasicCommissioningWindow(...) onConnectionSuccessCallback" + block: ^{ onConnectionSuccessCallback(videoPlayer); }]; }, [clientQueue, onConnectionFailureCallback](CHIP_ERROR err) { - [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:@"openBasicCommissioningWindow(...) onConnectionFailureCallback" queue:clientQueue block: ^{ + [[CastingServerBridge getSharedInstance] + dispatchOnClientQueue:clientQueue + description:@"openBasicCommissioningWindow(...) onConnectionFailureCallback" + block: ^{ onConnectionFailureCallback( [[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]] ); @@ -587,7 +602,10 @@ - (void)openBasicCommissioningWindow:(dispatch_queue_t _Nonnull)clientQueue }, [clientQueue, onNewOrUpdatedEndpointCallback](TargetEndpointInfo * cppTargetEndpointInfo) { ContentApp * contentApp = [ConversionUtils convertToObjCContentAppFrom:cppTargetEndpointInfo]; - [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:@"openBasicCommissioningWindow(...) onNewOrUpdatedEndpointCallback" queue:clientQueue block: ^{ + [[CastingServerBridge getSharedInstance] + dispatchOnClientQueue:clientQueue + description:@"openBasicCommissioningWindow(...) onNewOrUpdatedEndpointCallback" + block: ^{ onNewOrUpdatedEndpointCallback(contentApp); }]; }); @@ -654,19 +672,28 @@ - (void)verifyOrEstablishConnection:(VideoPlayer * _Nonnull)videoPlayer targetVideoPlayerInfo, [clientQueue, onConnectionSuccessCallback](TargetVideoPlayerInfo * cppTargetVideoPlayerInfo) { VideoPlayer * videoPlayer = [ConversionUtils convertToObjCVideoPlayerFrom:cppTargetVideoPlayerInfo]; - [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:@"onConnectionSuccessCallback" queue:clientQueue block:^{ + [[CastingServerBridge getSharedInstance] + dispatchOnClientQueue:clientQueue + description:@"onConnectionSuccessCallback" + block:^{ onConnectionSuccessCallback(videoPlayer); }]; }, [clientQueue, onConnectionFailureCallback](CHIP_ERROR err) { - [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:@"onConnectionFailureCallback" queue:clientQueue block:^{ + [[CastingServerBridge getSharedInstance] + dispatchOnClientQueue:clientQueue + description:@"onConnectionFailureCallback" + block:^{ onConnectionFailureCallback([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); }]; }, [clientQueue, onNewOrUpdatedEndpointCallback](TargetEndpointInfo * cppTargetEndpointInfo) { ContentApp * contentApp = [ConversionUtils convertToObjCContentAppFrom:cppTargetEndpointInfo]; - [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:@"onNewOrUpdatedEndpointCallback" queue:clientQueue block:^{ + [[CastingServerBridge getSharedInstance] + dispatchOnClientQueue:clientQueue + description:@"onNewOrUpdatedEndpointCallback" + block:^{ onNewOrUpdatedEndpointCallback(contentApp); }]; }); @@ -812,11 +839,11 @@ - (void)contentLauncher_launchUrl:(ContentApp * _Nonnull)contentApp requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; return castingServer->ContentLauncherLaunchURL( @@ -891,7 +918,10 @@ - (void)contentLauncher_launchContent:(ContentApp * _Nonnull)contentApp CHIP_ERROR err = CastingServer::GetInstance()->ContentLauncher_LaunchContent(&endpoint, cppSearch, autoPlay, MakeOptional(chip::CharSpan([data UTF8String], [data lengthOfBytesUsingEncoding:NSUTF8StringEncoding])), [clientQueue, responseCallback](CHIP_ERROR err) { - [[CastingServerBridge getSharedInstance] dispatchOnClientQueue:@"responseCallback" queue:clientQueue block:^{ + [[CastingServerBridge getSharedInstance] + dispatchOnClientQueue:clientQueue + description:@"contentLauncher_launchContent(...) responseCallback" + block:^{ responseCallback(CHIP_NO_ERROR == err); }]; }); @@ -954,11 +984,11 @@ - (void)levelControl_step:(ContentApp * _Nonnull)contentApp requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -984,11 +1014,11 @@ - (void)levelControl_moveToLevel:(ContentApp * _Nonnull)contentApp requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { const NSString *description = [NSString stringWithFormat:@"levelControl_moveToLevel(...) with Content App endpoint ID %d", contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1146,11 +1176,11 @@ - (void)mediaPlayback_play:(ContentApp * _Nonnull)contentApp requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1164,11 +1194,11 @@ - (void)mediaPlayback_pause:(ContentApp * _Nonnull)contentApp requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1182,11 +1212,11 @@ - (void)mediaPlayback_stopPlayback:(ContentApp * _Nonnull)contentApp requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1200,11 +1230,11 @@ - (void)mediaPlayback_next:(ContentApp * _Nonnull)contentApp requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1219,11 +1249,11 @@ - (void)mediaPlayback_seek:(ContentApp * _Nonnull)contentApp requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1238,11 +1268,11 @@ - (void)mediaPlayback_skipForward:(ContentApp * _Nonnull)contentApp requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1257,11 +1287,11 @@ - (void)mediaPlayback_skipBackward:(ContentApp * _Nonnull)contentApp requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1623,11 +1653,11 @@ - (void)applicationLauncher_launchApp:(ContentApp * _Nonnull)contentApp application.applicationId = chip::CharSpan::fromCharString([applicationId UTF8String]); const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1652,11 +1682,11 @@ - (void)applicationLauncher_stopApp:(ContentApp * _Nonnull)contentApp application.applicationId = chip::CharSpan::fromCharString([applicationId UTF8String]); const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1680,11 +1710,11 @@ - (void)applicationLauncher_hideApp:(ContentApp * _Nonnull)contentApp application.applicationId = chip::CharSpan::fromCharString([applicationId UTF8String]); const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1704,11 +1734,11 @@ - (void)targetNavigator_navigateTarget:(ContentApp * _Nonnull)contentApp requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -1837,11 +1867,11 @@ - (void)keypadInput_sendKey:(ContentApp * _Nonnull)contentApp requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -2276,11 +2306,11 @@ - (void)onOff_on:(ContentApp * _Nonnull)contentApp requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -2294,11 +2324,11 @@ - (void)onOff_off:(ContentApp * _Nonnull)contentApp requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; @@ -2312,11 +2342,11 @@ - (void)onOff_toggle:(ContentApp * _Nonnull)contentApp requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { const NSString *description = [NSString stringWithFormat:@"%s(...) (Content App %d)", __func__, contentApp.endpointId]; - [self withCastingServerInvokeBlockWithResponse:description - withStartedCallback:requestSentHandler - andResponseCallback:responseCallback - onQueue:clientQueue - block: ^(CastingServer *castingServer, std::function responseFunction) { + [self withCastingServerInvokeBlock:description + callbackQueue:clientQueue + onBlockComplete:requestSentHandler + onResponse:responseCallback + block: ^(CastingServer *castingServer, std::function responseFunction) { TargetEndpointInfo endpoint; [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CertTestView.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CertTestView.swift index f38e84a7ac30fc..016b75f879f5a4 100644 --- a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CertTestView.swift +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CertTestView.swift @@ -1,7 +1,7 @@ /** * - * Copyright (c) 2020-2022 Project CHIP Authors + * Copyright (c) 2020-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. @@ -21,6 +21,7 @@ import SwiftUI struct CertTestView: View { @StateObject var viewModel = CertTestViewModel() @State private var targetContentAppId: String = "" + @State private var parallelizeTests = true var body: some View { VStack(alignment: .leading) { @@ -46,9 +47,17 @@ struct CertTestView: View { } .border(.secondary) } + HStack() { + Toggle(isOn: $parallelizeTests) { + Text("Parallelize Tests") + } + } Button("Launch Test") { - viewModel.launchTest(targetContentAppId: targetContentAppId) + viewModel.launchTests( + targetContentAppId: targetContentAppId, + inParallel: parallelizeTests + ) } .background(Color.blue) .foregroundColor(Color.white) diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CertTestViewModel.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CertTestViewModel.swift index 154c8156f22d97..57e1067093a736 100644 --- a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CertTestViewModel.swift +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CertTestViewModel.swift @@ -1,6 +1,6 @@ /** * - * Copyright (c) 2020-2022 Project CHIP Authors + * Copyright (c) 2020-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. @@ -18,352 +18,456 @@ import Foundation import os.log -class CallbackHelper { +private class CallbackHelper { var testCaseName: String; var certTestViewModel: CertTestViewModel; - let Log = Logger(subsystem: "com.matter.casting", - category: "CertTestViewModel") + let logger = Logger(subsystem: "com.matter.casting", category: "CertTestViewModel") init(testCaseName: String, certTestViewModel: CertTestViewModel) { self.testCaseName = testCaseName self.certTestViewModel = certTestViewModel } - func responseCallback(result: Bool) + func responseCallback(succeeded: Bool) { - self.Log.info("CertTestViewModel.responseCallback.\(self.testCaseName) result \(result)") - DispatchQueue.main.async { - self.certTestViewModel.status = result ? "Test \(self.testCaseName) successful" : "Test \(self.testCaseName) failed" + logger.info("CertTestViewModel.responseCallback.\(self.testCaseName) succeeded? \(succeeded)") + if (succeeded) { + certTestViewModel.onTestPassed(testCaseName) + } else { + certTestViewModel.onTestFailed(testCaseName) } } - func requestSentHandler(result: Bool) + func requestSentHandler(succeeded: Bool) { - self.Log.info("CertTestViewModel.requestSentHandler.\(self.testCaseName) result \(result)") + logger.info("CertTestViewModel.requestSentHandler.\(self.testCaseName) succeeded? \(succeeded)") + if (!succeeded) { + certTestViewModel.onTestFailed(testCaseName) + } + } + + func requestSentHandlerError(result: MatterError) + { + logger.warning("CertTestViewModel.requestSentHandler.\(self.testCaseName). Code : \(result.code). Message : \(result.message ?? "")") + requestSentHandler(succeeded: result.code == 0) } func successCallbackString(result: String) { - self.Log.info("CertTestViewModel.successCallback.\(self.testCaseName) result \(result)") - DispatchQueue.main.async { - self.certTestViewModel.status = "Test \(self.testCaseName) successful" - } + logger.info("CertTestViewModel.successCallback.\(self.testCaseName) result \(result)") + certTestViewModel.onTestPassed(testCaseName) } func successCallbackInteger(result: UInt16) { - self.Log.info("CertTestViewModel.successCallback.\(self.testCaseName) result \(result)") - DispatchQueue.main.async { - self.certTestViewModel.status = "Test \(self.testCaseName) successful" - } + logger.info("CertTestViewModel.successCallback.\(self.testCaseName) result \(result)") + certTestViewModel.onTestPassed(testCaseName) } func successCallbackNumber(result: NSNumber) { - self.Log.info("CertTestViewModel.successCallback.\(self.testCaseName) result \(result)") - DispatchQueue.main.async { - self.certTestViewModel.status = "Test \(self.testCaseName) successful" - } + logger.info("CertTestViewModel.successCallback.\(self.testCaseName) result \(result)") + certTestViewModel.onTestPassed(testCaseName) } func failureCallback(result: MatterError) { - self.Log.info("CertTestViewModel.failureCallback.\(self.testCaseName) failed. Code : \(result.code). Message : \(result.message ?? "")") - DispatchQueue.main.async { - self.certTestViewModel.status = "Test \(self.testCaseName) failed. Code : \(result.code). Message : \(result.message ?? "")" - } - } - - func requestSentHandlerError(result: MatterError) - { - self.Log.info("CertTestViewModel.requestSentHandler.\(self.testCaseName). Code : \(result.code). Message : result.message") + logger.info("CertTestViewModel.failureCallback.\(self.testCaseName) failed. Code : \(result.code). Message : \(result.message ?? "")") + certTestViewModel.onTestFailed(testCaseName) } +} +private struct TestContext { + let castingServerBridge: CastingServerBridge + let deviceEndpoint: ContentApp + let contentAppEndpoint: ContentApp + let parallalizationEnabled: Bool } class CertTestViewModel: ObservableObject { - let Log = Logger(subsystem: "com.matter.casting", - category: "CertTestViewModel") + private let logger = Logger(subsystem: "com.matter.casting", category: "CertTestViewModel") + + private let tests: [(String, (TestContext, CallbackHelper) -> ())] = [ + ("keypadInput_sendKey", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.keypadInput_sendKey( + context.deviceEndpoint, + keyCode: 10, + responseCallback:callbackHelper.responseCallback, + clientQueue: DispatchQueue.main, + requestSentHandler:callbackHelper.requestSentHandler + ) + }), + ("applicationLauncher_launch", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.applicationLauncher_launch( + context.deviceEndpoint, + catalogVendorId: 123, + applicationId: "exampleid", + data: nil, + responseCallback:callbackHelper.responseCallback, + clientQueue: DispatchQueue.main, + requestSentHandler:callbackHelper.requestSentHandler + ) + }), + ("applicationLauncher_stop", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.applicationLauncher_stop( + context.deviceEndpoint, + catalogVendorId: 123, applicationId: "exampleid", + responseCallback:callbackHelper.responseCallback, + clientQueue: DispatchQueue.main, + requestSentHandler:callbackHelper.requestSentHandler + ) + }), + ("applicationLauncher_hide", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.applicationLauncher_hide( + context.deviceEndpoint, + catalogVendorId: 123, applicationId: "exampleid", + responseCallback:callbackHelper.responseCallback, + clientQueue: DispatchQueue.main, + requestSentHandler:callbackHelper.requestSentHandler + ) + }), + ("targetNavigator_navigateTarget", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.targetNavigator_navigateTarget( + context.deviceEndpoint, + target: 1, data: "", + responseCallback:callbackHelper.responseCallback, + clientQueue: DispatchQueue.main, + requestSentHandler:callbackHelper.requestSentHandler + ) + }), + ("contentLauncher_launchUrl", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.contentLauncher_launchUrl( + context.contentAppEndpoint, + contentUrl: "https://dummyurl", + contentDisplayStr: "Dummy Content", + responseCallback:callbackHelper.responseCallback, + clientQueue: DispatchQueue.main, + requestSentHandler:callbackHelper.requestSentHandler + ) + }), + ("contentLauncher_launchContent", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.contentLauncher_launchContent( + context.contentAppEndpoint, + contentSearch: ContentLauncher_ContentSearch( + parameterList: [ + ContentLauncher_Parameter( + type: ContentLauncher_ParameterEnum.Video, + value: "Dummy Video", + externalIDList: [ + ContentLauncher_AdditionalInfo( + name: "imdb", + value: "dummyId" + ), + ] + ), + ] + ), + autoPlay: true, data: "", + responseCallback:callbackHelper.responseCallback, + clientQueue: DispatchQueue.main, + requestSentHandler:callbackHelper.requestSentHandler + ) + }), + ("mediaPlayback_play", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.mediaPlayback_play( + context.contentAppEndpoint, + responseCallback:callbackHelper.responseCallback, + clientQueue: DispatchQueue.main, + requestSentHandler:callbackHelper.requestSentHandler + ) + }), + ("mediaPlayback_next", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.mediaPlayback_next( + context.contentAppEndpoint, + responseCallback:callbackHelper.responseCallback, + clientQueue: DispatchQueue.main, + requestSentHandler:callbackHelper.requestSentHandler + ) + }), + ("mediaPlayback_skipForward", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.mediaPlayback_skipForward( + context.contentAppEndpoint, + deltaPositionMilliseconds: 10000, + responseCallback:callbackHelper.responseCallback, + clientQueue: DispatchQueue.main, + requestSentHandler:callbackHelper.requestSentHandler + ) + }), + ("mediaPlayback_skipBackward", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.mediaPlayback_skipBackward( + context.contentAppEndpoint, + deltaPositionMilliseconds: 10000, + responseCallback:callbackHelper.responseCallback, + clientQueue: DispatchQueue.main, + requestSentHandler:callbackHelper.requestSentHandler + ) + }), + ("mediaPlayback_pause", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.mediaPlayback_pause( + context.contentAppEndpoint, + responseCallback:callbackHelper.responseCallback, + clientQueue: DispatchQueue.main, + requestSentHandler:callbackHelper.requestSentHandler + ) + }), + ("mediaPlayback_stopPlayback", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.mediaPlayback_stopPlayback( + context.contentAppEndpoint, + responseCallback:callbackHelper.responseCallback, + clientQueue: DispatchQueue.main, + requestSentHandler:callbackHelper.requestSentHandler + ) + }), + ("onOff_on", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.onOff_( + on: context.deviceEndpoint, + responseCallback:callbackHelper.responseCallback, + clientQueue: DispatchQueue.main, + requestSentHandler:callbackHelper.requestSentHandler + ) + }), + ("onOff_off", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.onOff_off( + context.deviceEndpoint, + responseCallback:callbackHelper.responseCallback, + clientQueue: DispatchQueue.main, + requestSentHandler:callbackHelper.requestSentHandler + ) + }), + ("onOff_toggle", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.onOff_toggle( + context.deviceEndpoint, + responseCallback:callbackHelper.responseCallback, + clientQueue: DispatchQueue.main, + requestSentHandler:callbackHelper.requestSentHandler + ) + }), + ("applicationBasic_readApplicationVersion", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.applicationBasic_readApplicationVersion( + context.contentAppEndpoint, + clientQueue: DispatchQueue.main, + requestSentHandler: callbackHelper.requestSentHandlerError, + successCallback: callbackHelper.successCallbackString, + failureCallback: callbackHelper.failureCallback + ) + }), + ("applicationBasic_readVendorName", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.applicationBasic_readVendorName( + context.contentAppEndpoint, + clientQueue: DispatchQueue.main, + requestSentHandler: callbackHelper.requestSentHandlerError, + successCallback: callbackHelper.successCallbackString, + failureCallback: callbackHelper.failureCallback + ) + }), + ("applicationBasic_readApplicationName", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.applicationBasic_readApplicationName( + context.contentAppEndpoint, + clientQueue: DispatchQueue.main, + requestSentHandler: callbackHelper.requestSentHandlerError, + successCallback: callbackHelper.successCallbackString, + failureCallback: callbackHelper.failureCallback + ) + }), + ("applicationBasic_readVendorID", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.applicationBasic_readVendorID( + context.contentAppEndpoint, + clientQueue: DispatchQueue.main, + requestSentHandler: callbackHelper.requestSentHandlerError, + successCallback: callbackHelper.successCallbackNumber, + failureCallback: callbackHelper.failureCallback + ) + }), + ("applicationBasic_readProductID", { (context: TestContext, callbackHelper: CallbackHelper) -> () in + context.castingServerBridge.applicationBasic_readProductID( + context.contentAppEndpoint, + clientQueue: DispatchQueue.main, + requestSentHandler: callbackHelper.requestSentHandlerError, + successCallback: callbackHelper.successCallbackInteger, + failureCallback: callbackHelper.failureCallback + ) + }), + ] + + @Published var status: String? + + @Published var contentAppIds: [String] = [] + + private var targetVideoPlayer: VideoPlayer? + private var deviceEndpoint: ContentApp? + private var deviceSpeakerEndpoint: ContentApp? + private var testContext: TestContext? + private var testsCompleted: Int = 0 + + /** + Appends the result data to the View Model's text content. + + @param result The data to append. + */ + private func appendTestResult(_ result: String) { + status = status?.appending("\n\(result)") ?? result + } - @Published var status: String?; + /** + A helper function that logs a warning message and appends the warning to the View Model's text content. - @Published var contentAppIds: [String] = []; + @param message The message to log. + */ + private func warn(_ message: String) { + logger.warning("\(message)") + appendTestResult(message) + } - var targetVideoPlayer: VideoPlayer?; - var deviceEndpoint: ContentApp?; - var deviceSpeakerEndpoint: ContentApp?; - var testCaseName: String = ""; + /** + Executes a test and subscribes to receive callbacks when the test is complete. - func runCertTest(testCaseName: String, test: (CallbackHelper) -> ()) + @param description A description of the test to be used for logging and display to the user. + @param context A data structure representing the context in which the test is to be executed. + @param test The test to execute. + */ + private func runTest(_ description: String, context: TestContext, _ test: (TestContext, CallbackHelper) -> ()) { - self.testCaseName = testCaseName; - test(CallbackHelper(testCaseName: testCaseName, certTestViewModel: self)); + test(context, CallbackHelper(testCaseName: description, certTestViewModel: self)); } - func launchTest(targetContentAppId: String?) - { - if (targetContentAppId != nil && !targetContentAppId!.isEmpty) - { - var targetContentApp: ContentApp? - for contentApp in (targetVideoPlayer!.contentApps as! [ContentApp]) { - if(UInt16(targetContentAppId!) == contentApp.endpointId) - { - targetContentApp = contentApp - break - } + private func runNextText(context: TestContext) { + // The number of tests completed is the index of the next test to run. + let testsCompletedSnapshot = self.testsCompleted + guard testsCompletedSnapshot < self.tests.count else { + // There are no more tests to run, bail now. + return + } + + // Run the test + let (description, test) = tests[testsCompletedSnapshot] + runTest(description, context: context, test) + } + + /** + The function to be invoked when a test is completed. + + Note that this function is intentionally not thread safe (e.g. scheduled on a particular Dispatch Queue) to exercise the thread safety of the + APIs being invoked by the test cases themselves. In a real application, you would want to run this on a known Dispatch Queue for safety. + */ + private func onTestCompleted() { + // Increment the "tests completed" counter + testsCompleted += 1 + + // Run the next test, if we're running tests sequentially. + if let testContext = self.testContext { + let runningTestsSequentially = !testContext.parallalizationEnabled + if runningTestsSequentially { + runNextText(context: testContext) } + } + } - if let castingServerBridge = CastingServerBridge.getSharedInstance() - { - runCertTest(testCaseName: "keypadInput_sendKey", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.keypadInput_sendKey(deviceEndpoint!, keyCode: 10, - responseCallback:callbackHelper.responseCallback, - clientQueue: DispatchQueue.main, - requestSentHandler:callbackHelper.requestSentHandler - ) - } - ) - - runCertTest(testCaseName: "applicationLauncher_launch", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.applicationLauncher_launch(deviceEndpoint!, catalogVendorId: 123, applicationId: "exampleid", data: nil, - responseCallback:callbackHelper.responseCallback, - clientQueue: DispatchQueue.main, - requestSentHandler:callbackHelper.requestSentHandler - ) - } - ) - - runCertTest(testCaseName: "applicationLauncher_stop", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.applicationLauncher_stop(deviceEndpoint!, - catalogVendorId: 123, applicationId: "exampleid", - responseCallback:callbackHelper.responseCallback, - clientQueue: DispatchQueue.main, - requestSentHandler:callbackHelper.requestSentHandler - ) - } - ) - - runCertTest(testCaseName: "applicationLauncher_hide", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.applicationLauncher_hide(deviceEndpoint!, - catalogVendorId: 123, applicationId: "exampleid", - responseCallback:callbackHelper.responseCallback, - clientQueue: DispatchQueue.main, - requestSentHandler:callbackHelper.requestSentHandler - ) - } - ) - - runCertTest(testCaseName: "targetNavigator_navigateTarget", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.targetNavigator_navigateTarget(deviceEndpoint!, - target: 1, data: "", - responseCallback:callbackHelper.responseCallback, - clientQueue: DispatchQueue.main, - requestSentHandler:callbackHelper.requestSentHandler - ) - } - ) - - runCertTest(testCaseName: "contentLauncher_launchUrl", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.contentLauncher_launchUrl(targetContentApp!, - contentUrl: "https://dummyurl", - contentDisplayStr: "Dummy Content", - responseCallback:callbackHelper.responseCallback, - clientQueue: DispatchQueue.main, - requestSentHandler:callbackHelper.requestSentHandler - ) - } - ) - - runCertTest(testCaseName: "contentLauncher_launchContent", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.contentLauncher_launchContent(targetContentApp!, - contentSearch: ContentLauncher_ContentSearch(parameterList: [ContentLauncher_Parameter(type: ContentLauncher_ParameterEnum.Video, value: "Dummy Video", externalIDList: [ContentLauncher_AdditionalInfo(name: "imdb", value: "dummyId"),]),]), - autoPlay: true, data: "", - responseCallback:callbackHelper.responseCallback, - clientQueue: DispatchQueue.main, - requestSentHandler:callbackHelper.requestSentHandler - ) - } - ) - - runCertTest(testCaseName: "mediaPlayback_play", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.mediaPlayback_play(targetContentApp!, - responseCallback:callbackHelper.responseCallback, - clientQueue: DispatchQueue.main, - requestSentHandler:callbackHelper.requestSentHandler - ) - } - ) - - runCertTest(testCaseName: "mediaPlayback_next", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.mediaPlayback_next(targetContentApp!, - responseCallback:callbackHelper.responseCallback, - clientQueue: DispatchQueue.main, - requestSentHandler:callbackHelper.requestSentHandler - ) - } - ) - - runCertTest(testCaseName: "mediaPlayback_skipForward", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.mediaPlayback_skipForward(targetContentApp!, - deltaPositionMilliseconds: 10000, - responseCallback:callbackHelper.responseCallback, - clientQueue: DispatchQueue.main, - requestSentHandler:callbackHelper.requestSentHandler - ) - } - ) - - runCertTest(testCaseName: "mediaPlayback_skipBackward", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.mediaPlayback_skipBackward(targetContentApp!, - deltaPositionMilliseconds: 10000, - responseCallback:callbackHelper.responseCallback, - clientQueue: DispatchQueue.main, - requestSentHandler:callbackHelper.requestSentHandler - ) - } - ) - - runCertTest(testCaseName: "mediaPlayback_pause", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.mediaPlayback_pause(targetContentApp!, - responseCallback:callbackHelper.responseCallback, - clientQueue: DispatchQueue.main, - requestSentHandler:callbackHelper.requestSentHandler - ) - } - ) - - runCertTest(testCaseName: "mediaPlayback_stopPlayback", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.mediaPlayback_stopPlayback(targetContentApp!, - responseCallback:callbackHelper.responseCallback, - clientQueue: DispatchQueue.main, - requestSentHandler:callbackHelper.requestSentHandler - ) - } - ) - - runCertTest(testCaseName: "onOff_on", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.onOff_(on: deviceEndpoint!, - responseCallback:callbackHelper.responseCallback, - clientQueue: DispatchQueue.main, - requestSentHandler:callbackHelper.requestSentHandler - ) - } - ) - - runCertTest(testCaseName: "onOff_off", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.onOff_off(deviceEndpoint!, - responseCallback:callbackHelper.responseCallback, - clientQueue: DispatchQueue.main, - requestSentHandler:callbackHelper.requestSentHandler - ) - } - ) - - runCertTest(testCaseName: "onOff_toggle", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.onOff_toggle(deviceEndpoint!, - responseCallback:callbackHelper.responseCallback, - clientQueue: DispatchQueue.main, - requestSentHandler:callbackHelper.requestSentHandler - ) - } - ) - - runCertTest(testCaseName: "applicationBasic_readApplicationVersion", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.applicationBasic_readApplicationVersion(targetContentApp!, - clientQueue: DispatchQueue.main, - requestSentHandler: callbackHelper.requestSentHandlerError, - successCallback: callbackHelper.successCallbackString, - failureCallback: callbackHelper.failureCallback - ) - } - ) - - runCertTest(testCaseName: "applicationBasic_readVendorName", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.applicationBasic_readVendorName(targetContentApp!, - clientQueue: DispatchQueue.main, - requestSentHandler: callbackHelper.requestSentHandlerError, - successCallback: callbackHelper.successCallbackString, - failureCallback: callbackHelper.failureCallback - ) - } - ) - - runCertTest(testCaseName: "applicationBasic_readApplicationName", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.applicationBasic_readApplicationName(targetContentApp!, - clientQueue: DispatchQueue.main, - requestSentHandler: callbackHelper.requestSentHandlerError, - successCallback: callbackHelper.successCallbackString, - failureCallback: callbackHelper.failureCallback - ) - } - ) - - runCertTest(testCaseName: "applicationBasic_readVendorID", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.applicationBasic_readVendorID(targetContentApp!, - clientQueue: DispatchQueue.main, - requestSentHandler: callbackHelper.requestSentHandlerError, - successCallback: callbackHelper.successCallbackNumber, - failureCallback: callbackHelper.failureCallback - ) - } - ) - - runCertTest(testCaseName: "applicationBasic_readProductID", - test: { (callbackHelper: CallbackHelper) -> () in - castingServerBridge.applicationBasic_readProductID(targetContentApp!, - clientQueue: DispatchQueue.main, - requestSentHandler: callbackHelper.requestSentHandlerError, - successCallback: callbackHelper.successCallbackInteger, - failureCallback: callbackHelper.failureCallback - ) - } - ) + /** + The function to be invoked when a test is completed successfully. + + @param description The name of the test that passed. + */ + fileprivate func onTestPassed(_ description: String) { + onTestCompleted() + DispatchQueue.main.async { [weak self] in + guard let strongSelf = self else { + return } + strongSelf.appendTestResult("🟢 \(description) PASSED") } - else - { - Log.debug("CertTestViewModel.launchTest input(s) missing!") - self.status = "Missing input parameter(s)!" + } + + /** + The function to be invoked when a test is completed unsuccessfully. + + @param description The name of the test that failed. + */ + fileprivate func onTestFailed(_ description: String) { + onTestCompleted() + DispatchQueue.main.async { [weak self] in + guard let strongSelf = self else { + return + } + strongSelf.appendTestResult("🔴 \(description) FAILED") + } + } + + /** + Begins executing all certification tests. + + @param targetContentAppId: The Endpoint ID of the target Content App against which the tests will be run. + @param parallelizeTests: A flag that determines whether to run the tests in parallel (`true`) or sequentially (`false`). + */ + func launchTests(targetContentAppId: String?, inParallel parallelizeTests: Bool) + { + // Reset the status text at the beginning of the test run + status = "" + testContext = nil + testsCompleted = 0 + + guard let nonNilTargetContentAppId = targetContentAppId, !nonNilTargetContentAppId.isEmpty else { + warn("Missing input parameter(s)!") + return + } + + guard let targetVideoPlayer = self.targetVideoPlayer else { + warn("Target Video Player is not configured") + return + } + + guard let targetContentApp = (targetVideoPlayer.contentApps as! [ContentApp]).first( + where: { contentApp in return UInt16(targetContentAppId!) == contentApp.endpointId } + ) + else { + warn("Content App \(nonNilTargetContentAppId) is not supported") + return + } + + guard let castingServerBridge = CastingServerBridge.getSharedInstance() else { + warn("Casting Server is unavailable") + return + } + + // Set up the context for running the tests and store a snapshot in this View Model. + let testContext = TestContext( + castingServerBridge: castingServerBridge, + deviceEndpoint: deviceEndpoint!, + contentAppEndpoint: targetContentApp, + parallalizationEnabled: parallelizeTests + ) + self.testContext = testContext + + // If parallelization is enabled, we simply schedule all of the tests at the same time and let + // the Dispatch Queue figure it out; otherwise, we start the first test and schedule each + // subsequent test when the completion callback of the prior test is invoked. This also is a + // low-touch way of validating that callbacks can synchronously invoke CastingServerBridge APIs + // from the Dispatch Queue on which the callback is invoked. + if (parallelizeTests) { + for (description, test) in tests { + runTest(description, context: testContext, test) + } + } else { + runNextText(context: testContext) } } func populateAndInitializeEndpoints() { - if let castingServerBridge = CastingServerBridge.getSharedInstance() - { - castingServerBridge.getActiveTargetVideoPlayers(DispatchQueue.main, - activeTargetVideoPlayersHandler: { (targetVideoPlayers: NSMutableArray?) -> () in + guard let castingServerBridge = CastingServerBridge.getSharedInstance() else { + return + } + + castingServerBridge.getActiveTargetVideoPlayers( + DispatchQueue.main, + activeTargetVideoPlayersHandler: { (targetVideoPlayers: NSMutableArray?) -> () in let targetVideoPlayer: VideoPlayer = targetVideoPlayers![0] as! VideoPlayer if(targetVideoPlayer.isInitialized && targetVideoPlayer.isConnected) { self.targetVideoPlayer = targetVideoPlayer - for contentApp in (targetVideoPlayer.contentApps as! [ContentApp]) - { - if(contentApp.endpointId == 1) - { + for contentApp in (targetVideoPlayer.contentApps as! [ContentApp]) { + if(contentApp.endpointId == 1) { self.deviceEndpoint = contentApp - } else if(contentApp.endpointId == 2) - { + } else if(contentApp.endpointId == 2) { self.deviceSpeakerEndpoint = contentApp } else { @@ -371,7 +475,7 @@ class CertTestViewModel: ObservableObject { } } } - }) - } + } + ) } } diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningView.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningView.swift index f5cb7ddcfaeb74..923d986ce6d6d5 100644 --- a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningView.swift +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningView.swift @@ -1,6 +1,6 @@ /** * - * Copyright (c) 2020-2022 Project CHIP Authors + * Copyright (c) 2020-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. @@ -32,10 +32,10 @@ struct CommissioningView: View { if(viewModel.commisisoningWindowOpened == true) { Text("Commissioning window opened.").padding() - Text("Onboarding PIN: " + String((CastingServerBridge.getSharedInstance()?.getOnboardingPaylod().setupPasscode)!)) + Text("Onboarding PIN: " + String((CastingServerBridge.getSharedInstance()?.getOnboardingPayload().setupPasscode)!)) .border(Color.blue, width: 1) .padding() - Text("Discriminator: " + String((CastingServerBridge.getSharedInstance()?.getOnboardingPaylod().setupDiscriminator)!)) + Text("Discriminator: " + String((CastingServerBridge.getSharedInstance()?.getOnboardingPayload().setupDiscriminator)!)) .border(Color.blue, width: 1) .padding() diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlaybackViewModel.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlaybackViewModel.swift index 5a93a2ffe7c3cf..d6352b29b1b920 100644 --- a/examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlaybackViewModel.swift +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlaybackViewModel.swift @@ -1,6 +1,6 @@ /** * - * Copyright (c) 2020-2022 Project CHIP Authors + * Copyright (c) 2020-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. @@ -45,7 +45,7 @@ class MediaPlaybackViewModel: ObservableObject { break } } - + castingServerBridge.mediaPlayback_subscribeCurrentState(targetContentApp!, minInterval: UInt16(minInterval) ?? 0, maxInterval: UInt16(maxInterval) ?? 1, clientQueue: DispatchQueue.main, requestSentHandler: { (result: MatterError) -> () in self.Log.info("MediaPlaybackViewModel.subscribeToCurrentState.requestSentHandler result \(result)") From eb46551cc528eff457c1885b8aef97e110ee95d6 Mon Sep 17 00:00:00 2001 From: Michael Douglas Date: Wed, 1 Mar 2023 10:35:29 -0800 Subject: [PATCH 3/3] * Updating the documentation for modified APIs --- .../MatterTvCastingBridge/CastingServerBridge.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm index ea18494597f298..5bfedb38c3561e 100644 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm @@ -142,8 +142,8 @@ - (void) dispatchOnMatterSDKQueue:(const NSString * _Nullable)description /** Dispatches a client callback via a `dispatch_block_t` to be run on the client's `dispatch_queue_t`. - @param description Optional. A description of the callback to be dispatched for diagnostic purposes. @param queue The client's Dispatch Queue. + @param description Optional. A description of the callback to be dispatched for diagnostic purposes. @param block The Block to be invoked to invoke the client callback. */ - (void) dispatchOnClientQueue:(dispatch_queue_t)queue @@ -187,8 +187,8 @@ - (void) dispatchOnClientQueue:(dispatch_queue_t)queue The result of the Objective C Block will be relayed to the `blockCompleteCallback`. @param description Optional. A description of the Objective C Block to be invoked for diagnostic purposes. - @param blockCompleteCallback The callback to be invoked with the result of the Objective C Block. @param callbackQueue The Dispatch Queue on which the callback shall be invoked. + @param blockCompleteCallback The callback to be invoked with the result of the Objective C Block. @param block The Objective C Block to dispatch. */ - (void) withCastingServerInvokeBlock:(const NSString * _Nullable)description