pillarbox-cast-receiver
Provides a PillarboxPlayer implementation to handle GoogleCast TV receiver. Application needs to use PillarboxCastReceiverPlayer instead of PillarboxExoPlayer
.
Integration
To use this module, add the following dependency to your module's build.gradle
/build.gradle.kts
file:
implementation("ch.srgssr.pillarbox:pillarbox-cast-receiver:<pillarbox_version>")
Configuring Cast support
When a launch request is sent out by a sender application, an Intent is created with an application namespace. Application is responsible for handling it and creating an instance of the CastReceiverContext object when the TV app is launched. The CastReceiverContext object is needed to interact with Cast while the TV app is running. This object enables TV applications to accept Cast media messages coming from any connected senders.
Android TV Setup
Add a new intent filter to the activity that you want to handle the launch intent from your sender app:
<activity android:name="com.example.activity">
<intent-filter>
<action android:name="com.google.android.gms.cast.tv.action.LAUNCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Application needs to implement a ReceiverOptionsProvider to provide CastReceiverOptions:
class MyReceiverOptionsProvider : ReceiverOptionsProvider {
override fun getOptions(context: Context?): CastReceiverOptions {
return CastReceiverOptions.Builder(context)
// If you don't set setStatusText, it is pulled automatically from android:label in your Android TV manifest.
.setStatusText("My App")
.build()
}
}
Then specify the ReceiverOptionsProvider
in the application AndroidManifest
:
<meta-data
android:name="com.google.android.gms.cast.tv.RECEIVER_OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.example.mysimpleatvapplication.MyReceiverOptionsProvider" />
The ReceiverOptionsProvider
is used to provide the CastReceiverOptions
when CastReceiverContext
is initialized.
Cast receiver context
Initialize the CastReceiverContext when your app is created:
override fun onCreate() {
CastReceiverContext.initInstance(this)
}
Start the CastReceiverContext
when your app moves to the foreground:
CastReceiverContext.getInstance().start()
Call stop()
on the CastReceiverContext
after the app goes into the background for video apps or apps that don't support background playback:
// Player has stopped.
CastReceiverContext.getInstance().stop()
Additionally, if the application does support playing in the background, call
stop()
on theCastReceiverContext
when it stops playing while in the background.
Google Cast strongly recommends you use the LifecycleObserver
from the androidx.lifecycle
library to manage calling CastReceiverContext.start()
and CastReceiverContext.stop()
, especially if your native app has multiple activities. This avoids race conditions when you call start()
and stop()
from different activities.
// Create a LifecycleObserver class.
class MyLifecycleObserver : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
// App prepares to enter foreground.
CastReceiverContext.getInstance().start()
}
override fun onStop(owner: LifecycleOwner) {
// App has moved to the background or has terminated.
CastReceiverContext.getInstance().stop()
}
}
// Add the observer when your application is being created.
class MyApplication : Application() {
fun onCreate() {
super.onCreate()
// Initialize CastReceiverContext.
CastReceiverContext.initInstance(this /* android.content.Context */)
// Register LifecycleObserver
ProcessLifecycleOwner.get().lifecycle.addObserver(
MyLifecycleObserver())
}
}
Playback
Get the CastReceiverContext
val castReceiverContext = CastReceiverContext.getInstance()
Create the PillarboxCastReceiverPlayer that implements PillarboxPlayer and handles all incoming events from the cast senders.
val player : PillarboxPlayer = PillarboxCastReceiverPlayer(
player = PillarboxExoPlayer(this),
mediaItemConverter = SRGMediaItemConverter(), // It should be the same converter that is used by the Android senders.
castReceiverContext = castReceiverContext,
)
val mediaSession = PillarboxMediaSession.Builder(this, player).build()
Link the player MediaSession
with the CastReceiverContext
castReceiverContext.mediaManager.setSessionTokenFromPillarboxMediaSession(mediaSession)
Handle the cast intent in the Activity
in onNewIntent
and in onCreate
method after linking the session with the CastReceiver.
private fun handleIntent(intent: Intent) {
val mediaManager = CastReceiverContext.getInstance().mediaManager
if (mediaManager.onNewIntent(intent)) {
return
} else {
// Cast doesn't handle this intent do the stuff your application have to do.
}
}