Fixes in tv-casting-app to allow setting custom Setup Passcodes and backgrounding the app on iOS (#24046)

* tv-casting-app: Making getDiscoveredCommissioner API synchronous

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

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

* Addressing cliffamzn@'s feedback
diff --git a/examples/tv-casting-app/android/args.gni b/examples/tv-casting-app/android/args.gni
index 802f54f..e3a20c5 100644
--- a/examples/tv-casting-app/android/args.gni
+++ b/examples/tv-casting-app/android/args.gni
@@ -29,3 +29,5 @@
 chip_enable_additional_data_advertising = true
 
 chip_enable_rotating_device_id = true
+
+chip_config_network_layer_ble = false
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge.xcodeproj/project.pbxproj b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge.xcodeproj/project.pbxproj
index d85d5a6..ef0579e 100644
--- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge.xcodeproj/project.pbxproj
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge.xcodeproj/project.pbxproj
@@ -26,6 +26,7 @@
 		3CCB8742286A593700771BAD /* ConversionUtils.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3CCB873C286A593700771BAD /* ConversionUtils.hpp */; };
 		3CCB8743286A593700771BAD /* CastingServerBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CCB873D286A593700771BAD /* CastingServerBridge.mm */; };
 		3CCB8744286A593700771BAD /* ConversionUtils.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CCB873E286A593700771BAD /* ConversionUtils.mm */; };
+		3CE868F42946D76200FCB92B /* CommissionableDataProviderImpl.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CE868F32946D76200FCB92B /* CommissionableDataProviderImpl.mm */; };
 		3CF8532728E37F1000F07B9F /* MatterError.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CF8532628E37F1000F07B9F /* MatterError.mm */; };
 /* End PBXBuildFile section */
 
@@ -59,6 +60,7 @@
 		3CCB873C286A593700771BAD /* ConversionUtils.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ConversionUtils.hpp; sourceTree = "<group>"; };
 		3CCB873D286A593700771BAD /* CastingServerBridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CastingServerBridge.mm; sourceTree = "<group>"; };
 		3CCB873E286A593700771BAD /* ConversionUtils.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ConversionUtils.mm; sourceTree = "<group>"; };
+		3CE868F32946D76200FCB92B /* CommissionableDataProviderImpl.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CommissionableDataProviderImpl.mm; sourceTree = "<group>"; };
 		3CF8532528E37ED800F07B9F /* MatterError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MatterError.h; sourceTree = "<group>"; };
 		3CF8532628E37F1000F07B9F /* MatterError.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MatterError.mm; sourceTree = "<group>"; };
 /* End PBXFileReference section */
@@ -125,6 +127,7 @@
 				3C26AC8B2926FE0C00BA6881 /* DeviceAttestationCredentialsProviderImpl.hpp */,
 				3C26AC8F2927008900BA6881 /* DeviceAttestationCredentialsProviderImpl.mm */,
 				3C0D9CDF2920A30C00D3332B /* CommissionableDataProviderImpl.hpp */,
+				3CE868F32946D76200FCB92B /* CommissionableDataProviderImpl.mm */,
 			);
 			path = MatterTvCastingBridge;
 			sourceTree = "<group>";
@@ -241,6 +244,7 @@
 				3CCB8744286A593700771BAD /* ConversionUtils.mm in Sources */,
 				3C4E53B028E4F28100F293E8 /* MediaPlaybackTypes.mm in Sources */,
 				3C66FBFC290327BB00B63FE7 /* AppParameters.mm in Sources */,
+				3CE868F42946D76200FCB92B /* CommissionableDataProviderImpl.mm in Sources */,
 				3C26AC9329282B8100BA6881 /* DeviceAttestationCredentialsHolder.m in Sources */,
 				3C26AC902927008900BA6881 /* DeviceAttestationCredentialsProviderImpl.mm in Sources */,
 				3CCB873F286A593700771BAD /* DiscoveredNodeData.mm in Sources */,
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/AppParameters.h b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/AppParameters.h
index 9297223..9e445e2 100644
--- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/AppParameters.h
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/AppParameters.h
@@ -31,9 +31,9 @@
 
 @property uint32_t spake2pIterationCount;
 
-@property NSData * spake2pSalt;
+@property NSData * spake2pSaltBase64;
 
-@property NSData * spake2pVerifier;
+@property NSData * spake2pVerifierBase64;
 
 @property DeviceAttestationCredentialsHolder * deviceAttestationCredentials;
 
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h
index 8c8f8c8..8f1d7d1 100644
--- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h
@@ -54,7 +54,7 @@
 
  @param clientQueue Queue to dispatch the call to the discoveredCommissionerHandler on
 
- @param discoveredCommissionerHandler Handler to call after a discovered commissioner has been retrieved
+ @param discoveredCommissionerHandler Handler called synchronously after a discovered commissioner has been retrieved
  */
 - (void)getDiscoveredCommissioner:(int)index
                       clientQueue:(dispatch_queue_t _Nonnull)clientQueue
@@ -184,6 +184,16 @@
  */
 - (void)disconnect:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(nullable void (^)())requestSentHandler;
 
+/**
+ @brief Start the Matter server and reconnect to a previously connected Video Player (if any)
+ */
+- (void)startMatterServer;
+
+/**
+ @brief Stop the Matter server
+ */
+- (void)stopMatterServer;
+
 /*!
  @brief Send a ContentLauncher:LaunchURL request to a TV
 
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm
index d2620f6..cd86084 100644
--- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm
@@ -38,10 +38,14 @@
 
 @property OnboardingPayload * _Nonnull onboardingPayload;
 
-@property chip::DeviceLayer::CommissionableDataProviderImpl * commissionableDataProvider;
+@property CommissionableDataProviderImpl * commissionableDataProvider;
 
 @property chip::Credentials::DeviceAttestationCredentialsProvider * deviceAttestationCredentialsProvider;
 
+@property chip::CommonCaseDeviceServerInitParams * serverInitParams;
+
+@property TargetVideoPlayerInfo * previouslyConnectedVideoPlayer;
+
 // queue used to serialize all work performed by the CastingServerBridge
 @property (atomic) dispatch_queue_t chipWorkQueue;
 
@@ -111,10 +115,15 @@
     ChipLogProgress(AppServer, "CastingServerBridge().initApp() called");
 
     CHIP_ERROR err = CHIP_NO_ERROR;
-    _commissionableDataProvider = new chip::DeviceLayer::CommissionableDataProviderImpl();
+    _commissionableDataProvider = new CommissionableDataProviderImpl();
     _deviceAttestationCredentialsProvider = chip::Credentials::Examples::GetExampleDACProvider();
+
     _appParameters = appParameters;
     AppParams cppAppParams;
+    uint32_t setupPasscode = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE;
+    uint16_t setupDiscriminator = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR;
+    uint32_t spake2pIterationCount;
+    chip::ByteSpan spake2pSaltSpan, spake2pVerifierSpan;
     if (_appParameters != nil) {
         err = [ConversionUtils convertToCppAppParamsInfoFrom:_appParameters outAppParams:cppAppParams];
         if (err != CHIP_NO_ERROR) {
@@ -123,22 +132,31 @@
         }
 
         // set fields in commissionableDataProvider
-        _commissionableDataProvider->SetSpake2pIterationCount(_appParameters.spake2pIterationCount);
-        if (_appParameters.spake2pSalt != nil) {
-            chip::ByteSpan spake2pSaltSpan
-                = chip::ByteSpan(static_cast<const uint8_t *>(_appParameters.spake2pSalt.bytes), _appParameters.spake2pSalt.length);
-            _commissionableDataProvider->SetSpake2pSalt(spake2pSaltSpan);
-        }
-
-        if (_appParameters.spake2pVerifier != nil) {
-            chip::ByteSpan spake2pVerifierSpan = chip::ByteSpan(
-                static_cast<const uint8_t *>(_appParameters.spake2pVerifier.bytes), _appParameters.spake2pVerifier.length);
-            _commissionableDataProvider->SetSpake2pSalt(spake2pVerifierSpan);
-        }
-
         if (_appParameters.onboardingPayload != nil) {
-            _commissionableDataProvider->SetSetupPasscode(_appParameters.onboardingPayload.setupPasscode);
-            _commissionableDataProvider->SetSetupDiscriminator(_appParameters.onboardingPayload.setupDiscriminator);
+            setupPasscode = _appParameters.onboardingPayload.setupPasscode > 0 ? _appParameters.onboardingPayload.setupPasscode
+                                                                               : CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE;
+            setupDiscriminator = _appParameters.onboardingPayload.setupDiscriminator > 0
+                ? _appParameters.onboardingPayload.setupDiscriminator
+                : CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR;
+        }
+        spake2pIterationCount = _appParameters.spake2pIterationCount;
+        if (_appParameters.spake2pSaltBase64 != nil) {
+            spake2pSaltSpan = chip::ByteSpan(
+                static_cast<const uint8_t *>(_appParameters.spake2pSaltBase64.bytes), _appParameters.spake2pSaltBase64.length);
+        }
+
+        if (_appParameters.spake2pVerifierBase64 != nil) {
+            chip::ByteSpan spake2pVerifierSpan
+                = chip::ByteSpan(static_cast<const uint8_t *>(_appParameters.spake2pVerifierBase64.bytes),
+                    _appParameters.spake2pVerifierBase64.length);
+        }
+
+        err = _commissionableDataProvider->Initialize(_appParameters.spake2pVerifierBase64 != nil ? &spake2pVerifierSpan : nil,
+            _appParameters.spake2pSaltBase64 != nil ? &spake2pSaltSpan : nil, spake2pIterationCount, setupPasscode,
+            setupDiscriminator);
+        if (err != CHIP_NO_ERROR) {
+            ChipLogError(AppServer, "Failed to initialize CommissionableDataProvider: %s", ErrorStr(err));
+            return;
         }
 
         if (_appParameters.deviceAttestationCredentials != nil) {
@@ -182,8 +200,6 @@
     }
     chip::DeviceLayer::SetCommissionableDataProvider(_commissionableDataProvider);
 
-    uint32_t setupPasscode = 0;
-    uint16_t setupDiscriminator = 0;
     _commissionableDataProvider->GetSetupPasscode(setupPasscode);
     _commissionableDataProvider->GetSetupDiscriminator(setupDiscriminator);
     _onboardingPayload = [[OnboardingPayload alloc] initWithSetupPasscode:setupPasscode setupDiscriminator:setupDiscriminator];
@@ -199,14 +215,14 @@
     }
 
     // init app Server
-    static chip::CommonCaseDeviceServerInitParams initParams;
-    err = initParams.InitializeStaticResourcesBeforeServerInit();
+    _serverInitParams = new chip::CommonCaseDeviceServerInitParams();
+    err = _serverInitParams->InitializeStaticResourcesBeforeServerInit();
     if (err != CHIP_NO_ERROR) {
         ChipLogError(AppServer, "InitializeStaticResourcesBeforeServerInit failed: %s", ErrorStr(err));
         return;
     }
 
-    err = chip::Server::GetInstance().Init(initParams);
+    err = chip::Server::GetInstance().Init(*_serverInitParams);
     if (err != CHIP_NO_ERROR) {
         ChipLogError(AppServer, "chip::Server init failed: %s", ErrorStr(err));
         return;
@@ -261,7 +277,7 @@
 {
     ChipLogProgress(AppServer, "CastingServerBridge().getDiscoveredCommissioner() called");
 
-    dispatch_async(_chipWorkQueue, ^{
+    dispatch_sync(_chipWorkQueue, ^{
         chip::Optional<TargetVideoPlayerInfo *> associatedConnectableVideoPlayer;
         DiscoveredNodeData * commissioner = nil;
         const chip::Dnssd::DiscoveredNodeData * cppDiscoveredNodeData
@@ -275,7 +291,7 @@
             }
         }
 
-        dispatch_async(clientQueue, ^{
+        dispatch_sync(clientQueue, ^{
             discoveredCommissionerHandler(commissioner);
         });
     });
@@ -407,10 +423,9 @@
     ChipLogProgress(AppServer, "CastingServerBridge().getActiveTargetVideoPlayers() called");
 
     dispatch_async(_chipWorkQueue, ^{
-        NSMutableArray * videoPlayers = nil;
+        NSMutableArray * videoPlayers = [NSMutableArray new];
         TargetVideoPlayerInfo * cppTargetVideoPlayerInfo = CastingServer::GetInstance()->GetActiveTargetVideoPlayer();
-        if (cppTargetVideoPlayerInfo != nullptr) {
-            videoPlayers = [NSMutableArray new];
+        if (cppTargetVideoPlayerInfo != nullptr && cppTargetVideoPlayerInfo->IsInitialized()) {
             videoPlayers[0] = [ConversionUtils convertToObjCVideoPlayerFrom:cppTargetVideoPlayerInfo];
         }
 
@@ -495,6 +510,79 @@
     });
 }
 
+- (void)startMatterServer
+{
+    ChipLogProgress(AppServer, "CastingServerBridge().startMatterServer() called");
+
+    dispatch_sync(_chipWorkQueue, ^{
+        // Initialize the Matter server
+        CHIP_ERROR err = chip::Server::GetInstance().Init(*self->_serverInitParams);
+        if (err != CHIP_NO_ERROR) {
+            ChipLogError(AppServer, "chip::Server init failed: %s", ErrorStr(err));
+            return;
+        }
+
+        // Now reconnect to the VideoPlayer the casting app was previously connected to (if any)
+        if (self->_previouslyConnectedVideoPlayer != nil) {
+            ChipLogProgress(
+                AppServer, "CastingServerBridge().startMatterServer() reconnecting to previously connected VideoPlayer...");
+            err = CastingServer::GetInstance()->VerifyOrEstablishConnection(
+                *(self->_previouslyConnectedVideoPlayer), [](TargetVideoPlayerInfo * cppTargetVideoPlayerInfo) {},
+                [](CHIP_ERROR err) {}, [](TargetEndpointInfo * cppTargetEndpointInfo) {});
+        }
+    });
+}
+
+- (void)stopMatterServer
+{
+    ChipLogProgress(AppServer, "CastingServerBridge().stopMatterServer() called");
+
+    dispatch_sync(_chipWorkQueue, ^{
+        // capture pointer to previouslyConnectedVideoPlayer, to be deleted
+        TargetVideoPlayerInfo * videoPlayerForDeletion
+            = self->_previouslyConnectedVideoPlayer == nil ? nil : self->_previouslyConnectedVideoPlayer;
+
+        // On shutting down the Matter server, the casting app will be automatically disconnected from any Video Players it was
+        // connected to. Save the VideoPlayer that the casting app was targetting and connected to, so we can reconnect to it on
+        // re-starting the Matter server.
+        TargetVideoPlayerInfo * currentTargetVideoPlayerInfo = CastingServer::GetInstance()->GetActiveTargetVideoPlayer();
+        if (currentTargetVideoPlayerInfo != nil && currentTargetVideoPlayerInfo->IsInitialized()
+            && currentTargetVideoPlayerInfo->GetOperationalDeviceProxy() != nil) {
+            self->_previouslyConnectedVideoPlayer = new TargetVideoPlayerInfo();
+            self->_previouslyConnectedVideoPlayer->Initialize(currentTargetVideoPlayerInfo->GetNodeId(),
+                currentTargetVideoPlayerInfo->GetFabricIndex(), nullptr, nullptr, currentTargetVideoPlayerInfo->GetVendorId(),
+                currentTargetVideoPlayerInfo->GetProductId(), currentTargetVideoPlayerInfo->GetDeviceType(),
+                currentTargetVideoPlayerInfo->GetDeviceName(), currentTargetVideoPlayerInfo->GetNumIPs(),
+                const_cast<chip::Inet::IPAddress *>(currentTargetVideoPlayerInfo->GetIpAddresses()));
+
+            TargetEndpointInfo * prevEndpoints = self->_previouslyConnectedVideoPlayer->GetEndpoints();
+            if (prevEndpoints != nullptr) {
+                for (size_t i = 0; i < kMaxNumberOfEndpoints; i++) {
+                    prevEndpoints[i].Reset();
+                }
+            }
+            TargetEndpointInfo * currentEndpoints = currentTargetVideoPlayerInfo->GetEndpoints();
+            for (size_t i = 0; i < kMaxNumberOfEndpoints && currentEndpoints[i].IsInitialized(); i++) {
+                prevEndpoints[i].Initialize(currentEndpoints[i].GetEndpointId());
+                chip::ClusterId * currentClusters = currentEndpoints[i].GetClusters();
+                for (size_t j = 0; j < kMaxNumberOfClustersPerEndpoint && currentClusters[j] != chip::kInvalidClusterId; j++) {
+                    prevEndpoints[i].AddCluster(currentClusters[j]);
+                }
+            }
+        } else {
+            self->_previouslyConnectedVideoPlayer = nil;
+        }
+
+        // Now shutdown the Matter server
+        chip::Server::GetInstance().Shutdown();
+
+        // Delete the old previouslyConnectedVideoPlayer, if non-nil
+        if (videoPlayerForDeletion != nil) {
+            delete videoPlayerForDeletion;
+        }
+    });
+}
+
 - (void)disconnect:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(nullable void (^)())requestSentHandler
 {
     ChipLogProgress(AppServer, "CastingServerBridge().disconnect() called");
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissionableDataProviderImpl.hpp b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissionableDataProviderImpl.hpp
index b05ce4a..979c7c7 100644
--- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissionableDataProviderImpl.hpp
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissionableDataProviderImpl.hpp
@@ -1,6 +1,7 @@
-/**
+/*
  *
- *    Copyright (c) 2020-2022 Project CHIP Authors
+ *    Copyright (c) 2022 Project CHIP Authors
+ *    All rights reserved.
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
@@ -15,166 +16,47 @@
  *    limitations under the License.
  */
 
-#ifndef CommissionableDataProviderImpl_h
-#define CommissionableDataProviderImpl_h
-
 #pragma once
 
 #include <lib/core/CHIPError.h>
-#include <lib/support/Span.h>
+#include <lib/core/Optional.h>
 #include <platform/CommissionableDataProvider.h>
+#include <stdint.h>
+#include <vector>
 
-namespace chip {
-namespace DeviceLayer {
-
-class CommissionableDataProviderImpl : public CommissionableDataProvider
+class CommissionableDataProviderImpl : public chip::DeviceLayer::CommissionableDataProvider
 {
 public:
-    CommissionableDataProviderImpl() {}
-
-    CHIP_ERROR GetSetupPasscode(uint32_t & setupPasscode) override
-    {
-        if (mSetupPasscode > 0)
-        {
-            setupPasscode = mSetupPasscode;
-        }
-        else
-        {
-            setupPasscode = kDefaultTestPasscode;
-        }
-
-        return CHIP_NO_ERROR;
-    }
-
-    CHIP_ERROR SetSetupPasscode(uint32_t setupPasscode) override
-    {
-        mSetupPasscode = setupPasscode;
-        return CHIP_NO_ERROR;
-    }
-
-    CHIP_ERROR GetSetupDiscriminator(uint16_t & setupDiscriminator) override
-    {
-        if (mSetupDiscriminator > 0)
-        {
-            setupDiscriminator = mSetupDiscriminator;
-        }
-        else
-        {
-            setupDiscriminator = kDefaultTestDiscriminator;
-        }
-
-        return CHIP_NO_ERROR;
-    }
-
+    CHIP_ERROR Initialize(chip::ByteSpan * spake2pVerifierBase64, chip::ByteSpan * spake2pSaltBase64,
+                          uint32_t spake2pIterationCount, uint32_t setupPasscode, uint16_t discriminator);
+    CHIP_ERROR GetSetupDiscriminator(uint16_t & setupDiscriminator) override;
     CHIP_ERROR SetSetupDiscriminator(uint16_t setupDiscriminator) override
     {
-        mSetupDiscriminator = setupDiscriminator;
-        return CHIP_NO_ERROR;
+        // We don't support overriding the discriminator post-init (it is deprecated!)
+        return CHIP_ERROR_NOT_IMPLEMENTED;
     }
-
-    CHIP_ERROR GetSpake2pIterationCount(uint32_t & iterationCount) override
+    CHIP_ERROR GetSpake2pIterationCount(uint32_t & iterationCount) override;
+    CHIP_ERROR GetSpake2pSalt(chip::MutableByteSpan & saltBuf) override;
+    CHIP_ERROR GetSpake2pVerifier(chip::MutableByteSpan & verifierBuf, size_t & outVerifierLen) override;
+    CHIP_ERROR GetSetupPasscode(uint32_t & setupPasscode) override;
+    CHIP_ERROR SetSetupPasscode(uint32_t setupPasscode) override
     {
-        if (mSpake2pIterationCount > 0)
-        {
-            iterationCount = mSpake2pIterationCount;
-        }
-        else
-        {
-            iterationCount = kDefaultTestVerifierIterationCount;
-        }
-
-        return CHIP_NO_ERROR;
-    }
-
-    CHIP_ERROR SetSpake2pIterationCount(uint32_t iterationCount)
-    {
-        mSpake2pIterationCount = iterationCount;
-        return CHIP_NO_ERROR;
-    }
-
-    CHIP_ERROR GetSpake2pSalt(MutableByteSpan & saltBuf) override
-    {
-        size_t saltLen = mSpake2pSalt.data() == nullptr ? sizeof(kDefaultTestVerifierSalt) : mSpake2pSalt.size();
-        if (saltBuf.size() < saltLen)
-        {
-            return CHIP_ERROR_BUFFER_TOO_SMALL;
-        }
-
-        memcpy(saltBuf.data(), mSpake2pSalt.data() == nullptr ? kDefaultTestVerifierSalt : mSpake2pSalt.data(), saltLen);
-        saltBuf.reduce_size(saltLen);
-        return CHIP_NO_ERROR;
-    }
-
-    CHIP_ERROR SetSpake2pSalt(ByteSpan saltBuf)
-    {
-        size_t saltLen = saltBuf.size();
-        if (chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length < saltLen)
-        {
-            return CHIP_ERROR_BUFFER_TOO_SMALL;
-        }
-
-        mSpake2pSalt = MutableByteSpan(mSpake2pSaltBuf, chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length);
-
-        memcpy(mSpake2pSalt.data(), saltBuf.data(), saltLen);
-        mSpake2pSalt.reduce_size(saltLen);
-        return CHIP_NO_ERROR;
-    }
-
-    CHIP_ERROR GetSpake2pVerifier(MutableByteSpan & verifierBuf, size_t & outVerifierLen) override
-    {
-        outVerifierLen = mSpake2pVerifier.data() == nullptr ? sizeof(kDefaultTestVerifier) : mSpake2pVerifier.size();
-        if (verifierBuf.size() < outVerifierLen)
-        {
-            return CHIP_ERROR_BUFFER_TOO_SMALL;
-        }
-        memcpy(verifierBuf.data(), mSpake2pVerifier.data() == nullptr ? kDefaultTestVerifier : mSpake2pVerifier.data(),
-               outVerifierLen);
-        verifierBuf.reduce_size(outVerifierLen);
-        return CHIP_NO_ERROR;
-    }
-
-    CHIP_ERROR SetSpake2pVerifier(MutableByteSpan verifierBuf)
-    {
-        size_t inVerifierBufLen = verifierBuf.size();
-        if (chip::Crypto::kSpake2p_VerifierSerialized_Length < inVerifierBufLen)
-        {
-            return CHIP_ERROR_BUFFER_TOO_SMALL;
-        }
-
-        mSpake2pVerifier = MutableByteSpan(mSpake2pSaltBuf, chip::Crypto::kSpake2p_VerifierSerialized_Length);
-
-        memcpy(mSpake2pVerifier.data(), verifierBuf.data(), inVerifierBufLen);
-        mSpake2pVerifier.reduce_size(inVerifierBufLen);
-        return CHIP_NO_ERROR;
+        // We don't support overriding the passcode post-init (it is deprecated!)
+        return CHIP_ERROR_NOT_IMPLEMENTED;
     }
 
 private:
-    static constexpr uint32_t kDefaultTestPasscode               = 20202021;
-    static constexpr uint16_t kDefaultTestDiscriminator          = 3840;
-    static constexpr uint32_t kDefaultTestVerifierIterationCount = 1000;
-    static constexpr uint8_t kDefaultTestVerifierSalt[16]        = {
-        0x53, 0x50, 0x41, 0x4b, 0x45, 0x32, 0x50, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x53, 0x61, 0x6c, 0x74,
-    };
-    static constexpr uint8_t kDefaultTestVerifier[97] = {
-        0xb9, 0x61, 0x70, 0xaa, 0xe8, 0x03, 0x34, 0x68, 0x84, 0x72, 0x4f, 0xe9, 0xa3, 0xb2, 0x87, 0xc3, 0x03, 0x30, 0xc2, 0xa6,
-        0x60, 0x37, 0x5d, 0x17, 0xbb, 0x20, 0x5a, 0x8c, 0xf1, 0xae, 0xcb, 0x35, 0x04, 0x57, 0xf8, 0xab, 0x79, 0xee, 0x25, 0x3a,
-        0xb6, 0xa8, 0xe4, 0x6b, 0xb0, 0x9e, 0x54, 0x3a, 0xe4, 0x22, 0x73, 0x6d, 0xe5, 0x01, 0xe3, 0xdb, 0x37, 0xd4, 0x41, 0xfe,
-        0x34, 0x49, 0x20, 0xd0, 0x95, 0x48, 0xe4, 0xc1, 0x82, 0x40, 0x63, 0x0c, 0x4f, 0xf4, 0x91, 0x3c, 0x53, 0x51, 0x38, 0x39,
-        0xb7, 0xc0, 0x7f, 0xcc, 0x06, 0x27, 0xa1, 0xb8, 0x57, 0x3a, 0x14, 0x9f, 0xcd, 0x1f, 0xa4, 0x66, 0xcf,
-    };
-
-    uint32_t mSetupPasscode         = 0;
-    uint16_t mSetupDiscriminator    = 0;
-    uint32_t mSpake2pIterationCount = 0;
-
-    uint8_t mSpake2pSaltBuf[chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length];
-    MutableByteSpan mSpake2pSalt;
-
-    MutableByteSpan mSpake2pVerifier;
-    uint8_t mSpake2pVerifierBuf[chip::Crypto::kSpake2p_VerifierSerialized_Length];
+    friend CommissionableDataProviderImpl & CommissionableDataProviderMgrImpl();
+    static CommissionableDataProviderImpl sInstance;
+    bool mFirstUpdated = false;
+    std::vector<uint8_t> mSerializedPaseVerifier;
+    std::vector<uint8_t> mPaseSalt;
+    uint32_t mPaseIterationCount = 0;
+    chip::Optional<uint32_t> mSetupPasscode;
+    uint16_t mDiscriminator = 0;
 };
 
-} // namespace DeviceLayer
-} // namespace chip
-
-#endif /* CommissionableDataProviderImpl_h */
+inline CommissionableDataProviderImpl & CommissionableDataProviderMgrImpl()
+{
+    return CommissionableDataProviderImpl::sInstance;
+}
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissionableDataProviderImpl.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissionableDataProviderImpl.mm
new file mode 100644
index 0000000..c1e7c6e
--- /dev/null
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissionableDataProviderImpl.mm
@@ -0,0 +1,205 @@
+/*
+ *
+ *    Copyright (c) 2022 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include "CommissionableDataProviderImpl.hpp"
+
+#include <cstdint>
+#include <string.h>
+
+#include <crypto/CHIPCryptoPAL.h>
+#include <lib/support/Base64.h>
+#include <lib/support/CodeUtils.h>
+#include <lib/support/Span.h>
+#include <lib/support/logging/CHIPLogging.h>
+#include <platform/CHIPDeviceConfig.h>
+
+using namespace chip;
+using namespace chip::Crypto;
+
+namespace {
+
+CHIP_ERROR GeneratePaseSalt(std::vector<uint8_t> & spake2pSaltVector)
+{
+    constexpr size_t kSaltLen = kSpake2p_Max_PBKDF_Salt_Length;
+    spake2pSaltVector.resize(kSaltLen);
+    return DRBG_get_bytes(spake2pSaltVector.data(), spake2pSaltVector.size());
+}
+
+} // namespace
+
+CommissionableDataProviderImpl CommissionableDataProviderImpl::sInstance;
+
+CHIP_ERROR CommissionableDataProviderImpl::Initialize(chip::ByteSpan * spake2pVerifierBase64, chip::ByteSpan * spake2pSaltBase64,
+    uint32_t spake2pIterationCount, uint32_t setupPasscode, uint16_t discriminator)
+{
+    VerifyOrReturnLogError(discriminator <= chip::kMaxDiscriminatorValue, CHIP_ERROR_INVALID_ARGUMENT);
+
+    if (spake2pIterationCount == 0) {
+        spake2pIterationCount = CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT;
+    }
+    VerifyOrReturnLogError(
+        static_cast<uint32_t>(spake2pIterationCount) >= kSpake2p_Min_PBKDF_Iterations, CHIP_ERROR_INVALID_ARGUMENT);
+    VerifyOrReturnLogError(
+        static_cast<uint32_t>(spake2pIterationCount) <= kSpake2p_Max_PBKDF_Iterations, CHIP_ERROR_INVALID_ARGUMENT);
+
+    const bool havePaseVerifier = (spake2pVerifierBase64 != nullptr);
+    const bool havePaseSalt = (spake2pSaltBase64 != nullptr);
+    VerifyOrReturnLogError(!havePaseVerifier || (havePaseVerifier && havePaseSalt), CHIP_ERROR_INVALID_ARGUMENT);
+
+    CHIP_ERROR err;
+    // read verifier from paramter if provided
+    Spake2pVerifier providedVerifier;
+    std::vector<uint8_t> serializedSpake2pVerifier(kSpake2p_VerifierSerialized_Length);
+    if (havePaseVerifier) {
+        size_t maxBase64Size = BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_VerifierSerialized_Length);
+        VerifyOrReturnLogError(static_cast<unsigned>(spake2pVerifierBase64->size()) <= maxBase64Size, CHIP_ERROR_INVALID_ARGUMENT);
+
+        size_t decodedLen = chip::Base64Decode32(reinterpret_cast<const char *>(spake2pVerifierBase64->data()),
+            static_cast<uint32_t>(spake2pVerifierBase64->size()), reinterpret_cast<uint8_t *>(serializedSpake2pVerifier.data()));
+        VerifyOrReturnLogError(decodedLen == chip::Crypto::kSpake2p_VerifierSerialized_Length, CHIP_ERROR_INVALID_ARGUMENT);
+
+        chip::MutableByteSpan verifierSpan { serializedSpake2pVerifier.data(), decodedLen };
+        err = providedVerifier.Deserialize(verifierSpan);
+        VerifyOrReturnLogError(err == CHIP_NO_ERROR, err);
+
+        ChipLogProgress(Support, "Got externally provided verifier, using it.");
+    }
+
+    // read salt from paramter if provided or generate one
+    std::vector<uint8_t> spake2pSalt(chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length);
+    if (!havePaseSalt) {
+        ChipLogProgress(Support, "CommissionableDataProviderImpl didn't get a PASE salt, generating one.");
+        err = GeneratePaseSalt(spake2pSalt);
+        VerifyOrReturnLogError(err == CHIP_NO_ERROR, err);
+    } else {
+        size_t maxBase64Size = BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length);
+        VerifyOrReturnLogError(static_cast<unsigned>(spake2pSaltBase64->size()) <= maxBase64Size, CHIP_ERROR_INVALID_ARGUMENT);
+
+        size_t decodedLen = chip::Base64Decode32(reinterpret_cast<const char *>(spake2pSaltBase64->data()),
+            static_cast<uint32_t>(spake2pSaltBase64->size()), reinterpret_cast<uint8_t *>(spake2pSalt.data()));
+        VerifyOrReturnLogError(decodedLen >= chip::Crypto::kSpake2p_Min_PBKDF_Salt_Length
+                && decodedLen <= chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length,
+            CHIP_ERROR_INVALID_ARGUMENT);
+        spake2pSalt.resize(decodedLen);
+    }
+
+    // generate verifier from passcode if provided
+    const bool havePasscode = (setupPasscode > kMinSetupPasscode && setupPasscode < kMaxSetupPasscode);
+    Spake2pVerifier passcodeVerifier;
+    std::vector<uint8_t> serializedPasscodeVerifier(kSpake2p_VerifierSerialized_Length);
+    chip::MutableByteSpan saltSpan { spake2pSalt.data(), spake2pSalt.size() };
+    if (havePasscode) {
+        uint32_t u32SetupPasscode = static_cast<uint32_t>(setupPasscode);
+        err = passcodeVerifier.Generate(spake2pIterationCount, saltSpan, u32SetupPasscode);
+        VerifyOrReturnLogError(err == CHIP_NO_ERROR, err);
+
+        chip::MutableByteSpan verifierSpan { serializedPasscodeVerifier.data(), serializedPasscodeVerifier.size() };
+        err = passcodeVerifier.Serialize(verifierSpan);
+        VerifyOrReturnLogError(err == CHIP_NO_ERROR, err);
+    }
+
+    // Make sure we actually have a verifier
+    VerifyOrReturnLogError(havePasscode || havePaseVerifier, CHIP_ERROR_INVALID_ARGUMENT);
+
+    // If both passcode and external verifier were provided, validate they match, otherwise
+    // it's ambiguous.
+    if (havePasscode && havePaseVerifier) {
+        VerifyOrReturnLogError(serializedPasscodeVerifier == serializedSpake2pVerifier, CHIP_ERROR_INVALID_ARGUMENT);
+        ChipLogProgress(Support, "Validated externally provided passcode matches the one generated from provided passcode.");
+    }
+
+    // External PASE verifier takes precedence when present (even though it is identical to passcode-based
+    // one when the latter is present).
+    if (havePaseVerifier) {
+        mSerializedPaseVerifier = std::move(serializedSpake2pVerifier);
+    } else {
+        mSerializedPaseVerifier = std::move(serializedPasscodeVerifier);
+    }
+    mDiscriminator = discriminator;
+    mPaseSalt = std::move(spake2pSalt);
+    mPaseIterationCount = spake2pIterationCount;
+    if (havePasscode) {
+        mSetupPasscode.SetValue(setupPasscode);
+    }
+
+    // Set to global CommissionableDataProvider once success first time
+    if (!mFirstUpdated) {
+        DeviceLayer::SetCommissionableDataProvider(this);
+    }
+    mFirstUpdated = true;
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR CommissionableDataProviderImpl::GetSetupDiscriminator(uint16_t & setupDiscriminator)
+{
+    VerifyOrReturnError(mFirstUpdated, CHIP_ERROR_INCORRECT_STATE);
+    setupDiscriminator = mDiscriminator;
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR CommissionableDataProviderImpl::GetSpake2pIterationCount(uint32_t & iterationCount)
+{
+    ChipLogProgress(AppServer, "CommissionableDataProviderImpl::GetSpake2pIterationCount called");
+    VerifyOrReturnLogError(mFirstUpdated, CHIP_ERROR_INCORRECT_STATE);
+    iterationCount = mPaseIterationCount;
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR CommissionableDataProviderImpl::GetSpake2pSalt(chip::MutableByteSpan & saltBuf)
+{
+    ChipLogProgress(AppServer, "CommissionableDataProviderImpl::GetSpake2pSalt called");
+    VerifyOrReturnError(mFirstUpdated, CHIP_ERROR_INCORRECT_STATE);
+
+    VerifyOrReturnError(saltBuf.size() >= kSpake2p_Max_PBKDF_Salt_Length, CHIP_ERROR_BUFFER_TOO_SMALL);
+    memcpy(saltBuf.data(), mPaseSalt.data(), mPaseSalt.size());
+    saltBuf.reduce_size(mPaseSalt.size());
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR CommissionableDataProviderImpl::GetSpake2pVerifier(chip::MutableByteSpan & verifierBuf, size_t & outVerifierLen)
+{
+    ChipLogProgress(AppServer, "CommissionableDataProviderImpl::GetSpake2pVerifier called");
+    VerifyOrReturnError(mFirstUpdated, CHIP_ERROR_INCORRECT_STATE);
+
+    // By now, serialized verifier from Init should be correct size
+    VerifyOrReturnError(mSerializedPaseVerifier.size() == kSpake2p_VerifierSerialized_Length, CHIP_ERROR_INTERNAL);
+
+    outVerifierLen = mSerializedPaseVerifier.size();
+    VerifyOrReturnError(verifierBuf.size() >= outVerifierLen, CHIP_ERROR_BUFFER_TOO_SMALL);
+    memcpy(verifierBuf.data(), mSerializedPaseVerifier.data(), mSerializedPaseVerifier.size());
+    verifierBuf.reduce_size(mSerializedPaseVerifier.size());
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR CommissionableDataProviderImpl::GetSetupPasscode(uint32_t & setupPasscode)
+{
+    ChipLogProgress(AppServer, "CommissionableDataProviderImpl::GetSetupPasscode called");
+    VerifyOrReturnError(mFirstUpdated, CHIP_ERROR_INCORRECT_STATE);
+
+    // Pretend not implemented if we don't have a passcode value externally set
+    if (!mSetupPasscode.HasValue()) {
+        return CHIP_ERROR_NOT_IMPLEMENTED;
+    }
+
+    setupPasscode = mSetupPasscode.Value();
+    ChipLogProgress(AppServer, "CommissionableDataProviderImpl::GetSetupPasscode returning value %d", setupPasscode);
+    return CHIP_NO_ERROR;
+}
diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/TvCastingApp.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/TvCastingApp.swift
index daef2e7..322f1a1 100644
--- a/examples/tv-casting-app/darwin/TvCasting/TvCasting/TvCastingApp.swift
+++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/TvCastingApp.swift
@@ -22,6 +22,8 @@
 struct TvCastingApp: App {
     let Log = Logger(subsystem: "com.matter.casting",
                      category: "TvCastingApp")
+    @State
+    var firstAppActivation: Bool = true
 
     var body: some Scene {
         WindowGroup {
@@ -49,6 +51,36 @@
                         })
                     }
                 })
+                .onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in
+                    self.Log.info("TvCastingApp: UIApplication.willResignActiveNotification")
+                    if let castingServerBridge = CastingServerBridge.getSharedInstance()
+                    {
+                        castingServerBridge.stopMatterServer()
+                    }
+                }
+                .onReceive(NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)) { _ in
+                    self.Log.info("TvCastingApp: UIApplication.didBecomeActiveNotification")
+                    if(!firstAppActivation)
+                    {
+                        if let castingServerBridge = CastingServerBridge.getSharedInstance()
+                        {
+                            castingServerBridge.startMatterServer()
+                        }
+                    }
+                    firstAppActivation = false
+                }
+                .onReceive(NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)) { _ in
+                    self.Log.info("TvCastingApp: UIApplication.didEnterBackgroundNotification")
+                }
+                .onReceive(NotificationCenter.default.publisher(for: UIApplication.didFinishLaunchingNotification)) { _ in
+                    self.Log.info("TvCastingApp: UIApplication.didFinishLaunchingNotification")
+                }
+                .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
+                    self.Log.info("TvCastingApp: UIApplication.willEnterForegroundNotification")
+                }
+                .onReceive(NotificationCenter.default.publisher(for: UIApplication.willTerminateNotification)) { _ in
+                    self.Log.info("TvCastingApp: UIApplication.willTerminateNotification")
+                }
         }
     }
 }
diff --git a/examples/tv-casting-app/darwin/args.gni b/examples/tv-casting-app/darwin/args.gni
index 1171f4d..6435338 100644
--- a/examples/tv-casting-app/darwin/args.gni
+++ b/examples/tv-casting-app/darwin/args.gni
@@ -29,3 +29,5 @@
 chip_enable_additional_data_advertising = true
 
 chip_enable_rotating_device_id = true
+
+chip_config_network_layer_ble = false
diff --git a/examples/tv-casting-app/tv-casting-common/include/CHIPProjectAppConfig.h b/examples/tv-casting-app/tv-casting-common/include/CHIPProjectAppConfig.h
index b8daebc..e11b968 100644
--- a/examples/tv-casting-app/tv-casting-common/include/CHIPProjectAppConfig.h
+++ b/examples/tv-casting-app/tv-casting-common/include/CHIPProjectAppConfig.h
@@ -47,6 +47,10 @@
 
 #define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_NAME 1
 
+#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021
+
+#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00
+
 #define CHIP_DEVICE_CONFIG_DEVICE_NAME "Test TV casting app"
 
 #define CHIP_DEVICE_CONFIG_ENABLE_PAIRING_AUTOSTART 0