Skip to content

Commit 93c5213

Browse files
iOS tv-casting-app: simplified command/attribute APIs (project-chip#31640)
* iOS tv-casting-app: simplified command/attribute APIs
1 parent 69f8bd5 commit 93c5213

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2299
-47
lines changed

examples/tv-casting-app/APIs.md

+199-8
Original file line numberDiff line numberDiff line change
@@ -773,7 +773,8 @@ func connect(selectedCastingPlayer: MCCastingPlayer?) {
773773
774774
### Select an Endpoint on the Casting Player
775775
776-
_{Complete Endpoint selection examples: [Linux](linux/simple-app-helper.cpp)}_
776+
_{Complete Endpoint selection examples: [Linux](linux/simple-app-helper.cpp) |
777+
[iOS](darwin/TvCasting/TvCasting/MCContentLauncherLaunchURLExampleViewModel.swift)}_
777778
778779
On a successful connection with a `CastingPlayer`, a Casting Client may select
779780
one of the Endpoints to interact with based on its attributes (e.g. Vendor ID,
@@ -799,6 +800,19 @@ if (it != endpoints.end())
799800
}
800801
```
801802
803+
On iOS, it can select an `MCEndpoint` similarly and as shown below.
804+
805+
```swift
806+
// VendorId of the MCEndpoint on the MCCastingPlayer that the MCCastingApp desires to interact with after connection
807+
let sampleEndpointVid: Int = 65521
808+
...
809+
// select the MCEndpoint on the MCCastingPlayer to invoke the command on
810+
if let endpoint: MCEndpoint = castingPlayer.endpoints().filter({ $0.vendorId().intValue == sampleEndpointVid}).first
811+
{
812+
...
813+
}
814+
```
815+
802816
## Interacting with a Casting Endpoint
803817
804818
Once the Casting Client has selected an `Endpoint`, it is ready to
@@ -819,13 +833,14 @@ response types to use with these APIs:
819833
820834
### Issuing Commands
821835
822-
_{Complete Command invocation examples: [Linux](linux/simple-app-helper.cpp)}_
836+
_{Complete Command invocation examples: [Linux](linux/simple-app-helper.cpp) |
837+
[iOS](darwin/TvCasting/TvCasting/MCContentLauncherLaunchURLExampleViewModel.swift)}_
823838
824-
The Casting Client can get a reference to a `endpoint` on a `CastingPlayer`,
839+
The Casting Client can get a reference to an `Endpoint` on a `CastingPlayer`,
825840
check if it supports the required cluster/command, and send commands to it. It
826841
can then handle any command response / error the `CastingPlayer` sends back.
827842
828-
On Linux, for example, given an `endpoint`, it can send a `LaunchURL` command
843+
On Linux, for example, given an `Endpoint`, it can send a `LaunchURL` command
829844
(part of the Content Launcher cluster) by calling the `Invoke` API on a
830845
`Command` of type
831846
`matter::casting::core::Command<chip::app::Clusters::ContentLauncher::Commands::LaunchURL::Type>`
@@ -865,9 +880,65 @@ void InvokeContentLauncherLaunchURL(matter::casting::memory::Strong<matter::cast
865880
}
866881
```
867882
883+
On iOS, given an `MCEndpoint` endpoint, it can send a `LaunchURL` command (part
884+
of the Content Launcher cluster) by calling the `invoke` API on a
885+
`MCContentLauncherClusterLaunchURLCommand`
886+
887+
```swift
888+
// validate that the selected endpoint supports the ContentLauncher cluster
889+
if(!endpoint.hasCluster(MCEndpointClusterTypeContentLauncher))
890+
{
891+
self.Log.error("No ContentLauncher cluster supporting endpoint found")
892+
DispatchQueue.main.async
893+
{
894+
self.status = "No ContentLauncher cluster supporting endpoint found"
895+
}
896+
return
897+
}
898+
899+
// get ContentLauncher cluster from the endpoint
900+
let contentLaunchercluster: MCContentLauncherCluster = endpoint.cluster(for: MCEndpointClusterTypeContentLauncher) as! MCContentLauncherCluster
901+
902+
// get the launchURLCommand from the contentLauncherCluster
903+
let launchURLCommand: MCContentLauncherClusterLaunchURLCommand? = contentLaunchercluster.launchURLCommand()
904+
if(launchURLCommand == nil)
905+
{
906+
self.Log.error("LaunchURL not supported on cluster")
907+
DispatchQueue.main.async
908+
{
909+
self.status = "LaunchURL not supported on cluster"
910+
}
911+
return
912+
}
913+
914+
// create the LaunchURL request
915+
let request: MCContentLauncherClusterLaunchURLRequest = MCContentLauncherClusterLaunchURLRequest()
916+
request.contentURL = contentUrl
917+
request.displayString = displayString
918+
919+
// call invoke on launchURLCommand while passing in a completion block
920+
launchURLCommand!.invoke(request, context: nil, completion: { context, err, response in
921+
DispatchQueue.main.async
922+
{
923+
if(err == nil)
924+
{
925+
self.Log.info("LaunchURLCommand invoke completion success with \(String(describing: response))")
926+
self.status = "Success. Response data: \(String(describing: response?.data))"
927+
}
928+
else
929+
{
930+
self.Log.error("LaunchURLCommand invoke completion failure with \(String(describing: err))")
931+
self.status = "Failure: \(String(describing: err))"
932+
}
933+
}
934+
},
935+
timedInvokeTimeoutMs: 5000) // time out after 5000ms
936+
```
937+
868938
### Read Operations
869939
870-
_{Complete Attribute Read examples: [Linux](linux/simple-app-helper.cpp)}_
940+
_{Complete Attribute Read examples: [Linux](linux/simple-app-helper.cpp) |
941+
[iOS](darwin/TvCasting/TvCasting/MCApplicationBasicReadVendorIDExampleViewModel.swift)}_
871942
872943
The `CastingClient` may read an Attribute from the `Endpoint` on the
873944
`CastingPlayer`. It should ensure that the desired cluster / attribute are
@@ -914,11 +985,69 @@ void ReadApplicationBasicVendorID(matter::casting::memory::Strong<matter::castin
914985
}
915986
```
916987
988+
On iOS, given a `MCEndpoint`, the `VendorID` can be read similarly, by calling
989+
the `read` API on the `MCApplicationBasicClusterVendorIDAttribute`
990+
991+
```swift
992+
// validate that the selected endpoint supports the ApplicationBasic cluster
993+
if(!endpoint.hasCluster(MCEndpointClusterTypeApplicationBasic))
994+
{
995+
self.Log.error("No ApplicationBasic cluster supporting endpoint found")
996+
DispatchQueue.main.async
997+
{
998+
self.status = "No ApplicationBasic cluster supporting endpoint found"
999+
}
1000+
return
1001+
}
1002+
1003+
// get ApplicationBasic cluster from the endpoint
1004+
let applicationBasiccluster: MCApplicationBasicCluster = endpoint.cluster(for: MCEndpointClusterTypeApplicationBasic) as! MCApplicationBasicCluster
1005+
1006+
// get the vendorIDAttribute from the applicationBasiccluster
1007+
let vendorIDAttribute: MCApplicationBasicClusterVendorIDAttribute? = applicationBasiccluster.vendorIDAttribute()
1008+
if(vendorIDAttribute == nil)
1009+
{
1010+
self.Log.error("VendorID attribute not supported on cluster")
1011+
DispatchQueue.main.async
1012+
{
1013+
self.status = "VendorID attribute not supported on cluster"
1014+
}
1015+
return
1016+
}
1017+
1018+
// call read on vendorIDAttribute and pass in a completion block
1019+
vendorIDAttribute!.read(nil) { context, before, after, err in
1020+
DispatchQueue.main.async
1021+
{
1022+
if(err != nil)
1023+
{
1024+
self.Log.error("Error when reading VendorID value \(String(describing: err))")
1025+
self.status = "Error when reading VendorID value \(String(describing: err))"
1026+
return
1027+
}
1028+
1029+
if(before != nil)
1030+
{
1031+
self.Log.info("Read VendorID value: \(String(describing: after)) Before: \(String(describing: before))")
1032+
self.status = "Read VendorID value: \(String(describing: after)) Before: \(String(describing: before))"
1033+
}
1034+
else
1035+
{
1036+
self.Log.info("Read VendorID value: \(String(describing: after))")
1037+
self.status = "Read VendorID value: \(String(describing: after))"
1038+
}
1039+
}
1040+
}
1041+
```
1042+
9171043
### Subscriptions
9181044
9191045
_{Complete Attribute subscription examples:
9201046
[Linux](linux/simple-app-helper.cpp)}_
9211047
1048+
_{Complete Attribute Read examples: [Linux](linux/simple-app-helper.cpp) |
1049+
[iOS](darwin/TvCasting/TvCasting/MCMediaPlaybackSubscribeToCurrentStateExampleViewModel.swift)}_
1050+
9221051
A Casting Client may subscribe to an attribute on an `Endpoint` of the
9231052
`CastingPlayer` to get data reports when the attributes change.
9241053
@@ -966,7 +1095,69 @@ void SubscribeToMediaPlaybackCurrentState(matter::casting::memory::Strong<matter
9661095
}
9671096
```
9681097
1098+
On iOS, given a `MCEndpoint`, `CurrentState` can be subscribed to by calling the
1099+
`subscribe` API on the it can subscribe to the `CurrentState` (part of the Media
1100+
Playback Basic cluster) by calling the `Subscribe` API on the
1101+
`MCMediaPlaybackClusterCurrentStateAttribute`
1102+
1103+
```swift
1104+
// validate that the selected endpoint supports the MediaPlayback cluster
1105+
if(!endpoint.hasCluster(MCEndpointClusterTypeMediaPlayback))
1106+
{
1107+
self.Log.error("No MediaPlayback cluster supporting endpoint found")
1108+
DispatchQueue.main.async
1109+
{
1110+
self.status = "No MediaPlayback cluster supporting endpoint found"
1111+
}
1112+
return
1113+
}
1114+
1115+
// get MediaPlayback cluster from the endpoint
1116+
let mediaPlaybackCluster: MCMediaPlaybackCluster = endpoint.cluster(for: MCEndpointClusterTypeMediaPlayback) as! MCMediaPlaybackCluster
1117+
1118+
// get the currentStateAttribute from the mediaPlaybackCluster
1119+
let currentStateAttribute: MCMediaPlaybackClusterCurrentStateAttribute? = mediaPlaybackCluster.currentStateAttribute()
1120+
if(currentStateAttribute == nil)
1121+
{
1122+
self.Log.error("CurrentState attribute not supported on cluster")
1123+
DispatchQueue.main.async
1124+
{
1125+
self.status = "CurrentState attribute not supported on cluster"
1126+
}
1127+
return
1128+
}
1129+
1130+
// call read on currentStateAttribute and pass in a completion block
1131+
currentStateAttribute!.read(nil) { context, before, after, err in
1132+
1133+
let dateFormatter = DateFormatter()
1134+
dateFormatter.dateFormat = "HH:mm:ss"
1135+
let currentTime = dateFormatter.string(from: Date())
1136+
DispatchQueue.main.async
1137+
{
1138+
if(err != nil)
1139+
{
1140+
self.Log.error("Error when reading CurrentState value \(String(describing: err)) at \(currentTime)")
1141+
self.status = "Error when reading CurrentState value \(String(describing: err)) at \(currentTime)"
1142+
return
1143+
}
1144+
if(before != nil)
1145+
{
1146+
self.Log.info("Read CurrentState value: \(String(describing: after)) Before: \(String(describing: before)) at \(currentTime)")
1147+
self.status = "Read CurrentState value: \(String(describing: after)) Before: \(String(describing: before)) at \(currentTime)"
1148+
}
1149+
else
1150+
{
1151+
self.Log.info("Read CurrentState value: \(String(describing: after)) at \(currentTime)")
1152+
self.status = "Read CurrentState value: \(String(describing: after)) at \(currentTime)"
1153+
}
1154+
}
1155+
}
1156+
```
1157+
9691158
The Casting client can Shutdown all running Subscriptions by calling the
970-
`ShutdownAllSubscriptions` API on the `CastingApp`. See API and its
971-
documentation for [Linux](tv-casting-common/core/CastingApp.h), Android and
972-
[iOS](darwin/MatterTvCastingBridge/MatterTvCastingBridge/MCCastingApp.h).
1159+
`ShutdownAllSubscriptions` API on the `CastingApp` on Linux/Android and
1160+
`MCCastingApp` on iOS. See API and its documentation for
1161+
[Linux](tv-casting-common/core/CastingApp.h),
1162+
[Android](android/App/app/src/main/jni/com/matter/casting/core/CastingApp.java)
1163+
and [iOS](darwin/MatterTvCastingBridge/MatterTvCastingBridge/MCCastingApp.h).

0 commit comments

Comments
 (0)