tv-casting-app: Implementing PASE related callbacks (#28342)

* Linux tv-casting-app: Implementing AppDelegate

* Android tv-casting-app: Implementing AppDelegate

* iOS tv-casting-app: Implementing AppDelegate
diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/ConnectionFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/ConnectionFragment.java
index 2dfa712..d2a0f79 100644
--- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/ConnectionFragment.java
+++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/ConnectionFragment.java
@@ -8,6 +8,7 @@
 import android.widget.TextView;
 import androidx.annotation.Nullable;
 import androidx.fragment.app.Fragment;
+import com.chip.casting.CommissioningCallbacks;
 import com.chip.casting.ContentApp;
 import com.chip.casting.DiscoveredNodeData;
 import com.chip.casting.FailureCallback;
@@ -120,15 +121,59 @@
       FailureCallback onConnectionFailure,
       SuccessCallback<ContentApp> onNewOrUpdatedEndpoints) {
     Log.d(TAG, "Running commissioning");
+    MatterCallbackHandler commissioningCompleteCallback =
+        new MatterCallbackHandler() {
+          @Override
+          public void handle(MatterError error) {
+            Log.d(TAG, "handle() called on CommissioningComplete event with " + error);
+          }
+        };
+
+    SuccessCallback<Void> sessionEstablishmentStartedCallback =
+        new SuccessCallback<Void>() {
+          @Override
+          public void handle(Void response) {
+            Log.d(TAG, "handle() called on SessionEstablishmentStartedCallback");
+          }
+        };
+
+    SuccessCallback<Void> sessionEstablishedCallback =
+        new SuccessCallback<Void>() {
+          @Override
+          public void handle(Void response) {
+            Log.d(TAG, "handle() called on SessionEstablishedCallback");
+          }
+        };
+
+    FailureCallback sessionEstablishmentErrorCallback =
+        new FailureCallback() {
+          @Override
+          public void handle(MatterError error) {
+            Log.d(TAG, "handle() called on SessionEstablishmentError event with " + error);
+          }
+        };
+
+    FailureCallback sessionEstablishmentStoppedCallback =
+        new FailureCallback() {
+          @Override
+          public void handle(MatterError error) {
+            Log.d(TAG, "handle() called on SessionEstablishmentStopped event with " + error);
+          }
+        };
+
+    CommissioningCallbacks commissioningCallbacks =
+        new CommissioningCallbacks.Builder()
+            .commissioningComplete(commissioningCompleteCallback)
+            .sessionEstablishmentStarted(sessionEstablishmentStartedCallback)
+            .sessionEstablished(sessionEstablishedCallback)
+            .sessionEstablishmentError(sessionEstablishmentErrorCallback)
+            .sessionEstablishmentStopped(sessionEstablishmentStoppedCallback)
+            .build();
+
     this.openCommissioningWindowSuccess =
         tvCastingApp.openBasicCommissioningWindow(
             GlobalCastingConstants.CommissioningWindowDurationSecs,
-            new MatterCallbackHandler() {
-              @Override
-              public void handle(MatterError error) {
-                Log.d(TAG, "handle() called on CommissioningComplete event with " + error);
-              }
-            },
+            commissioningCallbacks,
             onConnectionSuccess,
             onConnectionFailure,
             onNewOrUpdatedEndpoints);
diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/CommissioningCallbacks.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/CommissioningCallbacks.java
new file mode 100644
index 0000000..9a44aba
--- /dev/null
+++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/CommissioningCallbacks.java
@@ -0,0 +1,113 @@
+/*
+ *   Copyright (c) 2023 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.
+ *
+ */
+package com.chip.casting;
+
+public class CommissioningCallbacks {
+  /**
+   * This is called when the PBKDFParamRequest is received and indicates the start of the session
+   * establishment process
+   */
+  private SuccessCallback<Void> sessionEstablishmentStarted;
+
+  /** This is called when the commissioning session has been established */
+  private SuccessCallback<Void> sessionEstablished;
+
+  /**
+   * This is called when the PASE establishment failed (such as, when an invalid passcode is
+   * provided) or PASE was established fine but then the fail-safe expired (including being expired
+   * by the commissioner). The error param indicates the error that occurred during session
+   * establishment or the error accompanying the fail-safe timeout.
+   */
+  private FailureCallback sessionEstablishmentError;
+
+  /**
+   * This is called when the PASE establishment failed or PASE was established fine but then the
+   * fail-safe expired (including being expired by the commissioner) AND the commissioning window is
+   * closed. The window may be closed because the commissioning attempts limit was reached or
+   * advertising/listening for PASE failed.
+   */
+  private FailureCallback sessionEstablishmentStopped;
+
+  /** This is called when the commissioning has been completed */
+  private Object commissioningComplete;
+
+  private CommissioningCallbacks(Builder builder) {
+    this.sessionEstablishmentStarted = builder.sessionEstablishmentStarted;
+    this.sessionEstablished = builder.sessionEstablished;
+    this.sessionEstablishmentError = builder.sessionEstablishmentError;
+    this.sessionEstablishmentStopped = builder.sessionEstablishmentStopped;
+    this.commissioningComplete = builder.commissioningComplete;
+  }
+
+  public SuccessCallback<Void> getSessionEstablishmentStarted() {
+    return sessionEstablishmentStarted;
+  }
+
+  public SuccessCallback<Void> getSessionEstablished() {
+    return sessionEstablished;
+  }
+
+  public FailureCallback getSessionEstablishmentError() {
+    return sessionEstablishmentError;
+  }
+
+  public FailureCallback getSessionEstablishmentStopped() {
+    return sessionEstablishmentStopped;
+  }
+
+  public Object getCommissioningComplete() {
+    return commissioningComplete;
+  }
+
+  public static class Builder {
+    private SuccessCallback<Void> sessionEstablishmentStarted;
+    private SuccessCallback<Void> sessionEstablished;
+    private FailureCallback sessionEstablishmentError;
+    private FailureCallback sessionEstablishmentStopped;
+    private Object commissioningComplete;
+
+    public Builder sessionEstablishmentStarted(SuccessCallback<Void> sessionEstablishmentStarted) {
+      this.sessionEstablishmentStarted = sessionEstablishmentStarted;
+      return this;
+    }
+
+    public Builder sessionEstablished(SuccessCallback<Void> sessionEstablished) {
+      this.sessionEstablished = sessionEstablished;
+      return this;
+    }
+
+    public Builder sessionEstablishmentError(FailureCallback sessionEstablishmentError) {
+      this.sessionEstablishmentError = sessionEstablishmentError;
+      return this;
+    }
+
+    public Builder sessionEstablishmentStopped(FailureCallback sessionEstablishmentStopped) {
+      this.sessionEstablishmentStopped = sessionEstablishmentStopped;
+      return this;
+    }
+
+    public Builder commissioningComplete(Object commissioningComplete) {
+      this.commissioningComplete = commissioningComplete;
+      return this;
+    }
+
+    public CommissioningCallbacks build() {
+      return new CommissioningCallbacks(this);
+    }
+  }
+}
diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/TvCastingApp.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/TvCastingApp.java
index 7fc9d44..f30132f 100644
--- a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/TvCastingApp.java
+++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/TvCastingApp.java
@@ -180,7 +180,7 @@
 
   public native boolean openBasicCommissioningWindow(
       int duration,
-      Object commissioningCompleteHandler,
+      CommissioningCallbacks commissioningCallbacks,
       SuccessCallback<VideoPlayer> onConnectionSuccess,
       FailureCallback onConnectionFailure,
       SuccessCallback<ContentApp> onNewOrUpdatedEndpointCallback);
diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.h b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.h
index 749f5e8..c05eef0 100644
--- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.h
+++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.h
@@ -104,6 +104,30 @@
 SuccessHandlerJNI<T>::~SuccessHandlerJNI(){};
 
 // COMMISSIONING AND CONNECTION
+class SessionEstablishmentStartedHandlerJNI : public SuccessHandlerJNI<void *>
+{
+public:
+    SessionEstablishmentStartedHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Object;)V") {}
+    jobject ConvertToJObject(void * responseData)
+    {
+        // return nullptr because the Java callback extends SuccessCallback<Void> and its handle() expects a Void param.
+        // It expects a Void becauase no value is passed as part of this callback.
+        return nullptr;
+    }
+};
+
+class SessionEstablishedHandlerJNI : public SuccessHandlerJNI<void *>
+{
+public:
+    SessionEstablishedHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Object;)V") {}
+    jobject ConvertToJObject(void * responseData)
+    {
+        // return nullptr because the Java callback extends SuccessCallback<Void> and its handle() expects a Void param.
+        // It expects a Void becauase no value is passed as part of this callback.
+        return nullptr;
+    }
+};
+
 class OnConnectionSuccessHandlerJNI : public SuccessHandlerJNI<TargetVideoPlayerInfo *>
 {
 public:
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 c4af2c3..5293cc3 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
@@ -113,15 +113,82 @@
 }
 
 JNI_METHOD(jboolean, openBasicCommissioningWindow)
-(JNIEnv * env, jobject, jint duration, jobject jCommissioningCompleteHandler, jobject jOnConnectionSuccessHandler,
+(JNIEnv * env, jobject, jint duration, jobject jCommissioningCallbacks, jobject jOnConnectionSuccessHandler,
  jobject jOnConnectionFailureHandler, jobject jOnNewOrUpdatedEndpointHandler)
 {
     chip::DeviceLayer::StackLock lock;
 
     ChipLogProgress(AppServer, "JNI_METHOD openBasicCommissioningWindow called with duration %d", duration);
-    CHIP_ERROR err = TvCastingAppJNIMgr().getCommissioningCompleteHandler().SetUp(env, jCommissioningCompleteHandler);
-    VerifyOrExit(CHIP_NO_ERROR == err,
-                 ChipLogError(AppServer, "MatterCallbackHandlerJNI::SetUp failed %" CHIP_ERROR_FORMAT, err.Format()));
+
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    CommissioningCallbacks commissioningCallbacks;
+    jclass jCommissioningCallbacksClass;
+    chip::JniReferences::GetInstance().GetClassRef(env, "com/chip/casting/CommissioningCallbacks", jCommissioningCallbacksClass);
+
+    jfieldID jCommissioningCompleteField =
+        env->GetFieldID(jCommissioningCallbacksClass, "commissioningComplete", "Ljava/lang/Object;");
+    jobject jCommissioningComplete = env->GetObjectField(jCommissioningCallbacks, jCommissioningCompleteField);
+    if (jCommissioningComplete != nullptr)
+    {
+        err = TvCastingAppJNIMgr().getCommissioningCompleteHandler().SetUp(env, jCommissioningComplete);
+        VerifyOrReturnValue(err == CHIP_NO_ERROR, false,
+                            ChipLogError(AppServer, "MatterCallbackHandlerJNI::SetUp failed %" CHIP_ERROR_FORMAT, err.Format()));
+        commissioningCallbacks.commissioningComplete = [](CHIP_ERROR err) {
+            TvCastingAppJNIMgr().getCommissioningCompleteHandler().Handle(err);
+        };
+    }
+
+    jfieldID jSessionEstablishmentStartedField =
+        env->GetFieldID(jCommissioningCallbacksClass, "sessionEstablishmentStarted", "Lcom/chip/casting/SuccessCallback;");
+    jobject jSessionEstablishmentStarted = env->GetObjectField(jCommissioningCallbacks, jSessionEstablishmentStartedField);
+    if (jSessionEstablishmentStarted != nullptr)
+    {
+        err = TvCastingAppJNIMgr().getSessionEstablishmentStartedHandler().SetUp(env, jSessionEstablishmentStarted);
+        VerifyOrReturnValue(
+            err == CHIP_NO_ERROR, false,
+            ChipLogError(AppServer, "SessionEstablishmentStartedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format()));
+        commissioningCallbacks.sessionEstablishmentStarted = []() {
+            TvCastingAppJNIMgr().getSessionEstablishmentStartedHandler().Handle(nullptr);
+        };
+    }
+
+    jfieldID jSessionEstablishedField =
+        env->GetFieldID(jCommissioningCallbacksClass, "sessionEstablished", "Lcom/chip/casting/SuccessCallback;");
+    jobject jSessionEstablished = env->GetObjectField(jCommissioningCallbacks, jSessionEstablishedField);
+    if (jSessionEstablished != nullptr)
+    {
+        err = TvCastingAppJNIMgr().getSessionEstablishedHandler().SetUp(env, jSessionEstablished);
+        VerifyOrReturnValue(err == CHIP_NO_ERROR, false,
+                            ChipLogError(AppServer, "SessionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format()));
+        commissioningCallbacks.sessionEstablished = []() { TvCastingAppJNIMgr().getSessionEstablishedHandler().Handle(nullptr); };
+    }
+
+    jfieldID jSessionEstablishmentErrorField =
+        env->GetFieldID(jCommissioningCallbacksClass, "sessionEstablishmentError", "Lcom/chip/casting/FailureCallback;");
+    jobject jSessionEstablishmentError = env->GetObjectField(jCommissioningCallbacks, jSessionEstablishmentErrorField);
+    if (jSessionEstablishmentError != nullptr)
+    {
+        err = TvCastingAppJNIMgr().getSessionEstablishmentErrorHandler().SetUp(env, jSessionEstablishmentError);
+        VerifyOrReturnValue(err == CHIP_NO_ERROR, false);
+        commissioningCallbacks.sessionEstablishmentError = [](CHIP_ERROR err) {
+            TvCastingAppJNIMgr().getSessionEstablishmentErrorHandler().Handle(err);
+        };
+    }
+
+    jfieldID jSessionEstablishmentStoppedField =
+        env->GetFieldID(jCommissioningCallbacksClass, "sessionEstablishmentStopped", "Lcom/chip/casting/FailureCallback;");
+    jobject jSessionEstablishmentStopped = env->GetObjectField(jCommissioningCallbacks, jSessionEstablishmentStoppedField);
+    if (jSessionEstablishmentStopped != nullptr)
+    {
+        err = TvCastingAppJNIMgr().getSessionEstablishmentStoppedHandler().SetUp(env, jSessionEstablishmentStopped);
+        VerifyOrReturnValue(
+            err == CHIP_NO_ERROR, false,
+            ChipLogError(AppServer, "SessionEstablishmentStoppedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format()));
+        commissioningCallbacks.sessionEstablishmentStopped = []() {
+            TvCastingAppJNIMgr().getSessionEstablishmentStoppedHandler().Handle(CHIP_NO_ERROR);
+        };
+    }
 
     err = TvCastingAppJNIMgr().getOnConnectionSuccessHandler(false).SetUp(env, jOnConnectionSuccessHandler);
     VerifyOrExit(CHIP_NO_ERROR == err,
@@ -136,7 +203,7 @@
                  ChipLogError(AppServer, "OnNewOrUpdatedEndpointHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format()));
 
     err = CastingServer::GetInstance()->OpenBasicCommissioningWindow(
-        [](CHIP_ERROR err) { TvCastingAppJNIMgr().getCommissioningCompleteHandler().Handle(err); },
+        commissioningCallbacks,
         [](TargetVideoPlayerInfo * videoPlayer) { TvCastingAppJNIMgr().getOnConnectionSuccessHandler(false).Handle(videoPlayer); },
         [](CHIP_ERROR err) { TvCastingAppJNIMgr().getOnConnectionFailureHandler(false).Handle(err); },
         [](TargetEndpointInfo * endpoint) { TvCastingAppJNIMgr().getOnNewOrUpdatedEndpointHandler(false).Handle(endpoint); });
diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.h b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.h
index d77f3a7..863e269 100644
--- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.h
+++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.h
@@ -27,10 +27,20 @@
 {
 public:
     MatterCallbackHandlerJNI & getCommissioningCompleteHandler() { return mCommissioningCompleteHandler; }
+
+    SessionEstablishmentStartedHandlerJNI & getSessionEstablishmentStartedHandler() { return mSessionEstablishmentStartedHandler; }
+
+    SessionEstablishedHandlerJNI & getSessionEstablishedHandler() { return mSessionEstablishedHandler; }
+
+    FailureHandlerJNI & getSessionEstablishmentErrorHandler() { return mSessionEstablishmentErrorHandler; }
+
+    FailureHandlerJNI & getSessionEstablishmentStoppedHandler() { return mSessionEstablishmentStoppedHandler; }
+
     OnConnectionSuccessHandlerJNI & getOnConnectionSuccessHandler(bool preCommissioned)
     {
         return preCommissioned ? mPreCommissionedOnConnectionSuccessHandler : mCommissioningOnConnectionSuccessHandler;
     }
+
     FailureHandlerJNI & getOnConnectionFailureHandler(bool preCommissioned)
     {
         return preCommissioned ? mPreCommissionedOnConnectionFailureHandler : mCommissioningOnConnectionFailureHandler;
@@ -100,6 +110,10 @@
     static TvCastingAppJNI sInstance;
 
     MatterCallbackHandlerJNI mCommissioningCompleteHandler;
+    SessionEstablishmentStartedHandlerJNI mSessionEstablishmentStartedHandler;
+    SessionEstablishedHandlerJNI mSessionEstablishedHandler;
+    FailureHandlerJNI mSessionEstablishmentErrorHandler;
+    FailureHandlerJNI mSessionEstablishmentStoppedHandler;
     OnConnectionSuccessHandlerJNI mCommissioningOnConnectionSuccessHandler;
     FailureHandlerJNI mCommissioningOnConnectionFailureHandler;
     OnNewOrUpdatedEndpointHandlerJNI mCommissioningOnNewOrUpdatedEndpointHandler;
diff --git a/examples/tv-casting-app/android/BUILD.gn b/examples/tv-casting-app/android/BUILD.gn
index 7a12b9a..d072dd4 100644
--- a/examples/tv-casting-app/android/BUILD.gn
+++ b/examples/tv-casting-app/android/BUILD.gn
@@ -65,6 +65,7 @@
 
   sources = [
     "App/app/src/main/jni/com/chip/casting/AppParameters.java",
+    "App/app/src/main/jni/com/chip/casting/CommissioningCallbacks.java",
     "App/app/src/main/jni/com/chip/casting/ContentApp.java",
     "App/app/src/main/jni/com/chip/casting/ContentLauncherTypes.java",
     "App/app/src/main/jni/com/chip/casting/DACProvider.java",
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 1591df3..cbc52e4 100644
--- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge.xcodeproj/project.pbxproj
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge.xcodeproj/project.pbxproj
@@ -27,6 +27,8 @@
 		3CCB8743286A593700771BAD /* CastingServerBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CCB873D286A593700771BAD /* CastingServerBridge.mm */; };
 		3CCB8744286A593700771BAD /* ConversionUtils.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CCB873E286A593700771BAD /* ConversionUtils.mm */; };
 		3CD6D01A298CDA2100D7569A /* CommissionerDiscoveryDelegateImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CD6D019298CDA2100D7569A /* CommissionerDiscoveryDelegateImpl.h */; };
+		3CE5ECCE2A673B30007CF331 /* CommissioningCallbackHandlers.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CE5ECCD2A673B30007CF331 /* CommissioningCallbackHandlers.h */; };
+		3CE5ECD02A673E2C007CF331 /* CommissioningCallbackHandlers.m in Sources */ = {isa = PBXBuildFile; fileRef = 3CE5ECCF2A673E2C007CF331 /* CommissioningCallbackHandlers.m */; };
 		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 */
@@ -62,6 +64,8 @@
 		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>"; };
 		3CD6D019298CDA2100D7569A /* CommissionerDiscoveryDelegateImpl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CommissionerDiscoveryDelegateImpl.h; sourceTree = "<group>"; };
+		3CE5ECCD2A673B30007CF331 /* CommissioningCallbackHandlers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CommissioningCallbackHandlers.h; sourceTree = "<group>"; };
+		3CE5ECCF2A673E2C007CF331 /* CommissioningCallbackHandlers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CommissioningCallbackHandlers.m; 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>"; };
@@ -131,6 +135,8 @@
 				3C0D9CDF2920A30C00D3332B /* CommissionableDataProviderImpl.hpp */,
 				3CE868F32946D76200FCB92B /* CommissionableDataProviderImpl.mm */,
 				3CD6D019298CDA2100D7569A /* CommissionerDiscoveryDelegateImpl.h */,
+				3CE5ECCD2A673B30007CF331 /* CommissioningCallbackHandlers.h */,
+				3CE5ECCF2A673E2C007CF331 /* CommissioningCallbackHandlers.m */,
 			);
 			path = MatterTvCastingBridge;
 			sourceTree = "<group>";
@@ -145,6 +151,7 @@
 				3CD6D01A298CDA2100D7569A /* CommissionerDiscoveryDelegateImpl.h in Headers */,
 				3C26AC8C2926FE0C00BA6881 /* DeviceAttestationCredentialsProviderImpl.hpp in Headers */,
 				3CCB8740286A593700771BAD /* CastingServerBridge.h in Headers */,
+				3CE5ECCE2A673B30007CF331 /* CommissioningCallbackHandlers.h in Headers */,
 				3CCB8742286A593700771BAD /* ConversionUtils.hpp in Headers */,
 				3CCB8741286A593700771BAD /* DiscoveredNodeData.h in Headers */,
 				3CCB87212869085400771BAD /* MatterTvCastingBridge.h in Headers */,
@@ -249,6 +256,7 @@
 			files = (
 				3CCB8743286A593700771BAD /* CastingServerBridge.mm in Sources */,
 				3C4E53B228E5184C00F293E8 /* TargetNavigatorTypes.mm in Sources */,
+				3CE5ECD02A673E2C007CF331 /* CommissioningCallbackHandlers.m in Sources */,
 				3CF8532728E37F1000F07B9F /* MatterError.mm in Sources */,
 				3C4E53B628E5595A00F293E8 /* ContentLauncherTypes.mm in Sources */,
 				3C81C75028F7A7D3001CB9D1 /* VideoPlayer.m in Sources */,
@@ -419,9 +427,6 @@
 					"$(CHIP_ROOT)/third_party/nlassert/repo/include",
 					"$(CHIP_ROOT)/third_party/nlio/repo/include",
 					"$(TEMP_DIR)/out/gen/include",
-					/* Compile time codegen would need this: 
-					   "$(TEMP_DIR)/out/gen/src/controller/data_model/zapgen/", 
-					 */
 					"$(CHIP_ROOT)/zzz_generated/app-common",
 				);
 				INFOPLIST_KEY_NSHumanReadableCopyright = "";
@@ -502,9 +507,6 @@
 					"$(CHIP_ROOT)/third_party/nlassert/repo/include",
 					"$(CHIP_ROOT)/third_party/nlio/repo/include",
 					"$(TEMP_DIR)/out/gen/include",
-					/* Compile time codegen would need this: 
-					   "$(TEMP_DIR)/out/gen/src/controller/data_model/zapgen/", 
-					 */
 					"$(CHIP_ROOT)/zzz_generated/app-common",
 				);
 				INFOPLIST_KEY_NSHumanReadableCopyright = "";
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h
index d90e4db..2489f98 100644
--- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h
@@ -16,6 +16,7 @@
  */
 
 #import "AppParameters.h"
+#import "CommissioningCallbackHandlers.h"
 #import "ContentApp.h"
 #import "ContentLauncherTypes.h"
 #import "DiscoveredNodeData.h"
@@ -109,8 +110,7 @@
 
  @param clientQueue Queue to dispatch the call to the commissioningWindowRequestedHandler on
 
- @param commissioningCompleteCallback Callback for when commissioning of this app has been completed  via a call to the general
- commissioning cluster (by usually an on-network TV/Media device acting as a Matter commissioner)
+ @param commissioningCallbackHandlers Optional parameter to specific handlers for callbacks during commissioning
 
  @param onConnectionSuccessCallback Handles a VideoPlayer * once connection is successfully established
 
@@ -118,15 +118,12 @@
 
  @param onNewOrUpdatedEndpointCallback Handles a ContentApp * for each new ContentApp is found. May be called multiple times based
  on the number of ContentApp
-
- @param commissioningWindowRequestedHandler Handler to call on requesting the opening of a commissioning window
  */
 - (void)openBasicCommissioningWindow:(dispatch_queue_t _Nonnull)clientQueue
-    commissioningWindowRequestedHandler:(void (^_Nonnull)(bool))commissioningWindowRequestedHandler
-          commissioningCompleteCallback:(void (^_Nonnull)(bool))commissioningCompleteCallback
-            onConnectionSuccessCallback:(void (^_Nonnull)(VideoPlayer * _Nonnull))onConnectionSuccessCallback
-            onConnectionFailureCallback:(void (^_Nonnull)(MatterError * _Nonnull))onConnectionFailureCallback
-         onNewOrUpdatedEndpointCallback:(void (^_Nonnull)(ContentApp * _Nonnull))onNewOrUpdatedEndpointCallback;
+       commissioningCallbackHandlers:(CommissioningCallbackHandlers * _Nullable)commissioningCallbackHandlers
+         onConnectionSuccessCallback:(void (^_Nonnull)(VideoPlayer * _Nonnull))onConnectionSuccessCallback
+         onConnectionFailureCallback:(void (^_Nonnull)(MatterError * _Nonnull))onConnectionFailureCallback
+      onNewOrUpdatedEndpointCallback:(void (^_Nonnull)(ContentApp * _Nonnull))onNewOrUpdatedEndpointCallback;
 
 /*!
  @brief Gets the list of VideoPlayers currently connected
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm
index 50c2467..3f4dbce 100644
--- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm
@@ -565,24 +565,89 @@
 }
 
 - (void)openBasicCommissioningWindow:(dispatch_queue_t _Nonnull)clientQueue
-    commissioningWindowRequestedHandler:(void (^_Nonnull)(bool))commissioningWindowRequestedHandler
-          commissioningCompleteCallback:(void (^_Nonnull)(bool))commissioningCompleteCallback
-            onConnectionSuccessCallback:(void (^_Nonnull)(VideoPlayer * _Nonnull))onConnectionSuccessCallback
-            onConnectionFailureCallback:(void (^_Nonnull)(MatterError * _Nonnull))onConnectionFailureCallback
-         onNewOrUpdatedEndpointCallback:(void (^_Nonnull)(ContentApp * _Nonnull))onNewOrUpdatedEndpointCallback
+       commissioningCallbackHandlers:(CommissioningCallbackHandlers * _Nullable)commissioningCallbackHandlers
+         onConnectionSuccessCallback:(void (^_Nonnull)(VideoPlayer * _Nonnull))onConnectionSuccessCallback
+         onConnectionFailureCallback:(void (^_Nonnull)(MatterError * _Nonnull))onConnectionFailureCallback
+      onNewOrUpdatedEndpointCallback:(void (^_Nonnull)(ContentApp * _Nonnull))onNewOrUpdatedEndpointCallback
 {
     [self
         dispatchOnMatterSDKQueue:@"openBasicCommissioningWindow(...)"
                            block:^{
+                               CommissioningCallbacks commissioningCallbacks;
+                               if (commissioningCallbackHandlers != nil) {
+                                   if (commissioningCallbackHandlers.commissioningCompleteCallback != nil) {
+                                       commissioningCallbacks.commissioningComplete = [clientQueue, commissioningCallbackHandlers](
+                                                                                          CHIP_ERROR err) {
+                                           [[CastingServerBridge getSharedInstance]
+                                               dispatchOnClientQueue:clientQueue
+                                                         description:
+                                                             @"openBasicCommissioningWindow(...) commissioningCompleteCallback"
+                                                               block:^{
+                                                                   commissioningCallbackHandlers.commissioningCompleteCallback(
+                                                                       CHIP_NO_ERROR == err);
+                                                               }];
+                                       };
+                                   }
+
+                                   if (commissioningCallbackHandlers.sessionEstablishmentStartedCallback != nil) {
+                                       commissioningCallbacks.sessionEstablishmentStarted
+                                           = [clientQueue, commissioningCallbackHandlers]() {
+                                                 [[CastingServerBridge getSharedInstance]
+                                                     dispatchOnClientQueue:clientQueue
+                                                               description:@"openBasicCommissioningWindow(...) "
+                                                                           @"sessionEstablishmentStartedCallback"
+                                                                     block:^{
+                                                                         commissioningCallbackHandlers
+                                                                             .sessionEstablishmentStartedCallback();
+                                                                     }];
+                                             };
+                                   }
+
+                                   if (commissioningCallbackHandlers.sessionEstablishedCallback != nil) {
+                                       commissioningCallbacks.sessionEstablished = [clientQueue, commissioningCallbackHandlers]() {
+                                           [[CastingServerBridge getSharedInstance]
+                                               dispatchOnClientQueue:clientQueue
+                                                         description:@"openBasicCommissioningWindow(...) sessionEstablishedCallback"
+                                                               block:^{
+                                                                   commissioningCallbackHandlers.sessionEstablishedCallback();
+                                                               }];
+                                       };
+                                   }
+
+                                   if (commissioningCallbackHandlers.sessionEstablishmentErrorCallback != nil) {
+                                       commissioningCallbacks.sessionEstablishmentError = [clientQueue,
+                                                                                              commissioningCallbackHandlers](
+                                                                                              CHIP_ERROR err) {
+                                           [[CastingServerBridge getSharedInstance]
+                                               dispatchOnClientQueue:clientQueue
+                                                         description:@"openBasicCommissioningWindow(...) "
+                                                                     @"sessionEstablishmentErrorCallback"
+                                                               block:^{
+                                                                   commissioningCallbackHandlers.sessionEstablishmentErrorCallback(
+                                                                       [[MatterError alloc]
+                                                                           initWithCode:err.AsInteger()
+                                                                                message:[NSString
+                                                                                            stringWithUTF8String:err.AsString()]]);
+                                                               }];
+                                       };
+                                   }
+
+                                   if (commissioningCallbackHandlers.sessionEstablishmentStoppedCallback != nil) {
+                                       commissioningCallbacks.sessionEstablishmentStopped
+                                           = [clientQueue, commissioningCallbackHandlers]() {
+                                                 [[CastingServerBridge getSharedInstance]
+                                                     dispatchOnClientQueue:clientQueue
+                                                               description:@"openBasicCommissioningWindow(...) "
+                                                                           @"sessionEstablishmentStoppedCallback"
+                                                                     block:^{
+                                                                         commissioningCallbackHandlers
+                                                                             .sessionEstablishmentStoppedCallback();
+                                                                     }];
+                                             };
+                                   }
+                               }
                                CHIP_ERROR err = CastingServer::GetInstance()->OpenBasicCommissioningWindow(
-                                   [clientQueue, commissioningCompleteCallback](CHIP_ERROR err) {
-                                       [[CastingServerBridge getSharedInstance]
-                                           dispatchOnClientQueue:clientQueue
-                                                     description:@"openBasicCommissioningWindow(...) commissioningCompleteCallback"
-                                                           block:^{
-                                                               commissioningCompleteCallback(CHIP_NO_ERROR == err);
-                                                           }];
-                                   },
+                                   commissioningCallbacks,
                                    [clientQueue, onConnectionSuccessCallback](TargetVideoPlayerInfo * cppTargetVideoPlayerInfo) {
                                        VideoPlayer * videoPlayer =
                                            [ConversionUtils convertToObjCVideoPlayerFrom:cppTargetVideoPlayerInfo];
@@ -614,10 +679,13 @@
                                                            }];
                                    });
 
-                               dispatch_async(clientQueue, ^{
-                                   ChipLogProgress(AppServer, "[async] Dispatching commissioningWindowRequestedHandler");
-                                   commissioningWindowRequestedHandler(CHIP_NO_ERROR == err);
-                               });
+                               if (commissioningCallbackHandlers != nil
+                                   && commissioningCallbackHandlers.commissioningWindowRequestedHandler != nil) {
+                                   dispatch_async(clientQueue, ^{
+                                       ChipLogProgress(AppServer, "[async] Dispatching commissioningWindowRequestedHandler");
+                                       commissioningCallbackHandlers.commissioningWindowRequestedHandler(CHIP_NO_ERROR == err);
+                                   });
+                               }
                            }];
 }
 
@@ -750,6 +818,9 @@
                                      return;
                                  }
 
+                                 // Initialize AppDelegation
+                                 CastingServer::GetInstance()->InitAppDelegation();
+
                                  // Initialize binding handlers
                                  err = CastingServer::GetInstance()->InitBindingHandlers();
                                  if (err != CHIP_NO_ERROR) {
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissioningCallbackHandlers.h b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissioningCallbackHandlers.h
new file mode 100644
index 0000000..14288d7
--- /dev/null
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissioningCallbackHandlers.h
@@ -0,0 +1,70 @@
+/**
+ *
+ *    Copyright (c) 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.
+ *    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.
+ */
+
+#import "MatterError.h"
+#import <Foundation/Foundation.h>
+
+#ifndef CommissioningCallbacksHandlers_h
+#define CommissioningCallbacksHandlers_h
+
+@interface CommissioningCallbackHandlers : NSObject
+
+- (CommissioningCallbackHandlers * _Nonnull)
+    initWithCommissioningWindowRequestedHandler:(void (^_Nonnull)(bool))commissioningWindowRequestedHandler
+                  commissioningCompleteCallback:(void (^_Nonnull)(bool))commissioningCompleteCallback
+            sessionEstablishmentStartedCallback:(void (^_Nullable)(void))sessionEstablishmentStartedCallback
+                     sessionEstablishedCallback:(void (^_Nullable)(void))sessionEstablishedCallback
+              sessionEstablishmentErrorCallback:(void (^_Nullable)(MatterError * _Nonnull))sessionEstablishmentErrorCallback
+            sessionEstablishmentStoppedCallback:(void (^_Nullable)(void))sessionEstablishmentStoppedCallback;
+
+/**
+ * This is called when request to open the commissioning window has been made.
+ */
+@property void (^_Nullable commissioningWindowRequestedHandler)(bool);
+
+/**
+ * This is called when the commissioning has been completed
+ */
+@property void (^_Nullable commissioningCompleteCallback)(bool);
+
+/**
+ * This is called when the PBKDFParamRequest is received and indicates the start of the session establishment process
+ */
+@property void (^_Nullable sessionEstablishmentStartedCallback)(void);
+
+/**
+ * This is called when the commissioning session has been established
+ */
+@property void (^_Nullable sessionEstablishedCallback)(void);
+
+/**
+ * This is called when the PASE establishment failed (such as, when an invalid passcode is provided) or PASE was established
+ * fine but then the fail-safe expired (including being expired by the commissioner). The error param indicates the error that
+ * occurred during session establishment or the error accompanying the fail-safe timeout.
+ */
+@property void (^_Nullable sessionEstablishmentErrorCallback)(MatterError * _Nonnull);
+
+/**
+ * This is called when the PASE establishment failed or PASE was established fine but then the fail-safe expired (including
+ * being expired by the commissioner) AND the commissioning window is closed. The window may be closed because the commissioning
+ * attempts limit was reached or advertising/listening for PASE failed.
+ */
+@property void (^_Nullable sessionEstablishmentStoppedCallback)(void);
+
+@end
+
+#endif /* CommissioningCallbacksHandlers_h */
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissioningCallbackHandlers.m b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissioningCallbackHandlers.m
new file mode 100644
index 0000000..be79d40
--- /dev/null
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CommissioningCallbackHandlers.m
@@ -0,0 +1,42 @@
+/**
+ *
+ *    Copyright (c) 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.
+ *    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.
+ */
+
+#import "CommissioningCallbackHandlers.h"
+
+@implementation CommissioningCallbackHandlers
+
+- (CommissioningCallbackHandlers * _Nonnull)
+    initWithCommissioningWindowRequestedHandler:(void (^_Nonnull)(bool))commissioningWindowRequestedHandler
+                  commissioningCompleteCallback:(void (^_Nonnull)(bool))commissioningCompleteCallback
+            sessionEstablishmentStartedCallback:(void (^_Nullable)(void))sessionEstablishmentStartedCallback
+                     sessionEstablishedCallback:(void (^_Nullable)(void))sessionEstablishedCallback
+              sessionEstablishmentErrorCallback:(void (^_Nullable)(MatterError * _Nonnull))sessionEstablishmentErrorCallback
+            sessionEstablishmentStoppedCallback:(void (^_Nullable)(void))sessionEstablishmentStoppedCallback
+{
+    self = [super init];
+    if (self) {
+        _commissioningWindowRequestedHandler = commissioningWindowRequestedHandler;
+        _commissioningCompleteCallback = commissioningCompleteCallback;
+        _sessionEstablishmentStartedCallback = sessionEstablishmentStartedCallback;
+        _sessionEstablishedCallback = sessionEstablishedCallback;
+        _sessionEstablishmentErrorCallback = sessionEstablishmentErrorCallback;
+        _sessionEstablishmentStoppedCallback = sessionEstablishmentStoppedCallback;
+    }
+    return self;
+}
+
+@end
diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningViewModel.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningViewModel.swift
index a0d4163..ec0c542 100644
--- a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningViewModel.swift
+++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningViewModel.swift
@@ -58,17 +58,32 @@
         if let castingServerBridge = CastingServerBridge.getSharedInstance()
         {
             castingServerBridge.openBasicCommissioningWindow(DispatchQueue.main,
-                commissioningWindowRequestedHandler: { (result: Bool) -> () in
-                    DispatchQueue.main.async {
-                        self.commisisoningWindowOpened = result
+                commissioningCallbackHandlers: CommissioningCallbackHandlers(
+                    commissioningWindowRequestedHandler: { (result: Bool) -> () in
+                        DispatchQueue.main.async {
+                            self.Log.info("Commissioning Window opening status: \(result)")
+                            self.commisisoningWindowOpened = result
+                        }
+                    },
+                    commissioningCompleteCallback: { (result: Bool) -> () in
+                        self.Log.info("Commissioning status: \(result)")
+                        DispatchQueue.main.async {
+                            self.commisisoningComplete = result
+                        }
+                    },
+                    sessionEstablishmentStartedCallback: {
+                        self.Log.info("PASE session establishment started")
+                    },
+                    sessionEstablishedCallback: {
+                        self.Log.info("PASE session established")
+                    },
+                    sessionEstablishmentErrorCallback: { (err: MatterError) -> () in
+                        self.Log.info("PASE session establishment error : \(err)")
+                    },
+                    sessionEstablishmentStoppedCallback: {
+                        self.Log.info("PASE session establishment stopped")
                     }
-                },
-                commissioningCompleteCallback: { (result: Bool) -> () in
-                    self.Log.info("Commissioning status: \(result)")
-                    DispatchQueue.main.async {
-                        self.commisisoningComplete = result
-                    }
-                },
+                ),
                 onConnectionSuccessCallback: { (videoPlayer: VideoPlayer) -> () in
                     DispatchQueue.main.async {
                         self.connectionSuccess = true
@@ -92,7 +107,7 @@
         
     }
     
-    private func sendUserDirectedCommissioningRequest(selectedCommissioner: DiscoveredNodeData?) {        
+    private func sendUserDirectedCommissioningRequest(selectedCommissioner: DiscoveredNodeData?) {
         if let castingServerBridge = CastingServerBridge.getSharedInstance()
         {
             castingServerBridge.sendUserDirectedCommissioningRequest(selectedCommissioner!, clientQueue: DispatchQueue.main, udcRequestSentHandler: { (result: Bool) -> () in
diff --git a/examples/tv-casting-app/linux/CastingUtils.cpp b/examples/tv-casting-app/linux/CastingUtils.cpp
index 5e15a2e..dca65f5 100644
--- a/examples/tv-casting-app/linux/CastingUtils.cpp
+++ b/examples/tv-casting-app/linux/CastingUtils.cpp
@@ -18,6 +18,8 @@
 
 #include "CastingUtils.h"
 
+#include "CommissioningCallbacks.h"
+
 using namespace chip;
 using namespace chip::System;
 using namespace chip::DeviceLayer;
@@ -62,8 +64,10 @@
 {
     CastingServer::GetInstance()->Init();
 
-    CastingServer::GetInstance()->OpenBasicCommissioningWindow(HandleCommissioningCompleteCallback, OnConnectionSuccess,
-                                                               OnConnectionFailure, OnNewOrUpdatedEndpoint);
+    CommissioningCallbacks commissioningCallbacks;
+    commissioningCallbacks.commissioningComplete = HandleCommissioningCompleteCallback;
+    CastingServer::GetInstance()->OpenBasicCommissioningWindow(commissioningCallbacks, OnConnectionSuccess, OnConnectionFailure,
+                                                               OnNewOrUpdatedEndpoint);
 
     // Display onboarding payload
     chip::DeviceLayer::ConfigurationMgr().LogDeviceConfig();
diff --git a/examples/tv-casting-app/tv-casting-common/include/CastingServer.h b/examples/tv-casting-app/tv-casting-common/include/CastingServer.h
index b24fe0f..fd427af 100644
--- a/examples/tv-casting-app/tv-casting-common/include/CastingServer.h
+++ b/examples/tv-casting-app/tv-casting-common/include/CastingServer.h
@@ -22,6 +22,7 @@
 #include "ApplicationBasic.h"
 #include "ApplicationLauncher.h"
 #include "Channel.h"
+#include "CommissioningCallbacks.h"
 #include "ContentLauncher.h"
 #include "KeypadInput.h"
 #include "LevelControl.h"
@@ -33,6 +34,7 @@
 #include "TargetVideoPlayerInfo.h"
 
 #include <app-common/zap-generated/cluster-objects.h>
+#include <app/server/AppDelegate.h>
 #include <app/server/Server.h>
 #include <controller/CHIPCluster.h>
 #include <controller/CHIPCommissionableNodeController.h>
@@ -45,7 +47,7 @@
  *  and then have it send TV Casting/Media related commands. This is to be instantiated
  *  as a singleton and is to be used across Linux, Android and iOS.
  */
-class CastingServer
+class CastingServer : public AppDelegate
 {
 public:
     CastingServer(CastingServer & other) = delete;
@@ -55,11 +57,12 @@
     CHIP_ERROR PreInit(AppParams * AppParams = nullptr);
     CHIP_ERROR Init(AppParams * AppParams = nullptr);
     CHIP_ERROR InitBindingHandlers();
+    void InitAppDelegation();
 
     CHIP_ERROR DiscoverCommissioners(chip::Controller::DeviceDiscoveryDelegate * deviceDiscoveryDelegate = nullptr);
     const chip::Dnssd::DiscoveredNodeData *
     GetDiscoveredCommissioner(int index, chip::Optional<TargetVideoPlayerInfo *> & outAssociatedConnectableVideoPlayer);
-    CHIP_ERROR OpenBasicCommissioningWindow(std::function<void(CHIP_ERROR)> commissioningCompleteCallback,
+    CHIP_ERROR OpenBasicCommissioningWindow(CommissioningCallbacks commissioningCallbacks,
                                             std::function<void(TargetVideoPlayerInfo *)> onConnectionSuccess,
                                             std::function<void(CHIP_ERROR)> onConnectionFailure,
                                             std::function<void(TargetEndpointInfo *)> onNewOrUpdatedEndpoint);
@@ -429,6 +432,13 @@
     static void DeviceEventCallback(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg);
     void ReadServerClusters(chip::EndpointId endpointId);
 
+    void OnCommissioningSessionEstablishmentStarted() override;
+    void OnCommissioningSessionStarted() override;
+    void OnCommissioningSessionEstablishmentError(CHIP_ERROR err) override;
+    void OnCommissioningSessionStopped() override;
+    void OnCommissioningWindowOpened() override {}
+    void OnCommissioningWindowClosed() override {}
+
     /**
      * @brief Retrieve the IP Address to use for the UDC request.
      * This function will look for an IPv4 address in the list of IPAddresses passed in if available and return
@@ -456,7 +466,8 @@
     chip::Inet::IPAddress mTargetVideoPlayerIpAddress[chip::Dnssd::CommonResolutionData::kMaxIPAddresses];
 
     chip::Controller::CommissionableNodeController mCommissionableNodeController;
-    std::function<void(CHIP_ERROR)> mCommissioningCompleteCallback;
+
+    CommissioningCallbacks mCommissioningCallbacks;
 
     std::function<void(TargetEndpointInfo *)> mOnNewOrUpdatedEndpoint;
     std::function<void(TargetVideoPlayerInfo *)> mOnConnectionSuccessClientCallback;
diff --git a/examples/tv-casting-app/tv-casting-common/include/CommissioningCallbacks.h b/examples/tv-casting-app/tv-casting-common/include/CommissioningCallbacks.h
new file mode 100644
index 0000000..06d31eb
--- /dev/null
+++ b/examples/tv-casting-app/tv-casting-common/include/CommissioningCallbacks.h
@@ -0,0 +1,53 @@
+/*
+ *
+ *    Copyright (c) 2023 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.
+ */
+
+#pragma once
+
+struct CommissioningCallbacks
+{
+    /**
+     * This is called when the PBKDFParamRequest is received and indicates the start of the session establishment process
+     */
+    std::function<void()> sessionEstablishmentStarted = {};
+
+    /**
+     * This is called when the commissioning session has been established
+     */
+    std::function<void()> sessionEstablished = {};
+
+    /**
+     * This is called when the PASE establishment failed (such as, when an invalid passcode is provided) or PASE was established
+     * fine but then the fail-safe expired (including being expired by the commissioner)
+     *
+     * The CHIP_ERROR param indicates the error that occurred during session establishment or the error accompanying the fail-safe
+     * timeout.
+     */
+    std::function<void(CHIP_ERROR)> sessionEstablishmentError = {};
+
+    /**
+     * This is called when the PASE establishment failed or PASE was established fine but then the fail-safe expired (including
+     * being expired by the commissioner) AND the commissioning window is closed. The window may be closed because the commissioning
+     * attempts limit was reached or advertising/listening for PASE failed.
+     */
+    std::function<void()> sessionEstablishmentStopped = {};
+
+    /**
+     * This is called when the commissioning has been completed
+     */
+    std::function<void(CHIP_ERROR)> commissioningComplete = {};
+};
diff --git a/examples/tv-casting-app/tv-casting-common/include/TargetVideoPlayerInfo.h b/examples/tv-casting-app/tv-casting-common/include/TargetVideoPlayerInfo.h
index 076149f..bbc086a 100644
--- a/examples/tv-casting-app/tv-casting-common/include/TargetVideoPlayerInfo.h
+++ b/examples/tv-casting-app/tv-casting-common/include/TargetVideoPlayerInfo.h
@@ -110,7 +110,6 @@
     static void HandleDeviceConnected(void * context, chip::Messaging::ExchangeManager & exchangeMgr,
                                       const chip::SessionHandle & sessionHandle)
     {
-        ChipLogProgress(AppServer, "tmplog: HandleDeviceConnected called");
         VideoPlayerConnectionContext * connectionContext = static_cast<VideoPlayerConnectionContext *>(context);
         if (connectionContext == nullptr || connectionContext->mTargetVideoPlayerInfo == nullptr)
         {
diff --git a/examples/tv-casting-app/tv-casting-common/src/CastingServer.cpp b/examples/tv-casting-app/tv-casting-common/src/CastingServer.cpp
index 313a6dc..1d40cb5 100644
--- a/examples/tv-casting-app/tv-casting-common/src/CastingServer.cpp
+++ b/examples/tv-casting-app/tv-casting-common/src/CastingServer.cpp
@@ -54,6 +54,9 @@
         return CHIP_NO_ERROR;
     }
 
+    // Set CastingServer as AppDelegate
+    InitAppDelegation();
+
     // Initialize binding handlers
     ReturnErrorOnFailure(InitBindingHandlers());
 
@@ -67,6 +70,11 @@
     return CHIP_NO_ERROR;
 }
 
+void CastingServer::InitAppDelegation()
+{
+    chip::Server::Server::GetInstance().GetCommissioningWindowManager().SetAppDelegate(this);
+}
+
 CHIP_ERROR CastingServer::SetRotatingDeviceIdUniqueId(chip::Optional<chip::ByteSpan> rotatingDeviceIdUniqueIdOptional)
 {
 #if CHIP_ENABLE_ROTATING_DEVICE_ID
@@ -130,18 +138,55 @@
         Dnssd::DiscoveryFilter(Dnssd::DiscoveryFilterType::kDeviceType, static_cast<uint16_t>(35)));
 }
 
-CHIP_ERROR CastingServer::OpenBasicCommissioningWindow(std::function<void(CHIP_ERROR)> commissioningCompleteCallback,
+CHIP_ERROR CastingServer::OpenBasicCommissioningWindow(CommissioningCallbacks commissioningCallbacks,
                                                        std::function<void(TargetVideoPlayerInfo *)> onConnectionSuccess,
                                                        std::function<void(CHIP_ERROR)> onConnectionFailure,
                                                        std::function<void(TargetEndpointInfo *)> onNewOrUpdatedEndpoint)
 {
-    mCommissioningCompleteCallback     = commissioningCompleteCallback;
+    mCommissioningCallbacks            = commissioningCallbacks;
     mOnConnectionSuccessClientCallback = onConnectionSuccess;
     mOnConnectionFailureClientCallback = onConnectionFailure;
     mOnNewOrUpdatedEndpoint            = onNewOrUpdatedEndpoint;
     return Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow(kCommissioningWindowTimeout);
 }
 
+void CastingServer::OnCommissioningSessionStarted()
+{
+    ChipLogProgress(AppServer, "CastingServer::OnCommissioningSessionStarted");
+    if (mCommissioningCallbacks.sessionEstablished)
+    {
+
+        mCommissioningCallbacks.sessionEstablished();
+    }
+}
+
+void CastingServer::OnCommissioningSessionEstablishmentError(CHIP_ERROR err)
+{
+    ChipLogProgress(AppServer, "CastingServer::OnCommissioningSessionEstablishmentError");
+    if (mCommissioningCallbacks.sessionEstablishmentError)
+    {
+        mCommissioningCallbacks.sessionEstablishmentError(err);
+    }
+}
+
+void CastingServer::OnCommissioningSessionStopped()
+{
+    ChipLogProgress(AppServer, "CastingServer::OnCommissioningSessionStopped");
+    if (mCommissioningCallbacks.sessionEstablishmentStopped)
+    {
+        mCommissioningCallbacks.sessionEstablishmentStopped();
+    }
+}
+
+void CastingServer::OnCommissioningSessionEstablishmentStarted()
+{
+    ChipLogProgress(AppServer, "CastingServer::OnCommissioningSessionEstablishmentStarted");
+    if (mCommissioningCallbacks.sessionEstablishmentStarted)
+    {
+        mCommissioningCallbacks.sessionEstablishmentStarted();
+    }
+}
+
 #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
 CHIP_ERROR CastingServer::SendUserDirectedCommissioningRequest(chip::Transport::PeerAddress commissioner)
 {
@@ -433,7 +478,10 @@
             {
                 ChipLogError(AppServer, "CastingServer::DeviceEventCallback accessingFabricIndex: %d did not match bindings",
                              event->BindingsChanged.fabricIndex);
-                CastingServer::GetInstance()->mCommissioningCompleteCallback(CHIP_ERROR_INCORRECT_STATE);
+                if (CastingServer::GetInstance()->mCommissioningCallbacks.commissioningComplete)
+                {
+                    CastingServer::GetInstance()->mCommissioningCallbacks.commissioningComplete(CHIP_ERROR_INCORRECT_STATE);
+                }
                 return;
             }
         }
@@ -472,7 +520,10 @@
             ChipLogError(AppServer, "AddVideoPlayer(ToCache) error: %" CHIP_ERROR_FORMAT, err.Format());
         }
 
-        CastingServer::GetInstance()->mCommissioningCompleteCallback(err);
+        if (CastingServer::GetInstance()->mCommissioningCallbacks.commissioningComplete)
+        {
+            CastingServer::GetInstance()->mCommissioningCallbacks.commissioningComplete(err);
+        }
     }
 }