Skip to content

Commit fa06c9d

Browse files
asd
1 parent 060e4c3 commit fa06c9d

File tree

12 files changed

+555
-63
lines changed

12 files changed

+555
-63
lines changed

examples/tv-casting-app/APIs.md

+106-29
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,11 @@ samples so you can see the experience end to end.
3434

3535
A Casting Client (e.g. a mobile phone app) is expected to be a Matter
3636
Commissionable Node and a `CastingPlayer` (i.e. a TV) is expected to be a Matter
37-
Commissioner. In the context of the
38-
[Matter Video Player architecture](https://github.com/CHIP-Specifications/connectedhomeip-spec/blob/master/src/app_clusters/media/VideoPlayerArchitecture.adoc),
39-
a `CastingPlayer` would map to
40-
[Casting "Video" Player](https://github.com/CHIP-Specifications/connectedhomeip-spec/blob/master/src/app_clusters/media/VideoPlayerArchitecture.adoc#1-introduction).
41-
The `CastingPlayer` is expected to be hosting one or more `Endpoints` (some of
42-
which can represent
43-
[Content Apps](https://github.com/CHIP-Specifications/connectedhomeip-spec/blob/master/src/app_clusters/media/VideoPlayerArchitecture.adoc#1-introduction)
44-
in the Matter Video Player architecture) that support one or more Matter Media
45-
`Clusters`.
37+
Commissioner. In the context of the Matter Video Player architecture, a
38+
`CastingPlayer` would map to Casting "Video" Player. The `CastingPlayer` is
39+
expected to be hosting one or more `Endpoints` (some of which can represent
40+
Content Apps) in the Matter Video Player architecture) that support one or more
41+
Matter Media `Clusters`.
4642

4743
The steps to start a casting session are:
4844

@@ -91,10 +87,10 @@ A Casting Client must first initialize the Matter SDK and define the following
9187
`DataProvider` objects for the the Matter Casting library to use throughout the
9288
client's lifecycle:
9389

94-
1. **Rotating Device Identifier** - Refer to the Matter specification for
95-
details on how to generate the
96-
[Rotating Device Identifier](https://github.com/CHIP-Specifications/connectedhomeip-spec/blob/master/src/rendezvous/DeviceDiscovery.adoc#245-rotating-device-identifier)).
97-
Then, instantiate a `DataProvider` object as described below.
90+
1. **Rotating Device Identifier** - This unique per-device identifier SHALL
91+
consist of a randomly-generated 128-bit or longer octet string. Refer to the
92+
Matter specification for more details. Instantiate a `DataProvider` object
93+
as described below to provide this identifier.
9894

9995
On Linux, define a `RotatingDeviceIdUniqueIdProvider` to provide the Casting
10096
Client's `RotatingDeviceIdUniqueId`, by implementing a
@@ -152,10 +148,13 @@ client's lifecycle:
152148
```
153149

154150
2. **Commissioning Data** - This object contains the passcode, discriminator,
155-
etc which identify the app and are provided to the `CastingPlayer` during
156-
the commissioning process. Refer to the Matter specification's
157-
[Onboarding Payload](https://github.com/CHIP-Specifications/connectedhomeip-spec/blob/master/src/qr_code/OnboardingPayload.adoc#ref_OnboardingPayload)
158-
section for details on commissioning data.
151+
etc. which identify the app and are provided to the `CastingPlayer` during
152+
the commissioning process. A Passcode SHALL be included as a 27-bit unsigned
153+
integer, which serves as proof of possession during commissioning. A
154+
Discriminator SHALL be included as a 12-bit unsigned integer, which SHALL
155+
match the value which a device advertises during commissioning. Refer to the
156+
Matter specification's "Onboarding Payload" section for more details on
157+
commissioning data.
159158

160159
On Linux, define a function `InitCommissionableDataProvider` to initialize
161160
initialize a `LinuxCommissionableDataProvider` that can provide the required
@@ -217,9 +216,8 @@ client's lifecycle:
217216
3. **Device Attestation Credentials** - This object contains the
218217
`DeviceAttestationCertificate`, `ProductAttestationIntermediateCertificate`,
219218
etc. and implements a way to sign messages when called upon by the Matter TV
220-
Casting Library as part of the
221-
[Device Attestation process](https://github.com/CHIP-Specifications/connectedhomeip-spec/blob/master/src/device_attestation/Device_Attestation_Specification.adoc)
222-
during commissioning.
219+
Casting Library as part of the Matter Device Attestation process during
220+
commissioning.
223221

224222
On Linux, implement a define a `dacProvider` to provide the Casting Client's
225223
Device Attestation Credentials, by implementing a
@@ -702,10 +700,9 @@ Each `CastingPlayer` object created during
702700
[Discovery](#discover-casting-players) contains information such as
703701
`deviceName`, `vendorId`, `productId`, etc. which can help the user pick the
704702
right `CastingPlayer`. A Casting Client can attempt to connect to the
705-
`selectedCastingPlayer` using
706-
[Matter User Directed Commissioning (UDC)](https://github.com/CHIP-Specifications/connectedhomeip-spec/blob/master/src/rendezvous/UserDirectedCommissioning.adoc).
707-
The Matter TV Casting library locally caches information required to reconnect
708-
to a `CastingPlayer`, once the Casting client has been commissioned by it. After
703+
`selectedCastingPlayer` using Matter User Directed Commissioning (UDC). The
704+
Matter TV Casting library locally caches information required to reconnect to a
705+
`CastingPlayer`, once the Casting client has been commissioned by it. After
709706
that, the Casting client is able to skip the full UDC process by establishing
710707
CASE with the `CastingPlayer` directly. Once connected, the `CastingPlayer`
711708
object will contain the list of available Endpoints on that `CastingPlayer`.
@@ -743,6 +740,59 @@ targetCastingPlayer->VerifyOrEstablishConnection(ConnectionHandler,
743740
...
744741
```
745742
743+
On Android, the Casting Client may call `verifyOrEstablishConnection` on the
744+
`CastingPlayer` object it wants to connect to.
745+
746+
```java
747+
private static final long MIN_CONNECTION_TIMEOUT_SEC = 3 * 60;
748+
749+
EndpointFilter desiredEndpointFilter = new EndpointFilter(null, DESIRED_ENDPOINT_VENDOR_ID, new ArrayList<>());
750+
751+
MatterError err = targetCastingPlayer.verifyOrEstablishConnection(
752+
MIN_CONNECTION_TIMEOUT_SEC,
753+
desiredEndpointFilter,
754+
new MatterCallback<Void>() {
755+
@Override
756+
public void handle(Void v) {
757+
Log.i(
758+
TAG,
759+
"Connected to CastingPlayer with deviceId: "
760+
+ targetCastingPlayer.getDeviceId());
761+
getActivity()
762+
.runOnUiThread(
763+
() -> {
764+
connectionFragmentStatusTextView.setText(
765+
"Connected to Casting Player with device name: "
766+
+ targetCastingPlayer.getDeviceName()
767+
+ "\n\n");
768+
connectionFragmentNextButton.setEnabled(true);
769+
});
770+
}
771+
},
772+
new MatterCallback<MatterError>() {
773+
@Override
774+
public void handle(MatterError err) {
775+
Log.e(TAG, "CastingPLayer connection failed: " + err);
776+
getActivity()
777+
.runOnUiThread(
778+
() -> {
779+
connectionFragmentStatusTextView.setText(
780+
"Casting Player connection failed due to: " + err + "\n\n");
781+
});
782+
}
783+
});
784+
785+
if (err.hasError())
786+
{
787+
getActivity()
788+
.runOnUiThread(
789+
() -> {
790+
connectionFragmentStatusTextView.setText(
791+
"Casting Player connection failed due to: " + err + "\n\n");
792+
});
793+
}
794+
```
795+
746796
On iOS, the Casting Client may call `verifyOrEstablishConnection` on the
747797
`MCCastingPlayer` object it wants to connect to and handle any `NSErrors` that
748798
may happen in the process.
@@ -777,6 +827,8 @@ func connect(selectedCastingPlayer: MCCastingPlayer?) {
777827
### Select an Endpoint on the Casting Player
778828
779829
_{Complete Endpoint selection examples: [Linux](linux/simple-app-helper.cpp) |
830+
[Android](android/App/app/src/main/java/com/matter/casting/ContentLauncherLaunchURLExampleFragment.java)
831+
|
780832
[iOS](darwin/TvCasting/TvCasting/MCContentLauncherLaunchURLExampleViewModel.swift)}_
781833
782834
On a successful connection with a `CastingPlayer`, a Casting Client may select
@@ -803,6 +855,34 @@ if (it != endpoints.end())
803855
}
804856
```
805857
858+
On Android, it can select an `Endpoint` as shown below.
859+
860+
```java
861+
private static final Integer SAMPLE_ENDPOINT_VID = 65521;
862+
863+
private Endpoint selectEndpoint()
864+
{
865+
Endpoint endpoint = null;
866+
if(selectedCastingPlayer != null)
867+
{
868+
List<Endpoint> endpoints = selectedCastingPlayer.getEndpoints();
869+
if (endpoints == null)
870+
{
871+
Log.e(TAG, "No Endpoints found on CastingPlayer");
872+
}
873+
else
874+
{
875+
endpoint = endpoints
876+
.stream()
877+
.filter(e -> SAMPLE_ENDPOINT_VID.equals(e.getVendorId()))
878+
.findFirst()
879+
.get();
880+
}
881+
}
882+
return endpoint;
883+
}
884+
```
885+
806886
On iOS, it can select an `MCEndpoint` similarly and as shown below.
807887
808888
```swift
@@ -1045,11 +1125,8 @@ vendorIDAttribute!.read(nil) { context, before, after, err in
10451125
10461126
### Subscriptions
10471127
1048-
_{Complete Attribute subscription examples:
1049-
[Linux](linux/simple-app-helper.cpp)}_
1050-
1051-
_{Complete Attribute Read examples: [Linux](linux/simple-app-helper.cpp) |
1052-
[iOS](darwin/TvCasting/TvCasting/MCMediaPlaybackSubscribeToCurrentStateExampleViewModel.swift)}_
1128+
_{Complete Attribute subscription examples: [Linux](linux/simple-app-helper.cpp)
1129+
|[iOS](darwin/TvCasting/TvCasting/MCMediaPlaybackSubscribeToCurrentStateExampleViewModel.swift)}_
10531130
10541131
A Casting Client may subscribe to an attribute on an `Endpoint` of the
10551132
`CastingPlayer` to get data reports when the attributes change.

examples/tv-casting-app/android/App/.idea/misc.xml

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/MainActivity.java

+13-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
import com.chip.casting.DiscoveredNodeData;
1111
import com.chip.casting.TvCastingApp;
1212
import com.chip.casting.util.GlobalCastingConstants;
13+
import com.matter.casting.ActionSelectorFragment;
1314
import com.matter.casting.ConnectionExampleFragment;
15+
import com.matter.casting.ContentLauncherLaunchURLExampleFragment;
1416
import com.matter.casting.DiscoveryExampleFragment;
1517
import com.matter.casting.InitializationExample;
1618
import com.matter.casting.PreferencesConfigurationManager;
@@ -22,7 +24,8 @@ public class MainActivity extends AppCompatActivity
2224
ConnectionFragment.Callback,
2325
SelectClusterFragment.Callback,
2426
DiscoveryExampleFragment.Callback,
25-
ConnectionExampleFragment.Callback {
27+
ConnectionExampleFragment.Callback,
28+
ActionSelectorFragment.Callback {
2629

2730
private static final String TAG = MainActivity.class.getSimpleName();
2831

@@ -73,9 +76,12 @@ public void handleCommissioningComplete() {
7376
@Override
7477
public void handleConnectionComplete(CastingPlayer castingPlayer) {
7578
Log.i(TAG, "MainActivity.handleConnectionComplete() called ");
79+
showFragment(ActionSelectorFragment.newInstance(castingPlayer));
80+
}
7681

77-
// TODO: Implement in following PRs. Select Cluster Fragment.
78-
// showFragment(SelectClusterFragment.newInstance(tvCastingApp));
82+
@Override
83+
public void handleContentLauncherLaunchURLSelected(CastingPlayer selectedCastingPlayer) {
84+
showFragment(ContentLauncherLaunchURLExampleFragment.newInstance(selectedCastingPlayer));
7985
}
8086

8187
@Override
@@ -95,7 +101,10 @@ public void handleMediaPlaybackSelected() {
95101

96102
@Override
97103
public void handleDisconnect() {
98-
showFragment(CommissionerDiscoveryFragment.newInstance(tvCastingApp));
104+
showFragment(
105+
GlobalCastingConstants.ChipCastingSimplified
106+
? DiscoveryExampleFragment.newInstance()
107+
: CommissionerDiscoveryFragment.newInstance(tvCastingApp));
99108
}
100109

101110
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (c) 2024 Project CHIP Authors
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package com.matter.casting;
18+
19+
import android.os.Bundle;
20+
import android.util.Log;
21+
import android.view.LayoutInflater;
22+
import android.view.View;
23+
import android.view.ViewGroup;
24+
import androidx.annotation.Nullable;
25+
import androidx.fragment.app.Fragment;
26+
import com.R;
27+
import com.matter.casting.core.CastingPlayer;
28+
29+
/** An interstitial {@link Fragment} to select one of the supported media actions to perform */
30+
public class ActionSelectorFragment extends Fragment {
31+
private static final String TAG = ActionSelectorFragment.class.getSimpleName();
32+
33+
private final CastingPlayer selectedCastingPlayer;
34+
35+
private View.OnClickListener selectContentLauncherButtonClickListener;
36+
private View.OnClickListener disconnectButtonClickListener;
37+
38+
public ActionSelectorFragment(CastingPlayer selectedCastingPlayer) {
39+
this.selectedCastingPlayer = selectedCastingPlayer;
40+
}
41+
42+
/**
43+
* Use this factory method to create a new instance of this fragment using the provided
44+
* parameters.
45+
*
46+
* @param selectedCastingPlayer CastingPlayer that the casting app connected to
47+
* @return A new instance of fragment SelectActionFragment.
48+
*/
49+
public static ActionSelectorFragment newInstance(CastingPlayer selectedCastingPlayer) {
50+
return new ActionSelectorFragment(selectedCastingPlayer);
51+
}
52+
53+
@Override
54+
public void onCreate(Bundle savedInstanceState) {
55+
super.onCreate(savedInstanceState);
56+
}
57+
58+
@Override
59+
public View onCreateView(
60+
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
61+
ActionSelectorFragment.Callback callback = (ActionSelectorFragment.Callback) this.getActivity();
62+
this.selectContentLauncherButtonClickListener =
63+
v -> {
64+
Log.d(TAG, "handle() called on selectContentLauncherButtonClickListener");
65+
callback.handleContentLauncherLaunchURLSelected(selectedCastingPlayer);
66+
};
67+
68+
this.disconnectButtonClickListener =
69+
v -> {
70+
Log.d(TAG, "Disconnecting from current casting player");
71+
selectedCastingPlayer.disconnect();
72+
callback.handleDisconnect();
73+
};
74+
75+
return inflater.inflate(R.layout.fragment_matter_action_selector, container, false);
76+
}
77+
78+
@Override
79+
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
80+
super.onViewCreated(view, savedInstanceState);
81+
Log.d(TAG, "ActionSelectorFragment.onViewCreated called");
82+
getView()
83+
.findViewById(R.id.selectContentLauncherLaunchURLButton)
84+
.setOnClickListener(selectContentLauncherButtonClickListener);
85+
86+
getView().findViewById(R.id.disconnectButton).setOnClickListener(disconnectButtonClickListener);
87+
}
88+
89+
/** Interface for notifying the host. */
90+
public interface Callback {
91+
/** Notifies listener to trigger transition on selection of Content Launcher cluster */
92+
void handleContentLauncherLaunchURLSelected(CastingPlayer selectedCastingPlayer);
93+
94+
/** Notifies listener to trigger transition on click of the Disconnect button */
95+
void handleDisconnect();
96+
}
97+
}

0 commit comments

Comments
 (0)