From 96b7ab3cef6803cd5b962671e826def7e0f26d75 Mon Sep 17 00:00:00 2001 From: Sharad Binjola <31142146+sharadb-amazon@users.noreply.github.com> Date: Mon, 17 Oct 2022 08:40:47 -0700 Subject: [PATCH] Linux/iOS/Android tv-casting-apps: Cache/recall/re-target previously connected VideoPlayers/Endpoints (#23181) * Linux/tv-casting-app: Cache/recall/re-target previously connected VideoPlayers/Endpoints * iOS/TvCasting app: Cache/recall/re-target previously connected VideoPlayers/Endpoints * Build fixes * Android TvCasting app: Cache/recall/re-target previously connected VideoPlayers/Endpoints --- .../com/chip/casting/app/CastingContext.java | 6 - .../app/CommissionerDiscoveryFragment.java | 122 ++-- .../casting/app/CommissioningFragment.java | 32 +- .../casting/app/ContentLauncherFragment.java | 4 + .../com/chip/casting/app/MainActivity.java | 4 +- .../casting/app/MediaPlaybackFragment.java | 4 + .../dnssd/CommissionerDiscoveryListener.java | 62 -- .../dnssd/CommissionerResolveListener.java | 100 --- .../main/jni/com/chip/casting/ContentApp.java | 63 ++ .../com/chip/casting}/DiscoveredNodeData.java | 19 +- .../chip/casting/NsdDiscoveryListener.java | 93 +++ .../com/chip/casting/NsdResolveListener.java | 88 +++ .../jni/com/chip/casting/TvCastingApp.java | 118 +++- .../jni/com/chip/casting/VideoPlayer.java | 121 ++++ .../app/src/main/jni/cpp/ConversionUtils.cpp | 287 +++++++++ .../app/src/main/jni/cpp/ConversionUtils.h | 33 + .../jni/cpp/MatterCallbackHandler-JNI.cpp | 28 +- .../main/jni/cpp/MatterCallbackHandler-JNI.h | 20 + .../app/src/main/jni/cpp/TvCastingApp-JNI.cpp | 583 ++++++++++++++---- .../app/src/main/jni/cpp/TvCastingApp-JNI.h | 21 + .../App/app/src/main/res/values/strings.xml | 7 +- examples/tv-casting-app/android/BUILD.gn | 7 + .../project.pbxproj | 28 +- .../CastingServerBridge.h | 314 +++++++--- .../CastingServerBridge.mm | 580 +++++++++++++---- ...eredNodeDataConverter.hpp => ContentApp.h} | 32 +- .../MatterTvCastingBridge/ContentApp.mm | 80 +++ .../MatterTvCastingBridge/ConversionUtils.hpp | 56 ++ .../MatterTvCastingBridge/ConversionUtils.mm | 149 +++++ .../DiscoveredNodeDataConverter.mm | 58 -- .../MatterTvCastingBridge/VideoPlayer.h | 61 ++ .../MatterTvCastingBridge/VideoPlayer.m | 59 ++ .../TvCasting.xcodeproj/project.pbxproj | 40 +- .../TvCasting/CommissionerDiscoveryView.swift | 4 +- .../TvCasting/CommissioningView.swift | 32 +- .../TvCasting/CommissioningViewModel.swift | 43 +- .../TvCasting/TvCasting/ConnectionView.swift | 78 +++ .../TvCasting/ConnectionViewModel.swift | 63 ++ .../TvCasting/ContentLauncherView.swift | 93 ++- .../TvCasting/ContentLauncherViewModel.swift | 46 +- .../TvCasting/TvCasting/ContentView.swift | 3 +- .../TvCasting/MediaPlaybackView.swift | 105 ++++ .../TvCasting/MediaPlaybackViewModel.swift | 120 ++++ .../TvCasting/TvCasting/MediaPlayerView.swift | 76 --- .../TvCasting/MediaPlayerViewModel.swift | 77 --- .../TvCasting/StartFromCacheView.swift | 74 +++ .../TvCasting/StartFromCacheViewModel.swift | 38 ++ .../linux/CastingShellCommands.cpp | 9 +- .../tv-casting-app/linux/CastingUtils.cpp | 119 +++- examples/tv-casting-app/linux/CastingUtils.h | 10 + examples/tv-casting-app/linux/main.cpp | 24 +- .../tv-casting-app/tv-casting-common/BUILD.gn | 2 + .../tv-casting-common/include/CastingServer.h | 150 +++-- .../tv-casting-common/include/MediaBase.h | 5 +- .../include/PersistenceManager.h | 59 ++ .../include/TargetEndpointInfo.h | 4 +- .../include/TargetVideoPlayerInfo.h | 49 +- .../tv-casting-common/src/CastingServer.cpp | 320 +++++++--- .../src/PersistenceManager.cpp | 322 ++++++++++ .../src/TargetEndpointInfo.cpp | 5 + .../src/TargetVideoPlayerInfo.cpp | 47 +- 61 files changed, 4184 insertions(+), 1072 deletions(-) delete mode 100644 examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/dnssd/CommissionerDiscoveryListener.java delete mode 100644 examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/dnssd/CommissionerResolveListener.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/ContentApp.java rename examples/tv-casting-app/android/App/app/src/main/{java/com/chip/casting/dnssd => jni/com/chip/casting}/DiscoveredNodeData.java (84%) create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdDiscoveryListener.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdResolveListener.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/VideoPlayer.java create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/cpp/ConversionUtils.cpp create mode 100644 examples/tv-casting-app/android/App/app/src/main/jni/cpp/ConversionUtils.h rename examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/{DiscoveredNodeDataConverter.hpp => ContentApp.h} (53%) create mode 100644 examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/ContentApp.mm create mode 100644 examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/ConversionUtils.hpp create mode 100644 examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/ConversionUtils.mm delete mode 100644 examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DiscoveredNodeDataConverter.mm create mode 100644 examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/VideoPlayer.h create mode 100644 examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/VideoPlayer.m create mode 100644 examples/tv-casting-app/darwin/TvCasting/TvCasting/ConnectionView.swift create mode 100644 examples/tv-casting-app/darwin/TvCasting/TvCasting/ConnectionViewModel.swift create mode 100644 examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlaybackView.swift create mode 100644 examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlaybackViewModel.swift delete mode 100644 examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlayerView.swift delete mode 100644 examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlayerViewModel.swift create mode 100644 examples/tv-casting-app/darwin/TvCasting/TvCasting/StartFromCacheView.swift create mode 100644 examples/tv-casting-app/darwin/TvCasting/TvCasting/StartFromCacheViewModel.swift create mode 100644 examples/tv-casting-app/tv-casting-common/include/PersistenceManager.h create mode 100644 examples/tv-casting-app/tv-casting-common/src/PersistenceManager.cpp diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CastingContext.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CastingContext.java index 400a2541e3cbd3..2ad1d29faf4382 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CastingContext.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CastingContext.java @@ -1,7 +1,6 @@ package com.chip.casting.app; import android.content.Context; -import android.net.nsd.NsdManager; import android.widget.LinearLayout; import androidx.fragment.app.FragmentActivity; @@ -20,11 +19,6 @@ public FragmentActivity getFragmentActivity() { return fragmentActivity; } - public NsdManager getNsdManager() { - return (NsdManager) - fragmentActivity.getApplicationContext().getSystemService(Context.NSD_SERVICE); - } - public LinearLayout getCommissionersLayout() { return (LinearLayout) fragmentActivity.findViewById(R.id.castingCommissioners); } 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 428867f35f497a..dc491e58b59170 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 @@ -4,24 +4,32 @@ import android.net.nsd.NsdManager; import android.net.wifi.WifiManager; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; +import android.widget.LinearLayout; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; -import com.chip.casting.dnssd.CommissionerDiscoveryListener; -import com.chip.casting.dnssd.DiscoveredNodeData; -import com.chip.casting.util.GlobalCastingConstants; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import com.chip.casting.DiscoveredNodeData; +import com.chip.casting.FailureCallback; +import com.chip.casting.MatterError; +import com.chip.casting.SuccessCallback; +import com.chip.casting.TvCastingApp; /** A {@link Fragment} to discover commissioners on the network */ public class CommissionerDiscoveryFragment extends Fragment { private static final String TAG = CommissionerDiscoveryFragment.class.getSimpleName(); + private static final long DISCOVERY_DURATION_SECS = 10; + private final TvCastingApp tvCastingApp; - public CommissionerDiscoveryFragment() {} + public CommissionerDiscoveryFragment(TvCastingApp tvCastingApp) { + this.tvCastingApp = tvCastingApp; + } /** * Use this factory method to create a new instance of this fragment using the provided @@ -29,14 +37,13 @@ public CommissionerDiscoveryFragment() {} * * @return A new instance of fragment CommissionerDiscoveryFragment. */ - public static CommissionerDiscoveryFragment newInstance() { - return new CommissionerDiscoveryFragment(); + public static CommissionerDiscoveryFragment newInstance(TvCastingApp tvCastingApp) { + return new CommissionerDiscoveryFragment(tvCastingApp); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - startCommissionerDiscovery(); } @Override @@ -49,47 +56,84 @@ public View onCreateView( @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + Button manualCommissioningButton = getView().findViewById(R.id.manualCommissioningButton); Callback callback = (Callback) this.getActivity(); - manualCommissioningButton.setOnClickListener( + View.OnClickListener manualCommissioningButtonOnClickListener = new View.OnClickListener() { @Override public void onClick(View v) { callback.handleCommissioningButtonClicked(null); } - }); - } + }; + manualCommissioningButton.setOnClickListener(manualCommissioningButtonOnClickListener); + + Context context = this.getContext(); + Context applicationContext = this.getContext().getApplicationContext(); + + SuccessCallback successCallback = + new SuccessCallback() { + @Override + public void handle(DiscoveredNodeData discoveredNodeData) { + Log.d(TAG, "Discovered a Video Player Commissioner: " + discoveredNodeData); + String buttonText = getCommissionerButtonText(discoveredNodeData); - private void startCommissionerDiscovery() { - Log.d(TAG, "CommissionerDiscoveryFragment.startCommissionerDiscovery called"); - WifiManager wifi = (WifiManager) this.getContext().getSystemService(Context.WIFI_SERVICE); - WifiManager.MulticastLock multicastLock = wifi.createMulticastLock("multicastLock"); - multicastLock.setReferenceCounted(true); - multicastLock.acquire(); + if (!buttonText.isEmpty()) { + Button commissionerButton = new Button(context); + commissionerButton.setText(buttonText); + CommissionerDiscoveryFragment.Callback callback = + (CommissionerDiscoveryFragment.Callback) getActivity(); + commissionerButton.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + Log.d( + TAG, + "CommissionerResolveListener.onServiceResolved.OnClickListener.onClick called for " + + discoveredNodeData); + callback.handleCommissioningButtonClicked(discoveredNodeData); + } + }); + new Handler(Looper.getMainLooper()) + .post( + () -> + ((LinearLayout) getActivity().findViewById(R.id.castingCommissioners)) + .addView(commissionerButton)); + } + } + }; - CastingContext castingContext = new CastingContext(this.getActivity()); - NsdManager.DiscoveryListener commissionerDiscoveryListener = - new CommissionerDiscoveryListener(castingContext); + FailureCallback failureCallback = + new FailureCallback() { + @Override + public void handle(MatterError matterError) { + Log.e(TAG, "Error occurred during video player commissioner discovery: " + matterError); + } + }; - NsdManager nsdManager = castingContext.getNsdManager(); - nsdManager.discoverServices( - GlobalCastingConstants.CommissionerServiceType, - NsdManager.PROTOCOL_DNS_SD, - commissionerDiscoveryListener); + tvCastingApp.discoverVideoPlayerCommissioners( + (WifiManager) context.getSystemService(Context.WIFI_SERVICE), + (NsdManager) applicationContext.getSystemService(Context.NSD_SERVICE), + DISCOVERY_DURATION_SECS, + successCallback, + failureCallback); + } - // Stop discovery after specified timeout - Executors.newSingleThreadScheduledExecutor() - .schedule( - new Runnable() { - @Override - public void run() { - nsdManager.stopServiceDiscovery(commissionerDiscoveryListener); - multicastLock.release(); - } - }, - 10, - TimeUnit.SECONDS); - Log.d(TAG, "CommissionerDiscoveryFragment.startCommissionerDiscovery ended"); + @VisibleForTesting + public String getCommissionerButtonText(DiscoveredNodeData commissioner) { + String main = commissioner.getDeviceName() != null ? commissioner.getDeviceName() : ""; + String aux = + "" + (commissioner.getProductId() > 0 ? "Product ID: " + commissioner.getProductId() : ""); + aux += + commissioner.getDeviceType() > 0 + ? (aux.isEmpty() ? "" : " ") + "Device Type: " + commissioner.getDeviceType() + : ""; + aux += + commissioner.getVendorId() > 0 + ? (aux.isEmpty() ? "" : " from ") + "Vendor ID: " + commissioner.getVendorId() + : ""; + aux = aux.isEmpty() ? aux : "\n[" + aux + "]"; + return main + aux; } /** Interface for notifying the host. */ diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissioningFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissioningFragment.java index 71b2d62b38b18d..ca01c26219cbf1 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissioningFragment.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissioningFragment.java @@ -8,10 +8,14 @@ import android.widget.TextView; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import com.chip.casting.ContentApp; +import com.chip.casting.DiscoveredNodeData; +import com.chip.casting.FailureCallback; import com.chip.casting.MatterCallbackHandler; import com.chip.casting.MatterError; +import com.chip.casting.SuccessCallback; import com.chip.casting.TvCastingApp; -import com.chip.casting.dnssd.DiscoveredNodeData; +import com.chip.casting.VideoPlayer; import com.chip.casting.util.GlobalCastingConstants; /** A {@link Fragment} to get the TV Casting App commissioned. */ @@ -56,9 +60,25 @@ public View onCreateView( @Override public void handle(MatterError error) { Log.d(TAG, "handle() called on CommissioningComplete event with " + error); - if (error.isNoError()) { - callback.handleCommissioningComplete(); - } + } + }, + new SuccessCallback() { + @Override + public void handle(VideoPlayer videoPlayer) { + Log.d(TAG, "handle() called on OnConnectionSuccess with " + videoPlayer); + callback.handleCommissioningComplete(); + } + }, + new FailureCallback() { + @Override + public void handle(MatterError matterError) { + Log.d(TAG, "handle() called on OnConnectionFailure with " + matterError); + } + }, + new SuccessCallback() { + @Override + public void handle(ContentApp contentApp) { + Log.d(TAG, "handle() called on OnNewOrUpdatedEndpoint with " + contentApp); } }); if (this.openCommissioningWindowSuccess) { @@ -71,9 +91,7 @@ public void handle(MatterError error) { + " port: " + selectedCommissioner.getPort()); - this.sendUdcSuccess = - tvCastingApp.sendUserDirectedCommissioningRequest( - ipAddress, selectedCommissioner.getPort()); + this.sendUdcSuccess = tvCastingApp.sendCommissioningRequest(selectedCommissioner); } } diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/ContentLauncherFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/ContentLauncherFragment.java index d939ad944265c6..c1bb7dba3d6c42 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/ContentLauncherFragment.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/ContentLauncherFragment.java @@ -9,6 +9,7 @@ import android.widget.TextView; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import com.chip.casting.ContentApp; import com.chip.casting.MatterCallbackHandler; import com.chip.casting.MatterError; import com.chip.casting.TvCastingApp; @@ -21,6 +22,8 @@ public class ContentLauncherFragment extends Fragment { private View.OnClickListener launchUrlButtonClickListener; + private static final ContentApp kContentApp = new ContentApp((short) 4, null); + public ContentLauncherFragment(TvCastingApp tvCastingApp) { this.tvCastingApp = tvCastingApp; } @@ -52,6 +55,7 @@ public void onClick(View v) { EditText contentDisplayString = getView().findViewById(R.id.contentDisplayStringEditText); tvCastingApp.contentLauncherLaunchURL( + kContentApp, contentUrl.getText().toString(), contentDisplayString.getText().toString(), new MatterCallbackHandler() { 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 c9d493d214b7cd..88b85610b475f6 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 @@ -16,8 +16,8 @@ import chip.platform.PreferencesConfigurationManager; import chip.platform.PreferencesKeyValueStoreManager; import com.chip.casting.DACProviderStub; +import com.chip.casting.DiscoveredNodeData; import com.chip.casting.TvCastingApp; -import com.chip.casting.dnssd.DiscoveredNodeData; import com.chip.casting.util.GlobalCastingConstants; public class MainActivity extends AppCompatActivity @@ -37,7 +37,7 @@ protected void onCreate(Bundle savedInstanceState) { initJni(); - Fragment fragment = CommissionerDiscoveryFragment.newInstance(); + Fragment fragment = CommissionerDiscoveryFragment.newInstance(tvCastingApp); getSupportFragmentManager() .beginTransaction() .add(R.id.main_fragment_container, fragment, fragment.getClass().getSimpleName()) diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MediaPlaybackFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MediaPlaybackFragment.java index 6745b94904e192..ad0df7878dc63c 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MediaPlaybackFragment.java +++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MediaPlaybackFragment.java @@ -8,6 +8,7 @@ import android.widget.TextView; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import com.chip.casting.ContentApp; import com.chip.casting.FailureCallback; import com.chip.casting.MatterError; import com.chip.casting.MediaPlaybackTypes; @@ -23,6 +24,8 @@ public class MediaPlaybackFragment extends Fragment { private View.OnClickListener subscribeToCurrentStateButtonClickListener; + private static final ContentApp kContentApp = new ContentApp((short) 4, null); + public MediaPlaybackFragment(TvCastingApp tvCastingApp) { this.tvCastingApp = tvCastingApp; } @@ -107,6 +110,7 @@ public void run() { boolean retVal = tvCastingApp.mediaPlayback_subscribeToCurrentState( + kContentApp, successCallback, failureCallback, Integer.parseInt(minInterval.getText().toString()), diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/dnssd/CommissionerDiscoveryListener.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/dnssd/CommissionerDiscoveryListener.java deleted file mode 100644 index 3c563cbfc1c6a9..00000000000000 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/dnssd/CommissionerDiscoveryListener.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.chip.casting.dnssd; - -import android.net.nsd.NsdManager; -import android.net.nsd.NsdServiceInfo; -import android.util.Log; -import com.chip.casting.app.CastingContext; -import com.chip.casting.util.GlobalCastingConstants; -import java.util.ArrayList; -import java.util.List; - -public class CommissionerDiscoveryListener implements NsdManager.DiscoveryListener { - - private static final String TAG = CommissionerDiscoveryListener.class.getSimpleName(); - - private final CastingContext castingContext; - private final List commissioners = new ArrayList<>(); - - public CommissionerDiscoveryListener(CastingContext castingContext) { - this.castingContext = castingContext; - } - - @Override - public void onDiscoveryStarted(String regType) { - Log.d(TAG, "Service discovery started. regType: " + regType); - } - - @Override - public void onServiceFound(NsdServiceInfo service) { - Log.d(TAG, "Service discovery success. " + service); - if (service.getServiceType().equals(GlobalCastingConstants.CommissionerServiceType)) { - castingContext - .getNsdManager() - .resolveService(service, new CommissionerResolveListener(castingContext, commissioners)); - } else { - Log.d(TAG, "Ignoring discovered service: " + service.toString()); - } - } - - @Override - public void onServiceLost(NsdServiceInfo service) { - // When the network service is no longer available. - // Internal bookkeeping code goes here. - Log.e(TAG, "Service lost: " + service); - } - - @Override - public void onDiscoveryStopped(String serviceType) { - Log.i(TAG, "Discovery stopped: " + serviceType); - } - - @Override - public void onStartDiscoveryFailed(String serviceType, int errorCode) { - Log.e(TAG, "Discovery failed to start: Error code:" + errorCode); - castingContext.getNsdManager().stopServiceDiscovery(this); - } - - @Override - public void onStopDiscoveryFailed(String serviceType, int errorCode) { - Log.e(TAG, "Discovery failed to stop: Error code:" + errorCode); - castingContext.getNsdManager().stopServiceDiscovery(this); - } -} diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/dnssd/CommissionerResolveListener.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/dnssd/CommissionerResolveListener.java deleted file mode 100644 index 15fa522a83c2d1..00000000000000 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/dnssd/CommissionerResolveListener.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.chip.casting.dnssd; - -import android.net.nsd.NsdManager; -import android.net.nsd.NsdServiceInfo; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; -import android.view.View; -import android.widget.Button; -import androidx.annotation.VisibleForTesting; -import com.chip.casting.app.CastingContext; -import com.chip.casting.app.CommissionerDiscoveryFragment; -import com.chip.casting.util.GlobalCastingConstants; -import java.util.List; - -public class CommissionerResolveListener implements NsdManager.ResolveListener { - - private static final String TAG = CommissionerResolveListener.class.getSimpleName(); - private final CastingContext castingContext; - private final List commissioners; - - public CommissionerResolveListener( - CastingContext castingContext, List commissioners) { - this.castingContext = castingContext; - this.commissioners = commissioners; - } - - @Override - public void onServiceResolved(NsdServiceInfo serviceInfo) { - DiscoveredNodeData commissioner = new DiscoveredNodeData(serviceInfo); - Log.d(TAG, "Commissioner resolved: " + commissioner); - - if (isPassingDeviceTypeFilter(commissioner)) { - commissioners.add(commissioner); - String buttonText = getCommissionerButtonText(commissioner); - if (!buttonText.isEmpty()) { - Button commissionerButton = new Button(castingContext.getApplicationContext()); - commissionerButton.setText(buttonText); - CommissionerDiscoveryFragment.Callback callback = - (CommissionerDiscoveryFragment.Callback) castingContext.getFragmentActivity(); - commissionerButton.setOnClickListener( - new View.OnClickListener() { - @Override - public void onClick(View v) { - Log.d( - TAG, - "CommissionerResolveListener.onServiceResolved.OnClickListener.onClick called for " - + commissioner); - callback.handleCommissioningButtonClicked(commissioner); - } - }); - new Handler(Looper.getMainLooper()) - .post(() -> castingContext.getCommissionersLayout().addView(commissionerButton)); - } - } else Log.e(TAG, "Skipped displaying " + commissioner); - } - - @Override - public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { - switch (errorCode) { - case NsdManager.FAILURE_ALREADY_ACTIVE: - Log.e(TAG, "FAILURE_ALREADY_ACTIVE - Service: " + serviceInfo); - castingContext - .getNsdManager() - .resolveService( - serviceInfo, new CommissionerResolveListener(castingContext, commissioners)); - break; - case NsdManager.FAILURE_INTERNAL_ERROR: - Log.e(TAG, "FAILURE_INTERNAL_ERROR - Service: " + serviceInfo); - break; - case NsdManager.FAILURE_MAX_LIMIT: - Log.e(TAG, "FAILURE_MAX_LIMIT - Service: " + serviceInfo); - break; - } - } - - @VisibleForTesting - public String getCommissionerButtonText(DiscoveredNodeData commissioner) { - String main = commissioner.getDeviceName() != null ? commissioner.getDeviceName() : ""; - String aux = - "" + (commissioner.getProductId() > 0 ? "Product ID: " + commissioner.getProductId() : ""); - aux += - commissioner.getDeviceType() > 0 - ? (aux.isEmpty() ? "" : " ") + "Device Type: " + commissioner.getDeviceType() - : ""; - aux += - commissioner.getVendorId() > 0 - ? (aux.isEmpty() ? "" : " from ") + "Vendor ID: " + commissioner.getVendorId() - : ""; - aux = aux.isEmpty() ? aux : "\n[" + aux + "]"; - return main + aux; - } - - private boolean isPassingDeviceTypeFilter(DiscoveredNodeData commissioner) { - return GlobalCastingConstants.CommissionerDeviceTypeFilter == null - || GlobalCastingConstants.CommissionerDeviceTypeFilter.isEmpty() - || GlobalCastingConstants.CommissionerDeviceTypeFilter.contains( - commissioner.getDeviceType()); - } -} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/ContentApp.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/ContentApp.java new file mode 100644 index 00000000000000..80efc22ef52024 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/ContentApp.java @@ -0,0 +1,63 @@ +/* + * 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. + * + */ +package com.chip.casting; + +import java.util.List; +import java.util.Objects; + +public class ContentApp { + private short endpointId; + private List clusterIds; + + private boolean isInitialized = false; + + public ContentApp(short endpointId, List clusterIds) { + this.endpointId = endpointId; + this.clusterIds = clusterIds; + this.isInitialized = true; + } + + public boolean equals(Object object) { + if (this == object) return true; + if (object == null || getClass() != object.getClass()) return false; + if (!super.equals(object)) return false; + ContentApp that = (ContentApp) object; + return endpointId == that.endpointId; + } + + public int hashCode() { + return Objects.hash(super.hashCode(), endpointId); + } + + @java.lang.Override + public java.lang.String toString() { + return "endpointId=" + endpointId; + } + + public short getEndpointId() { + return endpointId; + } + + public List getClusterIds() { + return clusterIds; + } + + public boolean isInitialized() { + return isInitialized; + } +} diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/dnssd/DiscoveredNodeData.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/DiscoveredNodeData.java similarity index 84% rename from examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/dnssd/DiscoveredNodeData.java rename to examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/DiscoveredNodeData.java index 3ba7bac85fb1b3..982fbd84800671 100644 --- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/dnssd/DiscoveredNodeData.java +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/DiscoveredNodeData.java @@ -1,4 +1,21 @@ -package com.chip.casting.dnssd; +/* + * 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. + * + */ +package com.chip.casting; import android.net.nsd.NsdServiceInfo; import java.net.InetAddress; 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 new file mode 100644 index 00000000000000..cbc2ccadbad571 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdDiscoveryListener.java @@ -0,0 +1,93 @@ +/* + * 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. + * + */ +package com.chip.casting; + +import android.net.nsd.NsdManager; +import android.net.nsd.NsdServiceInfo; +import android.util.Log; +import java.util.List; + +public class NsdDiscoveryListener implements NsdManager.DiscoveryListener { + private static final String TAG = NsdDiscoveryListener.class.getSimpleName(); + + private final NsdManager nsdManager; + private final String targetServiceType; + private final List deviceTypeFilter; + private final SuccessCallback successCallback; + private final FailureCallback failureCallback; + + public NsdDiscoveryListener( + NsdManager nsdManager, + String targetServiceType, + List deviceTypeFilter, + SuccessCallback successCallback, + FailureCallback failureCallback) { + this.nsdManager = nsdManager; + this.targetServiceType = targetServiceType; + this.deviceTypeFilter = deviceTypeFilter; + this.successCallback = successCallback; + this.failureCallback = failureCallback; + } + + @Override + public void onDiscoveryStarted(String regType) { + Log.d(TAG, "Service discovery started. regType: " + regType); + } + + @Override + public void onServiceFound(NsdServiceInfo service) { + Log.d(TAG, "Service discovery success. " + service); + if (service.getServiceType().equals(targetServiceType)) { + nsdManager.resolveService( + service, + new NsdResolveListener(nsdManager, deviceTypeFilter, successCallback, failureCallback)); + } else { + Log.d(TAG, "Ignoring discovered service: " + service.toString()); + } + } + + @Override + public void onServiceLost(NsdServiceInfo service) { + // When the network service is no longer available. + // Internal bookkeeping code goes here. + Log.e(TAG, "Service lost: " + service); + } + + @Override + public void onDiscoveryStopped(String serviceType) { + Log.i(TAG, "Discovery stopped: " + serviceType); + } + + @Override + public void onStartDiscoveryFailed(String serviceType, int errorCode) { + Log.e(TAG, "Discovery failed to start: Error code:" + errorCode); + failureCallback.handle( + new MatterError( + 3, "NsdDiscoveryListener Discovery failed to start: Nsd Error code:" + errorCode)); + nsdManager.stopServiceDiscovery(this); + } + + @Override + public void onStopDiscoveryFailed(String serviceType, int errorCode) { + Log.e(TAG, "Discovery failed to stop: Error code:" + errorCode); + failureCallback.handle( + new MatterError( + 3, "NsdDiscoveryListener Discovery failed to stop: Nsd Error code:" + errorCode)); + nsdManager.stopServiceDiscovery(this); + } +} 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 new file mode 100644 index 00000000000000..6275ad2b491a29 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdResolveListener.java @@ -0,0 +1,88 @@ +/* + * 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. + * + */ +package com.chip.casting; + +import android.net.nsd.NsdManager; +import android.net.nsd.NsdServiceInfo; +import android.util.Log; +import java.util.List; + +public class NsdResolveListener implements NsdManager.ResolveListener { + + private static final String TAG = NsdResolveListener.class.getSimpleName(); + + private final NsdManager nsdManager; + private final List deviceTypeFilter; + private final SuccessCallback successCallback; + private final FailureCallback failureCallback; + + public NsdResolveListener( + NsdManager nsdManager, + List deviceTypeFilter, + SuccessCallback successCallback, + FailureCallback failureCallback) { + this.nsdManager = nsdManager; + this.deviceTypeFilter = deviceTypeFilter; + this.successCallback = successCallback; + this.failureCallback = failureCallback; + } + + @Override + public void onServiceResolved(NsdServiceInfo serviceInfo) { + DiscoveredNodeData discoveredNodeData = new DiscoveredNodeData(serviceInfo); + Log.d(TAG, "DiscoveredNodeData resolved: " + discoveredNodeData); + + if (isPassingDeviceTypeFilter(discoveredNodeData)) { + successCallback.handle(discoveredNodeData); + } else { + Log.d( + TAG, + "DiscoveredNodeData ignored because it did not pass the device type filter " + + discoveredNodeData); + } + } + + @Override + public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { + switch (errorCode) { + case NsdManager.FAILURE_ALREADY_ACTIVE: + Log.e(TAG, "NsdResolveListener FAILURE_ALREADY_ACTIVE - Service: " + serviceInfo); + nsdManager.resolveService( + serviceInfo, + new NsdResolveListener(nsdManager, deviceTypeFilter, successCallback, failureCallback)); + break; + case NsdManager.FAILURE_INTERNAL_ERROR: + Log.e(TAG, "NsdResolveListener FAILURE_INTERNAL_ERROR - Service: " + serviceInfo); + failureCallback.handle( + new MatterError( + 3, "NsdResolveListener FAILURE_INTERNAL_ERROR - Service: " + serviceInfo)); + break; + case NsdManager.FAILURE_MAX_LIMIT: + Log.e(TAG, "NsdResolveListener FAILURE_MAX_LIMIT - Service: " + serviceInfo); + failureCallback.handle( + new MatterError(19, "NsdResolveListener FAILURE_MAX_LIMIT - Service: " + serviceInfo)); + break; + } + } + + private boolean isPassingDeviceTypeFilter(DiscoveredNodeData discoveredNodeData) { + return deviceTypeFilter == null + || deviceTypeFilter.isEmpty() + || deviceTypeFilter.contains(discoveredNodeData.getDeviceType()); + } +} 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 27408a4934f637..364b3a1502be0b 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,21 +17,81 @@ */ package com.chip.casting; +import android.net.nsd.NsdManager; +import android.net.wifi.WifiManager; +import android.util.Log; import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; public class TvCastingApp { private static final String TAG = TvCastingApp.class.getSimpleName(); + private final String TARGET_SERVICE_TYPE = "_matterd._udp."; + private final List DEVICE_TYPE_FILTER = Arrays.asList(35L); // Video player = 35; + + public native void init(); + public native void setDACProvider(DACProvider provider); + public void discoverVideoPlayerCommissioners( + WifiManager wifiManager, + NsdManager nsdManager, + long discoveryDurationSeconds, + SuccessCallback discoverySuccessCallback, + FailureCallback discoveryFailureCallback) { + Log.d(TAG, "TvCastingApp.discoverVideoPlayerCommissioners called"); + WifiManager.MulticastLock multicastLock = wifiManager.createMulticastLock("multicastLock"); + multicastLock.setReferenceCounted(true); + multicastLock.acquire(); + + NsdDiscoveryListener nsdDiscoveryListener = + new NsdDiscoveryListener( + nsdManager, + TARGET_SERVICE_TYPE, + DEVICE_TYPE_FILTER, + discoverySuccessCallback, + discoveryFailureCallback); + + nsdManager.discoverServices( + TARGET_SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, nsdDiscoveryListener); + + Executors.newSingleThreadScheduledExecutor() + .schedule( + new Runnable() { + @Override + public void run() { + nsdManager.stopServiceDiscovery(nsdDiscoveryListener); + multicastLock.release(); + } + }, + discoveryDurationSeconds, + TimeUnit.SECONDS); + Log.d(TAG, "TvCastingApp.discoverVideoPlayerCommissioners ended"); + } + public native boolean openBasicCommissioningWindow( - int duration, Object commissioningCompleteHandler); + int duration, + Object commissioningCompleteHandler, + SuccessCallback onConnectionSuccess, + FailureCallback onConnectionFailure, + SuccessCallback onNewOrUpdatedEndpointCallback); + + public native boolean sendCommissioningRequest(DiscoveredNodeData commissioner); public native boolean sendUserDirectedCommissioningRequest(String address, int port); - public native boolean discoverCommissioners(); + public native List readCachedVideoPlayers(); - public native void init(); + public native boolean verifyOrEstablishConnection( + VideoPlayer targetVideoPlayer, + SuccessCallback onConnectionSuccess, + FailureCallback onConnectionFailure, + SuccessCallback onNewOrUpdatedEndpointCallback); + + public native List getActiveTargetVideoPlayers(); /* * CONTENT LAUNCHER CLUSTER @@ -39,15 +99,17 @@ public native boolean openBasicCommissioningWindow( * TODO: Add API to subscribe to AcceptHeader */ public native boolean contentLauncherLaunchURL( - String contentUrl, String contentDisplayStr, Object launchURLHandler); + ContentApp contentApp, String contentUrl, String contentDisplayStr, Object launchURLHandler); public native boolean contentLauncher_launchContent( + ContentApp contentApp, ContentLauncherTypes.ContentSearch search, boolean autoPlay, String data, Object responseHandler); public native boolean contentLauncher_subscribeToSupportedStreamingProtocols( + ContentApp contentApp, SuccessCallback readSuccessHandler, FailureCallback readFailureHandler, int minInterval, @@ -58,6 +120,7 @@ public native boolean contentLauncher_subscribeToSupportedStreamingProtocols( * LEVEL CONTROL CLUSTER */ public native boolean levelControl_step( + ContentApp contentApp, byte stepMode, byte stepSize, short transitionTime, @@ -66,6 +129,7 @@ public native boolean levelControl_step( Object responseHandler); public native boolean levelControl_moveToLevel( + ContentApp contentApp, byte level, short transitionTime, byte optionMask, @@ -73,6 +137,7 @@ public native boolean levelControl_moveToLevel( Object responseHandler); public native boolean levelControl_subscribeToCurrentLevel( + ContentApp contentApp, SuccessCallback readSuccessHandler, FailureCallback readFailureHandler, int minInterval, @@ -80,6 +145,7 @@ public native boolean levelControl_subscribeToCurrentLevel( SubscriptionEstablishedCallback subscriptionEstablishedHandler); public native boolean levelControl_subscribeToMinLevel( + ContentApp contentApp, SuccessCallback readSuccessHandler, FailureCallback readFailureHandler, int minInterval, @@ -87,6 +153,7 @@ public native boolean levelControl_subscribeToMinLevel( SubscriptionEstablishedCallback subscriptionEstablishedHandler); public native boolean levelControl_subscribeToMaxLevel( + ContentApp contentApp, SuccessCallback readSuccessHandler, FailureCallback readFailureHandler, int minInterval, @@ -96,23 +163,25 @@ public native boolean levelControl_subscribeToMaxLevel( /* * MEDIA PLAYBACK CLUSTER */ - public native boolean mediaPlayback_play(Object responseHandler); + public native boolean mediaPlayback_play(ContentApp contentApp, Object responseHandler); - public native boolean mediaPlayback_pause(Object responseHandler); + public native boolean mediaPlayback_pause(ContentApp contentApp, Object responseHandler); - public native boolean mediaPlayback_stopPlayback(Object responseHandler); + public native boolean mediaPlayback_stopPlayback(ContentApp contentApp, Object responseHandler); - public native boolean mediaPlayback_next(Object responseHandler); + public native boolean mediaPlayback_next(ContentApp contentApp, Object responseHandler); - public native boolean mediaPlayback_seek(long position, Object responseHandler); + public native boolean mediaPlayback_seek( + ContentApp contentApp, long position, Object responseHandler); public native boolean mediaPlayback_skipForward( - long deltaPositionMilliseconds, Object responseHandler); + ContentApp contentApp, long deltaPositionMilliseconds, Object responseHandler); public native boolean mediaPlayback_skipBackward( - long deltaPositionMilliseconds, Object responseHandler); + ContentApp contentApp, long deltaPositionMilliseconds, Object responseHandler); public native boolean mediaPlayback_subscribeToCurrentState( + ContentApp contentApp, SuccessCallback readSuccessHandler, FailureCallback readFailureHandler, int minInterval, @@ -120,6 +189,7 @@ public native boolean mediaPlayback_subscribeToCurrentState( SubscriptionEstablishedCallback subscriptionEstablishedHandler); public native boolean mediaPlayback_subscribeToDuration( + ContentApp contentApp, SuccessCallback readSuccessHandler, FailureCallback readFailureHandler, int minInterval, @@ -127,6 +197,7 @@ public native boolean mediaPlayback_subscribeToDuration( SubscriptionEstablishedCallback subscriptionEstablishedHandler); public native boolean mediaPlayback_subscribeToSampledPosition( + ContentApp contentApp, SuccessCallback readSuccessHandler, FailureCallback readFailureHandler, int minInterval, @@ -134,6 +205,7 @@ public native boolean mediaPlayback_subscribeToSampledPosition( SubscriptionEstablishedCallback subscriptionEstablishedHandler); public native boolean mediaPlayback_subscribeToPlaybackSpeed( + ContentApp contentApp, SuccessCallback readSuccessHandler, FailureCallback readFailureHandler, int minInterval, @@ -141,6 +213,7 @@ public native boolean mediaPlayback_subscribeToPlaybackSpeed( SubscriptionEstablishedCallback subscriptionEstablishedHandler); public native boolean mediaPlayback_subscribeToSeekRangeEnd( + ContentApp contentApp, SuccessCallback readSuccessHandler, FailureCallback readFailureHandler, int minInterval, @@ -148,6 +221,7 @@ public native boolean mediaPlayback_subscribeToSeekRangeEnd( SubscriptionEstablishedCallback subscriptionEstablishedHandler); public native boolean mediaPlayback_subscribeToSeekRangeStart( + ContentApp contentApp, SuccessCallback readSuccessHandler, FailureCallback readFailureHandler, int minInterval, @@ -158,21 +232,26 @@ public native boolean mediaPlayback_subscribeToSeekRangeStart( * APPLICATION LAUNCHER CLUSTER */ public native boolean applicationLauncher_launchApp( - short catalogVendorId, String applicationId, byte[] data, Object responseHandler); + ContentApp contentApp, + short catalogVendorId, + String applicationId, + byte[] data, + Object responseHandler); public native boolean applicationLauncher_stopApp( - short catalogVendorId, String applicationId, Object responseHandler); + ContentApp contentApp, short catalogVendorId, String applicationId, Object responseHandler); public native boolean applicationLauncher_hideApp( - short catalogVendorId, String applicationId, Object responseHandler); + ContentApp contentApp, short catalogVendorId, String applicationId, Object responseHandler); /* * TARGET NAVIGATOR CLUSTER */ public native boolean targetNavigator_navigateTarget( - byte target, String data, Object responseHandler); + ContentApp contentApp, byte target, String data, Object responseHandler); public native boolean targetNavigator_subscribeToCurrentTarget( + ContentApp contentApp, SuccessCallback readSuccessHandler, FailureCallback readFailureHandler, int minInterval, @@ -180,6 +259,7 @@ public native boolean targetNavigator_subscribeToCurrentTarget( SubscriptionEstablishedCallback subscriptionEstablishedHandler); public native boolean targetNavigator_subscribeToTargetList( + ContentApp contentApp, SuccessCallback> readSuccessHandler, FailureCallback readFailureHandler, int minInterval, @@ -189,7 +269,8 @@ public native boolean targetNavigator_subscribeToTargetList( /* * KEYPAD INPUT CLUSTER */ - public native boolean keypadInput_sendKey(byte keyCode, Object responseHandler); + public native boolean keypadInput_sendKey( + ContentApp contentApp, byte keyCode, Object responseHandler); /** * APPLICATION BASIC @@ -197,6 +278,7 @@ public native boolean targetNavigator_subscribeToTargetList( *

TODO: Add APIs to subscribe to Application, Status and AllowedVendorList */ public native boolean applicationBasic_subscribeToVendorName( + ContentApp contentApp, SuccessCallback readSuccessHandler, FailureCallback readFailureHandler, int minInterval, @@ -204,6 +286,7 @@ public native boolean applicationBasic_subscribeToVendorName( SubscriptionEstablishedCallback subscriptionEstablishedHandler); public native boolean applicationBasic_subscribeToVendorID( + ContentApp contentApp, SuccessCallback readSuccessHandler, FailureCallback readFailureHandler, int minInterval, @@ -211,6 +294,7 @@ public native boolean applicationBasic_subscribeToVendorID( SubscriptionEstablishedCallback subscriptionEstablishedHandler); public native boolean applicationBasic_subscribeToApplicationName( + ContentApp contentApp, SuccessCallback readSuccessHandler, FailureCallback readFailureHandler, int minInterval, @@ -218,6 +302,7 @@ public native boolean applicationBasic_subscribeToApplicationName( SubscriptionEstablishedCallback subscriptionEstablishedHandler); public native boolean applicationBasic_subscribeToProductID( + ContentApp contentApp, SuccessCallback readSuccessHandler, FailureCallback readFailureHandler, int minInterval, @@ -225,6 +310,7 @@ public native boolean applicationBasic_subscribeToProductID( SubscriptionEstablishedCallback subscriptionEstablishedHandler); public native boolean applicationBasic_subscribeToApplicationVersion( + ContentApp contentApp, SuccessCallback readSuccessHandler, FailureCallback readFailureHandler, int minInterval, diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/VideoPlayer.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/VideoPlayer.java new file mode 100644 index 00000000000000..85c487850cd08d --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/VideoPlayer.java @@ -0,0 +1,121 @@ +/* + * 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. + * + */ +package com.chip.casting; + +import java.util.List; +import java.util.Objects; + +public class VideoPlayer { + private long nodeId; + private byte fabricIndex; + private String deviceName; + private int vendorId; + private int productId; + private int deviceType; + private List contentApps; + private boolean isConnected = false; + + private boolean isInitialized = false; + + public VideoPlayer( + long nodeId, + byte fabricIndex, + String deviceName, + int vendorId, + int productId, + int deviceType, + List contentApps, + boolean isConnected) { + this.nodeId = nodeId; + this.fabricIndex = fabricIndex; + this.deviceName = deviceName; + this.vendorId = vendorId; + this.productId = productId; + this.deviceType = deviceType; + this.contentApps = contentApps; + this.isConnected = isConnected; + this.isInitialized = true; + } + + public boolean equals(Object object) { + if (this == object) return true; + if (object == null || getClass() != object.getClass()) return false; + if (!super.equals(object)) return false; + VideoPlayer that = (VideoPlayer) object; + return nodeId == that.nodeId && fabricIndex == that.fabricIndex; + } + + public int hashCode() { + return Objects.hash(super.hashCode(), nodeId, fabricIndex); + } + + @java.lang.Override + public java.lang.String toString() { + return "VideoPlayer{" + + "nodeId=" + + nodeId + + ", fabricIndex=" + + fabricIndex + + ", deviceName='" + + deviceName + + '\'' + + ", vendorId=" + + vendorId + + ", productId=" + + productId + + ", isConnected=" + + isConnected + + '}'; + } + + public long getNodeId() { + return nodeId; + } + + public byte getFabricIndex() { + return fabricIndex; + } + + public boolean isConnected() { + return isConnected; + } + + public List getContentApps() { + return contentApps; + } + + public String getDeviceName() { + return deviceName; + } + + public int getVendorId() { + return vendorId; + } + + public int getProductId() { + return productId; + } + + public int getDeviceType() { + return deviceType; + } + + public boolean isInitialized() { + return isInitialized; + } +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/ConversionUtils.cpp b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/ConversionUtils.cpp new file mode 100644 index 00000000000000..db59f4a08d1276 --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/ConversionUtils.cpp @@ -0,0 +1,287 @@ +/* + * + * Copyright (c) 2021 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. + */ +#include "ConversionUtils.h" + +#include +#include +#include +#include +#include + +CHIP_ERROR convertJContentAppToTargetEndpointInfo(jobject contentApp, TargetEndpointInfo & outTargetEndpointInfo) +{ + ChipLogProgress(AppServer, "convertJContentAppToTargetEndpointInfo called"); + JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); + + jclass jContentAppClass; + ReturnErrorOnFailure(chip::JniReferences::GetInstance().GetClassRef(env, "com/chip/casting/ContentApp", jContentAppClass)); + + jfieldID jEndpointIdField = env->GetFieldID(jContentAppClass, "endpointId", "S"); + jshort jEndpointId = env->GetShortField(contentApp, jEndpointIdField); + outTargetEndpointInfo.Initialize(static_cast(jEndpointId)); + + jfieldID jclusterIdsField = env->GetFieldID(jContentAppClass, "clusterIds", "Ljava/util/List;"); + jobject jClusterIds = env->GetObjectField(contentApp, jclusterIdsField); + if (jClusterIds == nullptr) + { + return CHIP_NO_ERROR; + } + + jobject jIterator = env->CallObjectMethod( + jClusterIds, env->GetMethodID(env->GetObjectClass(jClusterIds), "iterator", "()Ljava/util/Iterator;")); + jmethodID jNextMid = env->GetMethodID(env->GetObjectClass(jIterator), "next", "()Ljava/lang/Object;"); + jmethodID jHasNextMid = env->GetMethodID(env->GetObjectClass(jIterator), "hasNext", "()Z"); + + while (env->CallBooleanMethod(jIterator, jHasNextMid)) + { + jobject jClusterId = env->CallObjectMethod(jIterator, jNextMid); + jclass jIntegerClass = env->FindClass("java/lang/Integer"); + jmethodID jIntValueMid = env->GetMethodID(jIntegerClass, "intValue", "()I"); + outTargetEndpointInfo.AddCluster(static_cast(env->CallIntMethod(jClusterId, jIntValueMid))); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR convertTargetEndpointInfoToJContentApp(TargetEndpointInfo * targetEndpointInfo, jobject & outContentApp) +{ + ChipLogProgress(AppServer, "convertTargetEndpointInfoToJContentApp called"); + if (targetEndpointInfo != nullptr && targetEndpointInfo->IsInitialized()) + { + JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); + + jclass jContentAppClass; + ReturnErrorOnFailure(chip::JniReferences::GetInstance().GetClassRef(env, "com/chip/casting/ContentApp", jContentAppClass)); + jmethodID jContentAppConstructor = env->GetMethodID(jContentAppClass, "", "(SLjava/util/List;)V"); + chip::ClusterId * clusters = targetEndpointInfo->GetClusters(); + jobject jClustersArrayList = nullptr; + if (clusters != nullptr) + { + chip::JniReferences::GetInstance().CreateArrayList(jClustersArrayList); + for (size_t i = 0; i < kMaxNumberOfClustersPerEndpoint && clusters[i] != chip::kInvalidClusterId; i++) + { + jobject jCluster = nullptr; + chip::JniReferences::GetInstance().CreateBoxedObject("java/lang/Integer", "(I)V", clusters[i], jCluster); + chip::JniReferences::GetInstance().AddToList(jClustersArrayList, jCluster); + } + } + outContentApp = + env->NewObject(jContentAppClass, jContentAppConstructor, targetEndpointInfo->GetEndpointId(), jClustersArrayList); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR convertJVideoPlayerToTargetVideoPlayerInfo(jobject videoPlayer, TargetVideoPlayerInfo & outTargetVideoPlayerInfo) +{ + ChipLogProgress(AppServer, "convertJVideoPlayerToTargetVideoPlayerInfo called"); + JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); + + jclass jVideoPlayerClass; + ReturnErrorOnFailure(chip::JniReferences::GetInstance().GetClassRef(env, "com/chip/casting/VideoPlayer", jVideoPlayerClass)); + + jfieldID jNodeIdField = env->GetFieldID(jVideoPlayerClass, "nodeId", "J"); + chip::NodeId nodeId = static_cast(env->GetLongField(videoPlayer, jNodeIdField)); + + jfieldID jFabricIndexField = env->GetFieldID(jVideoPlayerClass, "fabricIndex", "B"); + chip::FabricIndex fabricIndex = static_cast(env->GetByteField(videoPlayer, jFabricIndexField)); + + jfieldID jVendorIdField = env->GetFieldID(jVideoPlayerClass, "vendorId", "S"); + uint16_t vendorId = static_cast(env->GetShortField(videoPlayer, jVendorIdField)); + + jfieldID jProductIdField = env->GetFieldID(jVideoPlayerClass, "productId", "S"); + uint16_t productId = static_cast(env->GetShortField(videoPlayer, jProductIdField)); + + jfieldID jDeviceType = env->GetFieldID(jVideoPlayerClass, "deviceType", "S"); + uint16_t deviceType = static_cast(env->GetShortField(videoPlayer, jDeviceType)); + + jfieldID getDeviceNameField = env->GetFieldID(jVideoPlayerClass, "deviceName", "Ljava/lang/String;"); + jstring jDeviceName = static_cast(env->GetObjectField(videoPlayer, getDeviceNameField)); + const char * deviceName = env->GetStringUTFChars(jDeviceName, 0); + outTargetVideoPlayerInfo.Initialize(nodeId, fabricIndex, nullptr, nullptr, vendorId, productId, deviceType, deviceName); + + jfieldID jContentAppsField = env->GetFieldID(jVideoPlayerClass, "contentApps", "Ljava/util/List;"); + jobject jContentApps = env->GetObjectField(videoPlayer, jContentAppsField); + if (jContentApps == nullptr) + { + return CHIP_NO_ERROR; + } + + jobject jIterator = env->CallObjectMethod( + jContentApps, env->GetMethodID(env->GetObjectClass(jContentApps), "iterator", "()Ljava/util/Iterator;")); + jmethodID jNextMid = env->GetMethodID(env->GetObjectClass(jIterator), "next", "()Ljava/lang/Object;"); + jmethodID jHasNextMid = env->GetMethodID(env->GetObjectClass(jIterator), "hasNext", "()Z"); + + while (env->CallBooleanMethod(jIterator, jHasNextMid)) + { + jobject jContentApp = env->CallObjectMethod(jIterator, jNextMid); + + jclass jContentAppClass; + ReturnErrorOnFailure(chip::JniReferences::GetInstance().GetClassRef(env, "com/chip/casting/ContentApp", jContentAppClass)); + jfieldID jEndpointIdField = env->GetFieldID(jContentAppClass, "endpointId", "S"); + chip::EndpointId endpointId = static_cast(env->GetShortField(jContentApp, jEndpointIdField)); + TargetEndpointInfo * endpoint = outTargetVideoPlayerInfo.GetOrAddEndpoint(endpointId); + + ReturnErrorOnFailure(convertJContentAppToTargetEndpointInfo(jContentApp, *endpoint)); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR convertTargetVideoPlayerInfoToJVideoPlayer(TargetVideoPlayerInfo * targetVideoPlayerInfo, jobject & outVideoPlayer) +{ + ChipLogProgress(AppServer, "convertTargetVideoPlayerInfoToJVideoPlayer called"); + if (targetVideoPlayerInfo != nullptr && targetVideoPlayerInfo->IsInitialized()) + { + JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); + + jclass jVideoPlayerClass; + ReturnErrorOnFailure( + chip::JniReferences::GetInstance().GetClassRef(env, "com/chip/casting/VideoPlayer", jVideoPlayerClass)); + jmethodID jVideoPlayerConstructor = + env->GetMethodID(jVideoPlayerClass, "", "(JBLjava/lang/String;IIILjava/util/List;Z)V"); + + jobject jContentAppList = nullptr; + TargetEndpointInfo * endpoints = targetVideoPlayerInfo->GetEndpoints(); + if (endpoints != nullptr) + { + chip::JniReferences::GetInstance().CreateArrayList(jContentAppList); + for (size_t i = 0; i < kMaxNumberOfEndpoints && endpoints[i].IsInitialized(); i++) + { + jobject contentApp = nullptr; + ReturnErrorOnFailure(convertTargetEndpointInfoToJContentApp(&endpoints[i], contentApp)); + chip::JniReferences::GetInstance().AddToList(jContentAppList, contentApp); + } + } + jstring deviceName = env->NewStringUTF(targetVideoPlayerInfo->GetDeviceName()); + outVideoPlayer = env->NewObject(jVideoPlayerClass, jVideoPlayerConstructor, targetVideoPlayerInfo->GetNodeId(), + targetVideoPlayerInfo->GetFabricIndex(), deviceName, targetVideoPlayerInfo->GetVendorId(), + targetVideoPlayerInfo->GetProductId(), targetVideoPlayerInfo->GetDeviceType(), + jContentAppList, targetVideoPlayerInfo->GetOperationalDeviceProxy() != nullptr); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR convertJDiscoveredNodeDataToCppDiscoveredNodeData(jobject jDiscoveredNodeData, + chip::Dnssd::DiscoveredNodeData & outCppDiscoveredNodeData) +{ + ChipLogProgress(AppServer, "convertJDiscoveredNodeDataToCppDiscoveredNodeData called"); + + JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); + + jclass jDiscoveredNodeDataClass; + ReturnErrorOnFailure( + chip::JniReferences::GetInstance().GetClassRef(env, "com/chip/casting/DiscoveredNodeData", jDiscoveredNodeDataClass)); + + jfieldID getHostNameField = env->GetFieldID(jDiscoveredNodeDataClass, "hostName", "Ljava/lang/String;"); + jstring jHostName = static_cast(env->GetObjectField(jDiscoveredNodeData, getHostNameField)); + if (jHostName != nullptr) + { + chip::Platform::CopyString(outCppDiscoveredNodeData.resolutionData.hostName, chip::Dnssd::kHostNameMaxLength + 1, + env->GetStringUTFChars(jHostName, 0)); + } + + jfieldID getInstanceNameField = env->GetFieldID(jDiscoveredNodeDataClass, "deviceName", "Ljava/lang/String;"); + jstring jInstanceName = static_cast(env->GetObjectField(jDiscoveredNodeData, getInstanceNameField)); + if (jInstanceName != nullptr) + { + chip::Platform::CopyString(outCppDiscoveredNodeData.commissionData.instanceName, + chip::Dnssd::Commission::kInstanceNameMaxLength + 1, env->GetStringUTFChars(jInstanceName, 0)); + } + + jfieldID jLongDiscriminatorField = env->GetFieldID(jDiscoveredNodeDataClass, "longDiscriminator", "J"); + outCppDiscoveredNodeData.commissionData.vendorId = + static_cast(env->GetLongField(jDiscoveredNodeData, jLongDiscriminatorField)); + + jfieldID jVendorIdField = env->GetFieldID(jDiscoveredNodeDataClass, "vendorId", "J"); + outCppDiscoveredNodeData.commissionData.vendorId = + static_cast(env->GetLongField(jDiscoveredNodeData, jVendorIdField)); + + jfieldID jProductIdField = env->GetFieldID(jDiscoveredNodeDataClass, "productId", "J"); + outCppDiscoveredNodeData.commissionData.productId = + static_cast(env->GetLongField(jDiscoveredNodeData, jProductIdField)); + + jfieldID jCommissioningModeField = env->GetFieldID(jDiscoveredNodeDataClass, "commissioningMode", "B"); + outCppDiscoveredNodeData.commissionData.commissioningMode = + static_cast(env->GetByteField(jDiscoveredNodeData, jCommissioningModeField)); + + jfieldID jDeviceTypeField = env->GetFieldID(jDiscoveredNodeDataClass, "deviceType", "J"); + outCppDiscoveredNodeData.commissionData.deviceType = + static_cast(env->GetLongField(jDiscoveredNodeData, jDeviceTypeField)); + + jfieldID getDeviceNameField = env->GetFieldID(jDiscoveredNodeDataClass, "deviceName", "Ljava/lang/String;"); + jstring jDeviceName = static_cast(env->GetObjectField(jDiscoveredNodeData, getDeviceNameField)); + chip::Platform::CopyString(outCppDiscoveredNodeData.commissionData.deviceName, chip::Dnssd::kMaxDeviceNameLen + 1, + env->GetStringUTFChars(jDeviceName, 0)); + + // TODO: map rotating ID + jfieldID jRotatingIdLenField = env->GetFieldID(jDiscoveredNodeDataClass, "rotatingIdLen", "I"); + outCppDiscoveredNodeData.commissionData.rotatingIdLen = + static_cast(env->GetIntField(jDiscoveredNodeData, jRotatingIdLenField)); + + jfieldID jPairingHintField = env->GetFieldID(jDiscoveredNodeDataClass, "pairingHint", "S"); + outCppDiscoveredNodeData.commissionData.pairingHint = + static_cast(env->GetShortField(jDiscoveredNodeData, jPairingHintField)); + + jfieldID getPairingInstructionField = env->GetFieldID(jDiscoveredNodeDataClass, "pairingInstruction", "Ljava/lang/String;"); + jstring jPairingInstruction = static_cast(env->GetObjectField(jDiscoveredNodeData, getPairingInstructionField)); + if (jPairingInstruction != nullptr) + { + chip::Platform::CopyString(outCppDiscoveredNodeData.commissionData.pairingInstruction, + chip::Dnssd::kMaxPairingInstructionLen + 1, env->GetStringUTFChars(jPairingInstruction, 0)); + } + + jfieldID jPortField = env->GetFieldID(jDiscoveredNodeDataClass, "port", "I"); + outCppDiscoveredNodeData.resolutionData.port = static_cast(env->GetIntField(jDiscoveredNodeData, jPortField)); + + jfieldID jNumIpsField = env->GetFieldID(jDiscoveredNodeDataClass, "numIPs", "I"); + outCppDiscoveredNodeData.resolutionData.numIPs = static_cast(env->GetIntField(jDiscoveredNodeData, jNumIpsField)); + + jfieldID jIPAddressesField = env->GetFieldID(jDiscoveredNodeDataClass, "ipAddresses", "Ljava/util/List;"); + jobject jIPAddresses = env->GetObjectField(jDiscoveredNodeData, jIPAddressesField); + if (jIPAddresses == nullptr && outCppDiscoveredNodeData.resolutionData.numIPs > 0) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + jobject jIterator = env->CallObjectMethod( + jIPAddresses, env->GetMethodID(env->GetObjectClass(jIPAddresses), "iterator", "()Ljava/util/Iterator;")); + jmethodID jNextMid = env->GetMethodID(env->GetObjectClass(jIterator), "next", "()Ljava/lang/Object;"); + jmethodID jHasNextMid = env->GetMethodID(env->GetObjectClass(jIterator), "hasNext", "()Z"); + + size_t ipAddressCount = 0; + while (env->CallBooleanMethod(jIterator, jHasNextMid)) + { + jobject jIPAddress = env->CallObjectMethod(jIterator, jNextMid); + jclass jIPAddressClass; + ReturnErrorOnFailure(chip::JniReferences::GetInstance().GetClassRef(env, "java/net/InetAddress", jIPAddressClass)); + jmethodID jGetHostAddressMid = env->GetMethodID(jIPAddressClass, "getHostAddress", "()Ljava/lang/String;"); + jstring jIPAddressStr = static_cast(env->CallObjectMethod(jIPAddress, jGetHostAddressMid)); + + chip::Inet::IPAddress addressInet; + chip::JniUtfString addressJniString(env, jIPAddressStr); + VerifyOrReturnError(chip::Inet::IPAddress::FromString(addressJniString.c_str(), addressInet), CHIP_ERROR_INVALID_ARGUMENT); + outCppDiscoveredNodeData.resolutionData.ipAddress[ipAddressCount] = addressInet; + + if (ipAddressCount == 0) + { + outCppDiscoveredNodeData.resolutionData.interfaceId = chip::Inet::InterfaceId::FromIPAddress(addressInet); + } + ipAddressCount++; + } + + return CHIP_NO_ERROR; +} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/ConversionUtils.h b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/ConversionUtils.h new file mode 100644 index 00000000000000..192ffa2b65961d --- /dev/null +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/ConversionUtils.h @@ -0,0 +1,33 @@ +/* + * + * Copyright (c) 2021 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. + */ +#pragma once + +#include "TargetEndpointInfo.h" +#include "TargetVideoPlayerInfo.h" + +#include + +CHIP_ERROR convertJContentAppToTargetEndpointInfo(jobject contentApp, TargetEndpointInfo & outTargetEndpointInfo); + +CHIP_ERROR convertTargetEndpointInfoToJContentApp(TargetEndpointInfo * targetEndpointInfo, jobject & outContentApp); + +CHIP_ERROR convertJVideoPlayerToTargetVideoPlayerInfo(jobject videoPlayer, TargetVideoPlayerInfo & targetVideoPlayerInfo); + +CHIP_ERROR convertTargetVideoPlayerInfoToJVideoPlayer(TargetVideoPlayerInfo * targetVideoPlayerInfo, jobject & outVideoPlayer); + +CHIP_ERROR convertJDiscoveredNodeDataToCppDiscoveredNodeData(jobject jDiscoveredNodeData, + chip::Dnssd::DiscoveredNodeData & cppDiscoveredNodeData); diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.cpp b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.cpp index f9bbe7a649f531..60a10ea2696f5e 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.cpp +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.cpp @@ -55,6 +55,7 @@ void FailureHandlerJNI::Handle(CHIP_ERROR callbackErr) JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); UtfString jniCallbackErrString(env, callbackErr.AsString()); + chip::DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; VerifyOrExit(mObject != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); @@ -72,6 +73,7 @@ void SubscriptionEstablishedHandlerJNI::Handle() JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + chip::DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; VerifyOrExit(mObject != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); @@ -166,8 +168,32 @@ jobject ConvertToIntegerJObject(uint32_t responseData) return env->NewObject(responseTypeClass, constructor, responseData); } -// MEDIA PLAYBACK +// COMMISSIONING AND CONNECTION +jobject OnConnectionSuccessHandlerJNI::ConvertToJObject(TargetVideoPlayerInfo * targetVideoPlayerInfo) +{ + ChipLogProgress(AppServer, "OnConnectionSuccessHandlerJNI::ConvertToJObject called"); + jobject videoPlayer = nullptr; + CHIP_ERROR err = convertTargetVideoPlayerInfoToJVideoPlayer(targetVideoPlayerInfo, videoPlayer); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "OnConnectionSuccessHandlerJNI::ConvertToJObject failed with %" CHIP_ERROR_FORMAT, err.Format()); + } + return nullptr; +} +jobject OnNewOrUpdatedEndpointHandlerJNI::ConvertToJObject(TargetEndpointInfo * targetEndpointInfo) +{ + ChipLogProgress(AppServer, "OnNewOrUpdatedEndpointHandlerJNI::ConvertToJObject called"); + jobject contentApp = nullptr; + CHIP_ERROR err = convertTargetEndpointInfoToJContentApp(targetEndpointInfo, contentApp); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "OnNewOrUpdatedEndpointHandlerJNI::ConvertToJObject failed with %" CHIP_ERROR_FORMAT, err.Format()); + } + return contentApp; +} + +// MEDIA PLAYBACK jobject CurrentStateSuccessHandlerJNI::ConvertToJObject( chip::app::Clusters::MediaPlayback::Attributes::CurrentState::TypeInfo::DecodableArgType responseData) { 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 91babd44a4fb7b..d78988699b88f9 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 @@ -18,6 +18,10 @@ #pragma once +#include "ConversionUtils.h" +#include "TargetEndpointInfo.h" +#include "TargetVideoPlayerInfo.h" + #include #include #include @@ -80,6 +84,7 @@ class SuccessHandlerJNI : public CallbackBaseJNI JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread(); jobject jResponseData = ConvertToJObject(responseData); + chip::DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; VerifyOrExit(mObject != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); @@ -95,6 +100,21 @@ class SuccessHandlerJNI : public CallbackBaseJNI template SuccessHandlerJNI::~SuccessHandlerJNI(){}; +// COMMISSIONING AND CONNECTION +class OnConnectionSuccessHandlerJNI : public SuccessHandlerJNI +{ +public: + OnConnectionSuccessHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Object;)V") {} + jobject ConvertToJObject(TargetVideoPlayerInfo * responseData); +}; + +class OnNewOrUpdatedEndpointHandlerJNI : public SuccessHandlerJNI +{ +public: + OnNewOrUpdatedEndpointHandlerJNI() : SuccessHandlerJNI("(Ljava/lang/Object;)V") {} + jobject ConvertToJObject(TargetEndpointInfo * responseData); +}; + // MEDIA PLAYBACK class CurrentStateSuccessHandlerJNI : public SuccessHandlerJNI 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 cec6ec3c2962bc..928f489e2b84a7 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 @@ -19,6 +19,7 @@ #include "TvCastingApp-JNI.h" #include "CastingServer.h" #include "Constants.h" +#include "ConversionUtils.h" #include "JNIDACProvider.h" #include @@ -29,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -59,7 +61,9 @@ JNI_METHOD(void, setDACProvider)(JNIEnv *, jobject, jobject provider) } } -JNI_METHOD(jboolean, openBasicCommissioningWindow)(JNIEnv * env, jobject, jint duration, jobject jCommissioningCompleteHandler) +JNI_METHOD(jboolean, openBasicCommissioningWindow) +(JNIEnv * env, jobject, jint duration, jobject jCommissioningCompleteHandler, jobject jOnConnectionSuccessHandler, + jobject jOnConnectionFailureHandler, jobject jOnNewOrUpdatedEndpointHandler) { chip::DeviceLayer::StackLock lock; @@ -68,8 +72,96 @@ JNI_METHOD(jboolean, openBasicCommissioningWindow)(JNIEnv * env, jobject, jint d VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI::SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + err = TvCastingAppJNIMgr().getOnConnectionSuccessHandler(false).SetUp(env, jOnConnectionSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "OnConnectionSuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getOnConnectionFailureHandler(false).SetUp(env, jOnConnectionFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "OnConnectionFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getOnNewOrUpdatedEndpointHandler(false).SetUp(env, jOnNewOrUpdatedEndpointHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "OnNewOrUpdatedEndpointHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + err = CastingServer::GetInstance()->OpenBasicCommissioningWindow( - [](CHIP_ERROR err) { TvCastingAppJNIMgr().getCommissioningCompleteHandler().Handle(err); }); + [](CHIP_ERROR err) { TvCastingAppJNIMgr().getCommissioningCompleteHandler().Handle(err); }, + [](TargetVideoPlayerInfo * videoPlayer) { TvCastingAppJNIMgr().getOnConnectionSuccessHandler(false).Handle(videoPlayer); }, + [](CHIP_ERROR err) { TvCastingAppJNIMgr().getOnConnectionFailureHandler(false).Handle(err); }, + [](TargetEndpointInfo * endpoint) { TvCastingAppJNIMgr().getOnNewOrUpdatedEndpointHandler(false).Handle(endpoint); }); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "CastingServer::OpenBasicCommissioningWindow failed: %" CHIP_ERROR_FORMAT, err.Format())); + +exit: + if (err != CHIP_NO_ERROR) + { + return false; + } + + return true; +} + +JNI_METHOD(jobject, readCachedVideoPlayers)(JNIEnv * env, jobject) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD readCachedVideoPlayers called"); + + jobject jVideoPlayerList = nullptr; + TargetVideoPlayerInfo * targetVideoPlayerInfoList = CastingServer::GetInstance()->ReadCachedTargetVideoPlayerInfos(); + if (targetVideoPlayerInfoList != nullptr) + { + chip::JniReferences::GetInstance().CreateArrayList(jVideoPlayerList); + for (size_t i = 0; targetVideoPlayerInfoList[i].IsInitialized(); i++) + { + jobject jVideoPlayer = nullptr; + CHIP_ERROR err = convertTargetVideoPlayerInfoToJVideoPlayer(&targetVideoPlayerInfoList[i], jVideoPlayer); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, + "Conversion from TargetVideoPlayerInfo * to jobject VideoPlayer failed: %" CHIP_ERROR_FORMAT, + err.Format()); + continue; + } + chip::JniReferences::GetInstance().AddToList(jVideoPlayerList, jVideoPlayer); + } + } + + return jVideoPlayerList; +} + +JNI_METHOD(jboolean, verifyOrEstablishConnection) +(JNIEnv * env, jobject, jobject videoPlayer, jobject jOnConnectionSuccessHandler, jobject jOnConnectionFailureHandler, + jobject jOnNewOrUpdatedEndpointHandler) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD verifyOrEstablishConnection called"); + + TargetVideoPlayerInfo targetVideoPlayerInfo; + CHIP_ERROR err = convertJVideoPlayerToTargetVideoPlayerInfo(videoPlayer, targetVideoPlayerInfo); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, + "Conversion from jobject VideoPlayer to TargetVideoPlayerInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getOnConnectionSuccessHandler(true).SetUp(env, jOnConnectionSuccessHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "OnConnectionSuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getOnConnectionFailureHandler(true).SetUp(env, jOnConnectionFailureHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "OnConnectionFailureHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = TvCastingAppJNIMgr().getOnNewOrUpdatedEndpointHandler(true).SetUp(env, jOnNewOrUpdatedEndpointHandler); + VerifyOrExit(CHIP_NO_ERROR == err, + ChipLogError(AppServer, "OnNewOrUpdatedEndpointHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); + + err = CastingServer::GetInstance()->VerifyOrEstablishConnection( + targetVideoPlayerInfo, + [](TargetVideoPlayerInfo * videoPlayer) { TvCastingAppJNIMgr().getOnConnectionSuccessHandler(true).Handle(videoPlayer); }, + [](CHIP_ERROR err) { TvCastingAppJNIMgr().getOnConnectionFailureHandler(true).Handle(err); }, + [](TargetEndpointInfo * endpoint) { TvCastingAppJNIMgr().getOnNewOrUpdatedEndpointHandler(true).Handle(endpoint); }); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "CastingServer::OpenBasicCommissioningWindow failed: %" CHIP_ERROR_FORMAT, err.Format())); @@ -82,6 +174,32 @@ JNI_METHOD(jboolean, openBasicCommissioningWindow)(JNIEnv * env, jobject, jint d return true; } +JNI_METHOD(jobject, getActiveTargetVideoPlayers)(JNIEnv * env, jobject) +{ + chip::DeviceLayer::StackLock lock; + + ChipLogProgress(AppServer, "JNI_METHOD getActiveTargetVideoPlayers called"); + + jobject jVideoPlayerList = nullptr; + TargetVideoPlayerInfo * targetVideoPlayerInfo = CastingServer::GetInstance()->GetActiveTargetVideoPlayer(); + if (targetVideoPlayerInfo != nullptr) + { + chip::JniReferences::GetInstance().CreateArrayList(jVideoPlayerList); + jobject jVideoPlayer = nullptr; + CHIP_ERROR err = convertTargetVideoPlayerInfoToJVideoPlayer(targetVideoPlayerInfo, jVideoPlayer); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "Conversion from TargetVideoPlayerInfo * to jobject VideoPlayer failed: %" CHIP_ERROR_FORMAT, + err.Format()); + } + else + { + chip::JniReferences::GetInstance().AddToList(jVideoPlayerList, jVideoPlayer); + } + } + return jVideoPlayerList; +} + JNI_METHOD(jboolean, sendUserDirectedCommissioningRequest)(JNIEnv * env, jobject, jstring addressJStr, jint port) { ChipLogProgress(AppServer, "JNI_METHOD sendUserDirectedCommissioningRequest called with port %d", port); @@ -105,16 +223,25 @@ JNI_METHOD(jboolean, sendUserDirectedCommissioningRequest)(JNIEnv * env, jobject return true; } -JNI_METHOD(jboolean, discoverCommissioners)(JNIEnv *, jobject) +JNI_METHOD(jboolean, sendCommissioningRequest)(JNIEnv * env, jobject, jobject jDiscoveredNodeData) { - ChipLogProgress(AppServer, "JNI_METHOD discoverCommissioners called"); - CHIP_ERROR err = CastingServer::GetInstance()->DiscoverCommissioners(); + ChipLogProgress(AppServer, "JNI_METHOD sendCommissioningRequest called"); + + chip::Dnssd::DiscoveredNodeData commissioner; + CHIP_ERROR err = convertJDiscoveredNodeDataToCppDiscoveredNodeData(jDiscoveredNodeData, commissioner); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, + "Conversion from jobject DiscoveredNodeData to Cpp DiscoveredNodeData failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = CastingServer::GetInstance()->SendUserDirectedCommissioningRequest(&commissioner); + +exit: if (err != CHIP_NO_ERROR) { - ChipLogError(AppServer, "TVCastingApp-JNI::discoverCommissioners failed: %" CHIP_ERROR_FORMAT, err.Format()); + ChipLogError(AppServer, "TVCastingApp-JNI::sendCommissioningRequest failed: %" CHIP_ERROR_FORMAT, err.Format()); return false; } - return true; } @@ -125,7 +252,7 @@ JNI_METHOD(void, init)(JNIEnv *, jobject) } JNI_METHOD(jboolean, contentLauncherLaunchURL) -(JNIEnv * env, jobject, jstring contentUrl, jstring contentDisplayStr, jobject jResponseHandler) +(JNIEnv * env, jobject, jobject contentApp, jstring contentUrl, jstring contentDisplayStr, jobject jResponseHandler) { chip::DeviceLayer::StackLock lock; @@ -133,13 +260,19 @@ JNI_METHOD(jboolean, contentLauncherLaunchURL) const char * nativeContentUrl = env->GetStringUTFChars(contentUrl, 0); const char * nativeContentDisplayStr = env->GetStringUTFChars(contentDisplayStr, 0); - CHIP_ERROR err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(ContentLauncher_LaunchURL).SetUp(env, jResponseHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(ContentLauncher_LaunchURL).SetUp(env, jResponseHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI::SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); - err = CastingServer::GetInstance()->ContentLauncherLaunchURL(nativeContentUrl, nativeContentDisplayStr, [](CHIP_ERROR err) { - TvCastingAppJNIMgr().getMediaCommandResponseHandler(ContentLauncher_LaunchURL).Handle(err); - }); + err = CastingServer::GetInstance()->ContentLauncherLaunchURL( + &endpoint, nativeContentUrl, nativeContentDisplayStr, + [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(ContentLauncher_LaunchURL).Handle(err); }); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "CastingServer::ContentLauncherLaunchURL failed %" CHIP_ERROR_FORMAT, err.Format())); @@ -213,7 +346,7 @@ CHIP_ERROR CreateContentSearch(JNIEnv * env, jobject jSearch, } JNI_METHOD(jboolean, contentLauncher_1launchContent) -(JNIEnv * env, jobject, jobject jSearch, jboolean jAutoplay, jstring jData, jobject jResponseHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jSearch, jboolean jAutoplay, jstring jData, jobject jResponseHandler) { chip::DeviceLayer::StackLock lock; @@ -228,6 +361,13 @@ JNI_METHOD(jboolean, contentLauncher_1launchContent) ListFreer listFreer; chip::app::Clusters::ContentLauncher::Structs::ContentSearch::Type search; CHIP_ERROR err = CreateContentSearch(env, jSearch, search, listFreer); + + TargetEndpointInfo endpoint; + err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "contentLauncher_1launchContent::Could not create ContentSearch object %" CHIP_ERROR_FORMAT, @@ -237,7 +377,7 @@ JNI_METHOD(jboolean, contentLauncher_1launchContent) VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI::SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); - err = CastingServer::GetInstance()->ContentLauncher_LaunchContent(search, autoplay, data, [](CHIP_ERROR err) { + err = CastingServer::GetInstance()->ContentLauncher_LaunchContent(&endpoint, search, autoplay, data, [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(ContentLauncher_LaunchContent).Handle(err); }); VerifyOrExit(CHIP_NO_ERROR == err, @@ -255,14 +395,20 @@ JNI_METHOD(jboolean, contentLauncher_1launchContent) } JNI_METHOD(jboolean, contentLauncher_1subscribeToSupportedStreamingProtocols) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD ContentLauncher_subscribeToSupportedStreamingProtocols called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getSupportedStreamingProtocolsSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getSupportedStreamingProtocolsSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr() @@ -278,7 +424,7 @@ JNI_METHOD(jboolean, contentLauncher_1subscribeToSupportedStreamingProtocols) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->ContentLauncher_SubscribeToSupportedStreamingProtocols( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::ContentLauncher::Attributes::SupportedStreamingProtocols::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getSupportedStreamingProtocolsSuccessHandler().Handle(responseData); @@ -306,19 +452,25 @@ JNI_METHOD(jboolean, contentLauncher_1subscribeToSupportedStreamingProtocols) } JNI_METHOD(jboolean, levelControl_1step) -(JNIEnv * env, jobject, jbyte stepMode, jbyte stepSize, jshort transitionTime, jbyte optionMask, jbyte optionOverride, - jobject jResponseHandler) +(JNIEnv * env, jobject, jobject contentApp, jbyte stepMode, jbyte stepSize, jshort transitionTime, jbyte optionMask, + jbyte optionOverride, jobject jResponseHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD levelControl_step called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(LevelControl_Step).SetUp(env, jResponseHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(LevelControl_Step).SetUp(env, jResponseHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->LevelControl_Step( - static_cast(stepMode), static_cast(stepSize), + &endpoint, static_cast(stepMode), static_cast(stepSize), static_cast(transitionTime), static_cast(optionMask), static_cast(optionOverride), [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(LevelControl_Step).Handle(err); }); VerifyOrExit(CHIP_NO_ERROR == err, @@ -334,18 +486,25 @@ JNI_METHOD(jboolean, levelControl_1step) } JNI_METHOD(jboolean, levelControl_1moveToLevel) -(JNIEnv * env, jobject, jbyte level, jshort transitionTime, jbyte optionMask, jbyte optionOverride, jobject jResponseHandler) +(JNIEnv * env, jobject, jobject contentApp, jbyte level, jshort transitionTime, jbyte optionMask, jbyte optionOverride, + jobject jResponseHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD levelControl_moveToLevel called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(LevelControl_MoveToLevel).SetUp(env, jResponseHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(LevelControl_MoveToLevel).SetUp(env, jResponseHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->LevelControl_MoveToLevel( - static_cast(level), static_cast(transitionTime), static_cast(optionMask), + &endpoint, static_cast(level), static_cast(transitionTime), static_cast(optionMask), static_cast(optionOverride), [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(LevelControl_MoveToLevel).Handle(err); }); VerifyOrExit(CHIP_NO_ERROR == err, @@ -361,14 +520,20 @@ JNI_METHOD(jboolean, levelControl_1moveToLevel) } JNI_METHOD(jboolean, levelControl_1subscribeToCurrentLevel) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD levelControl_subscribeToCurrentLevel called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getCurrentLevelSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getCurrentLevelSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(LevelControl_CurrentLevel).SetUp(env, jReadFailureHandler); @@ -382,7 +547,7 @@ JNI_METHOD(jboolean, levelControl_1subscribeToCurrentLevel) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->LevelControl_SubscribeToCurrentLevel( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::LevelControl::Attributes::CurrentLevel::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getCurrentLevelSuccessHandler().Handle(responseData); }, @@ -406,14 +571,20 @@ JNI_METHOD(jboolean, levelControl_1subscribeToCurrentLevel) } JNI_METHOD(jboolean, levelControl_1subscribeToMinLevel) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD levelControl_subscribeToMinLevel called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getMinLevelSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMinLevelSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(LevelControl_MinLevel).SetUp(env, jReadFailureHandler); @@ -425,7 +596,7 @@ JNI_METHOD(jboolean, levelControl_1subscribeToMinLevel) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->LevelControl_SubscribeToMinLevel( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::LevelControl::Attributes::MinLevel::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getMinLevelSuccessHandler().Handle(responseData); }, @@ -449,14 +620,20 @@ JNI_METHOD(jboolean, levelControl_1subscribeToMinLevel) } JNI_METHOD(jboolean, levelControl_1subscribeToMaxLevel) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD levelControl_subscribeToMaxLevel called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getMaxLevelSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMaxLevelSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(LevelControl_MaxLevel).SetUp(env, jReadFailureHandler); @@ -468,7 +645,7 @@ JNI_METHOD(jboolean, levelControl_1subscribeToMaxLevel) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->LevelControl_SubscribeToMaxLevel( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::LevelControl::Attributes::MaxLevel::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getMaxLevelSuccessHandler().Handle(responseData); }, @@ -492,18 +669,24 @@ JNI_METHOD(jboolean, levelControl_1subscribeToMaxLevel) } JNI_METHOD(jboolean, mediaPlayback_1play) -(JNIEnv * env, jobject, jobject jResponseHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jResponseHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_play called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_Play).SetUp(env, jResponseHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_Play).SetUp(env, jResponseHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->MediaPlayback_Play( - [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_Play).Handle(err); }); + &endpoint, [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_Play).Handle(err); }); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "CastingServer.MediaPlayback_Play failed %" CHIP_ERROR_FORMAT, err.Format())); @@ -517,18 +700,24 @@ JNI_METHOD(jboolean, mediaPlayback_1play) } JNI_METHOD(jboolean, mediaPlayback_1pause) -(JNIEnv * env, jobject, jobject jResponseHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jResponseHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_pause called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_Pause).SetUp(env, jResponseHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_Pause).SetUp(env, jResponseHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->MediaPlayback_Pause( - [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_Pause).Handle(err); }); + &endpoint, [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_Pause).Handle(err); }); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "CastingServer.MediaPlayback_Pause failed %" CHIP_ERROR_FORMAT, err.Format())); @@ -542,18 +731,25 @@ JNI_METHOD(jboolean, mediaPlayback_1pause) } JNI_METHOD(jboolean, mediaPlayback_1stopPlayback) -(JNIEnv * env, jobject, jobject jResponseHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jResponseHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_stopPlayback called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_StopPlayback).SetUp(env, jResponseHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_StopPlayback).SetUp(env, jResponseHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); - err = CastingServer::GetInstance()->MediaPlayback_StopPlayback( - [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_StopPlayback).Handle(err); }); + err = CastingServer::GetInstance()->MediaPlayback_StopPlayback(&endpoint, [](CHIP_ERROR err) { + TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_StopPlayback).Handle(err); + }); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "CastingServer.MediaPlayback_StopPlayback failed %" CHIP_ERROR_FORMAT, err.Format())); @@ -567,18 +763,24 @@ JNI_METHOD(jboolean, mediaPlayback_1stopPlayback) } JNI_METHOD(jboolean, mediaPlayback_1next) -(JNIEnv * env, jobject, jobject jResponseHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jResponseHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_next called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_Next).SetUp(env, jResponseHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_Next).SetUp(env, jResponseHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->MediaPlayback_Next( - [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_Next).Handle(err); }); + &endpoint, [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_Next).Handle(err); }); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "CastingServer.MediaPlayback_Next failed %" CHIP_ERROR_FORMAT, err.Format())); @@ -592,17 +794,23 @@ JNI_METHOD(jboolean, mediaPlayback_1next) } JNI_METHOD(jboolean, mediaPlayback_1seek) -(JNIEnv * env, jobject, jlong position, jobject jResponseHandler) +(JNIEnv * env, jobject, jobject contentApp, jlong position, jobject jResponseHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_seek called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_Seek).SetUp(env, jResponseHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_Seek).SetUp(env, jResponseHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); - err = CastingServer::GetInstance()->MediaPlayback_Seek(static_cast(position), [](CHIP_ERROR err) { + err = CastingServer::GetInstance()->MediaPlayback_Seek(&endpoint, static_cast(position), [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_Seek).Handle(err); }); VerifyOrExit(CHIP_NO_ERROR == err, @@ -618,18 +826,24 @@ JNI_METHOD(jboolean, mediaPlayback_1seek) } JNI_METHOD(jboolean, mediaPlayback_1skipForward) -(JNIEnv * env, jobject, jlong deltaPositionMilliseconds, jobject jResponseHandler) +(JNIEnv * env, jobject, jobject contentApp, jlong deltaPositionMilliseconds, jobject jResponseHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_skipForward called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_SkipForward).SetUp(env, jResponseHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_SkipForward).SetUp(env, jResponseHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->MediaPlayback_SkipForward( - static_cast(deltaPositionMilliseconds), + &endpoint, static_cast(deltaPositionMilliseconds), [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_SkipForward).Handle(err); }); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "CastingServer.MediaPlayback_SkipForward failed %" CHIP_ERROR_FORMAT, err.Format())); @@ -644,18 +858,24 @@ JNI_METHOD(jboolean, mediaPlayback_1skipForward) } JNI_METHOD(jboolean, mediaPlayback_1skipBackward) -(JNIEnv * env, jobject, jlong deltaPositionMilliseconds, jobject jResponseHandler) +(JNIEnv * env, jobject, jobject contentApp, jlong deltaPositionMilliseconds, jobject jResponseHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_skipBackward called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_SkipBackward).SetUp(env, jResponseHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_SkipBackward).SetUp(env, jResponseHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->MediaPlayback_SkipBackward( - static_cast(deltaPositionMilliseconds), + &endpoint, static_cast(deltaPositionMilliseconds), [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(MediaPlayback_SkipBackward).Handle(err); }); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "CastingServer.MediaPlayback_SkipBackward failed %" CHIP_ERROR_FORMAT, err.Format())); @@ -670,14 +890,20 @@ JNI_METHOD(jboolean, mediaPlayback_1skipBackward) } JNI_METHOD(jboolean, mediaPlayback_1subscribeToCurrentState) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_subscribeToCurrentState called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getCurrentStateSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getCurrentStateSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_CurrentState).SetUp(env, jReadFailureHandler); @@ -691,7 +917,7 @@ JNI_METHOD(jboolean, mediaPlayback_1subscribeToCurrentState) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->MediaPlayback_SubscribeToCurrentState( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::MediaPlayback::Attributes::CurrentState::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getCurrentStateSuccessHandler().Handle(responseData); }, @@ -715,14 +941,20 @@ JNI_METHOD(jboolean, mediaPlayback_1subscribeToCurrentState) } JNI_METHOD(jboolean, mediaPlayback_1subscribeToDuration) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_1subscribeToDuration called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getDurationSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getDurationSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_Duration).SetUp(env, jReadFailureHandler); @@ -735,7 +967,7 @@ JNI_METHOD(jboolean, mediaPlayback_1subscribeToDuration) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->MediaPlayback_SubscribeToDuration( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::MediaPlayback::Attributes::Duration::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getDurationSuccessHandler().Handle(responseData); }, @@ -759,14 +991,20 @@ JNI_METHOD(jboolean, mediaPlayback_1subscribeToDuration) } JNI_METHOD(jboolean, mediaPlayback_1subscribeToSampledPosition) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_1subscribeToSampledPosition called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getSampledPositionSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getSampledPositionSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_SampledPosition).SetUp(env, jReadFailureHandler); @@ -780,7 +1018,7 @@ JNI_METHOD(jboolean, mediaPlayback_1subscribeToSampledPosition) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->MediaPlayback_SubscribeToSampledPosition( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::MediaPlayback::Attributes::SampledPosition::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getSampledPositionSuccessHandler().Handle(responseData); @@ -805,14 +1043,20 @@ JNI_METHOD(jboolean, mediaPlayback_1subscribeToSampledPosition) } JNI_METHOD(jboolean, mediaPlayback_1subscribeToPlaybackSpeed) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_1subscribeToPlaybackSpeed called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getPlaybackSpeedSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getPlaybackSpeedSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_PlaybackSpeed).SetUp(env, jReadFailureHandler); @@ -826,7 +1070,7 @@ JNI_METHOD(jboolean, mediaPlayback_1subscribeToPlaybackSpeed) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->MediaPlayback_SubscribeToPlaybackSpeed( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::MediaPlayback::Attributes::PlaybackSpeed::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getPlaybackSpeedSuccessHandler().Handle(responseData); }, @@ -850,14 +1094,20 @@ JNI_METHOD(jboolean, mediaPlayback_1subscribeToPlaybackSpeed) } JNI_METHOD(jboolean, mediaPlayback_1subscribeToSeekRangeEnd) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_1subscribeToSeekRangeEnd called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getSeekRangeEndSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getSeekRangeEndSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_SeekRangeEnd).SetUp(env, jReadFailureHandler); @@ -871,7 +1121,7 @@ JNI_METHOD(jboolean, mediaPlayback_1subscribeToSeekRangeEnd) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->MediaPlayback_SubscribeToSeekRangeEnd( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::MediaPlayback::Attributes::SeekRangeEnd::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getSeekRangeEndSuccessHandler().Handle(responseData); }, @@ -895,14 +1145,20 @@ JNI_METHOD(jboolean, mediaPlayback_1subscribeToSeekRangeEnd) } JNI_METHOD(jboolean, mediaPlayback_1subscribeToSeekRangeStart) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD mediaPlayback_1subscribeToSeekRangeStart called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getSeekRangeStartSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getSeekRangeStartSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(MediaPlayback_SeekRangeStart).SetUp(env, jReadFailureHandler); @@ -916,7 +1172,7 @@ JNI_METHOD(jboolean, mediaPlayback_1subscribeToSeekRangeStart) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->MediaPlayback_SubscribeToSeekRangeStart( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::MediaPlayback::Attributes::SeekRangeStart::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getSeekRangeStartSuccessHandler().Handle(responseData); @@ -941,7 +1197,8 @@ JNI_METHOD(jboolean, mediaPlayback_1subscribeToSeekRangeStart) } JNI_METHOD(jboolean, applicationLauncher_1launchApp) -(JNIEnv * env, jobject, jshort catalogVendorId, jstring applicationId, jbyteArray data, jobject jResponseHandler) +(JNIEnv * env, jobject, jobject contentApp, jshort catalogVendorId, jstring applicationId, jbyteArray data, + jobject jResponseHandler) { chip::DeviceLayer::StackLock lock; @@ -953,13 +1210,18 @@ JNI_METHOD(jboolean, applicationLauncher_1launchApp) application.applicationId = CharSpan::fromCharString(nativeApplicationId); JniByteArray dataByteArray(env, data); - CHIP_ERROR err = - TvCastingAppJNIMgr().getMediaCommandResponseHandler(ApplicationLauncher_LaunchApp).SetUp(env, jResponseHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(ApplicationLauncher_LaunchApp).SetUp(env, jResponseHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->ApplicationLauncher_LaunchApp( - application, chip::MakeOptional(dataByteArray.byteSpan()), + &endpoint, application, chip::MakeOptional(dataByteArray.byteSpan()), [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(ApplicationLauncher_LaunchApp).Handle(err); }); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "CastingServer.ApplicationLauncher_LaunchApp failed %" CHIP_ERROR_FORMAT, err.Format())); @@ -975,7 +1237,7 @@ JNI_METHOD(jboolean, applicationLauncher_1launchApp) } JNI_METHOD(jboolean, applicationLauncher_1stopApp) -(JNIEnv * env, jobject, jshort catalogVendorId, jstring applicationId, jobject jResponseHandler) +(JNIEnv * env, jobject, jobject contentApp, jshort catalogVendorId, jstring applicationId, jobject jResponseHandler) { chip::DeviceLayer::StackLock lock; @@ -986,11 +1248,17 @@ JNI_METHOD(jboolean, applicationLauncher_1stopApp) const char * nativeApplicationId = env->GetStringUTFChars(applicationId, 0); application.applicationId = CharSpan::fromCharString(nativeApplicationId); - CHIP_ERROR err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(ApplicationLauncher_StopApp).SetUp(env, jResponseHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(ApplicationLauncher_StopApp).SetUp(env, jResponseHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); - err = CastingServer::GetInstance()->ApplicationLauncher_StopApp(application, [&](CHIP_ERROR err) { + err = CastingServer::GetInstance()->ApplicationLauncher_StopApp(&endpoint, application, [&](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(ApplicationLauncher_StopApp).Handle(err); }); VerifyOrExit(CHIP_NO_ERROR == err, @@ -1007,7 +1275,7 @@ JNI_METHOD(jboolean, applicationLauncher_1stopApp) } JNI_METHOD(jboolean, applicationLauncher_1hideApp) -(JNIEnv * env, jobject, jshort catalogVendorId, jstring applicationId, jobject jResponseHandler) +(JNIEnv * env, jobject, jobject contentApp, jshort catalogVendorId, jstring applicationId, jobject jResponseHandler) { chip::DeviceLayer::StackLock lock; @@ -1018,11 +1286,17 @@ JNI_METHOD(jboolean, applicationLauncher_1hideApp) const char * nativeApplicationId = env->GetStringUTFChars(applicationId, 0); application.applicationId = CharSpan::fromCharString(nativeApplicationId); - CHIP_ERROR err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(ApplicationLauncher_HideApp).SetUp(env, jResponseHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(ApplicationLauncher_HideApp).SetUp(env, jResponseHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); - err = CastingServer::GetInstance()->ApplicationLauncher_HideApp(application, [](CHIP_ERROR err) { + err = CastingServer::GetInstance()->ApplicationLauncher_HideApp(&endpoint, application, [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(ApplicationLauncher_HideApp).Handle(err); }); VerifyOrExit(CHIP_NO_ERROR == err, @@ -1039,7 +1313,7 @@ JNI_METHOD(jboolean, applicationLauncher_1hideApp) } JNI_METHOD(jboolean, targetNavigator_1navigateTarget) -(JNIEnv * env, jobject, jbyte target, jstring data, jobject jResponseHandler) +(JNIEnv * env, jobject, jobject contentApp, jbyte target, jstring data, jobject jResponseHandler) { chip::DeviceLayer::StackLock lock; @@ -1047,13 +1321,18 @@ JNI_METHOD(jboolean, targetNavigator_1navigateTarget) const char * nativeData = env->GetStringUTFChars(data, 0); - CHIP_ERROR err = - TvCastingAppJNIMgr().getMediaCommandResponseHandler(TargetNavigator_NavigateTarget).SetUp(env, jResponseHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(TargetNavigator_NavigateTarget).SetUp(env, jResponseHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->TargetNavigator_NavigateTarget( - static_cast(target), chip::MakeOptional(CharSpan::fromCharString(nativeData)), + &endpoint, static_cast(target), chip::MakeOptional(CharSpan::fromCharString(nativeData)), [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(TargetNavigator_NavigateTarget).Handle(err); }); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "CastingServer.TargetNavigator_NavigateTarget failed %" CHIP_ERROR_FORMAT, err.Format())); @@ -1069,14 +1348,20 @@ JNI_METHOD(jboolean, targetNavigator_1navigateTarget) } JNI_METHOD(jboolean, targetNavigator_1subscribeToCurrentTarget) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD targetNavigator_1subscribeToCurrentTarget called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getCurrentTargetSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getCurrentTargetSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(TargetNavigator_CurrentTarget).SetUp(env, jReadFailureHandler); @@ -1090,7 +1375,7 @@ JNI_METHOD(jboolean, targetNavigator_1subscribeToCurrentTarget) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->TargetNavigator_SubscribeToCurrentTarget( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::TargetNavigator::Attributes::CurrentTarget::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getCurrentTargetSuccessHandler().Handle(responseData); @@ -1115,14 +1400,20 @@ JNI_METHOD(jboolean, targetNavigator_1subscribeToCurrentTarget) } JNI_METHOD(jboolean, targetNavigator_1subscribeToTargetList) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD targetNavigator_1subscribeToTargetList called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getTargetListSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getTargetListSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(TargetNavigator_TargetList).SetUp(env, jReadFailureHandler); @@ -1136,7 +1427,7 @@ JNI_METHOD(jboolean, targetNavigator_1subscribeToTargetList) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->TargetNavigator_SubscribeToTargetList( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::TargetNavigator::Attributes::TargetList::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getTargetListSuccessHandler().Handle(responseData); }, @@ -1160,18 +1451,24 @@ JNI_METHOD(jboolean, targetNavigator_1subscribeToTargetList) } JNI_METHOD(jboolean, keypadInput_1sendKey) -(JNIEnv * env, jobject, jbyte keyCode, jobject jResponseHandler) +(JNIEnv * env, jobject, jobject contentApp, jbyte keyCode, jobject jResponseHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD keypadInput_sendKey called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(KeypadInput_SendKey).SetUp(env, jResponseHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getMediaCommandResponseHandler(KeypadInput_SendKey).SetUp(env, jResponseHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "MatterCallbackHandlerJNI.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->KeypadInput_SendKey( - static_cast(keyCode), + &endpoint, static_cast(keyCode), [](CHIP_ERROR err) { TvCastingAppJNIMgr().getMediaCommandResponseHandler(KeypadInput_SendKey).Handle(err); }); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "CastingServer.KeypadInput_SendKey failed %" CHIP_ERROR_FORMAT, err.Format())); @@ -1187,14 +1484,20 @@ JNI_METHOD(jboolean, keypadInput_1sendKey) // APPLICATION BASIC JNI_METHOD(jboolean, applicationBasic_1subscribeToVendorName) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD applicationBasic_1subscribeToVendorName called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getVendorNameSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getVendorNameSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(ApplicationBasic_VendorName).SetUp(env, jReadFailureHandler); @@ -1208,7 +1511,7 @@ JNI_METHOD(jboolean, applicationBasic_1subscribeToVendorName) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->ApplicationBasic_SubscribeToVendorName( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::VendorName::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getVendorNameSuccessHandler().Handle(responseData); }, @@ -1232,14 +1535,20 @@ JNI_METHOD(jboolean, applicationBasic_1subscribeToVendorName) } JNI_METHOD(jboolean, applicationBasic_1subscribeToVendorID) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD applicationBasic_1subscribeToVendorID called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getVendorIDSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getVendorIDSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(ApplicationBasic_VendorID).SetUp(env, jReadFailureHandler); @@ -1253,7 +1562,7 @@ JNI_METHOD(jboolean, applicationBasic_1subscribeToVendorID) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->ApplicationBasic_SubscribeToVendorID( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::VendorID::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getVendorIDSuccessHandler().Handle(responseData); }, @@ -1277,14 +1586,20 @@ JNI_METHOD(jboolean, applicationBasic_1subscribeToVendorID) } JNI_METHOD(jboolean, applicationBasic_1subscribeToApplicationName) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD applicationBasic_1subscribeToApplicationName called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getApplicationNameSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getApplicationNameSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(ApplicationBasic_ApplicationName).SetUp(env, jReadFailureHandler); @@ -1298,7 +1613,7 @@ JNI_METHOD(jboolean, applicationBasic_1subscribeToApplicationName) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->ApplicationBasic_SubscribeToApplicationName( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::ApplicationName::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getApplicationNameSuccessHandler().Handle(responseData); @@ -1323,14 +1638,20 @@ JNI_METHOD(jboolean, applicationBasic_1subscribeToApplicationName) } JNI_METHOD(jboolean, applicationBasic_1subscribeToProductID) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD applicationBasic_1subscribeToProductID called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getProductIDSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getProductIDSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = TvCastingAppJNIMgr().getSubscriptionReadFailureHandler(ApplicationBasic_ProductID).SetUp(env, jReadFailureHandler); @@ -1344,7 +1665,7 @@ JNI_METHOD(jboolean, applicationBasic_1subscribeToProductID) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->ApplicationBasic_SubscribeToProductID( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::ProductID::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getProductIDSuccessHandler().Handle(responseData); }, @@ -1368,14 +1689,20 @@ JNI_METHOD(jboolean, applicationBasic_1subscribeToProductID) } JNI_METHOD(jboolean, applicationBasic_1subscribeToApplicationVersion) -(JNIEnv * env, jobject, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, jint maxInterval, - jobject jSubscriptionEstablishedHandler) +(JNIEnv * env, jobject, jobject contentApp, jobject jReadSuccessHandler, jobject jReadFailureHandler, jint minInterval, + jint maxInterval, jobject jSubscriptionEstablishedHandler) { chip::DeviceLayer::StackLock lock; ChipLogProgress(AppServer, "JNI_METHOD applicationBasic_1subscribeToApplicationVersion called"); - CHIP_ERROR err = TvCastingAppJNIMgr().getApplicationVersionSuccessHandler().SetUp(env, jReadSuccessHandler); + TargetEndpointInfo endpoint; + CHIP_ERROR err = convertJContentAppToTargetEndpointInfo(contentApp, endpoint); + VerifyOrExit(err == CHIP_NO_ERROR, + ChipLogError(AppServer, "Conversion from jobject contentApp to TargetEndpointInfo * failed: %" CHIP_ERROR_FORMAT, + err.Format())); + + err = TvCastingAppJNIMgr().getApplicationVersionSuccessHandler().SetUp(env, jReadSuccessHandler); VerifyOrExit(CHIP_NO_ERROR == err, ChipLogError(AppServer, "SuccessHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = @@ -1390,7 +1717,7 @@ JNI_METHOD(jboolean, applicationBasic_1subscribeToApplicationVersion) ChipLogError(AppServer, "SubscriptionEstablishedHandler.SetUp failed %" CHIP_ERROR_FORMAT, err.Format())); err = CastingServer::GetInstance()->ApplicationBasic_SubscribeToApplicationVersion( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::ApplicationVersion::TypeInfo::DecodableArgType responseData) { TvCastingAppJNIMgr().getApplicationVersionSuccessHandler().Handle(responseData); 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 1336eb076d8ecd..71bd0bddb466be 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,6 +27,19 @@ class TvCastingAppJNI { public: MatterCallbackHandlerJNI & getCommissioningCompleteHandler() { return mCommissioningCompleteHandler; } + OnConnectionSuccessHandlerJNI & getOnConnectionSuccessHandler(bool preCommissioned) + { + return preCommissioned ? mPreCommissionedOnConnectionSuccessHandler : mCommissioningOnConnectionSuccessHandler; + } + FailureHandlerJNI & getOnConnectionFailureHandler(bool preCommissioned) + { + return preCommissioned ? mPreCommissionedOnConnectionFailureHandler : mCommissioningOnConnectionFailureHandler; + } + OnNewOrUpdatedEndpointHandlerJNI & getOnNewOrUpdatedEndpointHandler(bool preCommissioned) + { + return preCommissioned ? mPreCommissionedOnNewOrUpdatedEndpointHandler : mCommissioningOnNewOrUpdatedEndpointHandler; + } + MatterCallbackHandlerJNI & getMediaCommandResponseHandler(enum MediaCommandName name) { return mMediaCommandResponseHandler[name]; @@ -73,6 +86,14 @@ class TvCastingAppJNI static TvCastingAppJNI sInstance; MatterCallbackHandlerJNI mCommissioningCompleteHandler; + OnConnectionSuccessHandlerJNI mCommissioningOnConnectionSuccessHandler; + FailureHandlerJNI mCommissioningOnConnectionFailureHandler; + OnNewOrUpdatedEndpointHandlerJNI mCommissioningOnNewOrUpdatedEndpointHandler; + + OnConnectionSuccessHandlerJNI mPreCommissionedOnConnectionSuccessHandler; + FailureHandlerJNI mPreCommissionedOnConnectionFailureHandler; + OnNewOrUpdatedEndpointHandlerJNI mPreCommissionedOnNewOrUpdatedEndpointHandler; + MatterCallbackHandlerJNI mMediaCommandResponseHandler[MEDIA_COMMAND_COUNT]; FailureHandlerJNI mSubscriptionReadFailureHandler[MEDIA_ATTRIBUTE_COUNT]; SubscriptionEstablishedHandlerJNI mSubscriptionEstablishedHandler[MEDIA_ATTRIBUTE_COUNT]; diff --git a/examples/tv-casting-app/android/App/app/src/main/res/values/strings.xml b/examples/tv-casting-app/android/App/app/src/main/res/values/strings.xml index f180a85da282da..16900225b2e0cc 100644 --- a/examples/tv-casting-app/android/App/app/src/main/res/values/strings.xml +++ b/examples/tv-casting-app/android/App/app/src/main/res/values/strings.xml @@ -13,10 +13,11 @@ Media Playback Media Playback Subscribe to Current State - Minimum interval (in ms) + Minimum interval (in sec) 0 - Maximum interval (in ms) - 4000 + Maximum interval (in sec) + 1 Subscribe Reported Current State + Endpoint ID \ No newline at end of file diff --git a/examples/tv-casting-app/android/BUILD.gn b/examples/tv-casting-app/android/BUILD.gn index c0b60fed7367f4..dace5cd221db8a 100644 --- a/examples/tv-casting-app/android/BUILD.gn +++ b/examples/tv-casting-app/android/BUILD.gn @@ -25,6 +25,8 @@ shared_library("jni") { sources = [ "${chip_root}/examples/tv-casting-app/tv-casting-common/include/CHIPProjectAppConfig.h", "App/app/src/main/jni/cpp/Constants.h", + "App/app/src/main/jni/cpp/ConversionUtils.cpp", + "App/app/src/main/jni/cpp/ConversionUtils.h", "App/app/src/main/jni/cpp/JNIDACProvider.cpp", "App/app/src/main/jni/cpp/JNIDACProvider.h", "App/app/src/main/jni/cpp/MatterCallbackHandler-JNI.cpp", @@ -60,17 +62,22 @@ android_library("java") { ] sources = [ + "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", "App/app/src/main/jni/com/chip/casting/DACProviderStub.java", + "App/app/src/main/jni/com/chip/casting/DiscoveredNodeData.java", "App/app/src/main/jni/com/chip/casting/FailureCallback.java", "App/app/src/main/jni/com/chip/casting/MatterCallbackHandler.java", "App/app/src/main/jni/com/chip/casting/MatterError.java", "App/app/src/main/jni/com/chip/casting/MediaPlaybackTypes.java", + "App/app/src/main/jni/com/chip/casting/NsdDiscoveryListener.java", + "App/app/src/main/jni/com/chip/casting/NsdResolveListener.java", "App/app/src/main/jni/com/chip/casting/SubscriptionEstablishedCallback.java", "App/app/src/main/jni/com/chip/casting/SuccessCallback.java", "App/app/src/main/jni/com/chip/casting/TargetNavigatorTypes.java", "App/app/src/main/jni/com/chip/casting/TvCastingApp.java", + "App/app/src/main/jni/com/chip/casting/VideoPlayer.java", ] javac_flags = [ "-Xlint:deprecation" ] 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 0a4ab42cb3c900..b03d64304cf41e 100644 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge.xcodeproj/project.pbxproj +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge.xcodeproj/project.pbxproj @@ -11,15 +11,17 @@ 3C4E53B028E4F28100F293E8 /* MediaPlaybackTypes.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3C4E53AF28E4F28100F293E8 /* MediaPlaybackTypes.mm */; }; 3C4E53B228E5184C00F293E8 /* TargetNavigatorTypes.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3C4E53B128E5184C00F293E8 /* TargetNavigatorTypes.mm */; }; 3C4E53B628E5595A00F293E8 /* ContentLauncherTypes.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3C4E53B528E5595A00F293E8 /* ContentLauncherTypes.mm */; }; + 3C81C74C28F7A777001CB9D1 /* ContentApp.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3C81C74B28F7A777001CB9D1 /* ContentApp.mm */; }; + 3C81C75028F7A7D3001CB9D1 /* VideoPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C81C74F28F7A7D3001CB9D1 /* VideoPlayer.m */; }; 3CCB87212869085400771BAD /* MatterTvCastingBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CCB87202869085400771BAD /* MatterTvCastingBridge.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3CCB8737286A555500771BAD /* libTvCastingCommon.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CCB8735286A555500771BAD /* libTvCastingCommon.a */; }; 3CCB8738286A555500771BAD /* libmbedtls.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CCB8736286A555500771BAD /* libmbedtls.a */; settings = {ATTRIBUTES = (Required, ); }; }; 3CCB873F286A593700771BAD /* DiscoveredNodeData.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CCB8739286A593700771BAD /* DiscoveredNodeData.mm */; }; 3CCB8740286A593700771BAD /* CastingServerBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CCB873A286A593700771BAD /* CastingServerBridge.h */; }; 3CCB8741286A593700771BAD /* DiscoveredNodeData.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CCB873B286A593700771BAD /* DiscoveredNodeData.h */; }; - 3CCB8742286A593700771BAD /* DiscoveredNodeDataConverter.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3CCB873C286A593700771BAD /* DiscoveredNodeDataConverter.hpp */; }; + 3CCB8742286A593700771BAD /* ConversionUtils.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3CCB873C286A593700771BAD /* ConversionUtils.hpp */; }; 3CCB8743286A593700771BAD /* CastingServerBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CCB873D286A593700771BAD /* CastingServerBridge.mm */; }; - 3CCB8744286A593700771BAD /* DiscoveredNodeDataConverter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CCB873E286A593700771BAD /* DiscoveredNodeDataConverter.mm */; }; + 3CCB8744286A593700771BAD /* ConversionUtils.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CCB873E286A593700771BAD /* ConversionUtils.mm */; }; 3CF8532728E37F1000F07B9F /* MatterError.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CF8532628E37F1000F07B9F /* MatterError.mm */; }; /* End PBXBuildFile section */ @@ -31,6 +33,10 @@ 3C4E53B328E5185F00F293E8 /* TargetNavigatorTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TargetNavigatorTypes.h; sourceTree = ""; }; 3C4E53B428E5593700F293E8 /* ContentLauncherTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ContentLauncherTypes.h; sourceTree = ""; }; 3C4E53B528E5595A00F293E8 /* ContentLauncherTypes.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ContentLauncherTypes.mm; sourceTree = ""; }; + 3C81C74B28F7A777001CB9D1 /* ContentApp.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ContentApp.mm; sourceTree = ""; }; + 3C81C74E28F7A7AE001CB9D1 /* ContentApp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ContentApp.h; sourceTree = ""; }; + 3C81C74F28F7A7D3001CB9D1 /* VideoPlayer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VideoPlayer.m; sourceTree = ""; }; + 3C81C75128F7A7DF001CB9D1 /* VideoPlayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VideoPlayer.h; sourceTree = ""; }; 3CA1CA7728E243750023ED44 /* MediaPlaybackTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MediaPlaybackTypes.h; sourceTree = ""; }; 3CCB871D2869085400771BAD /* MatterTvCastingBridge.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MatterTvCastingBridge.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3CCB87202869085400771BAD /* MatterTvCastingBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MatterTvCastingBridge.h; sourceTree = ""; }; @@ -39,9 +45,9 @@ 3CCB8739286A593700771BAD /* DiscoveredNodeData.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DiscoveredNodeData.mm; sourceTree = ""; }; 3CCB873A286A593700771BAD /* CastingServerBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CastingServerBridge.h; sourceTree = ""; }; 3CCB873B286A593700771BAD /* DiscoveredNodeData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiscoveredNodeData.h; sourceTree = ""; }; - 3CCB873C286A593700771BAD /* DiscoveredNodeDataConverter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DiscoveredNodeDataConverter.hpp; sourceTree = ""; }; + 3CCB873C286A593700771BAD /* ConversionUtils.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ConversionUtils.hpp; sourceTree = ""; }; 3CCB873D286A593700771BAD /* CastingServerBridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CastingServerBridge.mm; sourceTree = ""; }; - 3CCB873E286A593700771BAD /* DiscoveredNodeDataConverter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DiscoveredNodeDataConverter.mm; sourceTree = ""; }; + 3CCB873E286A593700771BAD /* ConversionUtils.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ConversionUtils.mm; sourceTree = ""; }; 3CF8532528E37ED800F07B9F /* MatterError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MatterError.h; sourceTree = ""; }; 3CF8532628E37F1000F07B9F /* MatterError.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MatterError.mm; sourceTree = ""; }; /* End PBXFileReference section */ @@ -85,10 +91,14 @@ 3CCB873D286A593700771BAD /* CastingServerBridge.mm */, 3CCB873B286A593700771BAD /* DiscoveredNodeData.h */, 3CCB8739286A593700771BAD /* DiscoveredNodeData.mm */, - 3CCB873E286A593700771BAD /* DiscoveredNodeDataConverter.mm */, - 3CCB873C286A593700771BAD /* DiscoveredNodeDataConverter.hpp */, + 3CCB873C286A593700771BAD /* ConversionUtils.hpp */, + 3CCB873E286A593700771BAD /* ConversionUtils.mm */, 3C4AE64E286A7D40005B52A4 /* OnboardingPayload.h */, 3C4AE64F286A7D4D005B52A4 /* OnboardingPayload.m */, + 3C81C74E28F7A7AE001CB9D1 /* ContentApp.h */, + 3C81C74B28F7A777001CB9D1 /* ContentApp.mm */, + 3C81C75128F7A7DF001CB9D1 /* VideoPlayer.h */, + 3C81C74F28F7A7D3001CB9D1 /* VideoPlayer.m */, 3CF8532528E37ED800F07B9F /* MatterError.h */, 3CF8532628E37F1000F07B9F /* MatterError.mm */, 3C4E53B428E5593700F293E8 /* ContentLauncherTypes.h */, @@ -109,7 +119,7 @@ buildActionMask = 2147483647; files = ( 3CCB8740286A593700771BAD /* CastingServerBridge.h in Headers */, - 3CCB8742286A593700771BAD /* DiscoveredNodeDataConverter.hpp in Headers */, + 3CCB8742286A593700771BAD /* ConversionUtils.hpp in Headers */, 3CCB8741286A593700771BAD /* DiscoveredNodeData.h in Headers */, 3CCB87212869085400771BAD /* MatterTvCastingBridge.h in Headers */, ); @@ -208,9 +218,11 @@ 3C4E53B228E5184C00F293E8 /* TargetNavigatorTypes.mm in Sources */, 3CF8532728E37F1000F07B9F /* MatterError.mm in Sources */, 3C4E53B628E5595A00F293E8 /* ContentLauncherTypes.mm in Sources */, - 3CCB8744286A593700771BAD /* DiscoveredNodeDataConverter.mm in Sources */, + 3C81C75028F7A7D3001CB9D1 /* VideoPlayer.m in Sources */, + 3CCB8744286A593700771BAD /* ConversionUtils.mm in Sources */, 3C4E53B028E4F28100F293E8 /* MediaPlaybackTypes.mm in Sources */, 3CCB873F286A593700771BAD /* DiscoveredNodeData.mm in Sources */, + 3C81C74C28F7A777001CB9D1 /* ContentApp.mm in Sources */, 3C4AE650286A7D4D005B52A4 /* OnboardingPayload.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h index 6d43a0d280c659..f828ae5f01c70f 100644 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.h @@ -15,12 +15,14 @@ * limitations under the License. */ +#import "ContentApp.h" #import "ContentLauncherTypes.h" #import "DiscoveredNodeData.h" #import "MatterError.h" #import "MediaPlaybackTypes.h" #import "OnboardingPayload.h" #import "TargetNavigatorTypes.h" +#import "VideoPlayer.h" #import #ifndef CastingServerBridge_h @@ -72,6 +74,19 @@ clientQueue:(dispatch_queue_t _Nonnull)clientQueue udcRequestSentHandler:(nullable void (^)(bool))udcRequestSentHandler; +/*! + @brief Send a User Directed Commissioning request to a commissioner TV + + @param commissioner Commissioner to request commissioning from + + @param clientQueue Queue to dispatch the call to the udcRequestSentHandler on + + @param udcRequestSentHandler Handler to call on sending the User Directed Commissioning request + */ +- (void)sendUserDirectedCommissioningRequest:(DiscoveredNodeData * _Nonnull)commissioner + clientQueue:(dispatch_queue_t _Nonnull)clientQueue + udcRequestSentHandler:(nullable void (^)(bool))udcRequestSentHandler; + /*! @brief Return the onboarding payload for this app (setup passcode, discriminator) @@ -82,31 +97,87 @@ /*! @brief Request opening of a basic commissioning window + @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 clientQueue Queue to dispatch the call to the commissioningWindowRequestedHandler on + @param onConnectionSuccessCallback Handles a VideoPlayer * once connection is successfully established + + @param onConnectionFailureCallback Handles MatterError if there is a failure in establishing connection + + @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:(void (^_Nonnull)(bool))commissioningCompleteCallback - clientQueue:(dispatch_queue_t _Nonnull)clientQueue - commissioningWindowRequestedHandler:(void (^_Nonnull)(bool))commissioningWindowRequestedHandler; +- (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; + +/*! + @brief Gets the list of VideoPlayers currently connected + + @param clientQueue Queue to invoke callbacks on + + @param activeTargetVideoPlayersHandler Handles NSMutableArray of active/currently connected VideoPlayers. Nil, if no such + VideoPlayers are found. + */ +- (void)getActiveTargetVideoPlayers:(dispatch_queue_t _Nonnull)clientQueue + activeTargetVideoPlayersHandler:(nullable void (^)(NSMutableArray * _Nullable))activeTargetVideoPlayersHandler; + +/*! + @brief Reads all previously connected video players from cache. These are not connected. + + @param clientQueue Queue to invoke callbacks on + + @param readCachedVideoPlayersHandler Handles NSMutableArray of VideoPlayers from the cache. Empty, if no such VideoPlayers are + found. + */ +- (void)readCachedVideoPlayers:(dispatch_queue_t _Nonnull)clientQueue + readCachedVideoPlayersHandler:(nullable void (^)(NSMutableArray * _Nullable))readCachedVideoPlayersHandler; + +/*! + @brief Verify if a connection exists or connect to the VideoPlayer passed in as parameter. + + @param clientQueue Queue to invoke callbacks on + + @param requestSentHandler Handles MatterError and called after the request has been sent + + @param onConnectionSuccessCallback Handles a VideoPlayer * once connection is successfully established + + @param onConnectionFailureCallback Handles MatterError if there is a failure in establishing connection + + @param onNewOrUpdatedEndpointCallback Handles a ContentApp * for each new ContentApp is found. May be called multiple times based + on the number of ContentApp + */ +- (void)verifyOrEstablishConnection:(VideoPlayer * _Nonnull)videoPlayer + clientQueue:(dispatch_queue_t _Nonnull)clientQueue + requestSentHandler:(nullable void (^)(MatterError * _Nonnull))requestSentHandler + onConnectionSuccessCallback:(void (^_Nonnull)(VideoPlayer * _Nonnull))onConnectionSuccessCallback + onConnectionFailureCallback:(void (^_Nonnull)(MatterError * _Nonnull))onConnectionFailureCallback + onNewOrUpdatedEndpointCallback:(void (^_Nonnull)(ContentApp * _Nonnull))onNewOrUpdatedEndpointCallback; /*! @brief Send a ContentLauncher:LaunchURL request to a TV + @param contentApp Content app endpoint to target + @param contentUrl URL of the content to launch on the TV @param contentDisplayStr Display string value corresponding to the content @param responseCallback Callback for when the response has been received - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request */ -- (void)contentLauncher_launchUrl:(NSString * _Nonnull)contentUrl +- (void)contentLauncher_launchUrl:(ContentApp * _Nonnull)contentApp + contentUrl:(NSString * _Nonnull)contentUrl contentDisplayStr:(NSString * _Nonnull)contentDisplayStr responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue @@ -115,6 +186,8 @@ /*! @brief Send a ContentLauncher:LaunchContent request to a TV + @param contentApp Content app endpoint to target + @param contentSearch Indicates the content to launch @param autoPlay Play Best match automatically if true, otherwise display matches @@ -123,11 +196,12 @@ @param responseCallback Callback for when the response has been received - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request */ -- (void)contentLauncher_launchContent:(ContentLauncher_ContentSearch * _Nonnull)contentSearch +- (void)contentLauncher_launchContent:(ContentApp * _Nonnull)contentApp + contentSearch:(ContentLauncher_ContentSearch * _Nonnull)contentSearch autoPlay:(bool)autoPlay data:(NSString * _Nullable)data responseCallback:(void (^_Nonnull)(bool))responseCallback @@ -137,11 +211,13 @@ /*! @brief Subscribe to ContentLauncher:SupportedStreamingProtocols + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -151,7 +227,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)contentLauncher_subscribeSupportedStreamingProtocols:(uint16_t)minInterval +- (void)contentLauncher_subscribeSupportedStreamingProtocols:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -162,6 +239,8 @@ /*! @brief Send a LevelControl:Step request to a TV + @param contentApp Content app endpoint to target + @param stepMode Increase (0x00) or Decrease (0x01) the device’s level @param stepSize Number of units to step the device's level by @@ -174,11 +253,12 @@ @param responseCallback Callback for when the response has been received - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request */ -- (void)levelControl_step:(uint8_t)stepMode +- (void)levelControl_step:(ContentApp * _Nonnull)contentApp + stepMode:(uint8_t)stepMode stepSize:(uint8_t)stepSize transitionTime:(uint16_t)transitionTime optionMask:(uint8_t)optionMask @@ -190,6 +270,8 @@ /*! @brief Send a LevelControl:MoveToLevel request to a TV + @param contentApp Content app endpoint to target + @param level the level to which the device should move @param transitionTime Time that SHALL be taken to perform the step, in tenths of a second @@ -200,11 +282,12 @@ @param responseCallback Callback for when the response has been received - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request */ -- (void)levelControl_moveToLevel:(uint8_t)level +- (void)levelControl_moveToLevel:(ContentApp * _Nonnull)contentApp + level:(uint8_t)level transitionTime:(uint16_t)transitionTime optionMask:(uint8_t)optionMask optionOverride:(uint8_t)optionOverride @@ -215,11 +298,13 @@ /*! @brief Subscribe to LevelControl:CurrentLevel + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -229,7 +314,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)levelControl_subscribeCurrentLevel:(uint16_t)minInterval +- (void)levelControl_subscribeCurrentLevel:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -240,11 +326,13 @@ /*! @brief Subscribe to LevelControl:MinLevel + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -254,7 +342,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)levelControl_subscribeMinLevel:(uint16_t)minInterval +- (void)levelControl_subscribeMinLevel:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -265,11 +354,13 @@ /*! @brief Subscribe to LevelControl:MaxLevel + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -279,7 +370,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)levelControl_subscribeMaxLevel:(uint16_t)minInterval +- (void)levelControl_subscribeMaxLevel:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -290,67 +382,82 @@ /*! @brief Send a MediaPlayback:Play request to a TV + @param contentApp Content app endpoint to target + @param responseCallback Callback for when the response has been received - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request */ -- (void)mediaPlayback_play:(void (^_Nonnull)(bool))responseCallback +- (void)mediaPlayback_play:(ContentApp * _Nonnull)contentApp + responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler; /*! @brief Send a MediaPlayback:Pause request to a TV + @param contentApp Content app endpoint to target + @param responseCallback Callback for when the response has been received - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request */ -- (void)mediaPlayback_pause:(void (^_Nonnull)(bool))responseCallback +- (void)mediaPlayback_pause:(ContentApp * _Nonnull)contentApp + responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler; /*! @brief Send a MediaPlayback:StopPlayback request to a TV + @param contentApp Content app endpoint to target + @param responseCallback Callback for when the response has been received - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request */ -- (void)mediaPlayback_stopPlayback:(void (^_Nonnull)(bool))responseCallback +- (void)mediaPlayback_stopPlayback:(ContentApp * _Nonnull)contentApp + responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler; /*! @brief Send a MediaPlayback:Next request to a TV + @param contentApp Content app endpoint to target + @param responseCallback Callback for when the response has been received - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request */ -- (void)mediaPlayback_next:(void (^_Nonnull)(bool))responseCallback +- (void)mediaPlayback_next:(ContentApp * _Nonnull)contentApp + responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler; /*! @brief Send a MediaPlayback:Seek request to a TV + @param contentApp Content app endpoint to target + @param position the position (in milliseconds) in the media to seek to @param responseCallback Callback for when the response has been received - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request */ -- (void)mediaPlayback_seek:(uint8_t)position +- (void)mediaPlayback_seek:(ContentApp * _Nonnull)contentApp + position:(uint8_t)position responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler; @@ -358,15 +465,18 @@ /*! @brief Send a MediaPlayback:SkipForward request to a TV + @param contentApp Content app endpoint to target + @param deltaPositionMilliseconds the duration of the time span to skip forward in the media, in milliseconds @param responseCallback Callback for when the response has been received - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request */ -- (void)mediaPlayback_skipForward:(uint64_t)deltaPositionMilliseconds +- (void)mediaPlayback_skipForward:(ContentApp * _Nonnull)contentApp + deltaPositionMilliseconds:(uint64_t)deltaPositionMilliseconds responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler; @@ -374,15 +484,18 @@ /*! @brief Send a MediaPlayback:SkipBackward request to a TV + @param contentApp Content app endpoint to target + @param deltaPositionMilliseconds the duration of the time span to skip backward in the media, in milliseconds @param responseCallback Callback for when the response has been received - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request */ -- (void)mediaPlayback_skipBackward:(uint64_t)deltaPositionMilliseconds +- (void)mediaPlayback_skipBackward:(ContentApp * _Nonnull)contentApp + deltaPositionMilliseconds:(uint64_t)deltaPositionMilliseconds responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler; @@ -390,11 +503,13 @@ /*! @brief Subscribe to MediaPlayback:CurrentState + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -404,7 +519,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)mediaPlayback_subscribeCurrentState:(uint16_t)minInterval +- (void)mediaPlayback_subscribeCurrentState:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -415,11 +531,13 @@ /*! @brief Subscribe to MediaPlayback:StartTime + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -429,7 +547,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)mediaPlayback_subscribeStartTime:(uint16_t)minInterval +- (void)mediaPlayback_subscribeStartTime:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -440,11 +559,13 @@ /*! @brief Subscribe to MediaPlayback:Duration + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -454,7 +575,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)mediaPlayback_subscribeDuration:(uint16_t)minInterval +- (void)mediaPlayback_subscribeDuration:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -465,11 +587,13 @@ /*! @brief Subscribe to MediaPlayback:SampledPosition + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -479,7 +603,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)mediaPlayback_subscribeSampledPosition:(uint16_t)minInterval +- (void)mediaPlayback_subscribeSampledPosition:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -490,11 +615,13 @@ /*! @brief Subscribe to MediaPlayback:PlaybackSpeed + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -504,7 +631,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)mediaPlayback_subscribePlaybackSpeed:(uint16_t)minInterval +- (void)mediaPlayback_subscribePlaybackSpeed:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -515,11 +643,13 @@ /*! @brief Subscribe to MediaPlayback:SeekRangeEnd + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -529,7 +659,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)mediaPlayback_subscribeSeekRangeEnd:(uint16_t)minInterval +- (void)mediaPlayback_subscribeSeekRangeEnd:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -540,11 +671,13 @@ /*! @brief Subscribe to MediaPlayback:SeekRangeStart + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -554,7 +687,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)mediaPlayback_subscribeSeekRangeStart:(uint16_t)minInterval +- (void)mediaPlayback_subscribeSeekRangeStart:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -564,6 +698,8 @@ /*! @brief Send a ApplicationLauncher:LaunchApp request to a TV + @param contentApp Content app endpoint to target + @param catalogVendorId CSA-issued vendor ID for the catalog @param applicationId application identifier, unique within a catalog, expressed as a string, such as "PruneVideo" or "Company X" @@ -572,11 +708,12 @@ @param responseCallback Callback for when the response has been received - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request */ -- (void)applicationLauncher_launchApp:(uint16_t)catalogVendorId +- (void)applicationLauncher_launchApp:(ContentApp * _Nonnull)contentApp + catalogVendorId:(uint16_t)catalogVendorId applicationId:(NSString * _Nonnull)applicationId data:(NSData * _Nullable)data responseCallback:(void (^_Nonnull)(bool))responseCallback @@ -586,17 +723,20 @@ /*! @brief Send a ApplicationLauncher:StopApp request to a TV + @param contentApp Content app endpoint to target + @param catalogVendorId CSA-issued vendor ID for the catalog @param applicationId application identifier, unique within a catalog, expressed as a string, such as "PruneVideo" or "Company X" @param responseCallback Callback for when the response has been received - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request */ -- (void)applicationLauncher_stopApp:(uint16_t)catalogVendorId +- (void)applicationLauncher_stopApp:(ContentApp * _Nonnull)contentApp + catalogVendorId:(uint16_t)catalogVendorId applicationId:(NSString * _Nonnull)applicationId responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue @@ -605,17 +745,20 @@ /*! @brief Send a ApplicationLauncher:HideApp request to a TV + @param contentApp Content app endpoint to target + @param catalogVendorId CSA-issued vendor ID for the catalog @param applicationId application identifier, unique within a catalog, expressed as a string, such as "PruneVideo" or "Company X" @param responseCallback Callback for when the response has been received - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request */ -- (void)applicationLauncher_hideApp:(uint16_t)catalogVendorId +- (void)applicationLauncher_hideApp:(ContentApp * _Nonnull)contentApp + catalogVendorId:(uint16_t)catalogVendorId applicationId:(NSString * _Nonnull)applicationId responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue @@ -624,6 +767,8 @@ /*! @brief Send a TargetNavigator:NavigateTarget request to a TV + @param contentApp Content app endpoint to target + @param target Identifier for the target for UX navigation, contained within one of the TargetInfo objects in the TargetList attribute list. @@ -631,11 +776,12 @@ @param responseCallback Callback for when the response has been received - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request */ -- (void)targetNavigator_navigateTarget:(uint8_t)target +- (void)targetNavigator_navigateTarget:(ContentApp * _Nonnull)contentApp + target:(uint8_t)target data:(NSString * _Nullable)data responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue @@ -644,11 +790,13 @@ /*! @brief Subscribe to TargetNavigator:TargetList + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -658,7 +806,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)targetNavigator_subscribeTargetList:(uint16_t)minInterval +- (void)targetNavigator_subscribeTargetList:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -669,11 +818,13 @@ /*! @brief Subscribe to TargetNavigator:CurrentTarget + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -683,7 +834,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)targetNavigator_subscribeCurrentTarget:(uint16_t)minInterval +- (void)targetNavigator_subscribeCurrentTarget:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -694,17 +846,20 @@ /*! @brief Send a KeypadInput:SendKey request to a TV + @param contentApp Content app endpoint to target + @param keyCode Key Code to process. If a second SendKey request with the same KeyCode value is received within 200ms, then the endpoint will consider the first key press to be a press and hold. When such a repeat KeyCode value is not received within 200ms, then the endpoint will consider the last key press to be a release. @param responseCallback Callback for when the response has been received - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request */ -- (void)keypadInput_sendKey:(uint8_t)keyCode +- (void)keypadInput_sendKey:(ContentApp * _Nonnull)contentApp + keyCode:(uint8_t)keyCode responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler; @@ -712,11 +867,13 @@ /*! @brief Subscribe to ApplicationBasic:VendorName + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -726,7 +883,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)applicationBasic_subscribeVendorName:(uint16_t)minInterval +- (void)applicationBasic_subscribeVendorName:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -737,11 +895,13 @@ /*! @brief Subscribe to ApplicationBasic:VendorID + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -751,7 +911,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)applicationBasic_subscribeVendorID:(uint16_t)minInterval +- (void)applicationBasic_subscribeVendorID:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -762,11 +923,13 @@ /*! @brief Subscribe to ApplicationBasic:ApplicationName + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -776,7 +939,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)applicationBasic_subscribeApplicationName:(uint16_t)minInterval +- (void)applicationBasic_subscribeApplicationName:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -787,11 +951,13 @@ /*! @brief Subscribe to ApplicationBasic:ProductID + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -801,7 +967,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)applicationBasic_subscribeProductID:(uint16_t)minInterval +- (void)applicationBasic_subscribeProductID:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -812,11 +979,13 @@ /*! @brief Subscribe to ApplicationBasic:ApplicationVersion + @param contentApp Content app endpoint to target + @param minInterval Minimum interval between attribute read reports @param maxInterval Maximum interval between attribute read reports - @param clientQueue Queue to dispatch the call to the requestSentHandler on + @param clientQueue Queue to invoke callbacks on @param requestSentHandler Handler to call on sending the request @@ -826,7 +995,8 @@ @param subscriptionEstablishedCallback Callback for when the requested subscription has been established successfully */ -- (void)applicationBasic_subscribeApplicationVersion:(uint16_t)minInterval +- (void)applicationBasic_subscribeApplicationVersion:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm index c690e49af7ef7c..dd89e32cbd42fe 100644 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm @@ -18,7 +18,7 @@ #import "CastingServerBridge.h" #import "CastingServer.h" -#import "DiscoveredNodeDataConverter.hpp" +#import "ConversionUtils.hpp" #import "MatterCallbacks.h" #import "OnboardingPayload.h" @@ -40,6 +40,12 @@ @interface CastingServerBridge () @property void (^_Nonnull commissioningCompleteCallback)(bool); +@property void (^_Nonnull onConnectionSuccessCallback)(VideoPlayer *); + +@property void (^_Nonnull onConnectionFailureCallback)(MatterError *); + +@property void (^_Nonnull onNewOrUpdatedEndpointCallback)(ContentApp *); + @property NSMutableDictionary * commandResponseCallbacks; @property NSMutableDictionary * subscriptionEstablishedCallbacks; @@ -148,10 +154,10 @@ - (void)getDiscoveredCommissioner:(int)index dispatch_async(_chipWorkQueue, ^{ DiscoveredNodeData * commissioner = nil; - const chip::Dnssd::DiscoveredNodeData * chipDiscoveredNodeData + const chip::Dnssd::DiscoveredNodeData * cppDiscoveredNodeData = CastingServer::GetInstance()->GetDiscoveredCommissioner(index); - if (chipDiscoveredNodeData != nullptr) { - commissioner = [DiscoveredNodeDataConverter convertToObjC:chipDiscoveredNodeData]; + if (cppDiscoveredNodeData != nullptr) { + commissioner = [ConversionUtils convertToObjCDiscoveredNodeDataFrom:cppDiscoveredNodeData]; } dispatch_async(clientQueue, ^{ @@ -198,21 +204,81 @@ - (void)sendUserDirectedCommissioningRequest:(NSString * _Nonnull)commissionerIp }); } +- (void)sendUserDirectedCommissioningRequest:(DiscoveredNodeData * _Nonnull)commissioner + clientQueue:(dispatch_queue_t _Nonnull)clientQueue + udcRequestSentHandler:(nullable void (^)(bool))udcRequestSentHandler +{ + ChipLogProgress(AppServer, + "CastingServerBridge().sendUserDirectedCommissioningRequest() called with IP %s port %d platformInterface %d deviceName: " + "%s", + [commissioner.ipAddresses[0] UTF8String], commissioner.port, commissioner.platformInterface, + [commissioner.deviceName UTF8String]); + + dispatch_async(_chipWorkQueue, ^{ + bool udcRequestStatus; + + chip::Dnssd::DiscoveredNodeData cppCommissioner; + if ([ConversionUtils convertToCppDiscoveredNodeDataFrom:commissioner outDiscoveredNodeData:cppCommissioner] + != CHIP_NO_ERROR) { + ChipLogError(AppServer, + "CastingServerBridge().sendUserDirectedCommissioningRequest() failed to convert Commissioner(DiscoveredNodeData) " + "to Cpp type"); + udcRequestStatus = false; + } else { + CHIP_ERROR err = CastingServer::GetInstance()->SendUserDirectedCommissioningRequest(&cppCommissioner); + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "CastingServerBridge().sendUserDirectedCommissioningRequest() failed: %" CHIP_ERROR_FORMAT, + err.Format()); + udcRequestStatus = false; + } else { + udcRequestStatus = true; + } + } + + dispatch_async(clientQueue, ^{ + udcRequestSentHandler(udcRequestStatus); + }); + }); +} + - (OnboardingPayload *)getOnboardingPaylod { return _onboardingPayload; } -- (void)openBasicCommissioningWindow:(void (^_Nonnull)(bool))commissioningCompleteCallback - clientQueue:(dispatch_queue_t _Nonnull)clientQueue +- (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 { ChipLogProgress(AppServer, "CastingServerBridge().openBasicCommissioningWindow() called"); _commissioningCompleteCallback = commissioningCompleteCallback; + _onConnectionSuccessCallback = onConnectionSuccessCallback; + _onConnectionFailureCallback = onConnectionFailureCallback; + _onNewOrUpdatedEndpointCallback = onNewOrUpdatedEndpointCallback; + + CHIP_ERROR OpenBasicCommissioningWindow(std::function commissioningCompleteCallback, + std::function onConnectionSuccess, std::function onConnectionFailure, + std::function onNewOrUpdatedEndpoint); + dispatch_async(_chipWorkQueue, ^{ CHIP_ERROR err = CastingServer::GetInstance()->OpenBasicCommissioningWindow( - [](CHIP_ERROR err) { [CastingServerBridge getSharedInstance].commissioningCompleteCallback(CHIP_NO_ERROR == err); }); + [](CHIP_ERROR err) { [CastingServerBridge getSharedInstance].commissioningCompleteCallback(CHIP_NO_ERROR == err); }, + [](TargetVideoPlayerInfo * cppTargetVideoPlayerInfo) { + VideoPlayer * videoPlayer = [ConversionUtils convertToObjCVideoPlayerFrom:cppTargetVideoPlayerInfo]; + [CastingServerBridge getSharedInstance].onConnectionSuccessCallback(videoPlayer); + }, + [](CHIP_ERROR err) { + [CastingServerBridge getSharedInstance].onConnectionFailureCallback( + [[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); + }, + [](TargetEndpointInfo * cppTargetEndpointInfo) { + ContentApp * contentApp = [ConversionUtils convertToObjCContentAppFrom:cppTargetEndpointInfo]; + [CastingServerBridge getSharedInstance].onNewOrUpdatedEndpointCallback(contentApp); + }); dispatch_async(clientQueue, ^{ commissioningWindowRequestedHandler(CHIP_NO_ERROR == err); @@ -220,19 +286,106 @@ - (void)openBasicCommissioningWindow:(void (^_Nonnull)(bool))commissioningComple }); } -- (void)contentLauncher_launchUrl:(NSString * _Nonnull)contentUrl +- (void)getActiveTargetVideoPlayers:(dispatch_queue_t _Nonnull)clientQueue + activeTargetVideoPlayersHandler:(nullable void (^)(NSMutableArray * _Nullable))activeTargetVideoPlayersHandler +{ + ChipLogProgress(AppServer, "CastingServerBridge().getActiveTargetVideoPlayers() called"); + + dispatch_async(_chipWorkQueue, ^{ + NSMutableArray * videoPlayers = nil; + TargetVideoPlayerInfo * cppTargetVideoPlayerInfo = CastingServer::GetInstance()->GetActiveTargetVideoPlayer(); + if (cppTargetVideoPlayerInfo != nullptr) { + videoPlayers = [NSMutableArray new]; + videoPlayers[0] = [ConversionUtils convertToObjCVideoPlayerFrom:cppTargetVideoPlayerInfo]; + } + + dispatch_async(clientQueue, ^{ + activeTargetVideoPlayersHandler(videoPlayers); + }); + }); +} + +- (void)readCachedVideoPlayers:(dispatch_queue_t _Nonnull)clientQueue + readCachedVideoPlayersHandler:(nullable void (^)(NSMutableArray * _Nullable))readCachedVideoPlayersHandler +{ + ChipLogProgress(AppServer, "CastingServerBridge().readCachedVideoPlayers() called"); + + dispatch_async(_chipWorkQueue, ^{ + NSMutableArray * videoPlayers = nil; + TargetVideoPlayerInfo * cppTargetVideoPlayerInfos = CastingServer::GetInstance()->ReadCachedTargetVideoPlayerInfos(); + if (cppTargetVideoPlayerInfos != nullptr) { + videoPlayers = [NSMutableArray new]; + for (size_t i = 0; cppTargetVideoPlayerInfos[i].IsInitialized(); i++) { + ChipLogProgress(AppServer, + "CastingServerBridge().readCachedVideoPlayers() with nodeId: 0x" ChipLogFormatX64 + " fabricIndex: %d deviceName: %s vendorId: %d", + ChipLogValueX64(cppTargetVideoPlayerInfos[i].GetNodeId()), cppTargetVideoPlayerInfos[i].GetFabricIndex(), + cppTargetVideoPlayerInfos[i].GetDeviceName(), cppTargetVideoPlayerInfos[i].GetVendorId()); + videoPlayers[i] = [ConversionUtils convertToObjCVideoPlayerFrom:&cppTargetVideoPlayerInfos[i]]; + } + } + + dispatch_async(clientQueue, ^{ + readCachedVideoPlayersHandler(videoPlayers); + }); + }); +} + +- (void)verifyOrEstablishConnection:(VideoPlayer * _Nonnull)videoPlayer + clientQueue:(dispatch_queue_t _Nonnull)clientQueue + requestSentHandler:(nullable void (^)(MatterError * _Nonnull))requestSentHandler + onConnectionSuccessCallback:(void (^_Nonnull)(VideoPlayer * _Nonnull))onConnectionSuccessCallback + onConnectionFailureCallback:(void (^_Nonnull)(MatterError * _Nonnull))onConnectionFailureCallback + onNewOrUpdatedEndpointCallback:(void (^_Nonnull)(ContentApp * _Nonnull))onNewOrUpdatedEndpointCallback +{ + ChipLogProgress(AppServer, "CastingServerBridge().verifyOrEstablishConnection() called"); + _onConnectionSuccessCallback = onConnectionSuccessCallback; + _onConnectionFailureCallback = onConnectionFailureCallback; + _onNewOrUpdatedEndpointCallback = onNewOrUpdatedEndpointCallback; + + dispatch_async(_chipWorkQueue, ^{ + TargetVideoPlayerInfo targetVideoPlayerInfo; + [ConversionUtils convertToCppTargetVideoPlayerInfoFrom:videoPlayer outTargetVideoPlayerInfo:targetVideoPlayerInfo]; + + CHIP_ERROR err = CastingServer::GetInstance()->VerifyOrEstablishConnection( + targetVideoPlayerInfo, + [](TargetVideoPlayerInfo * cppTargetVideoPlayerInfo) { + VideoPlayer * videoPlayer = [ConversionUtils convertToObjCVideoPlayerFrom:cppTargetVideoPlayerInfo]; + [CastingServerBridge getSharedInstance].onConnectionSuccessCallback(videoPlayer); + }, + [](CHIP_ERROR err) { + [CastingServerBridge getSharedInstance].onConnectionFailureCallback( + [[MatterError alloc] initWithCode:err.AsInteger() message:[NSString stringWithUTF8String:err.AsString()]]); + }, + [](TargetEndpointInfo * cppTargetEndpointInfo) { + ContentApp * contentApp = [ConversionUtils convertToObjCContentAppFrom:cppTargetEndpointInfo]; + [CastingServerBridge getSharedInstance].onNewOrUpdatedEndpointCallback(contentApp); + }); + + dispatch_async(clientQueue, ^{ + requestSentHandler([[MatterError alloc] initWithCode:err.AsInteger() + message:[NSString stringWithUTF8String:err.AsString()]]); + }); + }); +} + +- (void)contentLauncher_launchUrl:(ContentApp * _Nonnull)contentApp + contentUrl:(NSString * _Nonnull)contentUrl contentDisplayStr:(NSString * _Nonnull)contentDisplayStr responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().contentLauncher_launchUrl() called"); + ChipLogProgress(AppServer, "CastingServerBridge().contentLauncher_launchUrl() called on Content App with endpoint ID %d", + contentApp.endpointId); [_commandResponseCallbacks setObject:responseCallback forKey:@"contentLauncher_launchUrl"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; CHIP_ERROR err = CastingServer::GetInstance()->ContentLauncherLaunchURL( - [contentUrl UTF8String], [contentDisplayStr UTF8String], [](CHIP_ERROR err) { + &endpoint, [contentUrl UTF8String], [contentDisplayStr UTF8String], [](CHIP_ERROR err) { void (^responseCallback)(bool) = [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"contentLauncher_launchUrl"]; responseCallback(CHIP_NO_ERROR == err); @@ -243,14 +396,16 @@ - (void)contentLauncher_launchUrl:(NSString * _Nonnull)contentUrl }); } -- (void)contentLauncher_launchContent:(ContentLauncher_ContentSearch * _Nonnull)contentSearch +- (void)contentLauncher_launchContent:(ContentApp * _Nonnull)contentApp + contentSearch:(ContentLauncher_ContentSearch * _Nonnull)contentSearch autoPlay:(bool)autoPlay data:(NSString * _Nullable)data responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().contentLauncher_launchContent() called"); + ChipLogProgress(AppServer, "CastingServerBridge().contentLauncher_launchContent() called on Content App with endpoint ID %d", + contentApp.endpointId); [_commandResponseCallbacks setObject:responseCallback forKey:@"contentLauncher_launchContent"]; @@ -259,6 +414,9 @@ - (void)contentLauncher_launchContent:(ContentLauncher_ContentSearch * _Nonnull) data = [data copy]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + ListFreer listFreer; chip::app::Clusters::ContentLauncher::Structs::ContentSearch::Type cppSearch; if (contentSearch.parameterList.count > 0) { @@ -301,7 +459,7 @@ - (void)contentLauncher_launchContent:(ContentLauncher_ContentSearch * _Nonnull) } } - CHIP_ERROR err = CastingServer::GetInstance()->ContentLauncher_LaunchContent(cppSearch, autoPlay, + CHIP_ERROR err = CastingServer::GetInstance()->ContentLauncher_LaunchContent(&endpoint, cppSearch, autoPlay, MakeOptional(chip::CharSpan([data UTF8String], [data lengthOfBytesUsingEncoding:NSUTF8StringEncoding])), [](CHIP_ERROR err) { void (^responseCallback)(bool) = [[CastingServerBridge getSharedInstance].commandResponseCallbacks @@ -314,7 +472,8 @@ - (void)contentLauncher_launchContent:(ContentLauncher_ContentSearch * _Nonnull) }); } -- (void)contentLauncher_subscribeSupportedStreamingProtocols:(uint16_t)minInterval +- (void)contentLauncher_subscribeSupportedStreamingProtocols:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -322,7 +481,9 @@ - (void)contentLauncher_subscribeSupportedStreamingProtocols:(uint16_t)minInterv failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().contentLauncher_subscribeSupportedStreamingProtocols() called"); + ChipLogProgress(AppServer, + "CastingServerBridge().contentLauncher_subscribeSupportedStreamingProtocols() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"contentLauncher_subscribeSupportedStreamingProtocols"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"contentLauncher_subscribeSupportedStreamingProtocols"]; @@ -330,8 +491,11 @@ - (void)contentLauncher_subscribeSupportedStreamingProtocols:(uint16_t)minInterv forKey:@"contentLauncher_subscribeSupportedStreamingProtocols"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->ContentLauncher_SubscribeToSupportedStreamingProtocols( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::ContentLauncher::Attributes::SupportedStreamingProtocols::TypeInfo::DecodableArgType supportedStreamingProtocols) { @@ -357,7 +521,8 @@ - (void)contentLauncher_subscribeSupportedStreamingProtocols:(uint16_t)minInterv }); } -- (void)levelControl_step:(uint8_t)stepMode +- (void)levelControl_step:(ContentApp * _Nonnull)contentApp + stepMode:(uint8_t)stepMode stepSize:(uint8_t)stepSize transitionTime:(uint16_t)transitionTime optionMask:(uint8_t)optionMask @@ -366,24 +531,29 @@ - (void)levelControl_step:(uint8_t)stepMode clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().levelControl_step() called"); + ChipLogProgress( + AppServer, "CastingServerBridge().levelControl_step() called on Content App with endpoint ID %d", contentApp.endpointId); [_commandResponseCallbacks setObject:responseCallback forKey:@"levelControl_step"]; dispatch_async(_chipWorkQueue, ^{ - CHIP_ERROR err - = CastingServer::GetInstance()->LevelControl_Step(static_cast(stepMode), - stepSize, transitionTime, optionMask, optionOverride, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"levelControl_step"]; - responseCallback(CHIP_NO_ERROR == err); - }); + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + + CHIP_ERROR err = CastingServer::GetInstance()->LevelControl_Step(&endpoint, + static_cast(stepMode), stepSize, transitionTime, optionMask, + optionOverride, [](CHIP_ERROR err) { + void (^responseCallback)(bool) = + [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"levelControl_step"]; + responseCallback(CHIP_NO_ERROR == err); + }); dispatch_async(clientQueue, ^{ requestSentHandler(CHIP_NO_ERROR == err); }); }); } -- (void)levelControl_moveToLevel:(uint8_t)level +- (void)levelControl_moveToLevel:(ContentApp * _Nonnull)contentApp + level:(uint8_t)level transitionTime:(uint16_t)transitionTime optionMask:(uint8_t)optionMask optionOverride:(uint8_t)optionOverride @@ -391,12 +561,16 @@ - (void)levelControl_moveToLevel:(uint8_t)level clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().levelControl_moveToLevel() called"); + ChipLogProgress(AppServer, "CastingServerBridge().levelControl_moveToLevel() called on Content App with endpoint ID %d", + contentApp.endpointId); [_commandResponseCallbacks setObject:responseCallback forKey:@"levelControl_moveToLevel"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->LevelControl_MoveToLevel( - level, transitionTime, optionMask, optionOverride, [](CHIP_ERROR err) { + &endpoint, level, transitionTime, optionMask, optionOverride, [](CHIP_ERROR err) { void (^responseCallback)(bool) = [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"levelControl_moveToLevel"]; responseCallback(CHIP_NO_ERROR == err); @@ -407,7 +581,8 @@ - (void)levelControl_moveToLevel:(uint8_t)level }); } -- (void)levelControl_subscribeCurrentLevel:(uint16_t)minInterval +- (void)levelControl_subscribeCurrentLevel:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -415,15 +590,20 @@ - (void)levelControl_subscribeCurrentLevel:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().levelControl_subscribeCurrentLevel() called"); + ChipLogProgress(AppServer, + "CastingServerBridge().levelControl_subscribeCurrentLevel() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"levelControl_subscribeCurrentLevel"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"levelControl_subscribeCurrentLevel"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"levelControl_subscribeCurrentLevel"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->LevelControl_SubscribeToCurrentLevel( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::LevelControl::Attributes::CurrentLevel::TypeInfo::DecodableArgType currentLevel) { void (^callback)(NSNumber * _Nullable) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks @@ -448,7 +628,8 @@ - (void)levelControl_subscribeCurrentLevel:(uint16_t)minInterval }); } -- (void)levelControl_subscribeMinLevel:(uint16_t)minInterval +- (void)levelControl_subscribeMinLevel:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -456,15 +637,19 @@ - (void)levelControl_subscribeMinLevel:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().levelControl_subscribeMinLevel() called"); + ChipLogProgress(AppServer, "CastingServerBridge().levelControl_subscribeMinLevel() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"levelControl_subscribeMinLevel"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"levelControl_subscribeMinLevel"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"levelControl_subscribeMinLevel"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->LevelControl_SubscribeToMinLevel( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::LevelControl::Attributes::MinLevel::TypeInfo::DecodableArgType minLevel) { void (^callback)(uint8_t) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks objectForKey:@"levelControl_subscribeMinLevel"]; @@ -488,7 +673,8 @@ - (void)levelControl_subscribeMinLevel:(uint16_t)minInterval }); } -- (void)levelControl_subscribeMaxLevel:(uint16_t)minInterval +- (void)levelControl_subscribeMaxLevel:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -496,15 +682,19 @@ - (void)levelControl_subscribeMaxLevel:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().levelControl_subscribeMaxLevel() called"); + ChipLogProgress(AppServer, "CastingServerBridge().levelControl_subscribeMaxLevel() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"levelControl_subscribeMaxLevel"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"levelControl_subscribeMaxLevel"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"levelControl_subscribeMaxLevel"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->LevelControl_SubscribeToMaxLevel( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::LevelControl::Attributes::MaxLevel::TypeInfo::DecodableArgType maxLevel) { void (^callback)(uint8_t) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks objectForKey:@"levelControl_subscribeMaxLevel"]; @@ -528,15 +718,20 @@ - (void)levelControl_subscribeMaxLevel:(uint16_t)minInterval }); } -- (void)mediaPlayback_play:(void (^_Nonnull)(bool))responseCallback +- (void)mediaPlayback_play:(ContentApp * _Nonnull)contentApp + responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_play() called"); + ChipLogProgress( + AppServer, "CastingServerBridge().mediaPlayback_play() called on Content App with endpoint ID %d", contentApp.endpointId); [_commandResponseCallbacks setObject:responseCallback forKey:@"mediaPlayback_play"]; dispatch_async(_chipWorkQueue, ^{ - CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_Play([](CHIP_ERROR err) { + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + + CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_Play(&endpoint, [](CHIP_ERROR err) { void (^responseCallback)(bool) = [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"mediaPlayback_play"]; responseCallback(CHIP_NO_ERROR == err); @@ -547,15 +742,20 @@ - (void)mediaPlayback_play:(void (^_Nonnull)(bool))responseCallback }); } -- (void)mediaPlayback_pause:(void (^_Nonnull)(bool))responseCallback +- (void)mediaPlayback_pause:(ContentApp * _Nonnull)contentApp + responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_pause() called"); + ChipLogProgress( + AppServer, "CastingServerBridge().mediaPlayback_pause() called on Content App with endpoint ID %d", contentApp.endpointId); [_commandResponseCallbacks setObject:responseCallback forKey:@"mediaPlayback_pause"]; dispatch_async(_chipWorkQueue, ^{ - CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_Pause([](CHIP_ERROR err) { + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + + CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_Pause(&endpoint, [](CHIP_ERROR err) { void (^responseCallback)(bool) = [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"mediaPlayback_pause"]; responseCallback(CHIP_NO_ERROR == err); @@ -566,15 +766,20 @@ - (void)mediaPlayback_pause:(void (^_Nonnull)(bool))responseCallback }); } -- (void)mediaPlayback_stopPlayback:(void (^_Nonnull)(bool))responseCallback +- (void)mediaPlayback_stopPlayback:(ContentApp * _Nonnull)contentApp + responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_stopPlayback() called"); + ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_stopPlayback() called on Content App with endpoint ID %d", + contentApp.endpointId); [_commandResponseCallbacks setObject:responseCallback forKey:@"mediaPlayback_stopPlayback"]; dispatch_async(_chipWorkQueue, ^{ - CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_StopPlayback([](CHIP_ERROR err) { + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + + CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_StopPlayback(&endpoint, [](CHIP_ERROR err) { void (^responseCallback)(bool) = [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"mediaPlayback_stopPlayback"]; responseCallback(CHIP_NO_ERROR == err); @@ -585,15 +790,20 @@ - (void)mediaPlayback_stopPlayback:(void (^_Nonnull)(bool))responseCallback }); } -- (void)mediaPlayback_next:(void (^_Nonnull)(bool))responseCallback +- (void)mediaPlayback_next:(ContentApp * _Nonnull)contentApp + responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_next() called"); + ChipLogProgress( + AppServer, "CastingServerBridge().mediaPlayback_next() called on Content App with endpoint ID %d", contentApp.endpointId); [_commandResponseCallbacks setObject:responseCallback forKey:@"mediaPlayback_next"]; dispatch_async(_chipWorkQueue, ^{ - CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_Next([](CHIP_ERROR err) { + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + + CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_Next(&endpoint, [](CHIP_ERROR err) { void (^responseCallback)(bool) = [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"mediaPlayback_next"]; responseCallback(CHIP_NO_ERROR == err); @@ -604,16 +814,21 @@ - (void)mediaPlayback_next:(void (^_Nonnull)(bool))responseCallback }); } -- (void)mediaPlayback_seek:(uint8_t)position +- (void)mediaPlayback_seek:(ContentApp * _Nonnull)contentApp + position:(uint8_t)position responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_seek() called"); + ChipLogProgress( + AppServer, "CastingServerBridge().mediaPlayback_seek() called on Content App with endpoint ID %d", contentApp.endpointId); [_commandResponseCallbacks setObject:responseCallback forKey:@"mediaPlayback_seek"]; dispatch_async(_chipWorkQueue, ^{ - CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_Seek(position, [](CHIP_ERROR err) { + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + + CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_Seek(&endpoint, position, [](CHIP_ERROR err) { void (^responseCallback)(bool) = [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"mediaPlayback_seek"]; responseCallback(CHIP_NO_ERROR == err); @@ -624,47 +839,60 @@ - (void)mediaPlayback_seek:(uint8_t)position }); } -- (void)mediaPlayback_skipForward:(uint64_t)deltaPositionMilliseconds +- (void)mediaPlayback_skipForward:(ContentApp * _Nonnull)contentApp + deltaPositionMilliseconds:(uint64_t)deltaPositionMilliseconds responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_skipForward() called"); + ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_skipForward() called on Content App with endpoint ID %d", + contentApp.endpointId); [_commandResponseCallbacks setObject:responseCallback forKey:@"mediaPlayback_skipForward"]; dispatch_async(_chipWorkQueue, ^{ - CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_SkipForward(deltaPositionMilliseconds, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"mediaPlayback_skipForward"]; - responseCallback(CHIP_NO_ERROR == err); - }); + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + + CHIP_ERROR err + = CastingServer::GetInstance()->MediaPlayback_SkipForward(&endpoint, deltaPositionMilliseconds, [](CHIP_ERROR err) { + void (^responseCallback)(bool) = + [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"mediaPlayback_skipForward"]; + responseCallback(CHIP_NO_ERROR == err); + }); dispatch_async(clientQueue, ^{ requestSentHandler(CHIP_NO_ERROR == err); }); }); } -- (void)mediaPlayback_skipBackward:(uint64_t)deltaPositionMilliseconds +- (void)mediaPlayback_skipBackward:(ContentApp * _Nonnull)contentApp + deltaPositionMilliseconds:(uint64_t)deltaPositionMilliseconds responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_skipBackward() called"); + ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_skipBackward() called on Content App with endpoint ID %d", + contentApp.endpointId); [_commandResponseCallbacks setObject:responseCallback forKey:@"mediaPlayback_skipBackward"]; dispatch_async(_chipWorkQueue, ^{ - CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_SkipBackward(deltaPositionMilliseconds, [](CHIP_ERROR err) { - void (^responseCallback)(bool) = - [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"mediaPlayback_skipBackward"]; - responseCallback(CHIP_NO_ERROR == err); - }); + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + + CHIP_ERROR err + = CastingServer::GetInstance()->MediaPlayback_SkipBackward(&endpoint, deltaPositionMilliseconds, [](CHIP_ERROR err) { + void (^responseCallback)(bool) = + [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"mediaPlayback_skipBackward"]; + responseCallback(CHIP_NO_ERROR == err); + }); dispatch_async(clientQueue, ^{ requestSentHandler(CHIP_NO_ERROR == err); }); }); } -- (void)mediaPlayback_subscribeCurrentState:(uint16_t)minInterval +- (void)mediaPlayback_subscribeCurrentState:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -672,15 +900,20 @@ - (void)mediaPlayback_subscribeCurrentState:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_subscribeCurrentState() called"); + ChipLogProgress(AppServer, + "CastingServerBridge().mediaPlayback_subscribeCurrentState() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"mediaPlayback_subscribeCurrentState"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"mediaPlayback_subscribeCurrentState"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"mediaPlayback_subscribeCurrentState"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_SubscribeToCurrentState( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::MediaPlayback::Attributes::CurrentState::TypeInfo::DecodableArgType currentState) { void (^callback)(MediaPlayback_PlaybackState) = @@ -706,7 +939,8 @@ - (void)mediaPlayback_subscribeCurrentState:(uint16_t)minInterval }); } -- (void)mediaPlayback_subscribeStartTime:(uint16_t)minInterval +- (void)mediaPlayback_subscribeStartTime:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -714,15 +948,19 @@ - (void)mediaPlayback_subscribeStartTime:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_subscribeStartTime() called"); + ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_subscribeStartTime() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"mediaPlayback_subscribeStartTime"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"mediaPlayback_subscribeStartTime"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"mediaPlayback_subscribeStartTime"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_SubscribeToStartTime( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::MediaPlayback::Attributes::StartTime::TypeInfo::DecodableArgType startTime) { void (^callback)(NSNumber * _Nullable) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks objectForKey:@"mediaPlayback_subscribeStartTime"]; @@ -746,7 +984,8 @@ - (void)mediaPlayback_subscribeStartTime:(uint16_t)minInterval }); } -- (void)mediaPlayback_subscribeDuration:(uint16_t)minInterval +- (void)mediaPlayback_subscribeDuration:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -754,15 +993,19 @@ - (void)mediaPlayback_subscribeDuration:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_subscribeDuration() called"); + ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_subscribeDuration() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"mediaPlayback_subscribeDuration"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"mediaPlayback_subscribeDuration"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"mediaPlayback_subscribeDuration"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_SubscribeToDuration( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::MediaPlayback::Attributes::Duration::TypeInfo::DecodableArgType startTime) { void (^callback)(NSNumber * _Nullable) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks objectForKey:@"mediaPlayback_subscribeDuration"]; @@ -786,7 +1029,8 @@ - (void)mediaPlayback_subscribeDuration:(uint16_t)minInterval }); } -- (void)mediaPlayback_subscribeSampledPosition:(uint16_t)minInterval +- (void)mediaPlayback_subscribeSampledPosition:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -794,15 +1038,20 @@ - (void)mediaPlayback_subscribeSampledPosition:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_subscribeSampledPosition() called"); + ChipLogProgress(AppServer, + "CastingServerBridge().mediaPlayback_subscribeSampledPosition() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"mediaPlayback_subscribeSampledPosition"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"mediaPlayback_subscribeSampledPosition"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"mediaPlayback_subscribeSampledPosition"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_SubscribeToSampledPosition( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::MediaPlayback::Attributes::SampledPosition::TypeInfo::DecodableArgType playbackPosition) { void (^callback)(MediaPlayback_PlaybackPosition * _Nullable) = @@ -840,7 +1089,8 @@ - (void)mediaPlayback_subscribeSampledPosition:(uint16_t)minInterval }); } -- (void)mediaPlayback_subscribePlaybackSpeed:(uint16_t)minInterval +- (void)mediaPlayback_subscribePlaybackSpeed:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -848,15 +1098,20 @@ - (void)mediaPlayback_subscribePlaybackSpeed:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_subscribePlaybackSpeed() called"); + ChipLogProgress(AppServer, + "CastingServerBridge().mediaPlayback_subscribePlaybackSpeed() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"mediaPlayback_subscribePlaybackSpeed"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"mediaPlayback_subscribePlaybackSpeed"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"mediaPlayback_subscribePlaybackSpeed"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_SubscribeToPlaybackSpeed( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::MediaPlayback::Attributes::PlaybackSpeed::TypeInfo::DecodableArgType playbackSpeed) { void (^callback)(float) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks @@ -881,7 +1136,8 @@ - (void)mediaPlayback_subscribePlaybackSpeed:(uint16_t)minInterval }); } -- (void)mediaPlayback_subscribeSeekRangeEnd:(uint16_t)minInterval +- (void)mediaPlayback_subscribeSeekRangeEnd:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -889,15 +1145,20 @@ - (void)mediaPlayback_subscribeSeekRangeEnd:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_subscribeSeekRangeEnd() called"); + ChipLogProgress(AppServer, + "CastingServerBridge().mediaPlayback_subscribeSeekRangeEnd() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"mediaPlayback_subscribeSeekRangeEnd"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"mediaPlayback_subscribeSeekRangeEnd"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"mediaPlayback_subscribeSeekRangeEnd"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_SubscribeToDuration( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::MediaPlayback::Attributes::SeekRangeEnd::TypeInfo::DecodableArgType seekRangeEnd) { void (^callback)(NSNumber * _Nullable) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks @@ -922,7 +1183,8 @@ - (void)mediaPlayback_subscribeSeekRangeEnd:(uint16_t)minInterval }); } -- (void)mediaPlayback_subscribeSeekRangeStart:(uint16_t)minInterval +- (void)mediaPlayback_subscribeSeekRangeStart:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -930,15 +1192,20 @@ - (void)mediaPlayback_subscribeSeekRangeStart:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().mediaPlayback_subscribeSeekRangeStart() called"); + ChipLogProgress(AppServer, + "CastingServerBridge().mediaPlayback_subscribeSeekRangeStart() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"mediaPlayback_subscribeSeekRangeStart"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"mediaPlayback_subscribeSeekRangeStart"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"mediaPlayback_subscribeSeekRangeStart"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_SubscribeToDuration( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::MediaPlayback::Attributes::SeekRangeEnd::TypeInfo::DecodableArgType seekRangeStart) { void (^callback)(NSNumber * _Nullable) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks @@ -963,14 +1230,16 @@ - (void)mediaPlayback_subscribeSeekRangeStart:(uint16_t)minInterval }); } -- (void)applicationLauncher_launchApp:(uint16_t)catalogVendorId +- (void)applicationLauncher_launchApp:(ContentApp * _Nonnull)contentApp + catalogVendorId:(uint16_t)catalogVendorId applicationId:(NSString * _Nonnull)applicationId data:(NSData * _Nullable)data responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().applicationLauncher_launchApp() called"); + ChipLogProgress(AppServer, "CastingServerBridge().applicationLauncher_launchApp() called on Content App with endpoint ID %d", + contentApp.endpointId); [_commandResponseCallbacks setObject:responseCallback forKey:@"applicationLauncher_launchApp"]; @@ -979,7 +1248,10 @@ - (void)applicationLauncher_launchApp:(uint16_t)catalogVendorId application.applicationId = chip::CharSpan::fromCharString([applicationId UTF8String]); dispatch_async(_chipWorkQueue, ^{ - CHIP_ERROR err = CastingServer::GetInstance()->ApplicationLauncher_LaunchApp(application, + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + + CHIP_ERROR err = CastingServer::GetInstance()->ApplicationLauncher_LaunchApp(&endpoint, application, chip::MakeOptional(chip::ByteSpan(static_cast(data.bytes), data.length)), [](CHIP_ERROR err) { void (^responseCallback)(bool) = [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"applicationLauncher_launchApp"]; @@ -991,13 +1263,15 @@ - (void)applicationLauncher_launchApp:(uint16_t)catalogVendorId }); } -- (void)applicationLauncher_stopApp:(uint16_t)catalogVendorId +- (void)applicationLauncher_stopApp:(ContentApp * _Nonnull)contentApp + catalogVendorId:(uint16_t)catalogVendorId applicationId:(NSString * _Nonnull)applicationId responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().applicationLauncher_stopApp() called"); + ChipLogProgress(AppServer, "CastingServerBridge().applicationLauncher_stopApp() called on Content App with endpoint ID %d", + contentApp.endpointId); [_commandResponseCallbacks setObject:responseCallback forKey:@"applicationLauncher_stopApp"]; @@ -1006,7 +1280,10 @@ - (void)applicationLauncher_stopApp:(uint16_t)catalogVendorId application.applicationId = chip::CharSpan::fromCharString([applicationId UTF8String]); dispatch_async(_chipWorkQueue, ^{ - CHIP_ERROR err = CastingServer::GetInstance()->ApplicationLauncher_StopApp(application, [](CHIP_ERROR err) { + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + + CHIP_ERROR err = CastingServer::GetInstance()->ApplicationLauncher_StopApp(&endpoint, application, [](CHIP_ERROR err) { void (^responseCallback)(bool) = [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"applicationLauncher_stopApp"]; responseCallback(CHIP_NO_ERROR == err); @@ -1017,13 +1294,15 @@ - (void)applicationLauncher_stopApp:(uint16_t)catalogVendorId }); } -- (void)applicationLauncher_hideApp:(uint16_t)catalogVendorId +- (void)applicationLauncher_hideApp:(ContentApp * _Nonnull)contentApp + catalogVendorId:(uint16_t)catalogVendorId applicationId:(NSString * _Nonnull)applicationId responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().applicationLauncher_hideApp() called"); + ChipLogProgress(AppServer, "CastingServerBridge().applicationLauncher_hideApp() called on Content App with endpoint ID %d", + contentApp.endpointId); [_commandResponseCallbacks setObject:responseCallback forKey:@"applicationLauncher_hideApp"]; @@ -1032,7 +1311,10 @@ - (void)applicationLauncher_hideApp:(uint16_t)catalogVendorId application.applicationId = chip::CharSpan::fromCharString([applicationId UTF8String]); dispatch_async(_chipWorkQueue, ^{ - CHIP_ERROR err = CastingServer::GetInstance()->ApplicationLauncher_HideApp(application, [](CHIP_ERROR err) { + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + + CHIP_ERROR err = CastingServer::GetInstance()->ApplicationLauncher_HideApp(&endpoint, application, [](CHIP_ERROR err) { void (^responseCallback)(bool) = [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"applicationLauncher_hideApp"]; responseCallback(CHIP_NO_ERROR == err); @@ -1043,19 +1325,24 @@ - (void)applicationLauncher_hideApp:(uint16_t)catalogVendorId }); } -- (void)targetNavigator_navigateTarget:(uint8_t)target +- (void)targetNavigator_navigateTarget:(ContentApp * _Nonnull)contentApp + target:(uint8_t)target data:(NSString * _Nullable)data responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().targetNavigator_navigateTarget() called"); + ChipLogProgress(AppServer, "CastingServerBridge().targetNavigator_navigateTarget() called on Content App with endpoint ID %d", + contentApp.endpointId); [_commandResponseCallbacks setObject:responseCallback forKey:@"targetNavigator_navigateTarget"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->TargetNavigator_NavigateTarget( - target, chip::MakeOptional(chip::CharSpan::fromCharString([data UTF8String])), [](CHIP_ERROR err) { + &endpoint, target, chip::MakeOptional(chip::CharSpan::fromCharString([data UTF8String])), [](CHIP_ERROR err) { void (^responseCallback)(bool) = [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"targetNavigator_navigateTarget"]; responseCallback(CHIP_NO_ERROR == err); @@ -1066,7 +1353,8 @@ - (void)targetNavigator_navigateTarget:(uint8_t)target }); } -- (void)targetNavigator_subscribeTargetList:(uint16_t)minInterval +- (void)targetNavigator_subscribeTargetList:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -1074,15 +1362,20 @@ - (void)targetNavigator_subscribeTargetList:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().targetNavigator_subscribeTargetList() called"); + ChipLogProgress(AppServer, + "CastingServerBridge().targetNavigator_subscribeTargetList() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"targetNavigator_subscribeTargetList"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"targetNavigator_subscribeTargetList"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"targetNavigator_subscribeTargetList"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->TargetNavigator_SubscribeToTargetList( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::TargetNavigator::Attributes::TargetList::TypeInfo::DecodableArgType targetList) { void (^callback)(NSMutableArray *) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks @@ -1122,7 +1415,8 @@ - (void)targetNavigator_subscribeTargetList:(uint16_t)minInterval }); } -- (void)targetNavigator_subscribeCurrentTarget:(uint16_t)minInterval +- (void)targetNavigator_subscribeCurrentTarget:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -1130,15 +1424,20 @@ - (void)targetNavigator_subscribeCurrentTarget:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().targetNavigator_subscribeCurrentTarget() called"); + ChipLogProgress(AppServer, + "CastingServerBridge().targetNavigator_subscribeCurrentTarget() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"targetNavigator_subscribeCurrentTarget"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"targetNavigator_subscribeCurrentTarget"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"targetNavigator_subscribeCurrentTarget"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->TargetNavigator_SubscribeToCurrentTarget( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::TargetNavigator::Attributes::CurrentTarget::TypeInfo::DecodableArgType currentTarget) { void (^callback)(uint8_t) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks @@ -1163,18 +1462,23 @@ - (void)targetNavigator_subscribeCurrentTarget:(uint16_t)minInterval }); } -- (void)keypadInput_sendKey:(uint8_t)keyCode +- (void)keypadInput_sendKey:(ContentApp * _Nonnull)contentApp + keyCode:(uint8_t)keyCode responseCallback:(void (^_Nonnull)(bool))responseCallback clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(bool))requestSentHandler { - ChipLogProgress(AppServer, "CastingServerBridge().keypadInput_sendKey() called"); + ChipLogProgress( + AppServer, "CastingServerBridge().keypadInput_sendKey() called on Content App with endpoint ID %d", contentApp.endpointId); [_commandResponseCallbacks setObject:responseCallback forKey:@"keypadInput_sendKey"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->KeypadInput_SendKey( - static_cast(keyCode), [](CHIP_ERROR err) { + &endpoint, static_cast(keyCode), [](CHIP_ERROR err) { void (^responseCallback)(bool) = [[CastingServerBridge getSharedInstance].commandResponseCallbacks objectForKey:@"keypadInput_sendKey"]; responseCallback(CHIP_NO_ERROR == err); @@ -1185,7 +1489,8 @@ - (void)keypadInput_sendKey:(uint8_t)keyCode }); } -- (void)applicationBasic_subscribeVendorName:(uint16_t)minInterval +- (void)applicationBasic_subscribeVendorName:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -1193,15 +1498,20 @@ - (void)applicationBasic_subscribeVendorName:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().applicationBasic_subscribeVendorName() called"); + ChipLogProgress(AppServer, + "CastingServerBridge().applicationBasic_subscribeVendorName() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"applicationBasic_subscribeVendorName"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"applicationBasic_subscribeVendorName"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"applicationBasic_subscribeVendorName"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->ApplicationBasic_SubscribeToVendorName( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::VendorName::TypeInfo::DecodableArgType vendorName) { void (^callback)(NSString * _Nonnull) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks @@ -1226,7 +1536,8 @@ - (void)applicationBasic_subscribeVendorName:(uint16_t)minInterval }); } -- (void)applicationBasic_subscribeVendorID:(uint16_t)minInterval +- (void)applicationBasic_subscribeVendorID:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -1234,15 +1545,20 @@ - (void)applicationBasic_subscribeVendorID:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().applicationBasic_subscribeVendorID() called"); + ChipLogProgress(AppServer, + "CastingServerBridge().applicationBasic_subscribeVendorID() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"applicationBasic_subscribeVendorID"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"applicationBasic_subscribeVendorID"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"applicationBasic_subscribeVendorID"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->ApplicationBasic_SubscribeToVendorID( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::VendorID::TypeInfo::DecodableArgType vendorID) { void (^callback)(NSNumber * _Nonnull) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks objectForKey:@"applicationBasic_subscribeVendorID"]; @@ -1266,7 +1582,8 @@ - (void)applicationBasic_subscribeVendorID:(uint16_t)minInterval }); } -- (void)applicationBasic_subscribeApplicationName:(uint16_t)minInterval +- (void)applicationBasic_subscribeApplicationName:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -1274,7 +1591,9 @@ - (void)applicationBasic_subscribeApplicationName:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().applicationBasic_subscribeApplicationName() called"); + ChipLogProgress(AppServer, + "CastingServerBridge().applicationBasic_subscribeApplicationName() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"applicationBasic_subscribeApplicationName"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"applicationBasic_subscribeApplicationName"]; @@ -1282,8 +1601,11 @@ - (void)applicationBasic_subscribeApplicationName:(uint16_t)minInterval forKey:@"applicationBasic_subscribeApplicationName"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->ApplicationBasic_SubscribeToApplicationName( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::ApplicationName::TypeInfo::DecodableArgType applicationName) { void (^callback)(NSString * _Nonnull) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks @@ -1308,7 +1630,8 @@ - (void)applicationBasic_subscribeApplicationName:(uint16_t)minInterval }); } -- (void)applicationBasic_subscribeProductID:(uint16_t)minInterval +- (void)applicationBasic_subscribeProductID:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -1316,15 +1639,20 @@ - (void)applicationBasic_subscribeProductID:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().applicationBasic_subscribeProductID() called"); + ChipLogProgress(AppServer, + "CastingServerBridge().applicationBasic_subscribeProductID() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"applicationBasic_subscribeProductID"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"applicationBasic_subscribeProductID"]; [_subscriptionEstablishedCallbacks setObject:subscriptionEstablishedCallback forKey:@"applicationBasic_subscribeProductID"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->ApplicationBasic_SubscribeToProductID( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::ProductID::TypeInfo::DecodableArgType productID) { void (^callback)(uint16_t) = [[CastingServerBridge getSharedInstance].subscriptionReadSuccessCallbacks objectForKey:@"applicationBasic_subscribeProductID"]; @@ -1348,7 +1676,8 @@ - (void)applicationBasic_subscribeProductID:(uint16_t)minInterval }); } -- (void)applicationBasic_subscribeApplicationVersion:(uint16_t)minInterval +- (void)applicationBasic_subscribeApplicationVersion:(ContentApp * _Nonnull)contentApp + minInterval:(uint16_t)minInterval maxInterval:(uint16_t)maxInterval clientQueue:(dispatch_queue_t _Nonnull)clientQueue requestSentHandler:(void (^_Nonnull)(MatterError * _Nonnull))requestSentHandler @@ -1356,7 +1685,9 @@ - (void)applicationBasic_subscribeApplicationVersion:(uint16_t)minInterval failureCallback:(void (^_Nonnull)(MatterError * _Nonnull))failureCallback subscriptionEstablishedCallback:(void (^_Nonnull)())subscriptionEstablishedCallback { - ChipLogProgress(AppServer, "CastingServerBridge().applicationBasic_subscribeApplicationVersion() called"); + ChipLogProgress(AppServer, + "CastingServerBridge().applicationBasic_subscribeApplicationVersion() called on Content App with endpoint ID %d", + contentApp.endpointId); [_subscriptionReadSuccessCallbacks setObject:successCallback forKey:@"applicationBasic_subscribeApplicationVersion"]; [_subscriptionReadFailureCallbacks setObject:failureCallback forKey:@"applicationBasic_subscribeApplicationVersion"]; @@ -1364,8 +1695,11 @@ - (void)applicationBasic_subscribeApplicationVersion:(uint16_t)minInterval forKey:@"applicationBasic_subscribeApplicationVersion"]; dispatch_async(_chipWorkQueue, ^{ + TargetEndpointInfo endpoint; + [ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:endpoint]; + CHIP_ERROR err = CastingServer::GetInstance()->ApplicationBasic_SubscribeToApplicationVersion( - nullptr, + &endpoint, nullptr, [](void * context, chip::app::Clusters::ApplicationBasic::Attributes::ApplicationVersion::TypeInfo::DecodableArgType applicationVersion) { diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DiscoveredNodeDataConverter.hpp b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/ContentApp.h similarity index 53% rename from examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DiscoveredNodeDataConverter.hpp rename to examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/ContentApp.h index 3833767bcae2c4..b9a7384b0a3f7e 100644 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DiscoveredNodeDataConverter.hpp +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/ContentApp.h @@ -17,16 +17,34 @@ #import -#import "DiscoveredNodeData.h" -#include +#ifndef ContentApp_h +#define ContentApp_h -#ifndef DiscoveredNodeDataConverter_h -#define DiscoveredNodeDataConverter_h +@interface ContentApp : NSObject -@interface DiscoveredNodeDataConverter : NSObject +@property uint16_t endpointId; -+ (DiscoveredNodeData *)convertToObjC:(const chip::Dnssd::DiscoveredNodeData *)chipDiscoveredNodedata; +@property NSMutableArray * clusterIds; + +/** + @brief true, if all the fields are initialized, false otherwise + */ +@property BOOL isInitialized; + +- (instancetype)initWithEndpointId:(uint16_t)endpointId clusterIds:(NSMutableArray *)clusterIds; + +- (BOOL)supportsClusterWithId:(uint32_t)clusterId; + +- (BOOL)supportsApplicationLauncher; + +- (BOOL)supportsContentLauncher; + +- (BOOL)supportsMediaPlayback; + +- (BOOL)supportsLevelControl; + +- (BOOL)supportsTargetNavigator; @end -#endif /* DiscoveredNodeDataConverter_h */ +#endif /* ContentApp_h */ diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/ContentApp.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/ContentApp.mm new file mode 100644 index 00000000000000..5497224aabce2c --- /dev/null +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/ContentApp.mm @@ -0,0 +1,80 @@ +/** + * + * Copyright (c) 2020-2022 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 + +#import "ContentApp.h" + +#include + +@implementation ContentApp + +- (instancetype)init +{ + if (self = [super init]) { + _isInitialized = false; + } + return self; +} + +- (instancetype)initWithEndpointId:(uint16_t)endpointId clusterIds:(NSMutableArray *)clusterIds +{ + if (self = [super init]) { + _endpointId = endpointId; + _clusterIds = clusterIds; + _isInitialized = true; + } + return self; +} + +- (BOOL)supportsClusterWithId:(uint32_t)clusterId +{ + if (_clusterIds != nil) { + for (NSNumber * clusterIdNSNumber in _clusterIds) { + if ([clusterIdNSNumber unsignedIntValue] == clusterId) { + return true; + } + } + } + return false; +} + +- (BOOL)supportsApplicationLauncher +{ + return [self supportsClusterWithId:chip::app::Clusters::ApplicationLauncher::Id]; +} + +- (BOOL)supportsContentLauncher +{ + return [self supportsClusterWithId:chip::app::Clusters::ContentLauncher::Id]; +} + +- (BOOL)supportsMediaPlayback +{ + return [self supportsClusterWithId:chip::app::Clusters::MediaPlayback::Id]; +} + +- (BOOL)supportsLevelControl +{ + return [self supportsClusterWithId:chip::app::Clusters::LevelControl::Id]; +} + +- (BOOL)supportsTargetNavigator +{ + return [self supportsClusterWithId:chip::app::Clusters::TargetNavigator::Id]; +} +@end diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/ConversionUtils.hpp b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/ConversionUtils.hpp new file mode 100644 index 00000000000000..df6a0360816ce8 --- /dev/null +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/ConversionUtils.hpp @@ -0,0 +1,56 @@ +/** + * + * Copyright (c) 2020-2022 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 + +#import "ContentApp.h" +#import "DiscoveredNodeData.h" +#import "VideoPlayer.h" + +#import +#import +#include + +#ifndef ConversionUtils_h +#define ConversionUtils_h + +@interface ConversionUtils : NSObject +/** + * @brief Objective C to C++ converters + */ ++ (CHIP_ERROR)convertToCppTargetEndpointInfoFrom:(ContentApp * _Nonnull)objCContentApp + outTargetEndpointInfo:(TargetEndpointInfo &)outTargetEndpointInfo; + ++ (CHIP_ERROR)convertToCppTargetVideoPlayerInfoFrom:(VideoPlayer * _Nonnull)objCVideoPlayer + outTargetVideoPlayerInfo:(TargetVideoPlayerInfo &)outTargetVideoPlayerInfo; + ++ (CHIP_ERROR)convertToCppDiscoveredNodeDataFrom:(DiscoveredNodeData * _Nonnull)objCDiscoveredNodeData + outDiscoveredNodeData:(chip::Dnssd::DiscoveredNodeData &)outDiscoveredNodeData; + +/** + * @brief C++ to Objective C converters + */ ++ (ContentApp * _Nonnull)convertToObjCContentAppFrom:(TargetEndpointInfo * _Nonnull)cppTargetEndpointInfo; + ++ (DiscoveredNodeData * _Nonnull)convertToObjCDiscoveredNodeDataFrom: + (const chip::Dnssd::DiscoveredNodeData * _Nonnull)cppDiscoveredNodedata; + ++ (VideoPlayer * _Nonnull)convertToObjCVideoPlayerFrom:(TargetVideoPlayerInfo * _Nonnull)cppTargetVideoPlayerInfo; + +@end + +#endif /* ConversionUtils_h */ diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/ConversionUtils.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/ConversionUtils.mm new file mode 100644 index 00000000000000..ca626201fdf236 --- /dev/null +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/ConversionUtils.mm @@ -0,0 +1,149 @@ +/** + * + * Copyright (c) 2020-2022 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 + +#import "ConversionUtils.hpp" + +@implementation ConversionUtils + ++ (CHIP_ERROR)convertToCppTargetEndpointInfoFrom:(ContentApp * _Nonnull)objCContentApp + outTargetEndpointInfo:(TargetEndpointInfo &)outTargetEndpointInfo +{ + VerifyOrReturnError(objCContentApp.isInitialized, CHIP_ERROR_INVALID_ARGUMENT); + outTargetEndpointInfo.Initialize(objCContentApp.endpointId); + for (NSNumber * clusterId in objCContentApp.clusterIds) { + VerifyOrReturnError(outTargetEndpointInfo.AddCluster([clusterId unsignedIntValue]), CHIP_ERROR_INVALID_ARGUMENT); + } + return CHIP_NO_ERROR; +} + ++ (CHIP_ERROR)convertToCppDiscoveredNodeDataFrom:(DiscoveredNodeData * _Nonnull)objCDiscoveredNodeData + outDiscoveredNodeData:(chip::Dnssd::DiscoveredNodeData &)outDiscoveredNodeData +{ + // setting CommissionNodeData + outDiscoveredNodeData.commissionData.deviceType = objCDiscoveredNodeData.deviceType; + outDiscoveredNodeData.commissionData.vendorId = objCDiscoveredNodeData.vendorId; + outDiscoveredNodeData.commissionData.productId = objCDiscoveredNodeData.productId; + outDiscoveredNodeData.commissionData.longDiscriminator = objCDiscoveredNodeData.longDiscriminator; + outDiscoveredNodeData.commissionData.commissioningMode = objCDiscoveredNodeData.commissioningMode; + outDiscoveredNodeData.commissionData.pairingHint = objCDiscoveredNodeData.pairingHint; + chip::Platform::CopyString(outDiscoveredNodeData.commissionData.deviceName, chip::Dnssd::kMaxDeviceNameLen + 1, + [objCDiscoveredNodeData.deviceName UTF8String]); + outDiscoveredNodeData.commissionData.rotatingIdLen = objCDiscoveredNodeData.rotatingIdLen; + memcpy( + outDiscoveredNodeData.commissionData.rotatingId, objCDiscoveredNodeData.rotatingId, objCDiscoveredNodeData.rotatingIdLen); + + // setting CommonResolutionData + outDiscoveredNodeData.resolutionData.port = objCDiscoveredNodeData.port; + chip::Platform::CopyString(outDiscoveredNodeData.resolutionData.hostName, chip::Dnssd::kHostNameMaxLength + 1, + [objCDiscoveredNodeData.hostName UTF8String]); + outDiscoveredNodeData.resolutionData.interfaceId = chip::Inet::InterfaceId(objCDiscoveredNodeData.platformInterface); + outDiscoveredNodeData.resolutionData.numIPs = objCDiscoveredNodeData.numIPs; + for (size_t i = 0; i < objCDiscoveredNodeData.numIPs; i++) { + chip::Inet::IPAddress::FromString( + [objCDiscoveredNodeData.ipAddresses[i] UTF8String], outDiscoveredNodeData.resolutionData.ipAddress[i]); + } + return CHIP_NO_ERROR; +} + ++ (CHIP_ERROR)convertToCppTargetVideoPlayerInfoFrom:(VideoPlayer * _Nonnull)objCVideoPlayer + outTargetVideoPlayerInfo:(TargetVideoPlayerInfo &)outTargetVideoPlayerInfo +{ + VerifyOrReturnError(objCVideoPlayer.isInitialized, CHIP_ERROR_INVALID_ARGUMENT); + ReturnErrorOnFailure(outTargetVideoPlayerInfo.Initialize(objCVideoPlayer.nodeId, objCVideoPlayer.fabricIndex, nullptr, nullptr, + objCVideoPlayer.vendorId, objCVideoPlayer.productId, objCVideoPlayer.deviceType, [objCVideoPlayer.deviceName UTF8String])); + for (ContentApp * contentApp in objCVideoPlayer.contentApps) { + TargetEndpointInfo * endpoint = outTargetVideoPlayerInfo.GetOrAddEndpoint(contentApp.endpointId); + VerifyOrReturnError(endpoint != nullptr, CHIP_ERROR_INCORRECT_STATE); + ReturnErrorOnFailure([ConversionUtils convertToCppTargetEndpointInfoFrom:contentApp outTargetEndpointInfo:*endpoint]); + } + return CHIP_NO_ERROR; +} + ++ (ContentApp *)convertToObjCContentAppFrom:(TargetEndpointInfo * _Nonnull)cppTargetEndpointInfo +{ + ContentApp * objCContentApp = [ContentApp new]; + if (cppTargetEndpointInfo->IsInitialized()) { + objCContentApp.endpointId = cppTargetEndpointInfo->GetEndpointId(); + objCContentApp.clusterIds = [NSMutableArray new]; + chip::ClusterId * clusterIds = cppTargetEndpointInfo->GetClusters(); + for (size_t i = 0; i < kMaxNumberOfClustersPerEndpoint && clusterIds[i] != chip::kInvalidClusterId; i++) { + objCContentApp.clusterIds[i] = @(clusterIds[i]); + } + objCContentApp.isInitialized = true; + } + return objCContentApp; +} + ++ (DiscoveredNodeData *)convertToObjCDiscoveredNodeDataFrom:(const chip::Dnssd::DiscoveredNodeData * _Nonnull)cppDiscoveredNodedata +{ + DiscoveredNodeData * objCDiscoveredNodeData = [DiscoveredNodeData new]; + + // from CommissionNodeData + objCDiscoveredNodeData.deviceType = cppDiscoveredNodedata->commissionData.deviceType; + objCDiscoveredNodeData.vendorId = cppDiscoveredNodedata->commissionData.vendorId; + objCDiscoveredNodeData.productId = cppDiscoveredNodedata->commissionData.productId; + objCDiscoveredNodeData.longDiscriminator = cppDiscoveredNodedata->commissionData.longDiscriminator; + objCDiscoveredNodeData.commissioningMode = cppDiscoveredNodedata->commissionData.commissioningMode; + objCDiscoveredNodeData.pairingHint = cppDiscoveredNodedata->commissionData.pairingHint; + objCDiscoveredNodeData.deviceName = [NSString stringWithCString:cppDiscoveredNodedata->commissionData.deviceName + encoding:NSASCIIStringEncoding]; + objCDiscoveredNodeData.rotatingIdLen = cppDiscoveredNodedata->commissionData.rotatingIdLen; + objCDiscoveredNodeData.rotatingId = cppDiscoveredNodedata->commissionData.rotatingId; + objCDiscoveredNodeData.instanceName = [NSString stringWithCString:cppDiscoveredNodedata->commissionData.instanceName + encoding:NSASCIIStringEncoding]; + + // from CommonResolutionData + objCDiscoveredNodeData.port = cppDiscoveredNodedata->resolutionData.port; + objCDiscoveredNodeData.hostName = [NSString stringWithCString:cppDiscoveredNodedata->resolutionData.hostName + encoding:NSASCIIStringEncoding]; + objCDiscoveredNodeData.platformInterface = cppDiscoveredNodedata->resolutionData.interfaceId.GetPlatformInterface(); + objCDiscoveredNodeData.numIPs = cppDiscoveredNodedata->resolutionData.numIPs; + if (cppDiscoveredNodedata->resolutionData.numIPs > 0) { + objCDiscoveredNodeData.ipAddresses = [NSMutableArray new]; + } + for (size_t i = 0; i < cppDiscoveredNodedata->resolutionData.numIPs; i++) { + char addrCString[chip::Inet::IPAddress::kMaxStringLength]; + cppDiscoveredNodedata->resolutionData.ipAddress->ToString(addrCString, chip::Inet::IPAddress::kMaxStringLength); + objCDiscoveredNodeData.ipAddresses[i] = [NSString stringWithCString:addrCString encoding:NSASCIIStringEncoding]; + } + return objCDiscoveredNodeData; +} + ++ (VideoPlayer *)convertToObjCVideoPlayerFrom:(TargetVideoPlayerInfo * _Nonnull)cppTargetVideoPlayerInfo +{ + VideoPlayer * objCVideoPlayer = [VideoPlayer new]; + if (cppTargetVideoPlayerInfo->IsInitialized()) { + objCVideoPlayer.nodeId = cppTargetVideoPlayerInfo->GetNodeId(); + objCVideoPlayer.fabricIndex = cppTargetVideoPlayerInfo->GetFabricIndex(); + objCVideoPlayer.vendorId = cppTargetVideoPlayerInfo->GetVendorId(); + objCVideoPlayer.productId = cppTargetVideoPlayerInfo->GetProductId(); + objCVideoPlayer.deviceType = cppTargetVideoPlayerInfo->GetDeviceType(); + objCVideoPlayer.isConnected = (cppTargetVideoPlayerInfo->GetOperationalDeviceProxy() != nil); + objCVideoPlayer.deviceName = [NSString stringWithCString:cppTargetVideoPlayerInfo->GetDeviceName() + encoding:NSASCIIStringEncoding]; + objCVideoPlayer.contentApps = [NSMutableArray new]; + TargetEndpointInfo * cppTargetEndpointInfos = cppTargetVideoPlayerInfo->GetEndpoints(); + for (size_t i = 0; i < kMaxNumberOfEndpoints && cppTargetEndpointInfos[i].IsInitialized(); i++) { + objCVideoPlayer.contentApps[i] = [ConversionUtils convertToObjCContentAppFrom:&cppTargetEndpointInfos[i]]; + } + objCVideoPlayer.isInitialized = true; + } + return objCVideoPlayer; +} + +@end diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DiscoveredNodeDataConverter.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DiscoveredNodeDataConverter.mm deleted file mode 100644 index 2c96ca48cb95ab..00000000000000 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DiscoveredNodeDataConverter.mm +++ /dev/null @@ -1,58 +0,0 @@ -/** - * - * Copyright (c) 2020-2022 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 - -#import "DiscoveredNodeDataConverter.hpp" - -@implementation DiscoveredNodeDataConverter - -+ (DiscoveredNodeData *)convertToObjC:(const chip::Dnssd::DiscoveredNodeData *)chipDiscoveredNodeData -{ - DiscoveredNodeData * objCDiscoveredNodeData = [DiscoveredNodeData new]; - - // from CommissionNodeData - objCDiscoveredNodeData.deviceType = chipDiscoveredNodeData->commissionData.deviceType; - objCDiscoveredNodeData.vendorId = chipDiscoveredNodeData->commissionData.vendorId; - objCDiscoveredNodeData.productId = chipDiscoveredNodeData->commissionData.productId; - objCDiscoveredNodeData.longDiscriminator = chipDiscoveredNodeData->commissionData.longDiscriminator; - objCDiscoveredNodeData.commissioningMode = chipDiscoveredNodeData->commissionData.commissioningMode; - objCDiscoveredNodeData.pairingHint = chipDiscoveredNodeData->commissionData.pairingHint; - objCDiscoveredNodeData.deviceName = [NSString stringWithCString:chipDiscoveredNodeData->commissionData.deviceName - encoding:NSASCIIStringEncoding]; - objCDiscoveredNodeData.rotatingIdLen = chipDiscoveredNodeData->commissionData.rotatingIdLen; - objCDiscoveredNodeData.rotatingId = chipDiscoveredNodeData->commissionData.rotatingId; - objCDiscoveredNodeData.instanceName = [NSString stringWithCString:chipDiscoveredNodeData->commissionData.instanceName - encoding:NSASCIIStringEncoding]; - - // from CommonResolutionData - objCDiscoveredNodeData.port = chipDiscoveredNodeData->resolutionData.port; - objCDiscoveredNodeData.hostName = [NSString stringWithCString:chipDiscoveredNodeData->resolutionData.hostName - encoding:NSASCIIStringEncoding]; - objCDiscoveredNodeData.platformInterface = chipDiscoveredNodeData->resolutionData.interfaceId.GetPlatformInterface(); - objCDiscoveredNodeData.numIPs = chipDiscoveredNodeData->resolutionData.numIPs; - if (chipDiscoveredNodeData->resolutionData.numIPs > 0) { - objCDiscoveredNodeData.ipAddresses = [NSMutableArray new]; - } - for (int i = 0; i < chipDiscoveredNodeData->resolutionData.numIPs; i++) { - char addrCString[chip::Inet::IPAddress::kMaxStringLength]; - chipDiscoveredNodeData->resolutionData.ipAddress->ToString(addrCString, chip::Inet::IPAddress::kMaxStringLength); - objCDiscoveredNodeData.ipAddresses[i] = [NSString stringWithCString:addrCString encoding:NSASCIIStringEncoding]; - } - return objCDiscoveredNodeData; -} - -@end diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/VideoPlayer.h b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/VideoPlayer.h new file mode 100644 index 00000000000000..64a320982a86f6 --- /dev/null +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/VideoPlayer.h @@ -0,0 +1,61 @@ +/** + * + * Copyright (c) 2020-2022 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. + */ + +#ifndef VideoPlayer_h +#define VideoPlayer_h + +@interface VideoPlayer : NSObject + +@property uint64_t nodeId; + +@property uint8_t fabricIndex; + +/** + * @brief true if this VideoPlayer is connected, false otherwise + */ +@property bool isConnected; + +/** + * @brief contentApps will be nil the VideoPlayer is not connected + */ +@property NSMutableArray * contentApps; + +@property NSString * deviceName; + +@property uint16_t vendorId; + +@property uint16_t productId; + +@property uint16_t deviceType; + +/** + @brief true, if all the required fields are initialized, false otherwise + */ +@property BOOL isInitialized; + +- (instancetype)initWithNodeId:(uint64_t)nodeId + fabricIndex:(uint8_t)fabricIndex + isConnected:(bool)isConnected + contentApps:(NSMutableArray *)contentApps + deviceName:(NSString *)deviceName + vendorId:(uint16_t)vendorId + productId:(uint16_t)productId + deviceType:(uint16_t)deviceType; + +@end + +#endif /* VideoPlayer_h */ diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/VideoPlayer.m b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/VideoPlayer.m new file mode 100644 index 00000000000000..2640fbb2045de0 --- /dev/null +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/VideoPlayer.m @@ -0,0 +1,59 @@ +/** + * + * Copyright (c) 2020-2022 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 + +#import "VideoPlayer.h" + +@implementation VideoPlayer + +- (instancetype)init +{ + if (self = [super init]) { + _isInitialized = false; + } + return self; +} + +- (instancetype)initWithNodeId:(uint64_t)nodeId + fabricIndex:(uint8_t)fabricIndex + isConnected:(bool)isConnected + contentApps:(NSMutableArray *)contentApps + deviceName:(NSString *)deviceName + vendorId:(uint16_t)vendorId + productId:(uint16_t)productId + deviceType:(uint16_t)deviceType; +{ + if (self = [super init]) { + _nodeId = nodeId; + _fabricIndex = fabricIndex; + _isConnected = isConnected; + _contentApps = contentApps; + _deviceName = deviceName; + _vendorId = vendorId; + _productId = productId; + _deviceType = deviceType; + _isInitialized = true; + } + return self; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ with Product ID: %d, Vendor ID: %d", _deviceName, _productId, _vendorId]; +} +@end diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting.xcodeproj/project.pbxproj b/examples/tv-casting-app/darwin/TvCasting/TvCasting.xcodeproj/project.pbxproj index ed740398a117f4..dfaf0a6813066d 100644 --- a/examples/tv-casting-app/darwin/TvCasting/TvCasting.xcodeproj/project.pbxproj +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting.xcodeproj/project.pbxproj @@ -7,9 +7,13 @@ objects = { /* Begin PBXBuildFile section */ + 3C81C75328F8C79E001CB9D1 /* StartFromCacheView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C81C75228F8C79E001CB9D1 /* StartFromCacheView.swift */; }; + 3C81C75528F8C7B6001CB9D1 /* StartFromCacheViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C81C75428F8C7B6001CB9D1 /* StartFromCacheViewModel.swift */; }; + 3C81C75728F8E418001CB9D1 /* ConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C81C75628F8E418001CB9D1 /* ConnectionView.swift */; }; + 3C81C75928F8E42D001CB9D1 /* ConnectionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C81C75828F8E42D001CB9D1 /* ConnectionViewModel.swift */; }; 3CA1CA7A28E281080023ED44 /* ClusterSelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CA1CA7928E281080023ED44 /* ClusterSelectorView.swift */; }; - 3CA1CA7C28E282150023ED44 /* MediaPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CA1CA7B28E282150023ED44 /* MediaPlayerView.swift */; }; - 3CA1CA7E28E284950023ED44 /* MediaPlayerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CA1CA7D28E284950023ED44 /* MediaPlayerViewModel.swift */; }; + 3CA1CA7C28E282150023ED44 /* MediaPlaybackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CA1CA7B28E282150023ED44 /* MediaPlaybackView.swift */; }; + 3CA1CA7E28E284950023ED44 /* MediaPlaybackViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CA1CA7D28E284950023ED44 /* MediaPlaybackViewModel.swift */; }; 3CC0E8FA2841DD3400EC6A18 /* TvCastingApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CC0E8F92841DD3400EC6A18 /* TvCastingApp.swift */; }; 3CC0E8FC2841DD3400EC6A18 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CC0E8FB2841DD3400EC6A18 /* ContentView.swift */; }; 3CC0E8FE2841DD3500EC6A18 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3CC0E8FD2841DD3500EC6A18 /* Assets.xcassets */; }; @@ -44,11 +48,15 @@ 3C7507AE28529A5F00D7DB3A /* CommissioningView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommissioningView.swift; sourceTree = ""; }; 3C7507B62853A3AD00D7DB3A /* CommissionerDiscoveryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommissionerDiscoveryViewModel.swift; sourceTree = ""; }; 3C7507B82853EFF000D7DB3A /* CommissioningViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommissioningViewModel.swift; sourceTree = ""; }; + 3C81C75228F8C79E001CB9D1 /* StartFromCacheView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartFromCacheView.swift; sourceTree = ""; }; + 3C81C75428F8C7B6001CB9D1 /* StartFromCacheViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartFromCacheViewModel.swift; sourceTree = ""; }; + 3C81C75628F8E418001CB9D1 /* ConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionView.swift; sourceTree = ""; }; + 3C81C75828F8E42D001CB9D1 /* ConnectionViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionViewModel.swift; sourceTree = ""; }; 3CA19434285BA780004768D5 /* ContentLauncherView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentLauncherView.swift; sourceTree = ""; }; 3CA19436285BA877004768D5 /* ContentLauncherViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentLauncherViewModel.swift; sourceTree = ""; }; 3CA1CA7928E281080023ED44 /* ClusterSelectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClusterSelectorView.swift; sourceTree = ""; }; - 3CA1CA7B28E282150023ED44 /* MediaPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPlayerView.swift; sourceTree = ""; }; - 3CA1CA7D28E284950023ED44 /* MediaPlayerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPlayerViewModel.swift; sourceTree = ""; }; + 3CA1CA7B28E282150023ED44 /* MediaPlaybackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPlaybackView.swift; sourceTree = ""; }; + 3CA1CA7D28E284950023ED44 /* MediaPlaybackViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPlaybackViewModel.swift; sourceTree = ""; }; 3CC0E8F62841DD3400EC6A18 /* TvCasting.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TvCasting.app; sourceTree = BUILT_PRODUCTS_DIR; }; 3CC0E8F92841DD3400EC6A18 /* TvCastingApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TvCastingApp.swift; sourceTree = ""; }; 3CC0E8FB2841DD3400EC6A18 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -103,6 +111,10 @@ 3C75075E284C1DF800D7DB3A /* TvCasting.entitlements */, 3CC0E8F92841DD3400EC6A18 /* TvCastingApp.swift */, 3CC0E8FB2841DD3400EC6A18 /* ContentView.swift */, + 3C81C75228F8C79E001CB9D1 /* StartFromCacheView.swift */, + 3C81C75428F8C7B6001CB9D1 /* StartFromCacheViewModel.swift */, + 3C81C75628F8E418001CB9D1 /* ConnectionView.swift */, + 3C81C75828F8E42D001CB9D1 /* ConnectionViewModel.swift */, 3C7507AC285299DF00D7DB3A /* CommissionerDiscoveryView.swift */, 3C7507B62853A3AD00D7DB3A /* CommissionerDiscoveryViewModel.swift */, 3C7507AE28529A5F00D7DB3A /* CommissioningView.swift */, @@ -110,8 +122,8 @@ 3CA1CA7928E281080023ED44 /* ClusterSelectorView.swift */, 3CA19434285BA780004768D5 /* ContentLauncherView.swift */, 3CA19436285BA877004768D5 /* ContentLauncherViewModel.swift */, - 3CA1CA7B28E282150023ED44 /* MediaPlayerView.swift */, - 3CA1CA7D28E284950023ED44 /* MediaPlayerViewModel.swift */, + 3CA1CA7B28E282150023ED44 /* MediaPlaybackView.swift */, + 3CA1CA7D28E284950023ED44 /* MediaPlaybackViewModel.swift */, 3CC0E8FF2841DD3500EC6A18 /* Preview Content */, ); path = TvCasting; @@ -208,16 +220,20 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3C81C75328F8C79E001CB9D1 /* StartFromCacheView.swift in Sources */, + 3C81C75528F8C7B6001CB9D1 /* StartFromCacheViewModel.swift in Sources */, 3CCB8745286A5D0F00771BAD /* CommissionerDiscoveryView.swift in Sources */, 3CCB8746286A5D0F00771BAD /* CommissionerDiscoveryViewModel.swift in Sources */, + 3C81C75928F8E42D001CB9D1 /* ConnectionViewModel.swift in Sources */, 3CA1CA7A28E281080023ED44 /* ClusterSelectorView.swift in Sources */, 3CCB8747286A5D0F00771BAD /* CommissioningView.swift in Sources */, 3CCB8748286A5D0F00771BAD /* CommissioningViewModel.swift in Sources */, - 3CA1CA7E28E284950023ED44 /* MediaPlayerViewModel.swift in Sources */, + 3CA1CA7E28E284950023ED44 /* MediaPlaybackViewModel.swift in Sources */, 3CCB8749286A5D0F00771BAD /* ContentLauncherView.swift in Sources */, 3CCB874A286A5D0F00771BAD /* ContentLauncherViewModel.swift in Sources */, + 3C81C75728F8E418001CB9D1 /* ConnectionView.swift in Sources */, 3CC0E8FC2841DD3400EC6A18 /* ContentView.swift in Sources */, - 3CA1CA7C28E282150023ED44 /* MediaPlayerView.swift in Sources */, + 3CA1CA7C28E282150023ED44 /* MediaPlaybackView.swift in Sources */, 3CC0E8FA2841DD3400EC6A18 /* TvCastingApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -355,7 +371,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"TvCasting/Preview Content\""; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = R7NUZ7N74U; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -404,7 +420,7 @@ CoreData, "-Wl,-unexported_symbol,\"__Z*\"", ); - PRODUCT_BUNDLE_IDENTIFIER = com.matter.TvCasting; + PRODUCT_BUNDLE_IDENTIFIER = "com.matter.TvCasting-sharadb"; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -425,7 +441,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"TvCasting/Preview Content\""; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = R7NUZ7N74U; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -451,7 +467,7 @@ "-Wformat-nonliteral", "-Wformat-security", ); - PRODUCT_BUNDLE_IDENTIFIER = com.matter.TvCasting; + PRODUCT_BUNDLE_IDENTIFIER = "com.matter.TvCasting-sharadb"; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_EMIT_LOC_STRINGS = YES; diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissionerDiscoveryView.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissionerDiscoveryView.swift index b49e774164ad94..3ee2ac30d4b724 100644 --- a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissionerDiscoveryView.swift +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissionerDiscoveryView.swift @@ -52,7 +52,7 @@ struct CommissionerDiscoveryView: View { } else if(!viewModel.commissioners.isEmpty) { - Text("Select a commissioner TV...") + Text("Select a commissioner video player...") ForEach(viewModel.commissioners) { commissioner in NavigationLink( destination: CommissioningView(_selectedCommissioner: commissioner), @@ -68,7 +68,7 @@ struct CommissionerDiscoveryView: View { } } } - .navigationTitle("TV Discovery") + .navigationTitle("Video Player Discovery") .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .top) } } diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningView.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningView.swift index 23cee1eb7d341b..f5cb7ddcfaeb74 100644 --- a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningView.swift +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningView.swift @@ -65,17 +65,29 @@ struct CommissioningView: View { if(viewModel.commisisoningComplete == true) { Text("Commissioning finished!").padding() - NavigationLink( - destination: ClusterSelectorView(), - label: { - Text("Next") - .frame(width: 100, height: 30, alignment: .center) - .border(Color.black, width: 1) + + if let connectionSuccess = viewModel.connectionSuccess + { + if let connectionStatus = viewModel.connectionStatus + { + Text(connectionStatus).padding() } - ).background(Color.blue) - .foregroundColor(Color.white) - .frame(maxHeight: .infinity, alignment: .bottom) - .padding() + + if(connectionSuccess) + { + NavigationLink( + destination: ClusterSelectorView(), + label: { + Text("Next") + .frame(width: 100, height: 30, alignment: .center) + .border(Color.black, width: 1) + } + ).background(Color.blue) + .foregroundColor(Color.white) + .frame(maxHeight: .infinity, alignment: .bottom) + .padding() + } + } } else if(viewModel.commisisoningComplete == false) { diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningViewModel.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningViewModel.swift index 5af7d263133557..1c2feaa3aac024 100644 --- a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningViewModel.swift +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningViewModel.swift @@ -29,20 +29,43 @@ class CommissioningViewModel: ObservableObject { @Published var commisisoningComplete: Bool?; + @Published var connectionSuccess: Bool?; + + @Published var connectionStatus: String?; + func prepareForCommissioning(selectedCommissioner: DiscoveredNodeData?) { if let castingServerBridge = CastingServerBridge.getSharedInstance() { - castingServerBridge.openBasicCommissioningWindow( - { (result: Bool) -> () in - // commissioning complete handler code + castingServerBridge.openBasicCommissioningWindow(DispatchQueue.main, + commissioningWindowRequestedHandler: { (result: Bool) -> () in + DispatchQueue.main.async { + self.commisisoningWindowOpened = result + } + }, + commissioningCompleteCallback: { (result: Bool) -> () in self.Log.info("Commissioning status: \(result)") DispatchQueue.main.async { self.commisisoningComplete = result } }, - clientQueue: DispatchQueue.main, - commissioningWindowRequestedHandler: { (result: Bool) -> () in - self.commisisoningWindowOpened = result + onConnectionSuccessCallback: { (videoPlayer: VideoPlayer) -> () in + DispatchQueue.main.async { + self.connectionSuccess = true + self.connectionStatus = "Connected to \(String(describing: videoPlayer))" + self.Log.info("ConnectionViewModel.verifyOrEstablishConnection.onConnectionSuccessCallback called with \(videoPlayer.nodeId)") + } + }, + onConnectionFailureCallback: { (error: MatterError) -> () in + DispatchQueue.main.async { + self.connectionSuccess = false + self.connectionStatus = "Failed to connect to video player!" + self.Log.info("ConnectionViewModel.verifyOrEstablishConnection.onConnectionFailureCallback called with \(error)") + } + }, + onNewOrUpdatedEndpointCallback: { (contentApp: ContentApp) -> () in + DispatchQueue.main.async { + self.Log.info("CommissioningViewModel.openBasicCommissioningWindow.onNewOrUpdatedEndpointCallback called with \(contentApp.endpointId)") + } }) } @@ -53,14 +76,10 @@ class CommissioningViewModel: ObservableObject { } } - private func sendUserDirectedCommissioningRequest(selectedCommissioner: DiscoveredNodeData?) { - let ipAddress: String = selectedCommissioner!.ipAddresses[0] as! String - let port: UInt16 = selectedCommissioner!.port - let platformInterface: UInt32 = selectedCommissioner!.platformInterface - + private func sendUserDirectedCommissioningRequest(selectedCommissioner: DiscoveredNodeData?) { if let castingServerBridge = CastingServerBridge.getSharedInstance() { - castingServerBridge.sendUserDirectedCommissioningRequest(ipAddress, commissionerPort: port, platformInterface: platformInterface, clientQueue: DispatchQueue.main, udcRequestSentHandler: { (result: Bool) -> () in + castingServerBridge.sendUserDirectedCommissioningRequest(selectedCommissioner!, clientQueue: DispatchQueue.main, udcRequestSentHandler: { (result: Bool) -> () in self.udcRequestSent = result }) } diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/ConnectionView.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/ConnectionView.swift new file mode 100644 index 00000000000000..c7bfacc6cca49e --- /dev/null +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/ConnectionView.swift @@ -0,0 +1,78 @@ +/** + * + * Copyright (c) 2020-2022 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 SwiftUI + +struct ConnectionView: View { + var selectedVideoPlayer: VideoPlayer? + + @StateObject var viewModel = ConnectionViewModel(); + + init(_selectedVideoPlayer: VideoPlayer?) { + self.selectedVideoPlayer = _selectedVideoPlayer + } + + var body: some View { + VStack(alignment: .leading) { + if let requestSent = viewModel.requestSent { + if(requestSent) + { + Text("Sent request to verify or connect to video player").padding() + } + else + { + Text("Failed in sending request to verify or connect to video player!").foregroundColor(Color.red).padding() + } + + if let connectionSuccess = viewModel.connectionSuccess + { + if let connectionStatus = viewModel.connectionStatus + { + Text(connectionStatus).padding() + } + + if(connectionSuccess) + { + NavigationLink( + destination: ClusterSelectorView(), + label: { + Text("Next") + .frame(width: 100, height: 30, alignment: .center) + .border(Color.black, width: 1) + } + ).background(Color.blue) + .foregroundColor(Color.white) + .frame(maxHeight: .infinity, alignment: .bottom) + .padding() + } + } + } + } + .navigationTitle("Connecting...") + .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .top) + .onAppear(perform: { + viewModel.verifyOrEstablishConnection(selectedVideoPlayer: self.selectedVideoPlayer) + }) + } +} + +struct ConnectionView_Previews: PreviewProvider { + static var previews: some View { + ConnectionView(_selectedVideoPlayer: nil) + } +} diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/ConnectionViewModel.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/ConnectionViewModel.swift new file mode 100644 index 00000000000000..2d97a47ab3966c --- /dev/null +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/ConnectionViewModel.swift @@ -0,0 +1,63 @@ +/** + * + * Copyright (c) 2020-2022 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 Foundation +import os.log + +class ConnectionViewModel: ObservableObject { + let Log = Logger(subsystem: "com.matter.casting", + category: "ConnectionViewModel") + + @Published var requestSent: Bool?; + + @Published var connectionSuccess: Bool?; + + @Published var connectionStatus: String?; + + func verifyOrEstablishConnection(selectedVideoPlayer: VideoPlayer?) { + if let castingServerBridge = CastingServerBridge.getSharedInstance() + { + castingServerBridge.verifyOrEstablishConnection(selectedVideoPlayer!, clientQueue: DispatchQueue.main, + requestSentHandler: { (error: MatterError) -> () in + DispatchQueue.main.async { + self.requestSent = (error.code == 0) + self.Log.info("ConnectionViewModel.verifyOrEstablishConnection.requestSentHandler called with \(error)") + } + }, + onConnectionSuccessCallback: { (videoPlayer: VideoPlayer) -> () in + DispatchQueue.main.async { + self.connectionSuccess = true + self.connectionStatus = "Connected to \(String(describing: videoPlayer))" + self.Log.info("ConnectionViewModel.verifyOrEstablishConnection.onConnectionSuccessCallback called with \(videoPlayer.nodeId)") + } + }, + onConnectionFailureCallback: { (error: MatterError) -> () in + DispatchQueue.main.async { + self.connectionSuccess = false + self.connectionStatus = "Failed to connect to video player!" + self.Log.info("ConnectionViewModel.verifyOrEstablishConnection.onConnectionFailureCallback called with \(error)") + } + }, + onNewOrUpdatedEndpointCallback: { (contentApp: ContentApp) -> () in + DispatchQueue.main.async { + self.Log.info("ConnectionViewModel.verifyOrEstablishConnection.onNewOrUpdatedEndpointCallback called with \(contentApp.endpointId)") + } + }) + } + } +} diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/ContentLauncherView.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/ContentLauncherView.swift index 120b6ee1a903d6..dc15dc66876fa6 100644 --- a/examples/tv-casting-app/darwin/TvCasting/TvCasting/ContentLauncherView.swift +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/ContentLauncherView.swift @@ -17,51 +17,86 @@ import SwiftUI +extension ContentApp : Identifiable { + public var id: UInt16 { + endpointId + } +} + struct ContentLauncherView: View { @StateObject var viewModel = ContentLauncherViewModel() @State private var contentUrl: String = "" @State private var contentDisplayStr: String = "" + @State private var targetContentAppId: String = "" var body: some View { VStack(alignment: .leading) { - HStack() { - Text("Content URL") - - TextField( - "https://www.test.com/videoid", - text: $contentUrl - ) - .textInputAutocapitalization(.never) - .disableAutocorrection(true) - .border(.secondary) + if(viewModel.contentAppIds.isEmpty) + { + Text("No Content Launcher cluster supporting content apps found on this video player!") } + else + { + HStack() { + Text("Content App Endpoint Id") + + VStack() + { + Picker("Select", selection: $targetContentAppId) { + Text("Select").tag(nil as String?) + ForEach(viewModel.contentAppIds, id: \.self) { contentAppId in + Text(String(contentAppId)) + } + } + .pickerStyle(.menu) + .padding(2) + } + .border(.secondary) + } - HStack() { - Text("Display string") + HStack() { + Text("Content URL") - TextField( - "Test video", - text: $contentDisplayStr - ) - .textInputAutocapitalization(.never) - .disableAutocorrection(true) - .border(.secondary) - } + TextField( + "https://www.test.com/videoid", + text: $contentUrl + ) + .textInputAutocapitalization(.never) + .disableAutocorrection(true) + .border(.secondary) + } - Button("Launch URL!") { - viewModel.launchUrl(contentUrl: contentUrl, contentDisplayStr: contentDisplayStr) - } - .background(Color.blue) - .foregroundColor(Color.white) - .cornerRadius(4) - .border(Color.black, width: 1) - .padding() + HStack() { + Text("Display string") + + TextField( + "Test video", + text: $contentDisplayStr + ) + .textInputAutocapitalization(.never) + .disableAutocorrection(true) + .border(.secondary) + } + + Button("Launch URL!") { + viewModel.launchUrl(targetContentAppId: targetContentAppId, contentUrl: contentUrl, contentDisplayStr: contentDisplayStr) + } + .background(Color.blue) + .foregroundColor(Color.white) + .cornerRadius(4) + .border(Color.black, width: 1) + .padding() - Text(viewModel.status ?? "") + Text(viewModel.status ?? "") + } + } .navigationTitle("Content Launcher") .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .top) + .onAppear(perform: { + viewModel.populateContentApps() + }) } } diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/ContentLauncherViewModel.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/ContentLauncherViewModel.swift index ee741f8bcae8f0..7003525e8d3360 100644 --- a/examples/tv-casting-app/darwin/TvCasting/TvCasting/ContentLauncherViewModel.swift +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/ContentLauncherViewModel.swift @@ -25,14 +25,27 @@ class ContentLauncherViewModel: ObservableObject { @Published var status: String?; - func launchUrl(contentUrl: String?, contentDisplayStr: String?) + @Published var contentAppIds: [String] = []; + + var targetVideoPlayer: VideoPlayer?; + + func launchUrl(targetContentAppId: String?, contentUrl: String?, contentDisplayStr: String?) { - if ((contentUrl != nil && !contentUrl!.isEmpty) && (contentDisplayStr != nil && !contentDisplayStr!.isEmpty)) + if ((targetContentAppId != nil && !targetContentAppId!.isEmpty) && (contentUrl != nil && !contentUrl!.isEmpty) && (contentDisplayStr != nil && !contentDisplayStr!.isEmpty)) { + var targetContentApp: ContentApp? + for contentApp in (targetVideoPlayer!.contentApps as! [ContentApp]) { + if(UInt16(targetContentAppId!) == contentApp.endpointId) + { + targetContentApp = contentApp + break + } + } + if let castingServerBridge = CastingServerBridge.getSharedInstance() { castingServerBridge - .contentLauncher_launchUrl(contentUrl!, + .contentLauncher_launchUrl(targetContentApp!, contentUrl: contentUrl!, contentDisplayStr: contentDisplayStr!, responseCallback: { (result: Bool) -> () in @@ -41,9 +54,8 @@ class ContentLauncherViewModel: ObservableObject { self.status = result ? "Launched URL successfully" : "Launch URL failure!" } }, - clientQueue: DispatchQueue.main, - requestSentHandler: - { (result: Bool) -> () in + clientQueue: DispatchQueue.main, + requestSentHandler: { (result: Bool) -> () in self.Log.info("ContentLauncherViewModel.launchUrl.launcUrlRequestSentHandler result \(result)") self.status = result ? "Sent Launch URL request" : "Failed to send Launch URL request!" }) @@ -55,4 +67,26 @@ class ContentLauncherViewModel: ObservableObject { self.status = "Missing input parameter(s)!" } } + + func populateContentApps() + { + if let castingServerBridge = CastingServerBridge.getSharedInstance() + { + castingServerBridge.getActiveTargetVideoPlayers(DispatchQueue.main, + activeTargetVideoPlayersHandler: { (targetVideoPlayers: NSMutableArray?) -> () in + let targetVideoPlayer: VideoPlayer = targetVideoPlayers![0] as! VideoPlayer + if(targetVideoPlayer.isInitialized && targetVideoPlayer.isConnected) + { + self.targetVideoPlayer = targetVideoPlayer + for contentApp in (targetVideoPlayer.contentApps as! [ContentApp]) + { + if(contentApp.supportsContentLauncher()) + { + self.contentAppIds.append(String(contentApp.endpointId)) + } + } + } + }) + } + } } diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/ContentView.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/ContentView.swift index 69b67095c60751..e7ca12c9b720cd 100644 --- a/examples/tv-casting-app/darwin/TvCasting/TvCasting/ContentView.swift +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/ContentView.swift @@ -20,7 +20,8 @@ import SwiftUI struct ContentView: View { var body: some View { NavigationView { - CommissionerDiscoveryView() + //CommissionerDiscoveryView() + StartFromCacheView() } } } diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlaybackView.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlaybackView.swift new file mode 100644 index 00000000000000..b41835adb0c139 --- /dev/null +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlaybackView.swift @@ -0,0 +1,105 @@ +/** + * + * Copyright (c) 2020-2022 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 SwiftUI + +struct MediaPlayerView: View { + @StateObject var viewModel = MediaPlaybackViewModel() + + @State private var minIntervalStr: String = "" + @State private var maxIntervalStr: String = "" + @State private var targetContentAppId: String = "" + + var body: some View { + VStack(alignment: .leading) + { + if(viewModel.contentAppIds.isEmpty) + { + Text("No Media Playback cluster supporting content apps found on this video player!") + } + else + { + Text("Subscribe to Current State") + + HStack() { + Text("Content App Endpoint Id") + + VStack() + { + Picker("Select", selection: $targetContentAppId) { + Text("Select").tag(nil as String?) + ForEach(viewModel.contentAppIds, id: \.self) { contentAppId in + Text(String(contentAppId)) + } + } + .pickerStyle(.menu) + .padding(2) + } + .border(.secondary) + } + + HStack() { + Text("Min Interval") + + TextField( + "0", + text: $minIntervalStr + ) + .textInputAutocapitalization(.never) + .disableAutocorrection(true) + .border(.secondary) + } + + HStack() { + Text("Max Interval") + + TextField( + "1", + text: $maxIntervalStr + ) + .textInputAutocapitalization(.never) + .disableAutocorrection(true) + .border(.secondary) + } + + Button("Subscribe!") { + viewModel.subscribeCurrentState(targetContentAppId: targetContentAppId, minInterval: minIntervalStr, maxInterval: maxIntervalStr) + } + .background(Color.blue) + .foregroundColor(Color.white) + .cornerRadius(4) + .border(Color.black, width: 1) + .padding() + + Text(viewModel.requestStatus ?? "") + Text(viewModel.subscriptionStatus ?? "") + Text(viewModel.readResponse ?? "") + } + } + .navigationTitle("Media Playback") + .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .top) + .onAppear(perform: { + viewModel.populateContentApps() + }) + } +} + +struct MediaPlayerView_Previews: PreviewProvider { + static var previews: some View { + MediaPlayerView() + } +} diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlaybackViewModel.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlaybackViewModel.swift new file mode 100644 index 00000000000000..5a93a2ffe7c3cf --- /dev/null +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlaybackViewModel.swift @@ -0,0 +1,120 @@ +/** + * + * Copyright (c) 2020-2022 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 Foundation +import os.log + +class MediaPlaybackViewModel: ObservableObject { + let Log = Logger(subsystem: "com.matter.casting", + category: "MediaPlaybackViewModel") + + @Published var requestStatus: String?; + @Published var subscriptionStatus: String?; + @Published var readResponse: String?; + + @Published var contentAppIds: [String] = []; + + var targetVideoPlayer: VideoPlayer?; + + func subscribeCurrentState(targetContentAppId: String?, minInterval: String, maxInterval: String) + { + if((targetContentAppId != nil && !targetContentAppId!.isEmpty)) + { + if let castingServerBridge = CastingServerBridge.getSharedInstance() + { + var targetContentApp: ContentApp? + for contentApp in (targetVideoPlayer!.contentApps as! [ContentApp]) { + if(UInt16(targetContentAppId!) == contentApp.endpointId) + { + targetContentApp = contentApp + break + } + } + + castingServerBridge.mediaPlayback_subscribeCurrentState(targetContentApp!, minInterval: UInt16(minInterval) ?? 0, maxInterval: UInt16(maxInterval) ?? 1, clientQueue: DispatchQueue.main, + requestSentHandler: { (result: MatterError) -> () in + self.Log.info("MediaPlaybackViewModel.subscribeToCurrentState.requestSentHandler result \(result)") + self.requestStatus = result.code == 0 ? "Subscribe request sent!" : "Failed to send Subscribe request!" + }, + successCallback: { (result: MediaPlayback_PlaybackState) -> () in + DispatchQueue.main.async { + self.Log.info("MediaPlaybackViewModel.subscribeToCurrentState.successCallback called") + switch(result) + { + case .Playing: + self.readResponse = "Current state: Playing" + break + case .Paused: + self.readResponse = "Current state: Paused" + break + case .NotPlaying: + self.readResponse = "Current state: NotPlaying" + break + case .Buffering: + self.readResponse = "Current state: Buffering" + break + default: + self.readResponse = "Current state: Unknown!" + break + } + } + }, + failureCallback: { (result: MatterError) -> () in + DispatchQueue.main.async { + self.Log.info("MediaPlaybackViewModel.subscribeToCurrentState.failureCallback called with \(result)") + self.readResponse = "Attribute read failure!" + } + }, + subscriptionEstablishedCallback: { () -> () in + DispatchQueue.main.async { + self.Log.info("MediaPlaybackViewModel.subscribeToCurrentState.subscriptionEstablishedCallback called") + self.subscriptionStatus = "Subscription established!" + } + } + ) + } + } + else + { + Log.debug("MediaPlaybackViewModel.subscribeToCurrentState No endpoint selected!") + self.requestStatus = "No endpoint selected!" + } + } + + func populateContentApps() + { + if let castingServerBridge = CastingServerBridge.getSharedInstance() + { + castingServerBridge.getActiveTargetVideoPlayers(DispatchQueue.main, + activeTargetVideoPlayersHandler: { (targetVideoPlayers: NSMutableArray?) -> () in + let targetVideoPlayer: VideoPlayer = targetVideoPlayers![0] as! VideoPlayer + if(targetVideoPlayer.isInitialized && targetVideoPlayer.isConnected) + { + self.targetVideoPlayer = targetVideoPlayer + for contentApp in (targetVideoPlayer.contentApps as! [ContentApp]) + { + if(contentApp.supportsMediaPlayback()) + { + self.contentAppIds.append(String(contentApp.endpointId)) + } + } + } + }) + } + } +} diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlayerView.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlayerView.swift deleted file mode 100644 index 296b0a78607f9a..00000000000000 --- a/examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlayerView.swift +++ /dev/null @@ -1,76 +0,0 @@ -/** - * - * Copyright (c) 2020-2022 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 SwiftUI - -struct MediaPlayerView: View { - @StateObject var viewModel = MediaPlayerViewModel() - - @State private var minIntervalStr: String = "" - @State private var maxIntervalStr: String = "" - - var body: some View { - VStack(alignment: .leading) { - Text("Subscribe to Current State") - - HStack() { - Text("Min Interval") - - TextField( - "0", - text: $minIntervalStr - ) - .textInputAutocapitalization(.never) - .disableAutocorrection(true) - .border(.secondary) - } - - HStack() { - Text("Max Interval") - - TextField( - "10", - text: $maxIntervalStr - ) - .textInputAutocapitalization(.never) - .disableAutocorrection(true) - .border(.secondary) - } - - Button("Subscribe!") { - viewModel.subscribeCurrentState(minInterval: minIntervalStr, maxInterval: maxIntervalStr) - } - .background(Color.blue) - .foregroundColor(Color.white) - .cornerRadius(4) - .border(Color.black, width: 1) - .padding() - - Text(viewModel.requestStatus ?? "") - Text(viewModel.subscriptionStatus ?? "") - Text(viewModel.readResponse ?? "") - } - .navigationTitle("Media Playback") - .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .top) - } -} - -struct MediaPlayerView_Previews: PreviewProvider { - static var previews: some View { - MediaPlayerView() - } -} diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlayerViewModel.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlayerViewModel.swift deleted file mode 100644 index d401d3f5247d5b..00000000000000 --- a/examples/tv-casting-app/darwin/TvCasting/TvCasting/MediaPlayerViewModel.swift +++ /dev/null @@ -1,77 +0,0 @@ -/** - * - * Copyright (c) 2020-2022 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 Foundation -import os.log - -class MediaPlayerViewModel: ObservableObject { - let Log = Logger(subsystem: "com.matter.casting", - category: "MediaPlayerViewModel") - - @Published var requestStatus: String?; - @Published var subscriptionStatus: String?; - @Published var readResponse: String?; - - func subscribeCurrentState(minInterval: String, maxInterval: String) - { - if let castingServerBridge = CastingServerBridge.getSharedInstance() - { - castingServerBridge.mediaPlayback_subscribeCurrentState(UInt16(minInterval) ?? 0, maxInterval: UInt16(maxInterval) ?? 10, clientQueue: DispatchQueue.main, - requestSentHandler: { (result: MatterError) -> () in - self.Log.info("MediaPlayerViewModel.subscribeToCurrentState.requestSentHandler result \(result)") - self.requestStatus = result.code == 0 ? "Subscribe request sent!" : "Failed to send Subscribe request!" - }, - successCallback: { (result: MediaPlayback_PlaybackState) -> () in - DispatchQueue.main.async { - self.Log.info("MediaPlayerViewModel.subscribeToCurrentState.successCallback called") - switch(result) - { - case .Playing: - self.readResponse = "Current state: Playing" - break - case .Paused: - self.readResponse = "Current state: Paused" - break - case .NotPlaying: - self.readResponse = "Current state: NotPlaying" - break - case .Buffering: - self.readResponse = "Current state: Buffering" - break - default: - self.readResponse = "Current state: Unknown!" - break - } - } - }, - failureCallback: { (result: MatterError) -> () in - DispatchQueue.main.async { - self.Log.info("MediaPlayerViewModel.subscribeToCurrentState.failureCallback called with \(result)") - self.readResponse = "Attribute read failure!" - } - }, - subscriptionEstablishedCallback: { () -> () in - DispatchQueue.main.async { - self.Log.info("MediaPlayerViewModel.subscribeToCurrentState.subscriptionEstablishedCallback called") - self.subscriptionStatus = "Subscription established!" - } - } - ) - } - } -} diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/StartFromCacheView.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/StartFromCacheView.swift new file mode 100644 index 00000000000000..9d4c0c8a659151 --- /dev/null +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/StartFromCacheView.swift @@ -0,0 +1,74 @@ +/** + * + * Copyright (c) 2020-2022 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 SwiftUI + +extension VideoPlayer : Identifiable { + public var id: String { + deviceName + } +} + +struct StartFromCacheView: View { + @StateObject var viewModel = StartFromCacheViewModel() + + var body: some View { + VStack(alignment: .leading) { + NavigationLink( + destination: CommissionerDiscoveryView(), + label: { + Text("Skip to commissioner discovery >>") + .frame(width: 300, height: 30, alignment: .center) + .border(Color.black, width: 1) + } + ).background(Color.blue) + .foregroundColor(Color.white) + .padding() + + if(viewModel.videoPlayers.isEmpty) + { + Text("No cached video players.") + } + else + { + Text("Pick a Video player") + ForEach(viewModel.videoPlayers) { videoPlayer in + NavigationLink( + destination: ConnectionView(_selectedVideoPlayer: videoPlayer), + label: { + Text(videoPlayer.description) + } + ) + .frame(width: 350, height: 50, alignment: .center) + .border(Color.black, width: 1) + .background(Color.blue) + .foregroundColor(Color.white) + .padding(1) + } + } + } + .navigationTitle("Starting from Cache") + .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .top) + .onAppear(perform: {viewModel.readFromCache()}) + } +} + +struct StartFromCacheView_Previews: PreviewProvider { + static var previews: some View { + StartFromCacheView() + } +} diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/StartFromCacheViewModel.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/StartFromCacheViewModel.swift new file mode 100644 index 00000000000000..202d92c5ccfff3 --- /dev/null +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/StartFromCacheViewModel.swift @@ -0,0 +1,38 @@ +/** + * + * Copyright (c) 2020-2022 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 Foundation +import os.log + +class StartFromCacheViewModel: ObservableObject { + let Log = Logger(subsystem: "com.matter.casting", + category: "StartFromCacheViewModel") + + @Published var videoPlayers: [VideoPlayer] = [] + + func readFromCache() { + if let castingServerBridge = CastingServerBridge.getSharedInstance() + { + castingServerBridge.readCachedVideoPlayers(DispatchQueue.main, readCachedVideoPlayersHandler: { (cachedVideoPlayers: NSMutableArray?) -> () in + if(cachedVideoPlayers != nil) + { + self.videoPlayers = cachedVideoPlayers! as! [VideoPlayer] + } + }) + } + } +} diff --git a/examples/tv-casting-app/linux/CastingShellCommands.cpp b/examples/tv-casting-app/linux/CastingShellCommands.cpp index bbcdcc7eb4bea5..e17053afe8d9f1 100644 --- a/examples/tv-casting-app/linux/CastingShellCommands.cpp +++ b/examples/tv-casting-app/linux/CastingShellCommands.cpp @@ -92,7 +92,8 @@ static CHIP_ERROR CastingHandler(int argc, char ** argv) char * eptr; chip::NodeId nodeId = (chip::NodeId) strtoull(argv[1], &eptr, 10); chip::FabricIndex fabricIndex = (chip::FabricIndex) strtol(argv[2], &eptr, 10); - return CastingServer::GetInstance()->TargetVideoPlayerInfoInit(nodeId, fabricIndex); + return CastingServer::GetInstance()->TargetVideoPlayerInfoInit(nodeId, fabricIndex, OnConnectionSuccess, + OnConnectionFailure, OnNewOrUpdatedEndpoint); } if (strcmp(argv[0], "discover") == 0) { @@ -120,7 +121,8 @@ static CHIP_ERROR CastingHandler(int argc, char ** argv) } char * url = argv[1]; char * display = argv[2]; - return CastingServer::GetInstance()->ContentLauncherLaunchURL(url, display, LaunchURLResponseCallback); + return CastingServer::GetInstance()->ContentLauncherLaunchURL( + CastingServer::GetInstance()->GetActiveTargetVideoPlayer()->GetEndpoint(4), url, display, LaunchURLResponseCallback); } if (strcmp(argv[0], "access") == 0) { @@ -173,7 +175,8 @@ static CHIP_ERROR CastingHandler(int argc, char ** argv) streamer_printf(streamer_get(), "ERROR - invalid fabric or video player nodeId not found\r\n"); return CHIP_ERROR_INVALID_ARGUMENT; } - return CastingServer::GetInstance()->TargetVideoPlayerInfoInit(nodeId, fabricIndex); + return CastingServer::GetInstance()->TargetVideoPlayerInfoInit(nodeId, fabricIndex, OnConnectionSuccess, + OnConnectionFailure, OnNewOrUpdatedEndpoint); } if (strcmp(argv[0], "cluster") == 0) { diff --git a/examples/tv-casting-app/linux/CastingUtils.cpp b/examples/tv-casting-app/linux/CastingUtils.cpp index 6f5ea539a501d2..760b0435124c47 100644 --- a/examples/tv-casting-app/linux/CastingUtils.cpp +++ b/examples/tv-casting-app/linux/CastingUtils.cpp @@ -60,7 +60,8 @@ void PrepareForCommissioning(const Dnssd::DiscoveredNodeData * selectedCommissio { CastingServer::GetInstance()->Init(); - CastingServer::GetInstance()->OpenBasicCommissioningWindow(HandleCommissioningCompleteCallback); + CastingServer::GetInstance()->OpenBasicCommissioningWindow(HandleCommissioningCompleteCallback, OnConnectionSuccess, + OnConnectionFailure, OnNewOrUpdatedEndpoint); // Display onboarding payload chip::DeviceLayer::ConfigurationMgr().LogDeviceConfig(); @@ -158,27 +159,113 @@ void OnCurrentStateSubscriptionEstablished(void * context) } } -void HandleCommissioningCompleteCallback(CHIP_ERROR err) +void doCastingDemoActions(TargetEndpointInfo * endpoint) { - ChipLogProgress(AppServer, "HandleCommissioningCompleteCallback called with %" CHIP_ERROR_FORMAT, err.Format()); - if (err == CHIP_NO_ERROR) + if (endpoint != nullptr && endpoint->IsInitialized()) + { + if (endpoint->HasCluster(chip::app::Clusters::MediaPlayback::Id)) + { + // Subscribe to MediaPlayback::CurrentState + ChipLogProgress(AppServer, + "doCastingDemoActions requesting subscription on MediaPlayback:CurrentState on endpoint ID: %d", + endpoint->GetEndpointId()); + CHIP_ERROR err = CastingServer::GetInstance()->MediaPlayback_SubscribeToCurrentState( + endpoint, static_cast(&gInitialContextVal), OnCurrentStateReadResponseSuccess, + OnCurrentStateReadResponseFailure, 0, 4000, OnCurrentStateSubscriptionEstablished); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "MediaPlayback_SubscribeToCurrentState call failed!"); + } + } + else + { + ChipLogProgress(AppServer, + "doCastingDemoActions: Not subscribing to MediaPlayback:CurrentState on endpoint ID %d as it does not " + "support the MediaPlayback cluster", + endpoint->GetEndpointId()); + } + + if (endpoint->HasCluster(chip::app::Clusters::ContentLauncher::Id)) + { + // Send a ContentLauncher::LaunchURL command + ChipLogProgress(AppServer, "doCastingDemoActions sending ContentLauncher:LaunchURL on endpoint ID: %d", + endpoint->GetEndpointId()); + CHIP_ERROR err = CastingServer::GetInstance()->ContentLauncherLaunchURL(endpoint, kContentUrl, kContentDisplayStr, + LaunchURLResponseCallback); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "ContentLauncherLaunchURL call failed!"); + } + } + else + { + ChipLogProgress(AppServer, + "doCastingDemoActions: Not sending ContentLauncher:LaunchURL on endpoint ID %d as it does not support " + "the ContentLauncher cluster", + endpoint->GetEndpointId()); + } + } +} + +void OnConnectionSuccess(TargetVideoPlayerInfo * videoPlayer) +{ + ChipLogProgress(AppServer, + "OnConnectionSuccess with Video Player(nodeId: 0x" ChipLogFormatX64 + ", fabricIndex: %d, deviceName: %s, vendorId: %d, productId: " + "%d, deviceType: %d)", + ChipLogValueX64(videoPlayer->GetNodeId()), videoPlayer->GetFabricIndex(), videoPlayer->GetDeviceName(), + videoPlayer->GetVendorId(), videoPlayer->GetProductId(), videoPlayer->GetDeviceType()); + + TargetEndpointInfo * endpoints = videoPlayer->GetEndpoints(); + if (endpoints != nullptr) { - // Subscribe to a media attribute - err = CastingServer::GetInstance()->MediaPlayback_SubscribeToCurrentState( - static_cast(&gInitialContextVal), OnCurrentStateReadResponseSuccess, OnCurrentStateReadResponseFailure, 0, 4000, - OnCurrentStateSubscriptionEstablished); - if (err != CHIP_NO_ERROR) + for (size_t i = 0; i < kMaxNumberOfEndpoints && endpoints[i].IsInitialized(); i++) { - ChipLogError(AppServer, "MediaPlayback_SubscribeToCurrentState call failed!"); + doCastingDemoActions(&endpoints[i]); // LaunchURL and Subscribe to CurrentState } + } +} + +void OnConnectionFailure(CHIP_ERROR err) +{ + ChipLogError(AppServer, "OnConnectionFailure error: %" CHIP_ERROR_FORMAT, err.AsString()); +} + +void OnNewOrUpdatedEndpoint(TargetEndpointInfo * endpoint) +{ + ChipLogProgress(AppServer, "OnNewOrUpdatedEndpoint called"); + doCastingDemoActions(endpoint); // LaunchURL and Subscribe to CurrentState +} - // Send a media command - err = CastingServer::GetInstance()->ContentLauncherLaunchURL(kContentUrl, kContentDisplayStr, LaunchURLResponseCallback); - if (err != CHIP_NO_ERROR) +CHIP_ERROR ConnectToCachedVideoPlayer() +{ + TargetVideoPlayerInfo * cachedVideoPlayers = CastingServer::GetInstance()->ReadCachedTargetVideoPlayerInfos(); + if (cachedVideoPlayers != nullptr) + { + for (size_t i = 0; i < kMaxCachedVideoPlayers; i++) { - ChipLogError(AppServer, "ContentLauncherLaunchURL call failed!"); + if (cachedVideoPlayers[i].IsInitialized()) + { + ChipLogProgress(AppServer, "Found a Cached video player with nodeId: 0x" ChipLogFormatX64 ", fabricIndex: %d", + ChipLogValueX64(cachedVideoPlayers[i].GetNodeId()), cachedVideoPlayers[i].GetFabricIndex()); + if (CastingServer::GetInstance()->VerifyOrEstablishConnection( + cachedVideoPlayers[i], OnConnectionSuccess, OnConnectionFailure, OnNewOrUpdatedEndpoint) == CHIP_NO_ERROR) + { + ChipLogProgress(AppServer, + "FindOrEstablish CASESession attempted for cached video player with nodeId: 0x" ChipLogFormatX64 + ", fabricIndex: %d", + ChipLogValueX64(cachedVideoPlayers[i].GetNodeId()), cachedVideoPlayers[i].GetFabricIndex()); + return CHIP_NO_ERROR; + } + } } } + return CHIP_ERROR_INVALID_CASE_PARAMETER; +} + +void HandleCommissioningCompleteCallback(CHIP_ERROR err) +{ + ChipLogProgress(AppServer, "HandleCommissioningCompleteCallback called with %" CHIP_ERROR_FORMAT, err.Format()); } #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT @@ -187,9 +274,7 @@ void HandleUDCSendExpiration(System::Layer * aSystemLayer, void * context) Dnssd::DiscoveredNodeData * selectedCommissioner = (Dnssd::DiscoveredNodeData *) context; // Send User Directed commissioning request - ReturnOnFailure(CastingServer::GetInstance()->SendUserDirectedCommissioningRequest(chip::Transport::PeerAddress::UDP( - selectedCommissioner->resolutionData.ipAddress[0], selectedCommissioner->resolutionData.port, - selectedCommissioner->resolutionData.interfaceId))); + ReturnOnFailure(CastingServer::GetInstance()->SendUserDirectedCommissioningRequest(selectedCommissioner)); } #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT diff --git a/examples/tv-casting-app/linux/CastingUtils.h b/examples/tv-casting-app/linux/CastingUtils.h index 172b01896c9675..13d9818662e3af 100644 --- a/examples/tv-casting-app/linux/CastingUtils.h +++ b/examples/tv-casting-app/linux/CastingUtils.h @@ -38,8 +38,18 @@ void PrepareForCommissioning(const chip::Dnssd::DiscoveredNodeData * selectedCom void InitCommissioningFlow(intptr_t commandArg); +void doCastingDemoActions(TargetEndpointInfo * endpoint); + void HandleCommissioningCompleteCallback(CHIP_ERROR err); +CHIP_ERROR ConnectToCachedVideoPlayer(); + +void OnConnectionSuccess(TargetVideoPlayerInfo * videoPlayer); + +void OnConnectionFailure(CHIP_ERROR err); + +void OnNewOrUpdatedEndpoint(TargetEndpointInfo * endpoint); + void LaunchURLResponseCallback(CHIP_ERROR err); void OnCurrentStateReadResponseSuccess( diff --git a/examples/tv-casting-app/linux/main.cpp b/examples/tv-casting-app/linux/main.cpp index 75222fed066ae5..d6d674ebb2a954 100644 --- a/examples/tv-casting-app/linux/main.cpp +++ b/examples/tv-casting-app/linux/main.cpp @@ -41,7 +41,6 @@ using namespace chip; using chip::ArgParser::HelpOptions; using chip::ArgParser::OptionDef; using chip::ArgParser::OptionSet; -using namespace chip::app::Clusters::ContentLauncher::Commands; #if defined(ENABLE_CHIP_SHELL) using chip::Shell::Engine; @@ -97,9 +96,9 @@ Commands gCommands; CHIP_ERROR ProcessClusterCommand(int argc, char ** argv) { - if (!CastingServer::GetInstance()->GetTargetVideoPlayerInfo()->IsInitialized()) + if (!CastingServer::GetInstance()->GetActiveTargetVideoPlayer()->IsInitialized()) { - CastingServer::GetInstance()->SetDefaultFabricIndex(); + CastingServer::GetInstance()->SetDefaultFabricIndex(OnConnectionSuccess, OnConnectionFailure, OnNewOrUpdatedEndpoint); } gCommands.Run(argc, argv); return CHIP_NO_ERROR; @@ -140,13 +139,20 @@ int main(int argc, char * argv[]) VerifyOrDie(CHIP_NO_ERROR == initParams.InitializeStaticResourcesBeforeServerInit()); VerifyOrDie(CHIP_NO_ERROR == chip::Server::GetInstance().Init(initParams)); - // Send discover commissioners request - SuccessOrExit(err = CastingServer::GetInstance()->DiscoverCommissioners()); + if (ConnectToCachedVideoPlayer() == CHIP_NO_ERROR) + { + ChipLogProgress(AppServer, "Skipping commissioner discovery / User directed commissioning flow."); + } + else + { + // Send discover commissioners request + SuccessOrExit(err = CastingServer::GetInstance()->DiscoverCommissioners()); - // Give commissioners some time to respond and then ScheduleWork to initiate commissioning - DeviceLayer::SystemLayer().StartTimer( - chip::System::Clock::Milliseconds32(kCommissionerDiscoveryTimeoutInMs), - [](System::Layer *, void *) { chip::DeviceLayer::PlatformMgr().ScheduleWork(InitCommissioningFlow); }, nullptr); + // Give commissioners some time to respond and then ScheduleWork to initiate commissioning + DeviceLayer::SystemLayer().StartTimer( + chip::System::Clock::Milliseconds32(kCommissionerDiscoveryTimeoutInMs), + [](System::Layer *, void *) { chip::DeviceLayer::PlatformMgr().ScheduleWork(InitCommissioningFlow); }, nullptr); + } registerClusters(gCommands, &gCredIssuerCommands); registerClusterSubscriptions(gCommands, &gCredIssuerCommands); diff --git a/examples/tv-casting-app/tv-casting-common/BUILD.gn b/examples/tv-casting-app/tv-casting-common/BUILD.gn index 571d659fecb7fe..1c356d5cb36b9e 100644 --- a/examples/tv-casting-app/tv-casting-common/BUILD.gn +++ b/examples/tv-casting-app/tv-casting-common/BUILD.gn @@ -58,6 +58,7 @@ chip_data_model("tv-casting-common") { "include/MediaCommandBase.h", "include/MediaPlayback.h", "include/MediaSubscriptionBase.h", + "include/PersistenceManager.h", "include/TargetEndpointInfo.h", "include/TargetNavigator.h", "include/TargetVideoPlayerInfo.h", @@ -68,6 +69,7 @@ chip_data_model("tv-casting-common") { "src/KeypadInput.cpp", "src/LevelControl.cpp", "src/MediaPlayback.cpp", + "src/PersistenceManager.cpp", "src/TargetEndpointInfo.cpp", "src/TargetNavigator.cpp", "src/TargetVideoPlayerInfo.cpp", 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 d78dc6ba7f1ad8..b77e2bd320604b 100644 --- a/examples/tv-casting-app/tv-casting-common/include/CastingServer.h +++ b/examples/tv-casting-app/tv-casting-common/include/CastingServer.h @@ -25,6 +25,7 @@ #include "KeypadInput.h" #include "LevelControl.h" #include "MediaPlayback.h" +#include "PersistenceManager.h" #include "TargetEndpointInfo.h" #include "TargetNavigator.h" #include "TargetVideoPlayerInfo.h" @@ -37,7 +38,6 @@ #include constexpr chip::System::Clock::Seconds16 kCommissioningWindowTimeout = chip::System::Clock::Seconds16(3 * 60); -constexpr chip::EndpointId kTvEndpoint = 4; /** * @brief Represents a TV Casting server that can get the casting app commissioned @@ -55,41 +55,59 @@ class CastingServer CHIP_ERROR DiscoverCommissioners(); const chip::Dnssd::DiscoveredNodeData * GetDiscoveredCommissioner(int index); - CHIP_ERROR OpenBasicCommissioningWindow(std::function commissioningCompleteCallback); + CHIP_ERROR OpenBasicCommissioningWindow(std::function commissioningCompleteCallback, + std::function onConnectionSuccess, + std::function onConnectionFailure, + std::function onNewOrUpdatedEndpoint); + #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT CHIP_ERROR SendUserDirectedCommissioningRequest(chip::Transport::PeerAddress commissioner); + CHIP_ERROR SendUserDirectedCommissioningRequest(chip::Dnssd::DiscoveredNodeData * selectedCommissioner); #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT - TargetVideoPlayerInfo * GetTargetVideoPlayerInfo() { return &mTargetVideoPlayerInfo; } - CHIP_ERROR TargetVideoPlayerInfoInit(chip::NodeId nodeId, chip::FabricIndex fabricIndex); - void ReadServerClusters(chip::EndpointId endpointId); + TargetVideoPlayerInfo * GetActiveTargetVideoPlayer() { return &mActiveTargetVideoPlayerInfo; } + + CHIP_ERROR TargetVideoPlayerInfoInit(chip::NodeId nodeId, chip::FabricIndex fabricIndex, + std::function onConnectionSuccess, + std::function onConnectionFailure, + std::function onNewOrUpdatedEndpoint); void ReadServerClustersForNode(chip::NodeId nodeId); static void OnDescriptorReadSuccessResponse(void * context, const chip::app::DataModel::DecodableList & responseList); static void OnDescriptorReadFailureResponse(void * context, CHIP_ERROR error); [[deprecated("Use ContentLauncher_LaunchURL(..) instead")]] CHIP_ERROR - ContentLauncherLaunchURL(const char * contentUrl, const char * contentDisplayStr, + ContentLauncherLaunchURL(TargetEndpointInfo * endpoint, const char * contentUrl, const char * contentDisplayStr, std::function launchURLResponseCallback); chip::NodeId GetVideoPlayerNodeForFabricIndex(chip::FabricIndex fabricIndex); chip::FabricIndex GetVideoPlayerFabricIndexForNode(chip::NodeId nodeId); - chip::FabricIndex CurrentFabricIndex() { return mTargetVideoPlayerInfo.GetFabricIndex(); } - void SetDefaultFabricIndex(); + chip::FabricIndex CurrentFabricIndex() { return mActiveTargetVideoPlayerInfo.GetFabricIndex(); } + void SetDefaultFabricIndex(std::function onConnectionSuccess, + std::function onConnectionFailure, + std::function onNewOrUpdatedEndpoint); + TargetVideoPlayerInfo * ReadCachedTargetVideoPlayerInfos(); + CHIP_ERROR VerifyOrEstablishConnection(TargetVideoPlayerInfo & targetVideoPlayerInfo, + std::function onConnectionSuccess, + std::function onConnectionFailure, + std::function onNewOrUpdatedEndpoint); + + CHIP_ERROR PurgeVideoPlayerCache(); /** * @brief Content Launcher cluster */ CHIP_ERROR ContentLauncher_LaunchURL( - const char * contentUrl, const char * contentDisplayStr, + TargetEndpointInfo * endpoint, const char * contentUrl, const char * contentDisplayStr, chip::Optional brandingInformation, std::function responseCallback); - CHIP_ERROR ContentLauncher_LaunchContent(chip::app::Clusters::ContentLauncher::Structs::ContentSearch::Type search, + CHIP_ERROR ContentLauncher_LaunchContent(TargetEndpointInfo * endpoint, + chip::app::Clusters::ContentLauncher::Structs::ContentSearch::Type search, bool autoPlay, chip::Optional data, std::function responseCallback); CHIP_ERROR ContentLauncher_SubscribeToAcceptHeader( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ContentLauncher::Attributes::AcceptHeader::TypeInfo::DecodableArgType> successFn, @@ -97,7 +115,7 @@ class CastingServer chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR ContentLauncher_SubscribeToSupportedStreamingProtocols( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ContentLauncher::Attributes::SupportedStreamingProtocols::TypeInfo::DecodableArgType> successFn, @@ -107,21 +125,22 @@ class CastingServer /** * @brief Level Control cluster */ - CHIP_ERROR LevelControl_Step(chip::app::Clusters::LevelControl::StepMode stepMode, uint8_t stepSize, uint16_t transitionTime, - uint8_t optionMask, uint8_t optionOverride, std::function responseCallback); - CHIP_ERROR LevelControl_MoveToLevel(uint8_t level, uint16_t transitionTime, uint8_t optionMask, uint8_t optionOverride, - std::function responseCallback); + CHIP_ERROR LevelControl_Step(TargetEndpointInfo * endpoint, chip::app::Clusters::LevelControl::StepMode stepMode, + uint8_t stepSize, uint16_t transitionTime, uint8_t optionMask, uint8_t optionOverride, + std::function responseCallback); + CHIP_ERROR LevelControl_MoveToLevel(TargetEndpointInfo * endpoint, uint8_t level, uint16_t transitionTime, uint8_t optionMask, + uint8_t optionOverride, std::function responseCallback); CHIP_ERROR LevelControl_SubscribeToCurrentLevel( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::LevelControl::Attributes::CurrentLevel::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR - LevelControl_SubscribeToMinLevel(void * context, + LevelControl_SubscribeToMinLevel(TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::LevelControl::Attributes::MinLevel::TypeInfo::DecodableArgType> successFn, @@ -129,7 +148,7 @@ class CastingServer uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR - LevelControl_SubscribeToMaxLevel(void * context, + LevelControl_SubscribeToMaxLevel(TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::LevelControl::Attributes::MaxLevel::TypeInfo::DecodableArgType> successFn, @@ -140,23 +159,26 @@ class CastingServer /** * @brief Media Playback cluster */ - CHIP_ERROR MediaPlayback_Play(std::function responseCallback); - CHIP_ERROR MediaPlayback_Pause(std::function responseCallback); - CHIP_ERROR MediaPlayback_StopPlayback(std::function responseCallback); - CHIP_ERROR MediaPlayback_Next(std::function responseCallback); - CHIP_ERROR MediaPlayback_Seek(uint64_t position, std::function responseCallback); - CHIP_ERROR MediaPlayback_SkipForward(uint64_t deltaPositionMilliseconds, std::function responseCallback); - CHIP_ERROR MediaPlayback_SkipBackward(uint64_t deltaPositionMilliseconds, std::function responseCallback); + CHIP_ERROR MediaPlayback_Play(TargetEndpointInfo * endpoint, std::function responseCallback); + CHIP_ERROR MediaPlayback_Pause(TargetEndpointInfo * endpoint, std::function responseCallback); + CHIP_ERROR MediaPlayback_StopPlayback(TargetEndpointInfo * endpoint, std::function responseCallback); + CHIP_ERROR MediaPlayback_Next(TargetEndpointInfo * endpoint, std::function responseCallback); + CHIP_ERROR MediaPlayback_Seek(TargetEndpointInfo * endpoint, uint64_t position, + std::function responseCallback); + CHIP_ERROR MediaPlayback_SkipForward(TargetEndpointInfo * endpoint, uint64_t deltaPositionMilliseconds, + std::function responseCallback); + CHIP_ERROR MediaPlayback_SkipBackward(TargetEndpointInfo * endpoint, uint64_t deltaPositionMilliseconds, + std::function responseCallback); CHIP_ERROR MediaPlayback_SubscribeToCurrentState( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::MediaPlayback::Attributes::CurrentState::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR - MediaPlayback_SubscribeToStartTime(void * context, + MediaPlayback_SubscribeToStartTime(TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::MediaPlayback::Attributes::StartTime::TypeInfo::DecodableArgType> successFn, @@ -164,7 +186,7 @@ class CastingServer uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR - MediaPlayback_SubscribeToDuration(void * context, + MediaPlayback_SubscribeToDuration(TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::MediaPlayback::Attributes::Duration::TypeInfo::DecodableArgType> successFn, @@ -172,28 +194,28 @@ class CastingServer uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR MediaPlayback_SubscribeToSampledPosition( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::MediaPlayback::Attributes::SampledPosition::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR MediaPlayback_SubscribeToPlaybackSpeed( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::MediaPlayback::Attributes::PlaybackSpeed::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR MediaPlayback_SubscribeToSeekRangeEnd( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::MediaPlayback::Attributes::SeekRangeEnd::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR MediaPlayback_SubscribeToSeekRangeStart( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::MediaPlayback::Attributes::SeekRangeStart::TypeInfo::DecodableArgType> successFn, @@ -203,16 +225,19 @@ class CastingServer /** * @brief Application Launcher cluster */ - CHIP_ERROR ApplicationLauncher_LaunchApp(chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application, + CHIP_ERROR ApplicationLauncher_LaunchApp(TargetEndpointInfo * endpoint, + chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application, chip::Optional data, std::function responseCallback); - CHIP_ERROR ApplicationLauncher_StopApp(chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application, + CHIP_ERROR ApplicationLauncher_StopApp(TargetEndpointInfo * endpoint, + chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application, std::function responseCallback); - CHIP_ERROR ApplicationLauncher_HideApp(chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application, + CHIP_ERROR ApplicationLauncher_HideApp(TargetEndpointInfo * endpoint, + chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application, std::function responseCallback); CHIP_ERROR ApplicationLauncher_SubscribeToCurrentApp( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationLauncher::Attributes::CurrentApp::TypeInfo::DecodableArgType> successFn, @@ -222,18 +247,19 @@ class CastingServer /** * @brief Target Navigator cluster */ - CHIP_ERROR TargetNavigator_NavigateTarget(const uint8_t target, const chip::Optional data, + CHIP_ERROR TargetNavigator_NavigateTarget(TargetEndpointInfo * endpoint, const uint8_t target, + const chip::Optional data, std::function responseCallback); CHIP_ERROR TargetNavigator_SubscribeToTargetList( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::TargetNavigator::Attributes::TargetList::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR TargetNavigator_SubscribeToCurrentTarget( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::TargetNavigator::Attributes::CurrentTarget::TypeInfo::DecodableArgType> successFn, @@ -243,49 +269,49 @@ class CastingServer /** * @brief Keypad Input cluster */ - CHIP_ERROR KeypadInput_SendKey(const chip::app::Clusters::KeypadInput::CecKeyCode keyCode, + CHIP_ERROR KeypadInput_SendKey(TargetEndpointInfo * endpoint, const chip::app::Clusters::KeypadInput::CecKeyCode keyCode, std::function responseCallback); /** * @brief Application Basic cluster */ CHIP_ERROR ApplicationBasic_SubscribeToVendorName( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::VendorName::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR ApplicationBasic_SubscribeToVendorID( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::VendorID::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR ApplicationBasic_SubscribeToApplicationName( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::ApplicationName::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR ApplicationBasic_SubscribeToProductID( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::ProductID::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR ApplicationBasic_SubscribeToApplication( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::Application::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR - ApplicationBasic_SubscribeToStatus(void * context, + ApplicationBasic_SubscribeToStatus(TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::Status::TypeInfo::DecodableArgType> successFn, @@ -293,14 +319,14 @@ class CastingServer uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR ApplicationBasic_SubscribeToApplicationVersion( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::ApplicationVersion::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); CHIP_ERROR ApplicationBasic_SubscribeToAllowedVendorList( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::AllowedVendorList::TypeInfo::DecodableArgType> successFn, @@ -310,27 +336,39 @@ class CastingServer /* * @brief Channel cluster */ - CHIP_ERROR Channel_ChangeChannelCommand(const chip::CharSpan & match, std::function responseCallback); + CHIP_ERROR Channel_ChangeChannelCommand(TargetEndpointInfo * endpoint, const chip::CharSpan & match, + std::function responseCallback); CHIP_ERROR Channel_SubscribeToLineup( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished); private: - CHIP_ERROR InitBindingHandlers(); - static void DeviceEventCallback(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); - static CastingServer * castingServer_; CastingServer(); + CHIP_ERROR InitBindingHandlers(); + static void DeviceEventCallback(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg); + void ReadServerClusters(chip::EndpointId endpointId); + + PersistenceManager mPersistenceManager; bool mInited = false; - TargetVideoPlayerInfo mTargetVideoPlayerInfo; + TargetVideoPlayerInfo mActiveTargetVideoPlayerInfo; + TargetVideoPlayerInfo mCachedTargetVideoPlayerInfo[kMaxCachedVideoPlayers]; + uint16_t mTargetVideoPlayerVendorId = 0; + uint16_t mTargetVideoPlayerProductId = 0; + uint16_t mTargetVideoPlayerDeviceType = 0; + char mTargetVideoPlayerDeviceName[chip::Dnssd::kMaxDeviceNameLen + 1] = {}; + chip::Controller::CommissionableNodeController mCommissionableNodeController; - std::function mLaunchURLResponseCallback; std::function mCommissioningCompleteCallback; + std::function mOnNewOrUpdatedEndpoint; + std::function mOnConnectionSuccessClientCallback; + std::function mOnConnectionFailureClientCallback; + /** * @brief Content Launcher cluster */ diff --git a/examples/tv-casting-app/tv-casting-common/include/MediaBase.h b/examples/tv-casting-app/tv-casting-common/include/MediaBase.h index 36861611e714cd..6a30c3c83f1224 100644 --- a/examples/tv-casting-app/tv-casting-common/include/MediaBase.h +++ b/examples/tv-casting-app/tv-casting-common/include/MediaBase.h @@ -31,7 +31,10 @@ class MediaBase auto deviceProxy = targetVideoPlayerInfo.GetOperationalDeviceProxy(); if (deviceProxy == nullptr) { - ChipLogError(AppServer, "Failed in getting an instance of OperationalDeviceProxy"); + ChipLogError(AppServer, + "Failed in getting an instance of OperationalDeviceProxy for nodeId: 0x" ChipLogFormatX64 + ", fabricIndex: %d", + ChipLogValueX64(targetVideoPlayerInfo.GetNodeId()), targetVideoPlayerInfo.GetFabricIndex()); return CHIP_ERROR_PEER_NODE_NOT_FOUND; } mTargetVideoPlayerInfo = &targetVideoPlayerInfo; diff --git a/examples/tv-casting-app/tv-casting-common/include/PersistenceManager.h b/examples/tv-casting-app/tv-casting-common/include/PersistenceManager.h new file mode 100644 index 00000000000000..d9505e00391126 --- /dev/null +++ b/examples/tv-casting-app/tv-casting-common/include/PersistenceManager.h @@ -0,0 +1,59 @@ +/* + * + * 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. + */ + +#pragma once + +#include "TargetEndpointInfo.h" +#include "TargetVideoPlayerInfo.h" + +constexpr size_t kMaxCachedVideoPlayers = 32; + +class PersistenceManager +{ +public: + CHIP_ERROR AddVideoPlayer(TargetVideoPlayerInfo * targetVideoPlayerInfo); + + CHIP_ERROR ReadAllVideoPlayers(TargetVideoPlayerInfo outVideoPlayers[]); + + CHIP_ERROR PurgeVideoPlayerCache(); + +private: + CHIP_ERROR WriteAllVideoPlayers(TargetVideoPlayerInfo videoPlayers[]); + + enum CastingTLVTag + { + kNodeIdTag = 1, + kFabricIndexTag, + kVideoPlayersContainerTag, + kContentAppEndpointsContainerTag, + kEndpointIdTag, + kClusterIdsContainerTag, + kClusterIdTag, + kCastingDataVersionTag, + kVideoPlayerVendorIdTag, + kVideoPlayerProductIdTag, + kVideoPlayerDeviceTypeIdTag, + kVideoPlayerDeviceNameTag, + + kContextTagMaxNum = UINT8_MAX + }; + + constexpr static size_t kCastingDataMaxBytes = 1024 * 100; // 100 KBs + constexpr static char * kCastingDataKey = (char *) "com.matter.casting"; + constexpr static uint32_t kCastingDataVersion = 1; +}; diff --git a/examples/tv-casting-app/tv-casting-common/include/TargetEndpointInfo.h b/examples/tv-casting-app/tv-casting-common/include/TargetEndpointInfo.h index 8cbb23709509c3..31cfde0d02b3f6 100644 --- a/examples/tv-casting-app/tv-casting-common/include/TargetEndpointInfo.h +++ b/examples/tv-casting-app/tv-casting-common/include/TargetEndpointInfo.h @@ -20,6 +20,8 @@ #include +constexpr size_t kMaxNumberOfClustersPerEndpoint = 10; + class TargetEndpointInfo { public: @@ -29,11 +31,11 @@ class TargetEndpointInfo chip::EndpointId GetEndpointId() const { return mEndpointId; } bool HasCluster(chip::ClusterId clusterId); + chip::ClusterId * GetClusters(); bool AddCluster(chip::ClusterId clusterId); void PrintInfo(); private: - static constexpr size_t kMaxNumberOfClustersPerEndpoint = 10; chip::ClusterId mClusters[kMaxNumberOfClustersPerEndpoint] = {}; chip::EndpointId mEndpointId; bool mInitialized = false; 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 9a703dbfa830d5..da58e8db11b63e 100644 --- a/examples/tv-casting-app/tv-casting-common/include/TargetVideoPlayerInfo.h +++ b/examples/tv-casting-app/tv-casting-common/include/TargetVideoPlayerInfo.h @@ -22,6 +22,8 @@ #include "app/clusters/bindings/BindingManager.h" #include +constexpr size_t kMaxNumberOfEndpoints = 5; + class TargetVideoPlayerInfo { public: @@ -29,10 +31,20 @@ class TargetVideoPlayerInfo mOnConnectedCallback(HandleDeviceConnected, this), mOnConnectionFailureCallback(HandleDeviceConnectionFailure, this) {} + bool operator==(const TargetVideoPlayerInfo & other) + { + return this->mNodeId == other.mNodeId && this->mFabricIndex == other.mFabricIndex; + } + bool IsInitialized() { return mInitialized; } + uint16_t GetVendorId() const { return mVendorId; } + uint16_t GetProductId() const { return mProductId; } + uint16_t GetDeviceType() const { return mDeviceType; } chip::NodeId GetNodeId() const { return mNodeId; } chip::FabricIndex GetFabricIndex() const { return mFabricIndex; } - const chip::OperationalDeviceProxy * GetOperationalDeviceProxy() const + const char * GetDeviceName() const { return mDeviceName; } + + chip::OperationalDeviceProxy * GetOperationalDeviceProxy() { if (mDeviceProxy.ConnectionReady()) { @@ -41,9 +53,15 @@ class TargetVideoPlayerInfo return nullptr; } - CHIP_ERROR Initialize(chip::NodeId nodeId, chip::FabricIndex fabricIndex); + CHIP_ERROR Initialize(chip::NodeId nodeId, chip::FabricIndex fabricIndex, + std::function onConnectionSuccess, + std::function onConnectionFailure, uint16_t vendorId = 0, uint16_t productId = 0, + uint16_t deviceType = 0, const char * deviceName = {}); + CHIP_ERROR FindOrEstablishCASESession(std::function onConnectionSuccess, + std::function onConnectionFailure); TargetEndpointInfo * GetOrAddEndpoint(chip::EndpointId endpointId); TargetEndpointInfo * GetEndpoint(chip::EndpointId endpointId); + TargetEndpointInfo * GetEndpoints(); bool HasEndpoint(chip::EndpointId endpointId); void PrintInfo(); @@ -54,23 +72,46 @@ class TargetVideoPlayerInfo TargetVideoPlayerInfo * _this = static_cast(context); _this->mDeviceProxy = chip::OperationalDeviceProxy(&exchangeMgr, sessionHandle); _this->mInitialized = true; - ChipLogProgress(AppServer, "HandleDeviceConnected created an instance of OperationalDeviceProxy"); + ChipLogProgress(AppServer, + "HandleDeviceConnected created an instance of OperationalDeviceProxy for nodeId: 0x" ChipLogFormatX64 + ", fabricIndex: %d", + ChipLogValueX64(_this->GetNodeId()), _this->GetFabricIndex()); + + if (_this->mOnConnectionSuccessClientCallback) + { + ChipLogProgress(AppServer, "HandleDeviceConnected calling mOnConnectionSuccessClientCallback"); + _this->mOnConnectionSuccessClientCallback(_this); + } } static void HandleDeviceConnectionFailure(void * context, const chip::ScopedNodeId & peerId, CHIP_ERROR error) { + ChipLogError(AppServer, + "HandleDeviceConnectionFailure called for peerId.nodeId: 0x" ChipLogFormatX64 + ", peer.fabricIndex: %d with error: %" CHIP_ERROR_FORMAT, + ChipLogValueX64(peerId.GetNodeId()), peerId.GetFabricIndex(), error.Format()); TargetVideoPlayerInfo * _this = static_cast(context); _this->mDeviceProxy = chip::OperationalDeviceProxy(); + if (_this->mOnConnectionFailureClientCallback) + { + ChipLogProgress(AppServer, "HandleDeviceConnectionFailure calling mOnConnectionFailureClientCallback"); + _this->mOnConnectionFailureClientCallback(error); + } } - static constexpr size_t kMaxNumberOfEndpoints = 5; TargetEndpointInfo mEndpoints[kMaxNumberOfEndpoints]; chip::NodeId mNodeId; chip::FabricIndex mFabricIndex; chip::OperationalDeviceProxy mDeviceProxy; + uint16_t mVendorId = 0; + uint16_t mProductId = 0; + uint16_t mDeviceType = 0; + char mDeviceName[chip::Dnssd::kMaxDeviceNameLen + 1] = {}; chip::Callback::Callback mOnConnectedCallback; chip::Callback::Callback mOnConnectionFailureCallback; + std::function mOnConnectionSuccessClientCallback; + std::function mOnConnectionFailureClientCallback; bool mInitialized = false; }; 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 1e654a59f86cc2..7891070728abfe 100644 --- a/examples/tv-casting-app/tv-casting-common/src/CastingServer.cpp +++ b/examples/tv-casting-app/tv-casting-common/src/CastingServer.cpp @@ -73,10 +73,17 @@ CHIP_ERROR CastingServer::InitBindingHandlers() return CHIP_NO_ERROR; } -CHIP_ERROR CastingServer::TargetVideoPlayerInfoInit(NodeId nodeId, FabricIndex fabricIndex) +CHIP_ERROR CastingServer::TargetVideoPlayerInfoInit(NodeId nodeId, FabricIndex fabricIndex, + std::function onConnectionSuccess, + std::function onConnectionFailure, + std::function onNewOrUpdatedEndpoint) { Init(); - return mTargetVideoPlayerInfo.Initialize(nodeId, fabricIndex); + mOnConnectionSuccessClientCallback = onConnectionSuccess; + mOnConnectionFailureClientCallback = onConnectionFailure; + mOnNewOrUpdatedEndpoint = onNewOrUpdatedEndpoint; + return mActiveTargetVideoPlayerInfo.Initialize(nodeId, fabricIndex, mOnConnectionSuccessClientCallback, + mOnConnectionFailureClientCallback); } CHIP_ERROR CastingServer::DiscoverCommissioners() @@ -86,9 +93,15 @@ CHIP_ERROR CastingServer::DiscoverCommissioners() Dnssd::DiscoveryFilter(Dnssd::DiscoveryFilterType::kDeviceType, static_cast(35))); } -CHIP_ERROR CastingServer::OpenBasicCommissioningWindow(std::function commissioningCompleteCallback) +CHIP_ERROR CastingServer::OpenBasicCommissioningWindow(std::function commissioningCompleteCallback, + std::function onConnectionSuccess, + std::function onConnectionFailure, + std::function onNewOrUpdatedEndpoint) { - mCommissioningCompleteCallback = commissioningCompleteCallback; + mCommissioningCompleteCallback = commissioningCompleteCallback; + mOnConnectionSuccessClientCallback = onConnectionSuccess; + mOnConnectionFailureClientCallback = onConnectionFailure; + mOnNewOrUpdatedEndpoint = onNewOrUpdatedEndpoint; return Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow(kCommissioningWindowTimeout); } @@ -97,6 +110,20 @@ CHIP_ERROR CastingServer::SendUserDirectedCommissioningRequest(chip::Transport:: { return Server::GetInstance().SendUserDirectedCommissioningRequest(commissioner); } + +CHIP_ERROR CastingServer::SendUserDirectedCommissioningRequest(Dnssd::DiscoveredNodeData * selectedCommissioner) +{ + // Send User Directed commissioning request + ReturnErrorOnFailure(SendUserDirectedCommissioningRequest(chip::Transport::PeerAddress::UDP( + selectedCommissioner->resolutionData.ipAddress[0], selectedCommissioner->resolutionData.port, + selectedCommissioner->resolutionData.interfaceId))); + mTargetVideoPlayerVendorId = selectedCommissioner->commissionData.vendorId; + mTargetVideoPlayerProductId = selectedCommissioner->commissionData.productId; + mTargetVideoPlayerDeviceType = selectedCommissioner->commissionData.deviceType; + chip::Platform::CopyString(mTargetVideoPlayerDeviceName, chip::Dnssd::kMaxDeviceNameLen + 1, + selectedCommissioner->commissionData.deviceName); + return CHIP_NO_ERROR; +} #endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT const Dnssd::DiscoveredNodeData * CastingServer::GetDiscoveredCommissioner(int index) @@ -116,13 +143,13 @@ void CastingServer::ReadServerClustersForNode(NodeId nodeId) binding.remote, ChipLogValueMEI(binding.clusterId.ValueOr(0))); if (binding.type == EMBER_UNICAST_BINDING && nodeId == binding.nodeId) { - if (!mTargetVideoPlayerInfo.HasEndpoint(binding.remote)) + if (!mActiveTargetVideoPlayerInfo.HasEndpoint(binding.remote)) { ReadServerClusters(binding.remote); } else { - TargetEndpointInfo * endpointInfo = mTargetVideoPlayerInfo.GetEndpoint(binding.remote); + TargetEndpointInfo * endpointInfo = mActiveTargetVideoPlayerInfo.GetEndpoint(binding.remote); if (endpointInfo != nullptr && endpointInfo->IsInitialized()) { endpointInfo->PrintInfo(); @@ -134,7 +161,7 @@ void CastingServer::ReadServerClustersForNode(NodeId nodeId) void CastingServer::ReadServerClusters(EndpointId endpointId) { - const OperationalDeviceProxy * deviceProxy = mTargetVideoPlayerInfo.GetOperationalDeviceProxy(); + const OperationalDeviceProxy * deviceProxy = mActiveTargetVideoPlayerInfo.GetOperationalDeviceProxy(); if (deviceProxy == nullptr) { ChipLogError(AppServer, "Failed in getting an instance of DeviceProxy"); @@ -145,7 +172,7 @@ void CastingServer::ReadServerClusters(EndpointId endpointId) chip::Controller::DescriptorCluster cluster(*deviceProxy->GetExchangeManager(), deviceProxy->GetSecureSession().Value(), endpointId); - TargetEndpointInfo * endpointInfo = mTargetVideoPlayerInfo.GetOrAddEndpoint(endpointId); + TargetEndpointInfo * endpointInfo = mActiveTargetVideoPlayerInfo.GetOrAddEndpoint(endpointId); if (cluster.ReadAttribute( endpointInfo, CastingServer::OnDescriptorReadSuccessResponse, CastingServer::OnDescriptorReadFailureResponse) != @@ -160,7 +187,6 @@ void CastingServer::ReadServerClusters(EndpointId endpointId) void CastingServer::OnDescriptorReadSuccessResponse(void * context, const app::DataModel::DecodableList & responseList) { TargetEndpointInfo * endpointInfo = static_cast(context); - ChipLogProgress(AppServer, "Descriptor: Default Success Response endpoint=%d", endpointInfo->GetEndpointId()); auto iter = responseList.begin(); @@ -171,19 +197,89 @@ void CastingServer::OnDescriptorReadSuccessResponse(void * context, const app::D } // Always print the target info after handling descriptor read response // Even when we get nothing back for any reasons - CastingServer::GetInstance()->mTargetVideoPlayerInfo.PrintInfo(); + CastingServer::GetInstance()->mActiveTargetVideoPlayerInfo.PrintInfo(); + + CHIP_ERROR err = CastingServer::GetInstance()->mPersistenceManager.AddVideoPlayer( + &CastingServer::GetInstance()->mActiveTargetVideoPlayerInfo); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "AddVideoPlayer(ToCache) error: %" CHIP_ERROR_FORMAT, err.Format()); + } + + if (CastingServer::GetInstance()->mOnNewOrUpdatedEndpoint) + { + CastingServer::GetInstance()->mOnNewOrUpdatedEndpoint(endpointInfo); + } } void CastingServer::OnDescriptorReadFailureResponse(void * context, CHIP_ERROR error) { + TargetEndpointInfo * endpointInfo = static_cast(context); ChipLogError(AppServer, "Descriptor: Default Failure Response: %" CHIP_ERROR_FORMAT, error.Format()); + + CHIP_ERROR err = CastingServer::GetInstance()->mPersistenceManager.AddVideoPlayer( + &CastingServer::GetInstance()->mActiveTargetVideoPlayerInfo); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "AddVideoPlayer(ToCache) error: %" CHIP_ERROR_FORMAT, err.Format()); + } + + if (CastingServer::GetInstance()->mOnNewOrUpdatedEndpoint) + { + CastingServer::GetInstance()->mOnNewOrUpdatedEndpoint(endpointInfo); + } +} + +TargetVideoPlayerInfo * CastingServer::ReadCachedTargetVideoPlayerInfos() +{ + CHIP_ERROR err = mPersistenceManager.ReadAllVideoPlayers(mCachedTargetVideoPlayerInfo); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, "ReadAllVideoPlayers error: %" CHIP_ERROR_FORMAT, err.Format()); + return nullptr; + } + return mCachedTargetVideoPlayerInfo; +} + +CHIP_ERROR CastingServer::VerifyOrEstablishConnection(TargetVideoPlayerInfo & targetVideoPlayerInfo, + std::function onConnectionSuccess, + std::function onConnectionFailure, + std::function onNewOrUpdatedEndpoint) +{ + if (!targetVideoPlayerInfo.IsInitialized()) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + mOnConnectionSuccessClientCallback = onConnectionSuccess; + mOnConnectionFailureClientCallback = onConnectionFailure; + mOnNewOrUpdatedEndpoint = onNewOrUpdatedEndpoint; + + return targetVideoPlayerInfo.FindOrEstablishCASESession( + [](TargetVideoPlayerInfo * videoPlayer) { + ChipLogProgress(AppServer, "CastingServer::OnConnectionSuccess lambda called"); + chip::OperationalDeviceProxy * prevDeviceProxy = + CastingServer::GetInstance()->mActiveTargetVideoPlayerInfo.GetOperationalDeviceProxy(); + if (prevDeviceProxy != nullptr) + { + ChipLogProgress(AppServer, "CastingServer::OnConnectionSuccess lambda Disconnecting deviceProxy"); + prevDeviceProxy->Disconnect(); + } + CastingServer::GetInstance()->mActiveTargetVideoPlayerInfo = *videoPlayer; + CastingServer::GetInstance()->mOnConnectionSuccessClientCallback(videoPlayer); + }, + onConnectionFailure); +} + +CHIP_ERROR CastingServer::PurgeVideoPlayerCache() +{ + return mPersistenceManager.PurgeVideoPlayerCache(); } [[deprecated("Use ContentLauncher_LaunchURL(..) instead")]] CHIP_ERROR -CastingServer::ContentLauncherLaunchURL(const char * contentUrl, const char * contentDisplayStr, +CastingServer::ContentLauncherLaunchURL(TargetEndpointInfo * endpoint, const char * contentUrl, const char * contentDisplayStr, std::function launchURLResponseCallback) { - return ContentLauncher_LaunchURL(contentUrl, contentDisplayStr, + return ContentLauncher_LaunchURL(endpoint, contentUrl, contentDisplayStr, MakeOptional(chip::app::Clusters::ContentLauncher::Structs::BrandingInformation::Type()), launchURLResponseCallback); } @@ -192,16 +288,20 @@ void CastingServer::DeviceEventCallback(const DeviceLayer::ChipDeviceEvent * eve { if (event->Type == DeviceLayer::DeviceEventType::kBindingsChangedViaCluster) { - if (CastingServer::GetInstance()->GetTargetVideoPlayerInfo()->IsInitialized()) + if (CastingServer::GetInstance()->GetActiveTargetVideoPlayer()->IsInitialized()) { CastingServer::GetInstance()->ReadServerClustersForNode( - CastingServer::GetInstance()->GetTargetVideoPlayerInfo()->GetNodeId()); + CastingServer::GetInstance()->GetActiveTargetVideoPlayer()->GetNodeId()); } } else if (event->Type == DeviceLayer::DeviceEventType::kCommissioningComplete) { - CHIP_ERROR err = CastingServer::GetInstance()->GetTargetVideoPlayerInfo()->Initialize( - event->CommissioningComplete.nodeId, event->CommissioningComplete.fabricIndex); + CHIP_ERROR err = CastingServer::GetInstance()->GetActiveTargetVideoPlayer()->Initialize( + event->CommissioningComplete.nodeId, event->CommissioningComplete.fabricIndex, + CastingServer::GetInstance()->mOnConnectionSuccessClientCallback, + CastingServer::GetInstance()->mOnConnectionFailureClientCallback, + CastingServer::GetInstance()->mTargetVideoPlayerVendorId, CastingServer::GetInstance()->mTargetVideoPlayerProductId, + CastingServer::GetInstance()->mTargetVideoPlayerDeviceType, CastingServer::GetInstance()->mTargetVideoPlayerDeviceName); CastingServer::GetInstance()->mCommissioningCompleteCallback(err); } @@ -250,7 +350,9 @@ FabricIndex CastingServer::GetVideoPlayerFabricIndexForNode(NodeId nodeId) return kUndefinedFabricIndex; } -void CastingServer::SetDefaultFabricIndex() +void CastingServer::SetDefaultFabricIndex(std::function onConnectionSuccess, + std::function onConnectionFailure, + std::function onNewOrUpdatedEndpoint) { Init(); @@ -276,7 +378,12 @@ void CastingServer::SetDefaultFabricIndex() continue; } - mTargetVideoPlayerInfo.Initialize(videoPlayerNodeId, fabricIndex); + mOnConnectionSuccessClientCallback = onConnectionSuccess; + mOnConnectionFailureClientCallback = onConnectionFailure; + mOnNewOrUpdatedEndpoint = onNewOrUpdatedEndpoint; + + mActiveTargetVideoPlayerInfo.Initialize(videoPlayerNodeId, fabricIndex, mOnConnectionSuccessClientCallback, + mOnConnectionFailureClientCallback); return; } ChipLogError(AppServer, " -- No initialized fabrics with video players"); @@ -286,46 +393,47 @@ void CastingServer::SetDefaultFabricIndex() * @brief Content Launcher cluster */ CHIP_ERROR CastingServer::ContentLauncher_LaunchURL( - const char * contentUrl, const char * contentDisplayStr, + TargetEndpointInfo * endpoint, const char * contentUrl, const char * contentDisplayStr, chip::Optional brandingInformation, std::function responseCallback) { - ReturnErrorOnFailure(mLaunchURLCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mLaunchURLCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mLaunchURLCommand.Invoke(contentUrl, contentDisplayStr, brandingInformation, responseCallback); } -CHIP_ERROR CastingServer::ContentLauncher_LaunchContent(chip::app::Clusters::ContentLauncher::Structs::ContentSearch::Type search, +CHIP_ERROR CastingServer::ContentLauncher_LaunchContent(TargetEndpointInfo * endpoint, + chip::app::Clusters::ContentLauncher::Structs::ContentSearch::Type search, bool autoPlay, chip::Optional data, std::function responseCallback) { - ReturnErrorOnFailure(mLaunchContentCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mLaunchContentCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mLaunchContentCommand.Invoke(search, autoPlay, data, responseCallback); } CHIP_ERROR CastingServer::ContentLauncher_SubscribeToAcceptHeader( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ContentLauncher::Attributes::AcceptHeader::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mAcceptHeaderSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mAcceptHeaderSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mAcceptHeaderSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ContentLauncher_SubscribeToSupportedStreamingProtocols( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ContentLauncher::Attributes::SupportedStreamingProtocols::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mSupportedStreamingProtocolsSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mSupportedStreamingProtocolsSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mSupportedStreamingProtocolsSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } @@ -333,11 +441,11 @@ CastingServer::ContentLauncher_SubscribeToSupportedStreamingProtocols( /** * @brief Level Control cluster */ -CHIP_ERROR CastingServer::LevelControl_Step(chip::app::Clusters::LevelControl::StepMode stepMode, uint8_t stepSize, - uint16_t transitionTime, uint8_t optionMask, uint8_t optionOverride, +CHIP_ERROR CastingServer::LevelControl_Step(TargetEndpointInfo * endpoint, chip::app::Clusters::LevelControl::StepMode stepMode, + uint8_t stepSize, uint16_t transitionTime, uint8_t optionMask, uint8_t optionOverride, std::function responseCallback) { - ReturnErrorOnFailure(mStepCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mStepCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); app::DataModel::Nullable nullableTransitionTime; nullableTransitionTime.SetNonNull(transitionTime); @@ -345,10 +453,11 @@ CHIP_ERROR CastingServer::LevelControl_Step(chip::app::Clusters::LevelControl::S return mStepCommand.Invoke(stepMode, stepSize, nullableTransitionTime, optionMask, optionOverride, responseCallback); } -CHIP_ERROR CastingServer::LevelControl_MoveToLevel(uint8_t level, uint16_t transitionTime, uint8_t optionMask, - uint8_t optionOverride, std::function responseCallback) +CHIP_ERROR CastingServer::LevelControl_MoveToLevel(TargetEndpointInfo * endpoint, uint8_t level, uint16_t transitionTime, + uint8_t optionMask, uint8_t optionOverride, + std::function responseCallback) { - ReturnErrorOnFailure(mMoveToLevelCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mMoveToLevelCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); app::DataModel::Nullable nullableTransitionTime; nullableTransitionTime.SetNonNull(transitionTime); @@ -357,34 +466,34 @@ CHIP_ERROR CastingServer::LevelControl_MoveToLevel(uint8_t level, uint16_t trans } CHIP_ERROR CastingServer::LevelControl_SubscribeToCurrentLevel( - void * context, + TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mCurrentLevelSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mCurrentLevelSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mCurrentLevelSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::LevelControl_SubscribeToMinLevel( - void * context, + TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mMinLevelSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mMinLevelSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mMinLevelSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::LevelControl_SubscribeToMaxLevel( - void * context, + TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mMaxLevelSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mMaxLevelSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mMaxLevelSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } @@ -392,126 +501,128 @@ CHIP_ERROR CastingServer::LevelControl_SubscribeToMaxLevel( /** * @brief Media Playback cluster */ -CHIP_ERROR CastingServer::MediaPlayback_Play(std::function responseCallback) +CHIP_ERROR CastingServer::MediaPlayback_Play(TargetEndpointInfo * endpoint, std::function responseCallback) { - ReturnErrorOnFailure(mPlayCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mPlayCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mPlayCommand.Invoke(responseCallback); } -CHIP_ERROR CastingServer::MediaPlayback_Pause(std::function responseCallback) +CHIP_ERROR CastingServer::MediaPlayback_Pause(TargetEndpointInfo * endpoint, std::function responseCallback) { - ReturnErrorOnFailure(mPauseCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mPauseCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mPauseCommand.Invoke(responseCallback); } -CHIP_ERROR CastingServer::MediaPlayback_StopPlayback(std::function responseCallback) +CHIP_ERROR CastingServer::MediaPlayback_StopPlayback(TargetEndpointInfo * endpoint, + std::function responseCallback) { - ReturnErrorOnFailure(mStopPlaybackCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mStopPlaybackCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mStopPlaybackCommand.Invoke(responseCallback); } -CHIP_ERROR CastingServer::MediaPlayback_Next(std::function responseCallback) +CHIP_ERROR CastingServer::MediaPlayback_Next(TargetEndpointInfo * endpoint, std::function responseCallback) { - ReturnErrorOnFailure(mNextCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mNextCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mNextCommand.Invoke(responseCallback); } -CHIP_ERROR CastingServer::MediaPlayback_Seek(uint64_t position, std::function responseCallback) +CHIP_ERROR CastingServer::MediaPlayback_Seek(TargetEndpointInfo * endpoint, uint64_t position, + std::function responseCallback) { - ReturnErrorOnFailure(mSeekCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mSeekCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mSeekCommand.Invoke(position, responseCallback); } -CHIP_ERROR CastingServer::MediaPlayback_SkipForward(uint64_t deltaPositionMilliseconds, +CHIP_ERROR CastingServer::MediaPlayback_SkipForward(TargetEndpointInfo * endpoint, uint64_t deltaPositionMilliseconds, std::function responseCallback) { - ReturnErrorOnFailure(mSkipForwardCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mSkipForwardCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mSkipForwardCommand.Invoke(deltaPositionMilliseconds, responseCallback); } -CHIP_ERROR CastingServer::MediaPlayback_SkipBackward(uint64_t deltaPositionMilliseconds, +CHIP_ERROR CastingServer::MediaPlayback_SkipBackward(TargetEndpointInfo * endpoint, uint64_t deltaPositionMilliseconds, std::function responseCallback) { - ReturnErrorOnFailure(mSkipBackwardCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mSkipBackwardCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mSkipBackwardCommand.Invoke(deltaPositionMilliseconds, responseCallback); } CHIP_ERROR CastingServer::MediaPlayback_SubscribeToCurrentState( - void * context, + TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mCurrentStateSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mCurrentStateSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mCurrentStateSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::MediaPlayback_SubscribeToStartTime( - void * context, + TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mStartTimeSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mStartTimeSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mStartTimeSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::MediaPlayback_SubscribeToDuration( - void * context, + TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mDurationSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mDurationSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mDurationSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::MediaPlayback_SubscribeToSampledPosition( - void * context, + TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mSampledPositionSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mSampledPositionSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mSampledPositionSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::MediaPlayback_SubscribeToPlaybackSpeed( - void * context, + TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mPlaybackSpeedSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mPlaybackSpeedSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mPlaybackSpeedSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::MediaPlayback_SubscribeToSeekRangeEnd( - void * context, + TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mSeekRangeEndSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mSeekRangeEndSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mSeekRangeEndSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::MediaPlayback_SubscribeToSeekRangeStart( - void * context, + TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mSeekRangeStartSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mSeekRangeStartSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mSeekRangeStartSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } @@ -520,37 +631,40 @@ CHIP_ERROR CastingServer::MediaPlayback_SubscribeToSeekRangeStart( * @brief Application Launcher cluster */ CHIP_ERROR -CastingServer::ApplicationLauncher_LaunchApp(chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application, +CastingServer::ApplicationLauncher_LaunchApp(TargetEndpointInfo * endpoint, + chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application, chip::Optional data, std::function responseCallback) { - ReturnErrorOnFailure(mLaunchAppCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mLaunchAppCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mLaunchAppCommand.Invoke(application, data, responseCallback); } CHIP_ERROR -CastingServer::ApplicationLauncher_StopApp(chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application, +CastingServer::ApplicationLauncher_StopApp(TargetEndpointInfo * endpoint, + chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application, std::function responseCallback) { - ReturnErrorOnFailure(mStopAppCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mStopAppCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mStopAppCommand.Invoke(application, responseCallback); } CHIP_ERROR -CastingServer::ApplicationLauncher_HideApp(chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application, +CastingServer::ApplicationLauncher_HideApp(TargetEndpointInfo * endpoint, + chip::app::Clusters::ApplicationLauncher::Structs::Application::Type application, std::function responseCallback) { - ReturnErrorOnFailure(mHideAppCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mHideAppCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mHideAppCommand.Invoke(application, responseCallback); } CHIP_ERROR CastingServer::ApplicationLauncher_SubscribeToCurrentApp( - void * context, + TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mCurrentAppSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mCurrentAppSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mCurrentAppSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } @@ -558,32 +672,33 @@ CHIP_ERROR CastingServer::ApplicationLauncher_SubscribeToCurrentApp( /** * @brief Target Navigator cluster */ -CHIP_ERROR CastingServer::TargetNavigator_NavigateTarget(const uint8_t target, const chip::Optional data, +CHIP_ERROR CastingServer::TargetNavigator_NavigateTarget(TargetEndpointInfo * endpoint, const uint8_t target, + const chip::Optional data, std::function responseCallback) { - ReturnErrorOnFailure(mNavigateTargetCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mNavigateTargetCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mNavigateTargetCommand.Invoke(target, data, responseCallback); } CHIP_ERROR CastingServer::TargetNavigator_SubscribeToTargetList( - void * context, + TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mTargetListSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mTargetListSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mTargetListSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::TargetNavigator_SubscribeToCurrentTarget( - void * context, + TargetEndpointInfo * endpoint, void * context, ReadResponseSuccessCallback successFn, ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mCurrentTargetSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mCurrentTargetSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mCurrentTargetSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } @@ -591,10 +706,11 @@ CHIP_ERROR CastingServer::TargetNavigator_SubscribeToCurrentTarget( /** * @brief Keypad Input cluster */ -CHIP_ERROR CastingServer::KeypadInput_SendKey(const chip::app::Clusters::KeypadInput::CecKeyCode keyCode, +CHIP_ERROR CastingServer::KeypadInput_SendKey(TargetEndpointInfo * endpoint, + const chip::app::Clusters::KeypadInput::CecKeyCode keyCode, std::function responseCallback) { - ReturnErrorOnFailure(mSendKeyCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mSendKeyCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mSendKeyCommand.Invoke(keyCode, responseCallback); } @@ -602,107 +718,107 @@ CHIP_ERROR CastingServer::KeypadInput_SendKey(const chip::app::Clusters::KeypadI * @brief Application Basic cluster */ CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToVendorName( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::VendorName::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mVendorNameSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mVendorNameSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mVendorNameSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToVendorID( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::VendorID::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mVendorIDSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mVendorIDSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mVendorIDSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToApplicationName( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::ApplicationName::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mApplicationNameSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mApplicationNameSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mApplicationNameSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToProductID( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::ProductID::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mProductIDSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mProductIDSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mProductIDSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToApplication( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::Application::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mApplicationSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mApplicationSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mApplicationSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToStatus( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::Status::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mStatusSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mStatusSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mStatusSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToApplicationVersion( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::ApplicationVersion::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mApplicationVersionSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mApplicationVersionSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mApplicationVersionSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToAllowedVendorList( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback< chip::app::Clusters::ApplicationBasic::Attributes::AllowedVendorList::TypeInfo::DecodableArgType> successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mAllowedVendorListSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mAllowedVendorListSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mAllowedVendorListSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } @@ -710,20 +826,20 @@ CHIP_ERROR CastingServer::ApplicationBasic_SubscribeToAllowedVendorList( /* * @brief Channel cluster */ -CHIP_ERROR CastingServer::Channel_ChangeChannelCommand(const chip::CharSpan & match, +CHIP_ERROR CastingServer::Channel_ChangeChannelCommand(TargetEndpointInfo * endpoint, const chip::CharSpan & match, std::function responseCallback) { - ReturnErrorOnFailure(mChangeChannelCommand.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mChangeChannelCommand.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mChangeChannelCommand.Invoke(match, responseCallback); } CHIP_ERROR CastingServer::Channel_SubscribeToLineup( - void * context, + TargetEndpointInfo * endpoint, void * context, chip::Controller::ReadResponseSuccessCallback successFn, chip::Controller::ReadResponseFailureCallback failureFn, uint16_t minInterval, uint16_t maxInterval, chip::Controller::SubscriptionEstablishedCallback onSubscriptionEstablished) { - ReturnErrorOnFailure(mLineupSubscriber.SetTarget(mTargetVideoPlayerInfo, kTvEndpoint)); + ReturnErrorOnFailure(mLineupSubscriber.SetTarget(mActiveTargetVideoPlayerInfo, endpoint->GetEndpointId())); return mLineupSubscriber.SubscribeAttribute(context, successFn, failureFn, minInterval, maxInterval, onSubscriptionEstablished); } diff --git a/examples/tv-casting-app/tv-casting-common/src/PersistenceManager.cpp b/examples/tv-casting-app/tv-casting-common/src/PersistenceManager.cpp new file mode 100644 index 00000000000000..f4fa83f682c21d --- /dev/null +++ b/examples/tv-casting-app/tv-casting-common/src/PersistenceManager.cpp @@ -0,0 +1,322 @@ +/* + * + * 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 "PersistenceManager.h" + +#include +#include + +using namespace chip; + +CHIP_ERROR PersistenceManager::AddVideoPlayer(TargetVideoPlayerInfo * targetVideoPlayerInfo) +{ + ChipLogProgress(AppServer, "PersistenceManager::AddVideoPlayer called"); + VerifyOrReturnError(targetVideoPlayerInfo != nullptr && targetVideoPlayerInfo->IsInitialized(), CHIP_ERROR_INVALID_ARGUMENT); + + // Read cache for video players targetted in previous runs + TargetVideoPlayerInfo cachedVideoPlayers[kMaxCachedVideoPlayers]; + CHIP_ERROR err = ReadAllVideoPlayers(cachedVideoPlayers); + if (err != CHIP_NO_ERROR) + { + ChipLogError(AppServer, + "PersistenceManager::AddVideoPlayer status of reading previously cached video players %" CHIP_ERROR_FORMAT, + err.Format()); + } + + // Add active video player to the list of video players from cache + bool newVideoPlayer = true; + size_t i; + for (i = 0; i < kMaxCachedVideoPlayers && cachedVideoPlayers[i].IsInitialized(); i++) + { + // found the same video player, overwrite the data + if (cachedVideoPlayers[i] == *targetVideoPlayerInfo) + { + cachedVideoPlayers[i] = *targetVideoPlayerInfo; + newVideoPlayer = false; + } + } + if (newVideoPlayer) + { + VerifyOrReturnError(i < kMaxCachedVideoPlayers, CHIP_ERROR_BUFFER_TOO_SMALL); + cachedVideoPlayers[i] = *targetVideoPlayerInfo; + } + + return WriteAllVideoPlayers(cachedVideoPlayers); +} + +CHIP_ERROR PersistenceManager::WriteAllVideoPlayers(TargetVideoPlayerInfo videoPlayers[]) +{ + ChipLogProgress(AppServer, "PersistenceManager::WriteAllVideoPlayers called"); + + VerifyOrReturnError(videoPlayers != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + TLV::TLVWriter tlvWriter; + uint8_t castingData[kCastingDataMaxBytes]; + tlvWriter.Init(castingData, kCastingDataMaxBytes); + + TLV::TLVType outerContainerType = TLV::kTLVType_Structure; + ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType)); + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kCastingDataVersionTag), kCastingDataVersion)); + + TLV::TLVType videoPlayersContainerType = TLV::kTLVType_Array; + // Video Players container starts + ReturnErrorOnFailure( + tlvWriter.StartContainer(TLV::ContextTag(kVideoPlayersContainerTag), TLV::kTLVType_Structure, videoPlayersContainerType)); + + for (size_t videoPlayerIndex = 0; videoPlayerIndex < kMaxCachedVideoPlayers && videoPlayers[videoPlayerIndex].IsInitialized(); + videoPlayerIndex++) + { + TargetVideoPlayerInfo * videoPlayer = &videoPlayers[videoPlayerIndex]; + if (videoPlayer->IsInitialized()) + { + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kNodeIdTag), videoPlayer->GetNodeId())); + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kFabricIndexTag), videoPlayer->GetFabricIndex())); + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kVideoPlayerVendorIdTag), videoPlayer->GetVendorId())); + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kVideoPlayerProductIdTag), videoPlayer->GetProductId())); + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kVideoPlayerDeviceTypeIdTag), videoPlayer->GetDeviceType())); + ReturnErrorOnFailure(tlvWriter.PutBytes(TLV::ContextTag(kVideoPlayerDeviceNameTag), + (const uint8_t *) videoPlayer->GetDeviceName(), + static_cast(strlen(videoPlayer->GetDeviceName()) + 1))); + TargetEndpointInfo * endpoints = videoPlayer->GetEndpoints(); + if (endpoints != nullptr) + { + TLV::TLVType contentAppEndpointsContainerType = TLV::kTLVType_Array; + // Content app endpoints container starts + ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::ContextTag(kContentAppEndpointsContainerTag), + TLV::kTLVType_Structure, contentAppEndpointsContainerType)); + for (size_t endpointIndex = 0; endpointIndex < kMaxNumberOfEndpoints && endpoints[endpointIndex].IsInitialized(); + endpointIndex++) + { + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kEndpointIdTag), endpoints[endpointIndex].GetEndpointId())); + + chip::ClusterId * clusterIds = endpoints[endpointIndex].GetClusters(); + if (clusterIds != nullptr) + { + TLV::TLVType clusterIdsContainerType = TLV::kTLVType_Array; + // ClusterIds container starts + ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::ContextTag(kClusterIdsContainerTag), + TLV::kTLVType_Structure, clusterIdsContainerType)); + for (size_t clusterIndex = 0; clusterIndex < kMaxNumberOfClustersPerEndpoint; clusterIndex++) + { + if (clusterIds[clusterIndex] != kInvalidClusterId) + { + ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(kClusterIdTag), clusterIds[clusterIndex])); + } + } + // ClusterIds container ends + ReturnErrorOnFailure(tlvWriter.EndContainer(clusterIdsContainerType)); + } + } + // Content app endpoints container ends + ReturnErrorOnFailure(tlvWriter.EndContainer(contentAppEndpointsContainerType)); + } + // Video Players container ends + ReturnErrorOnFailure(tlvWriter.EndContainer(videoPlayersContainerType)); + ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType)); + + ReturnErrorOnFailure(tlvWriter.Finalize()); + ChipLogProgress(AppServer, + "PersistenceManager::WriteAllVideoPlayers TLV(CastingData).LengthWritten: %d bytes and version: %d", + tlvWriter.GetLengthWritten(), kCastingDataVersion); + return chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Put(kCastingDataKey, castingData, + tlvWriter.GetLengthWritten()); + } + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR PersistenceManager::ReadAllVideoPlayers(TargetVideoPlayerInfo outVideoPlayers[]) +{ + ChipLogProgress(AppServer, "PersistenceManager::ReadAllVideoPlayers called"); + VerifyOrReturnError(outVideoPlayers != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + uint8_t castingData[kCastingDataMaxBytes]; + size_t castingDataSize = 0; + ReturnErrorOnFailure(chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Get(kCastingDataKey, castingData, + kCastingDataMaxBytes, &castingDataSize)); + ChipLogProgress(AppServer, "PersistenceManager::ReadAllVideoPlayers Read TLV(CastingData) from KVS store with size: %lu bytes", + castingDataSize); + + TLV::TLVReader reader; + reader.Init(castingData); + + // read the envelope (and version) + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag())); + TLV::TLVType outerContainerType = TLV::kTLVType_Structure; + ReturnErrorOnFailure(reader.EnterContainer(outerContainerType)); + ReturnErrorOnFailure(reader.Next()); + TLV::Tag outerContainerTag = reader.GetTag(); + uint8_t outerContainerTagTagNum = static_cast(TLV::TagNumFromTag(outerContainerTag)); + VerifyOrReturnError(outerContainerTagTagNum == kCastingDataVersionTag, CHIP_ERROR_INVALID_TLV_TAG); + uint32_t version; + ReturnErrorOnFailure(reader.Get(version)); + ChipLogProgress(AppServer, "PersistenceManager::ReadAllVideoPlayers TLV(CastingData) version: %d", version); + + // Entering Video Players container + TLV::TLVType videoPlayersContainerType = TLV::kTLVType_Array; + ReturnErrorOnFailure(reader.Next()); + ReturnErrorOnFailure(reader.EnterContainer(videoPlayersContainerType)); + size_t videoPlayerIndex = 0; + chip::NodeId nodeId = 0; + chip::FabricIndex fabricIndex = 0; + uint16_t vendorId = 0; + uint16_t productId = 0; + uint16_t deviceType = 0; + char deviceName[chip::Dnssd::kMaxDeviceNameLen + 1] = {}; + CHIP_ERROR err; + while ((err = reader.Next()) == CHIP_NO_ERROR) + { + TLV::Tag videoPlayersContainerTag = reader.GetTag(); + if (!TLV::IsContextTag(videoPlayersContainerTag)) + { + ChipLogError(AppServer, "Unexpected non-context TLV tag."); + return CHIP_ERROR_INVALID_TLV_TAG; + } + + uint8_t viewPlayersContainerTagNum = static_cast(TLV::TagNumFromTag(videoPlayersContainerTag)); + if (viewPlayersContainerTagNum == kNodeIdTag) + { + ReturnErrorOnFailure(reader.Get(nodeId)); + continue; + } + + if (viewPlayersContainerTagNum == kFabricIndexTag) + { + ReturnErrorOnFailure(reader.Get(fabricIndex)); + continue; + } + + if (viewPlayersContainerTagNum == kVideoPlayerVendorIdTag) + { + ReturnErrorOnFailure(reader.Get(vendorId)); + continue; + } + + if (viewPlayersContainerTagNum == kVideoPlayerProductIdTag) + { + ReturnErrorOnFailure(reader.Get(productId)); + continue; + } + + if (viewPlayersContainerTagNum == kVideoPlayerDeviceTypeIdTag) + { + ReturnErrorOnFailure(reader.Get(deviceType)); + continue; + } + + if (viewPlayersContainerTagNum == kVideoPlayerDeviceNameTag) + { + ReturnErrorOnFailure(reader.GetBytes(reinterpret_cast(deviceName), chip::Dnssd::kMaxDeviceNameLen + 1)); + continue; + } + + if (viewPlayersContainerTagNum == kContentAppEndpointsContainerTag) + { + outVideoPlayers[videoPlayerIndex].Initialize(nodeId, fabricIndex, nullptr, nullptr, vendorId, productId, deviceType, + deviceName); + // Entering Content App Endpoints container + TLV::TLVType contentAppEndpointArrayContainerType = TLV::kTLVType_Array; + ReturnErrorOnFailure(reader.EnterContainer(contentAppEndpointArrayContainerType)); + + // reset all endpoints + TargetEndpointInfo * endpoints = outVideoPlayers[videoPlayerIndex].GetEndpoints(); + if (endpoints != nullptr) + { + for (size_t i = 0; i < kMaxNumberOfEndpoints; i++) + { + endpoints[i].Reset(); + } + } + TargetEndpointInfo * endpoint = nullptr; + while ((err = reader.Next()) == CHIP_NO_ERROR) + { + TLV::Tag contentAppsContainerTag = reader.GetTag(); + if (!TLV::IsContextTag(contentAppsContainerTag)) + { + ChipLogError(AppServer, "Unexpected non-context TLV tag."); + return CHIP_ERROR_INVALID_TLV_TAG; + } + + uint8_t contentAppsContainerTagNum = static_cast(TLV::TagNumFromTag(contentAppsContainerTag)); + if (contentAppsContainerTagNum == kEndpointIdTag) + { + chip::EndpointId endpointId; + ReturnErrorOnFailure(reader.Get(endpointId)); + endpoint = outVideoPlayers[videoPlayerIndex].GetOrAddEndpoint(endpointId); + continue; + } + + if (endpoint != nullptr && contentAppsContainerTagNum == kClusterIdsContainerTag) + { + // Entering ClusterIds container + TLV::TLVType clusterIdArrayContainerType = TLV::kTLVType_Array; + ReturnErrorOnFailure(reader.EnterContainer(clusterIdArrayContainerType)); + while ((err = reader.Next()) == CHIP_NO_ERROR) + { + TLV::Tag clusterIdsContainerTag = reader.GetTag(); + if (!TLV::IsContextTag(clusterIdsContainerTag)) + { + ChipLogError(AppServer, "Unexpected non-context TLV tag."); + return CHIP_ERROR_INVALID_TLV_TAG; + } + + uint8_t clusterIdsContainerTagNum = static_cast(TLV::TagNumFromTag(clusterIdsContainerTag)); + if (clusterIdsContainerTagNum == kClusterIdTag) + { + chip::ClusterId clusterId; + ReturnErrorOnFailure(reader.Get(clusterId)); + if (clusterId != kInvalidClusterId) + { + endpoint->AddCluster(clusterId); + } + else + { + ChipLogError(AppServer, "PersistenceManager: ReadAllVideoPlayers ignoring invalid clusterId"); + } + continue; + } + } + if (err == CHIP_END_OF_TLV) + { + // Exiting ClusterIds container + ReturnErrorOnFailure(reader.ExitContainer(clusterIdArrayContainerType)); + continue; + } + } + } + if (err == CHIP_END_OF_TLV) + { + // Exiting Content App Endpoints container + ReturnErrorOnFailure(reader.ExitContainer(contentAppEndpointArrayContainerType)); + videoPlayerIndex++; + continue; + } + } + } + + VerifyOrReturnError(err == CHIP_END_OF_TLV, err); + ReturnErrorOnFailure(reader.ExitContainer(videoPlayersContainerType)); + ReturnErrorOnFailure(reader.ExitContainer(outerContainerType)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR PersistenceManager::PurgeVideoPlayerCache() +{ + ChipLogProgress(AppServer, "PersistenceManager::PurgeVideoPlayerCache called"); + return chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Delete(kCastingDataKey); +} diff --git a/examples/tv-casting-app/tv-casting-common/src/TargetEndpointInfo.cpp b/examples/tv-casting-app/tv-casting-common/src/TargetEndpointInfo.cpp index e8b2d75b88257d..c6a07484418580 100644 --- a/examples/tv-casting-app/tv-casting-common/src/TargetEndpointInfo.cpp +++ b/examples/tv-casting-app/tv-casting-common/src/TargetEndpointInfo.cpp @@ -41,6 +41,11 @@ bool TargetEndpointInfo::HasCluster(ClusterId clusterId) return false; } +chip::ClusterId * TargetEndpointInfo::GetClusters() +{ + return mClusters; +} + bool TargetEndpointInfo::AddCluster(ClusterId clusterId) { for (size_t i = 0; i < kMaxNumberOfClustersPerEndpoint; i++) diff --git a/examples/tv-casting-app/tv-casting-common/src/TargetVideoPlayerInfo.cpp b/examples/tv-casting-app/tv-casting-common/src/TargetVideoPlayerInfo.cpp index b4559757225c28..ff85e20eaaa0dd 100644 --- a/examples/tv-casting-app/tv-casting-common/src/TargetVideoPlayerInfo.cpp +++ b/examples/tv-casting-app/tv-casting-common/src/TargetVideoPlayerInfo.cpp @@ -21,38 +21,46 @@ using namespace chip; CASEClientPool gCASEClientPool; -CHIP_ERROR TargetVideoPlayerInfo::Initialize(NodeId nodeId, FabricIndex fabricIndex) +CHIP_ERROR TargetVideoPlayerInfo::Initialize(NodeId nodeId, FabricIndex fabricIndex, + std::function onConnectionSuccess, + std::function onConnectionFailure, uint16_t vendorId, + uint16_t productId, uint16_t deviceType, const char * deviceName) { ChipLogProgress(NotSpecified, "TargetVideoPlayerInfo nodeId=0x" ChipLogFormatX64 " fabricIndex=%d", ChipLogValueX64(nodeId), fabricIndex); mNodeId = nodeId; mFabricIndex = fabricIndex; + mVendorId = vendorId; + mProductId = productId; + mDeviceType = deviceType; + chip::Platform::CopyString(mDeviceName, chip::Dnssd::kMaxDeviceNameLen + 1, deviceName); for (auto & endpointInfo : mEndpoints) { endpointInfo.Reset(); } - Server * server = &(chip::Server::GetInstance()); - server->GetCASESessionManager()->FindOrEstablishSession(ScopedNodeId(nodeId, fabricIndex), &mOnConnectedCallback, - &mOnConnectionFailureCallback); - - if (!mDeviceProxy.ConnectionReady()) + if (onConnectionSuccess && onConnectionFailure) { - ChipLogError(AppServer, "Failed to find an existing instance of OperationalDeviceProxy to the peer"); - return CHIP_ERROR_INVALID_ARGUMENT; + ReturnErrorOnFailure(FindOrEstablishCASESession(onConnectionSuccess, onConnectionFailure)); } - ChipLogProgress(AppServer, "Created an instance of DeviceProxy"); mInitialized = true; return CHIP_NO_ERROR; } +CHIP_ERROR TargetVideoPlayerInfo::FindOrEstablishCASESession(std::function onConnectionSuccess, + std::function onConnectionFailure) +{ + mOnConnectionSuccessClientCallback = onConnectionSuccess; + mOnConnectionFailureClientCallback = onConnectionFailure; + Server * server = &(chip::Server::GetInstance()); + server->GetCASESessionManager()->FindOrEstablishSession(ScopedNodeId(mNodeId, mFabricIndex), &mOnConnectedCallback, + &mOnConnectionFailureCallback); + return CHIP_NO_ERROR; +} + TargetEndpointInfo * TargetVideoPlayerInfo::GetOrAddEndpoint(EndpointId endpointId) { - if (!mInitialized) - { - return nullptr; - } TargetEndpointInfo * endpoint = GetEndpoint(endpointId); if (endpoint != nullptr) { @@ -71,10 +79,6 @@ TargetEndpointInfo * TargetVideoPlayerInfo::GetOrAddEndpoint(EndpointId endpoint TargetEndpointInfo * TargetVideoPlayerInfo::GetEndpoint(EndpointId endpointId) { - if (!mInitialized) - { - return nullptr; - } for (auto & endpointInfo : mEndpoints) { if (endpointInfo.IsInitialized() && endpointInfo.GetEndpointId() == endpointId) @@ -85,12 +89,13 @@ TargetEndpointInfo * TargetVideoPlayerInfo::GetEndpoint(EndpointId endpointId) return nullptr; } +TargetEndpointInfo * TargetVideoPlayerInfo::GetEndpoints() +{ + return mEndpoints; +} + bool TargetVideoPlayerInfo::HasEndpoint(EndpointId endpointId) { - if (!mInitialized) - { - return false; - } for (auto & endpointInfo : mEndpoints) { if (endpointInfo.IsInitialized() && endpointInfo.GetEndpointId() == endpointId)