1 year ago
#278468
Lallawmzuala khawlhring
Google cast sender app not opening TV receiver app
I'm trying to implement video casting for my flutter app using the package cast
Ive registered my app on the cast console and able to cast my videos from the sender android mobile app made with flutter using the following code to the Android TV
session.value.stateStream.listen((state) async {
log('session state->' + state.toString());
if (state == CastSessionState.connecting) {
log('Connecting...');
}
if (state == CastSessionState.connected) {
var media = {
"contentId": _purchaseController.purchasedMedia.value.mpdH264,
'contentUrl': _purchaseController.purchasedMedia.value.mpdH264,
"streamType": "BUFFERED", // or LIVE
"contentType": "application/dash+xml",
"metadata": {
"metadataType": 1,
"title": video.title,
"studio": "Lersia",
"releaseDate": video.releaseYear,
"images": [
{"url": video.lgLandscape}
]
},
"customData": {
"token": _purchaseController.purchasedMedia.value.drmTokenH264,
}
};
try {
session.value.sendMessage(CastSession.kNamespaceMedia, {
'type': 'LOAD',
'autoPlay': true,
'media': media,
});
Get.snackbar("Cast Success", "Video casted to $_deviceName");
setupNotifications();
MediaPlayerCentral.add(video);
MediaPlayerCentral.playPause();
} catch (e) {
log('stateStreamOnConnectedError=>' + e.toString());
}
}
if (state == CastSessionState.closed) {
try {
Get.snackbar("Cast Disconnected", "Disconnected from $_deviceName");
connectedDevice.value = null;
castingVideo.value = null;
NotificationUtils.cancelNotification(100);
MediaPlayerCentral.stop();
connectedDevice.value = null;
if (session.value != null) {
await session.value.socket.flush();
await session.value.socket.close();
session.value = null;
} else {
session.value = null;
}
} catch (e) {
log('stateStreamOnClosedError=>' + e.toString());
}
}
});
var index = 0;
session.value.messageStream.listen((message) {
log("messageStream " + message.toString());
var _status = message['status'];
if (_status != null && _status is List && _status.isNotEmpty) {
var _returnedTime = _status.first['currentTime'];
currentPlayInSeconds.value = (_returnedTime is int)
? _returnedTime
: int.tryParse(_returnedTime.toString());
}
requestId.value = message['requestId'];
index += 1;
if (index == 4) {
Future.delayed(Duration(seconds: 2)).then((x) {
var media = {
"contentId": _purchaseController.purchasedMedia.value.mpdH264,
"streamType": "BUFFERED", // or LIVE
"contentType": "application/dash+xml",
"metadata": {
"metadataType": 1,
"title": video.title,
"studio": "Lersia",
"releaseDate": "30 Sep 2021",
'posterUrl': video.lgLandscape,
"images": [
{"url": video.lgLandscape}
]
},
"customData": {
"licenseUrl":
_purchaseController.purchasedMedia.value.drmWidevine,
"token": _purchaseController.purchasedMedia.value.drmTokenH264,
}
};
try {
session.value.sendMessage(CastSession.kNamespaceMedia, {
'requestId': 1,
'type': '',
'media': media,
});
} catch (e) {
log('messageStreamListenError=>' + e.toString());
}
});
}
});
session.value.sendMessage(CastSession.kNamespaceReceiver, {
'type': 'LAUNCH',
'appId': '0E0BA573', // set the appId of your app here
});
On the android TV, the cast message is received and the video is opened on the browser even when the TV app is installed. I've added the CastOptionsProvider class and specified it on the manifest like below
class CastOptionsProvider : OptionsProvider {
override fun getCastOptions(context: Context): CastOptions? {
val notificationOptions = NotificationOptions.Builder()
.build()
val mediaOptions = CastMediaOptions.Builder()
.setNotificationOptions(notificationOptions)
.build()
val credentialsData = CredentialsData.Builder()
.setCredentials("{\"userId\": \"abc\"}")
.build()
val launchOptions: LaunchOptions = LaunchOptions.Builder()
.setAndroidReceiverCompatible(true)
.setCredentialsData(credentialsData)
.build()
return CastOptions.Builder()
.setLaunchOptions(launchOptions)
.setReceiverApplicationId(context.getString(R.string.app_id))
.setCastMediaOptions(mediaOptions)
.build();
}
override fun getAdditionalSessionProviders(context: Context?): List<SessionProvider?>? {
return null
}
}
And this is the manifest file
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lersia.mobile">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:label="Lersia Play"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round">
<activity
android:name="com.lersia.mobile.MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:exported="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.lersia.mobile.CastOptionsProvider" />
<!-- Don't delete the meta-data below.CastOptionsProvider
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
I've also added the CastReceiverOptionsProvider on the TV app like below
class CastReceiverOptionsProvider : ReceiverOptionsProvider {
override fun getOptions(context: Context?): CastReceiverOptions? {
return CastReceiverOptions.Builder(context)
.setStatusText("Lersia tv status text")
.build()
}
}
and specified it on the manifest file of the TV app as below
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lersia.tv">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-feature android:name="android.software.leanback" android:required="true" />
<uses-feature android:name="android.hardware.touchscreen"
android:required="false" />
<application
android:name="com.lersia.tv.MyApplication"
android:label="Lersia Play"
android:banner="@drawable/launch_banner"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:banner="@drawable/launch_banner"
android:launchMode="singleTask"
android:theme="@style/LaunchTheme"
android:exported="true"
android:label="Lersia Play"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"/>
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="com.google.android.gms.cast.tv.action.LAUNCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name="com.lersia.tv.TestIntent"
android:exported="false"
android:launchMode="singleTask">
<intent-filter>
<action android:name="com.google.android.gms.cast.tv.action.LOAD"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<meta-data
android:name="com.google.android.gms.cast.tv.RECEIVER_OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.lersia.tv.CastReceiverOptionsProvider" />
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
Am I missing something on why the TV app is not opening? Would be glad if someone can help
android
flutter
google-cast
android-tv
google-cast-sdk
0 Answers
Your Answer