Connecting from custom Sender applications on Android
In general, the following flow should be followed:
- Set up Google Cast context with correct receiver application ID.
- Connect to Chromecast device.
- Set up Google Cast MediaInfo object with correct contentID and contentType.
- Send Google Cast LoadRequest with a serialized THEOplayer SourceDescription object as a key in the customData of the LoadRequest. So something like
{sourceDescription: ${SourceDescription you want to cast}}.
Usage
First, set up your CastOptionsProvider:
package com.yourcomp.chromecastSender
import android.content.Context
import com.google.android.gms.cast.framework.CastOptions
import com.google.android.gms.cast.framework.OptionsProvider
import com.google.android.gms.cast.framework.SessionProvider
class THEOCastOptionsProvider : OptionsProvider {
override fun getCastOptions(context: Context): CastOptions =
CastOptions.Builder()
.setReceiverApplicationId(DEFAULT_APP_ID)
.build()
override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? = null
companion object {
const val DEFAULT_APP_ID = "8E80B9CE"
}
}
And link to it in your AndroidManifest.xml file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yourcomp.chromecastSenderApp">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
...
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.yourcomp.chromecastSender.CastOptionsProvider" />
</application>
</manifest>
Fill in the correct class name by replacing com.yourcomp.chromecastSender.CastOptionsProvider!
You can change the DEFAULT_APP_ID to direct to your own Chromecast app. Next you can actually do the casting like the following:
package com.yourcomp.chromecastSender
import android.app.Activity
import androidx.mediarouter.app.MediaRouteChooserDialog
import com.google.android.gms.cast.MediaInfo
import com.google.android.gms.cast.MediaLoadOptions
import com.google.android.gms.cast.framework.CastContext
import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.cast.framework.SessionManagerListener
import org.json.JSONObject
private const val SOURCE_URL =
"https://amssamples.streaming.mediaservices.windows.net/622b189f-ec39-43f2-93a2-201ac4e31ce1/BigBuckBunny.ism/manifest(format=mpd-time-csf)"
class ChromecastSender {
fun sendSourceToChromecast(context: Activity) {
val castContext = CastContext.getSharedInstance(context)
showCastChooserDialog(context, castContext)
val sourceDescriptionJson = JSONObject(
"""
{
"sourceDescription": {
"sources": [
{
"src": "$SOURCE_URL",
"type": "application/dash+xml",
"contentProtection": {
"widevine": {
"licenseAcquisitionURL": "https://amssamples.keydelivery.mediaservices.windows.net/Widevine/?KID=1ab45440-532c-4399-94dc-5c5ad9584bac"
}
}
}
]
}
}
""".trimIndent()
)
val mediaLoadOptions = MediaLoadOptions.Builder().setCustomData(sourceDescriptionJson).build()
val mediaInfo = MediaInfo.Builder(SOURCE_URL)
.setContentType("application/dash+xml")
.build()
castContext.sessionManager.addSessionManagerListener(
object : SessionManagerListener<CastSession> {
override fun onSessionStarting(castSession: CastSession) {}
override fun onSessionStarted(castSession: CastSession, sessionId: String) {
castSession.remoteMediaClient?.load(mediaInfo, mediaLoadOptions)
}
override fun onSessionStartFailed(castSession: CastSession, error: Int) {}
override fun onSessionEnding(castSession: CastSession) {}
override fun onSessionEnded(castSession: CastSession, error: Int) {}
override fun onSessionResuming(castSession: CastSession, sessionId: String) {}
override fun onSessionResumed(castSession: CastSession, wasSuspended: Boolean) {}
override fun onSessionResumeFailed(castSession: CastSession, error: Int) {}
override fun onSessionSuspended(castSession: CastSession, reason: Int) {}
},
CastSession::class.java
)
}
private fun showCastChooserDialog(context: Activity, castContext: CastContext) {
MediaRouteChooserDialog(context).apply {
routeSelector = castContext.mergedSelector!!
}.show()
}
}
Instantiate this class and then connect to a device. This will start casting the source listed in the class to the Chromecast receiver.