tv-casting-app: Synchronizing on the use of NsdManager.resolveService() (#23549)

* tv-casting-app: Synchronizing on the use of NsdManager.resolveService()

* Making AppParameters.discriminator private
diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissionerDiscoveryFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissionerDiscoveryFragment.java
index ddc6136..0fda34f 100644
--- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissionerDiscoveryFragment.java
+++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissionerDiscoveryFragment.java
@@ -1,8 +1,6 @@
 package com.chip.casting.app;
 
 import android.content.Context;
-import android.net.nsd.NsdManager;
-import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -69,8 +67,6 @@
     manualCommissioningButton.setOnClickListener(manualCommissioningButtonOnClickListener);
 
     Context context = this.getContext();
-    Context applicationContext = this.getContext().getApplicationContext();
-
     SuccessCallback<DiscoveredNodeData> successCallback =
         new SuccessCallback<DiscoveredNodeData>() {
           @Override
@@ -112,11 +108,7 @@
         };
 
     tvCastingApp.discoverVideoPlayerCommissioners(
-        (WifiManager) context.getSystemService(Context.WIFI_SERVICE),
-        (NsdManager) applicationContext.getSystemService(Context.NSD_SERVICE),
-        DISCOVERY_DURATION_SECS,
-        successCallback,
-        failureCallback);
+        DISCOVERY_DURATION_SECS, successCallback, failureCallback);
   }
 
   @VisibleForTesting
diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java
index 8581228..a9884bf 100644
--- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java
+++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java
@@ -6,15 +6,6 @@
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentTransaction;
-import chip.appserver.ChipAppServer;
-import chip.platform.AndroidBleManager;
-import chip.platform.AndroidChipPlatform;
-import chip.platform.ChipMdnsCallbackImpl;
-import chip.platform.DiagnosticDataProviderImpl;
-import chip.platform.NsdManagerServiceBrowser;
-import chip.platform.NsdManagerServiceResolver;
-import chip.platform.PreferencesConfigurationManager;
-import chip.platform.PreferencesKeyValueStoreManager;
 import com.chip.casting.AppParameters;
 import com.chip.casting.DACProviderStub;
 import com.chip.casting.DiscoveredNodeData;
@@ -29,7 +20,6 @@
 
   private static final String TAG = MainActivity.class.getSimpleName();
 
-  private ChipAppServer chipAppServer;
   private TvCastingApp tvCastingApp;
 
   @Override
@@ -79,30 +69,17 @@
   private void initJni() {
     tvCastingApp = new TvCastingApp();
 
-    tvCastingApp.setDACProvider(new DACProviderStub());
     Context applicationContext = this.getApplicationContext();
-    AndroidChipPlatform chipPlatform =
-        new AndroidChipPlatform(
-            new AndroidBleManager(),
-            new PreferencesKeyValueStoreManager(applicationContext),
-            new PreferencesConfigurationManager(applicationContext),
-            new NsdManagerServiceResolver(applicationContext),
-            new NsdManagerServiceBrowser(applicationContext),
-            new ChipMdnsCallbackImpl(),
-            new DiagnosticDataProviderImpl(applicationContext));
-
-    chipPlatform.updateCommissionableDataProviderData(
-        null, null, 0, GlobalCastingConstants.SetupPasscode, GlobalCastingConstants.Discriminator);
-
-    chipAppServer = new ChipAppServer();
-    chipAppServer.startApp();
 
     AppParameters appParameters = new AppParameters();
     byte[] rotatingDeviceIdUniqueId =
         new byte[AppParameters.MIN_ROTATING_DEVICE_ID_UNIQUE_ID_LENGTH];
     new Random().nextBytes(rotatingDeviceIdUniqueId);
     appParameters.setRotatingDeviceIdUniqueId(rotatingDeviceIdUniqueId);
-    tvCastingApp.init(appParameters);
+    appParameters.setDacProvider(new DACProviderStub());
+    appParameters.setSetupPasscode(GlobalCastingConstants.SetupPasscode);
+    appParameters.setDiscriminator(GlobalCastingConstants.Discriminator);
+    tvCastingApp.initApp(applicationContext, appParameters);
   }
 
   private void showFragment(Fragment fragment, boolean showOnBack) {
diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/util/GlobalCastingConstants.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/util/GlobalCastingConstants.java
index ef9dd8e..4bd6d25 100644
--- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/util/GlobalCastingConstants.java
+++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/util/GlobalCastingConstants.java
@@ -1,12 +1,8 @@
 package com.chip.casting.util;
 
-import java.util.Arrays;
-import java.util.List;
-
 public class GlobalCastingConstants {
   public static final String CommissionerServiceType = "_matterd._udp.";
   public static final int CommissioningWindowDurationSecs = 3 * 60;
-  public static int SetupPasscode = 20202021;
-  public static int Discriminator = 0xF00;
-  public static List<Long> CommissionerDeviceTypeFilter = Arrays.asList(35L); // Video player = 35
+  public static final int SetupPasscode = 20202021;
+  public static final int Discriminator = 0xF00;
 }
diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/AppParameters.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/AppParameters.java
index ffca2ac..a98f9d8 100644
--- a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/AppParameters.java
+++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/AppParameters.java
@@ -19,8 +19,14 @@
 
 public class AppParameters {
   public static final int MIN_ROTATING_DEVICE_ID_UNIQUE_ID_LENGTH = 16;
+  private static final int TEST_SETUP_PASSCODE = 20202021;
+  private static final int TEST_DISCRIMINATOR = 0xF00;
+  private DACProvider TEST_DAC_PROVIDER = new DACProviderStub();
 
   private byte[] rotatingDeviceIdUniqueId;
+  private DACProvider dacProvider = TEST_DAC_PROVIDER;
+  private int setupPasscode = TEST_SETUP_PASSCODE;
+  private int discriminator = TEST_DISCRIMINATOR;
 
   public void setRotatingDeviceIdUniqueId(byte[] rotatingDeviceIdUniqueId) {
     this.rotatingDeviceIdUniqueId = rotatingDeviceIdUniqueId;
@@ -29,4 +35,28 @@
   public byte[] getRotatingDeviceIdUniqueId() {
     return rotatingDeviceIdUniqueId;
   }
+
+  public DACProvider getDacProvider() {
+    return dacProvider;
+  }
+
+  public void setDacProvider(DACProvider dacProvider) {
+    this.dacProvider = dacProvider;
+  }
+
+  public int getSetupPasscode() {
+    return setupPasscode;
+  }
+
+  public void setSetupPasscode(int setupPasscode) {
+    this.setupPasscode = setupPasscode;
+  }
+
+  public int getDiscriminator() {
+    return discriminator;
+  }
+
+  public void setDiscriminator(int discriminator) {
+    this.discriminator = discriminator;
+  }
 }
diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdDiscoveryListener.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdDiscoveryListener.java
index 5a0f485..e58f639 100644
--- a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdDiscoveryListener.java
+++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdDiscoveryListener.java
@@ -20,6 +20,7 @@
 import android.net.nsd.NsdManager;
 import android.net.nsd.NsdServiceInfo;
 import android.util.Log;
+import chip.platform.NsdManagerServiceResolver;
 import java.util.List;
 
 public class NsdDiscoveryListener implements NsdManager.DiscoveryListener {
@@ -31,6 +32,7 @@
   private final List<VideoPlayer> preCommissionedVideoPlayers;
   private final SuccessCallback<DiscoveredNodeData> successCallback;
   private final FailureCallback failureCallback;
+  private final NsdManagerServiceResolver.NsdManagerResolverAvailState nsdManagerResolverAvailState;
 
   public NsdDiscoveryListener(
       NsdManager nsdManager,
@@ -38,13 +40,15 @@
       List<Long> deviceTypeFilter,
       List<VideoPlayer> preCommissionedVideoPlayers,
       SuccessCallback<DiscoveredNodeData> successCallback,
-      FailureCallback failureCallback) {
+      FailureCallback failureCallback,
+      NsdManagerServiceResolver.NsdManagerResolverAvailState nsdManagerResolverAvailState) {
     this.nsdManager = nsdManager;
     this.targetServiceType = targetServiceType;
     this.deviceTypeFilter = deviceTypeFilter;
     this.preCommissionedVideoPlayers = preCommissionedVideoPlayers;
     this.successCallback = successCallback;
     this.failureCallback = failureCallback;
+    this.nsdManagerResolverAvailState = nsdManagerResolverAvailState;
   }
 
   @Override
@@ -56,6 +60,9 @@
   public void onServiceFound(NsdServiceInfo service) {
     Log.d(TAG, "Service discovery success. " + service);
     if (service.getServiceType().equals(targetServiceType)) {
+      if (nsdManagerResolverAvailState != null) {
+        nsdManagerResolverAvailState.acquireResolver();
+      }
       nsdManager.resolveService(
           service,
           new NsdResolveListener(
@@ -63,7 +70,8 @@
               deviceTypeFilter,
               preCommissionedVideoPlayers,
               successCallback,
-              failureCallback));
+              failureCallback,
+              nsdManagerResolverAvailState));
     } else {
       Log.d(TAG, "Ignoring discovered service: " + service.toString());
     }
@@ -79,6 +87,9 @@
   @Override
   public void onDiscoveryStopped(String serviceType) {
     Log.i(TAG, "Discovery stopped: " + serviceType);
+    if (nsdManagerResolverAvailState != null) {
+      nsdManagerResolverAvailState.signalFree();
+    }
   }
 
   @Override
@@ -93,6 +104,9 @@
   @Override
   public void onStopDiscoveryFailed(String serviceType, int errorCode) {
     Log.e(TAG, "Discovery failed to stop: Error code:" + errorCode);
+    if (nsdManagerResolverAvailState != null) {
+      nsdManagerResolverAvailState.signalFree();
+    }
     failureCallback.handle(
         new MatterError(
             3, "NsdDiscoveryListener Discovery failed to stop: Nsd Error code:" + errorCode));
diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdResolveListener.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdResolveListener.java
index 55de022..3232ed8 100644
--- a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdResolveListener.java
+++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdResolveListener.java
@@ -20,6 +20,7 @@
 import android.net.nsd.NsdManager;
 import android.net.nsd.NsdServiceInfo;
 import android.util.Log;
+import chip.platform.NsdManagerServiceResolver;
 import java.util.List;
 
 public class NsdResolveListener implements NsdManager.ResolveListener {
@@ -31,13 +32,15 @@
   private final List<VideoPlayer> preCommissionedVideoPlayers;
   private final SuccessCallback<DiscoveredNodeData> successCallback;
   private final FailureCallback failureCallback;
+  private final NsdManagerServiceResolver.NsdManagerResolverAvailState nsdManagerResolverAvailState;
 
   public NsdResolveListener(
       NsdManager nsdManager,
       List<Long> deviceTypeFilter,
       List<VideoPlayer> preCommissionedVideoPlayers,
       SuccessCallback<DiscoveredNodeData> successCallback,
-      FailureCallback failureCallback) {
+      FailureCallback failureCallback,
+      NsdManagerServiceResolver.NsdManagerResolverAvailState nsdManagerResolverAvailState) {
     this.nsdManager = nsdManager;
     this.deviceTypeFilter = deviceTypeFilter;
     this.preCommissionedVideoPlayers = preCommissionedVideoPlayers;
@@ -48,6 +51,7 @@
     }
     this.successCallback = successCallback;
     this.failureCallback = failureCallback;
+    this.nsdManagerResolverAvailState = nsdManagerResolverAvailState;
   }
 
   @Override
@@ -55,6 +59,10 @@
     DiscoveredNodeData discoveredNodeData = new DiscoveredNodeData(serviceInfo);
     Log.d(TAG, "DiscoveredNodeData resolved: " + discoveredNodeData);
 
+    if (nsdManagerResolverAvailState != null) {
+      nsdManagerResolverAvailState.signalFree();
+    }
+
     if (isPassingDeviceTypeFilter(discoveredNodeData)) {
       addCommissioningInfo(discoveredNodeData);
       successCallback.handle(discoveredNodeData);
@@ -68,6 +76,10 @@
 
   @Override
   public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
+    if (nsdManagerResolverAvailState != null) {
+      nsdManagerResolverAvailState.signalFree();
+    }
+
     switch (errorCode) {
       case NsdManager.FAILURE_ALREADY_ACTIVE:
         Log.e(TAG, "NsdResolveListener FAILURE_ALREADY_ACTIVE - Service: " + serviceInfo);
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 65cd2cb..b099483 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
@@ -17,10 +17,19 @@
  */
 package com.chip.casting;
 
+import android.content.Context;
 import android.net.nsd.NsdManager;
 import android.net.wifi.WifiManager;
 import android.util.Log;
-import java.util.ArrayList;
+import chip.appserver.ChipAppServer;
+import chip.platform.AndroidBleManager;
+import chip.platform.AndroidChipPlatform;
+import chip.platform.ChipMdnsCallbackImpl;
+import chip.platform.DiagnosticDataProviderImpl;
+import chip.platform.NsdManagerServiceBrowser;
+import chip.platform.NsdManagerServiceResolver;
+import chip.platform.PreferencesConfigurationManager;
+import chip.platform.PreferencesKeyValueStoreManager;
 import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.Executors;
@@ -28,38 +37,71 @@
 
 public class TvCastingApp {
   private static final String TAG = TvCastingApp.class.getSimpleName();
+  private static final String DISCOVERY_TARGET_SERVICE_TYPE = "_matterd._udp.";
+  private static final List<Long> DISCOVERY_TARGET_DEVICE_TYPE_FILTER =
+      Arrays.asList(35L); // Video player = 35;
 
-  private final String TARGET_SERVICE_TYPE = "_matterd._udp.";
-  private final List<Long> DEVICE_TYPE_FILTER = Arrays.asList(35L); // Video player = 35;
+  private Context applicationContext;
+  private ChipAppServer chipAppServer;
+  private NsdManagerServiceResolver.NsdManagerResolverAvailState nsdManagerResolverAvailState;
 
-  public native boolean init(AppParameters appParameters);
+  public boolean initApp(Context applicationContext, AppParameters appParameters) {
+    this.applicationContext = applicationContext;
+    nsdManagerResolverAvailState = new NsdManagerServiceResolver.NsdManagerResolverAvailState();
+    NsdManagerServiceResolver nsdManagerServiceResolver =
+        new NsdManagerServiceResolver(applicationContext, nsdManagerResolverAvailState);
 
-  public native void setDACProvider(DACProvider provider);
+    AndroidChipPlatform chipPlatform =
+        new AndroidChipPlatform(
+            new AndroidBleManager(),
+            new PreferencesKeyValueStoreManager(applicationContext),
+            new PreferencesConfigurationManager(applicationContext),
+            nsdManagerServiceResolver,
+            new NsdManagerServiceBrowser(applicationContext),
+            new ChipMdnsCallbackImpl(),
+            new DiagnosticDataProviderImpl(applicationContext));
+
+    chipPlatform.updateCommissionableDataProviderData(
+        null, null, 0, appParameters.getSetupPasscode(), appParameters.getDiscriminator());
+
+    chipAppServer = new ChipAppServer();
+    chipAppServer.startApp();
+
+    setDACProvider(appParameters.getDacProvider());
+    return initJni(appParameters);
+  }
+
+  private native void setDACProvider(DACProvider provider);
+
+  private native boolean initJni(AppParameters appParameters);
 
   public void discoverVideoPlayerCommissioners(
-      WifiManager wifiManager,
-      NsdManager nsdManager,
       long discoveryDurationSeconds,
       SuccessCallback<DiscoveredNodeData> discoverySuccessCallback,
       FailureCallback discoveryFailureCallback) {
     Log.d(TAG, "TvCastingApp.discoverVideoPlayerCommissioners called");
+
+    List<VideoPlayer> preCommissionedVideoPlayers = readCachedVideoPlayers();
+
+    WifiManager wifiManager =
+        (WifiManager) applicationContext.getSystemService(Context.WIFI_SERVICE);
     WifiManager.MulticastLock multicastLock = wifiManager.createMulticastLock("multicastLock");
     multicastLock.setReferenceCounted(true);
     multicastLock.acquire();
 
-    List<VideoPlayer> preCommissionedVideoPlayers = readCachedVideoPlayers();
-
+    NsdManager nsdManager = (NsdManager) applicationContext.getSystemService(Context.NSD_SERVICE);
     NsdDiscoveryListener nsdDiscoveryListener =
         new NsdDiscoveryListener(
             nsdManager,
-            TARGET_SERVICE_TYPE,
-            DEVICE_TYPE_FILTER,
+            DISCOVERY_TARGET_SERVICE_TYPE,
+            DISCOVERY_TARGET_DEVICE_TYPE_FILTER,
             preCommissionedVideoPlayers,
             discoverySuccessCallback,
-            discoveryFailureCallback);
+            discoveryFailureCallback,
+            nsdManagerResolverAvailState);
 
     nsdManager.discoverServices(
-        TARGET_SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, nsdDiscoveryListener);
+        DISCOVERY_TARGET_SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, nsdDiscoveryListener);
 
     Executors.newSingleThreadScheduledExecutor()
         .schedule(
@@ -85,7 +127,8 @@
 
   public native boolean sendCommissioningRequest(DiscoveredNodeData commissioner);
 
-  public native boolean sendUserDirectedCommissioningRequest(String address, int port);
+  /** @Deprecated Use sendCommissioningRequest(DiscoveredNodeData) instead */
+  private native boolean sendUserDirectedCommissioningRequest(String address, int port);
 
   public native List<VideoPlayer> readCachedVideoPlayers();
 
@@ -268,7 +311,7 @@
 
   public native boolean targetNavigator_subscribeToTargetList(
       ContentApp contentApp,
-      SuccessCallback<ArrayList<TargetNavigatorTypes.TargetInfo>> readSuccessHandler,
+      SuccessCallback<Object> readSuccessHandler,
       FailureCallback readFailureHandler,
       int minInterval,
       int maxInterval,
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 3261aa6..b37b9ec 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
@@ -181,7 +181,7 @@
     : public SuccessHandlerJNI<chip::app::Clusters::TargetNavigator::Attributes::TargetList::TypeInfo::DecodableArgType>
 {
 public:
-    TargetListSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/util/ArrayList;)V") {}
+    TargetListSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Object;)V") {}
     jobject ConvertToJObject(chip::app::Clusters::TargetNavigator::Attributes::TargetList::TypeInfo::DecodableArgType responseData);
 };
 
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 04c1196..c58df8f 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
@@ -52,10 +52,10 @@
     return AndroidAppServerJNI_OnUnload(jvm, reserved);
 }
 
-JNI_METHOD(jboolean, init)(JNIEnv *, jobject, jobject jAppParameters)
+JNI_METHOD(jboolean, initJni)(JNIEnv *, jobject, jobject jAppParameters)
 {
     chip::DeviceLayer::StackLock lock;
-    ChipLogProgress(AppServer, "JNI_METHOD init called");
+    ChipLogProgress(AppServer, "JNI_METHOD initJni called");
 
     CHIP_ERROR err = CHIP_NO_ERROR;
     if (jAppParameters == nullptr)
diff --git a/examples/tv-casting-app/android/BUILD.gn b/examples/tv-casting-app/android/BUILD.gn
index 0e29821..033ff3a 100644
--- a/examples/tv-casting-app/android/BUILD.gn
+++ b/examples/tv-casting-app/android/BUILD.gn
@@ -53,6 +53,8 @@
 
   deps = [
     ":android",
+    "${chip_root}/src/app/server/java",
+    "${chip_root}/src/platform/android:java",
     "${chip_root}/third_party/android_deps:annotation",
   ]
 
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h
index 0838333..8c8f8c8 100644
--- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h
@@ -480,7 +480,7 @@
  @param requestSentHandler Handler to call on sending the request
  */
 - (void)mediaPlayback_seek:(ContentApp * _Nonnull)contentApp
-                  position:(uint8_t)position
+                  position:(uint64_t)position
           responseCallback:(void (^_Nonnull)(bool))responseCallback
                clientQueue:(dispatch_queue_t _Nonnull)clientQueue
         requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler;
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm
index d9e36da..9ba421b 100644
--- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm
@@ -124,6 +124,8 @@
         _subscriptionEstablishedCallbacks = [NSMutableDictionary dictionary];
         _subscriptionReadSuccessCallbacks = [NSMutableDictionary dictionary];
         _subscriptionReadFailureCallbacks = [NSMutableDictionary dictionary];
+        _readSuccessCallbacks = [NSMutableDictionary dictionary];
+        _readFailureCallbacks = [NSMutableDictionary dictionary];
 
         chip::DeviceLayer::PlatformMgrImpl().StartEventLoopTask();
     }
@@ -139,9 +141,14 @@
     dispatch_async(_chipWorkQueue, ^{
         bool initAppStatus = true;
 
+        CHIP_ERROR err = CHIP_NO_ERROR;
         AppParams appParams;
+        if (appParameters == nil) {
+            err = CastingServer::GetInstance()->Init();
+        } else if ((err = [ConversionUtils convertToCppAppParamsInfoFrom:appParameters outAppParams:appParams]) == CHIP_NO_ERROR) {
+            err = CastingServer::GetInstance()->Init(&appParams);
+        }
 
-        CHIP_ERROR err = CastingServer::GetInstance()->Init();
         if (err != CHIP_NO_ERROR) {
             ChipLogError(AppServer, "CastingServerBridge().initApp() failed: %" CHIP_ERROR_FORMAT, err.Format());
             initAppStatus = false;
@@ -151,8 +158,6 @@
             initAppStatusHandler(initAppStatus);
         });
     });
-
-    CastingServer::GetInstance()->Init();
 }
 
 - (void)discoverCommissioners:(dispatch_queue_t _Nonnull)clientQueue
@@ -870,7 +875,7 @@
 }
 
 - (void)mediaPlayback_seek:(ContentApp * _Nonnull)contentApp
-                  position:(uint8_t)position
+                  position:(uint64_t)position
           responseCallback:(void (^_Nonnull)(bool))responseCallback
                clientQueue:(dispatch_queue_t _Nonnull)clientQueue
         requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler
@@ -1571,7 +1576,7 @@
                 chip::app::Clusters::ApplicationBasic::Attributes::VendorName::TypeInfo::DecodableArgType vendorName) {
                 void (^callback)(NSString * _Nonnull) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks
                     objectForKey:@"applicationBasic_subscribeVendorName"];
-                callback([NSString stringWithUTF8String:vendorName.data()]);
+                callback(vendorName.data() != nil ? [NSString stringWithUTF8String:vendorName.data()] : nil);
             },
             [](void * context, CHIP_ERROR err) {
                 void (^callback)(MatterError *) = [[CastingServerBridge getSharedInstance].subscriptionReadFailureCallbacks
@@ -1800,13 +1805,13 @@
             &endpoint, nullptr,
             [](void * context,
                 chip::app::Clusters::ApplicationBasic::Attributes::VendorName::TypeInfo::DecodableArgType vendorName) {
-                void (^callback)(NSString * _Nonnull) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks
-                    objectForKey:@"applicationBasic_readVendorName"];
+                void (^callback)(NSString * _Nonnull) =
+                    [[CastingServerBridge getSharedInstance].readSuccessCallbacks objectForKey:@"applicationBasic_readVendorName"];
                 callback([NSString stringWithUTF8String:vendorName.data()]);
             },
             [](void * context, CHIP_ERROR err) {
-                void (^callback)(MatterError *) = [[CastingServerBridge getSharedInstance].subscriptionReadFailureCallbacks
-                    objectForKey:@"applicationBasic_readVendorName"];
+                void (^callback)(MatterError *) =
+                    [[CastingServerBridge getSharedInstance].readFailureCallbacks objectForKey:@"applicationBasic_readVendorName"];
                 callback([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]);
             });
         dispatch_async(clientQueue, ^{
@@ -1835,13 +1840,13 @@
         CHIP_ERROR err = CastingServer::GetInstance()->ApplicationBasic_ReadVendorID(
             &endpoint, nullptr,
             [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::VendorID::TypeInfo::DecodableArgType vendorID) {
-                void (^callback)(NSNumber * _Nonnull) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks
-                    objectForKey:@"applicationBasic_readVendorID"];
+                void (^callback)(NSNumber * _Nonnull) =
+                    [[CastingServerBridge getSharedInstance].readSuccessCallbacks objectForKey:@"applicationBasic_readVendorID"];
                 callback(@(vendorID));
             },
             [](void * context, CHIP_ERROR err) {
-                void (^callback)(MatterError *) = [[CastingServerBridge getSharedInstance].subscriptionReadFailureCallbacks
-                    objectForKey:@"applicationBasic_readVendorID"];
+                void (^callback)(MatterError *) =
+                    [[CastingServerBridge getSharedInstance].readFailureCallbacks objectForKey:@"applicationBasic_readVendorID"];
                 callback([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]);
             });
         dispatch_async(clientQueue, ^{
@@ -1872,12 +1877,12 @@
             &endpoint, nullptr,
             [](void * context,
                 chip::app::Clusters::ApplicationBasic::Attributes::ApplicationName::TypeInfo::DecodableArgType applicationName) {
-                void (^callback)(NSString * _Nonnull) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks
+                void (^callback)(NSString * _Nonnull) = [[CastingServerBridge getSharedInstance].readSuccessCallbacks
                     objectForKey:@"applicationBasic_readApplicationName"];
                 callback([NSString stringWithUTF8String:applicationName.data()]);
             },
             [](void * context, CHIP_ERROR err) {
-                void (^callback)(MatterError *) = [[CastingServerBridge getSharedInstance].subscriptionReadFailureCallbacks
+                void (^callback)(MatterError *) = [[CastingServerBridge getSharedInstance].readFailureCallbacks
                     objectForKey:@"applicationBasic_readApplicationName"];
                 callback([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]);
             });
@@ -1907,13 +1912,13 @@
         CHIP_ERROR err = CastingServer::GetInstance()->ApplicationBasic_ReadProductID(
             &endpoint, nullptr,
             [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::ProductID::TypeInfo::DecodableArgType productID) {
-                void (^callback)(uint16_t) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks
-                    objectForKey:@"applicationBasic_readProductID"];
+                void (^callback)(uint16_t) =
+                    [[CastingServerBridge getSharedInstance].readSuccessCallbacks objectForKey:@"applicationBasic_readProductID"];
                 callback(productID);
             },
             [](void * context, CHIP_ERROR err) {
-                void (^callback)(MatterError *) = [[CastingServerBridge getSharedInstance].subscriptionReadFailureCallbacks
-                    objectForKey:@"applicationBasic_readProductID"];
+                void (^callback)(MatterError *) =
+                    [[CastingServerBridge getSharedInstance].readFailureCallbacks objectForKey:@"applicationBasic_readProductID"];
                 callback([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]);
             });
         dispatch_async(clientQueue, ^{
@@ -1945,12 +1950,12 @@
             [](void * context,
                 chip::app::Clusters::ApplicationBasic::Attributes::ApplicationVersion::TypeInfo::DecodableArgType
                     applicationVersion) {
-                void (^callback)(NSString * _Nonnull) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks
+                void (^callback)(NSString * _Nonnull) = [[CastingServerBridge getSharedInstance].readSuccessCallbacks
                     objectForKey:@"applicationBasic_readApplicationVersion"];
                 callback([NSString stringWithUTF8String:applicationVersion.data()]);
             },
             [](void * context, CHIP_ERROR err) {
-                void (^callback)(MatterError *) = [[CastingServerBridge getSharedInstance].subscriptionReadFailureCallbacks
+                void (^callback)(MatterError *) = [[CastingServerBridge getSharedInstance].readFailureCallbacks
                     objectForKey:@"applicationBasic_readApplicationVersion"];
                 callback([[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]);
             });