The Android TV Receiver SDK provides the ability to transfer a stream into and from
your native Android TV Receiver app. Note that stream transferring into your native
app will not work if your app has a
LaunchRequestChecker
that checks whether credentials data is valid, because the
CredentialsData
is empty in the launch request.
Transferring into native Android TV Receiver apps
Similar to load requests, stream transfer requests are passed to your app via intents.
You should first add the following intent filter to your AndroidManifest.xml:
<activity android:name="com.example.PlayerActivity">
<intent-filter>
<action android:name="com.google.android.gms.cast.tv.action.RESUME_SESSION"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
If you are calling MediaManager#onNewIntent(Intent)
for load intents already, you don’t need to do anything additional to forward
stream transfer intents to MediaManager
.
Next, override MediaCommandCallback#onResumeSession()
to handle the load
request:
public MyMediaCommandCallback extends MediaLoadCommandCallback {
@Override
public Task<MediaLoadRequestData> onResumeSession(
String senderId, MediaResumeSessionRequestData mediaResumeSessionRequestData) {
return Tasks.call(() -> {
// Extract the load request data from the request.
MediaLoadRequestData loadRequestData =
mediaResumeSessionRequestData.getSessionState().getLoadRequestData();
// Resolve the entity into your data structure and load media.
MediaInfo mediaInfo = loadRequestData.getMediaInfo();
// Fill in any missing parts of the mediaInfo.
myFillMediaInfo(new MediaInfoWriter(mediaInfo));
// Use the mediaInfo to load the content with your player.
myPlayerLoad(mediaInfo.getContentUrl());
// Update media metadata and state (this clears all previous status
// overrides).
castReceiverContext.getMediaManager()
.setDataFromLoad(loadRequestData);
…
// Broadcast an updated media status.
castReceiverContext.getMediaManager().broadcastMediaStatus();
// Return the resolved MediaLoadRequestData to indicate load success.
return loadRequestData;
});
}
Transferring out from Android TV Receiver apps
To transfer from your Android TV Receiver app to another device, declare
MediaStatus#COMMAND_STREAM_TRANSFER
in your supported media commands and handle the
MediaCommandCallback#onStoreSession()
method:
// Declare outward stream transfer is supported.
CastReceiverContext
.getInstance()
.getMediaManager()
.getMediaStatusModifier()
.setMediaCommandSupported(MediaStatus.COMMAND_STREAM_TRANSFER, true);
For the MediaCommandCallback#onStoreSession()
, there are three options:
1. Do not provide any implementation and the SDK will default to providing the
current SessionState
from the MediaStatus
.
2. Use the default SessionState
generated by the SDK using the MediaStatus
to create a new StoreSessionResponseData
.
// Handle storing the session state for stream transfer.
public class MyMediaCommandCallback extends MediaCommandCallback {
/** Callback for storing the session state. */
@Override
public Task<StoreSessionResponseData> onStoreSession(
String senderId, int type, StoreSessionRequestData requestData) {
return super
.onStoreSession(senderId, requestData)
.continueWith((responseData)
-> myProcessStoreSessionResponseData(responseData));
}
}
private StoreSessionResponseData myProcessStoreSessionResponseData(
Task<StoreSessionResponseData> defaultResponseTask) throws Exception {
if (!defaultResponseTask.isSuccessful()) {
throw defaultResponseTask.getException();
}
StoreSessionResponseData ssrd = defaultResponseTask.getResult();
SessionState originalSessionState = ssrd.getSessionState();
MediaLoadRequestData originaLoadRequestData =
originalSessionState.getLoadRequestData();
// Copy originalLoadRequestData and update fields as needed.
MediaLoadRequestData mediaLoadRequestData =
new MediaLoadRequestData.Builder(originaLoadRequestData)
...
.build();
SessionState sessionState = new SessionState.Builder()
.setLoadRequestData(mediaLoadRequestData)
.setCustomData(originalSessionState.getCustomData())
.build();
StoreSessionResponseData responseDataBuilder =
new StoreSessionResponseData.Builder()
.setSessionState(sessionState)
.setCustomData(ssrd.getCustomData())
.build();
return responseDataBuilder.build();
}
3. Generate your own SessionState
from scratch:
// Handle storing the session state for stream transfer.
public class MyMediaCommandCallback extends MediaCommandCallback {
/** Callback for storing the session state. */
@Override
public Task<StoreSessionResponseData> onStoreSession(
String senderId, int type, StoreSessionRequestData requestData) {
SessionState sessionState = myGenerateSessionState();
return Tasks.forResult(
new StoreSessionResponseData.Builder()
.setSessionState(sessionState)
.build());
}
}
private SessionState myGenerateSessionState() {
MediaLoadRequestData mediaLoadRequestData =
new MediaLoadRequestData.Builder()
.setMediaInfo(mMediaManager.getCurrentMediaStatus().getMediaInfo())
.setCurrentTime
(mMediaManager.getCurrentMediaStatus().getStreamPosition())
.setCustomData(mCustomData)
.setAutoplay(true)
.build();
SessionState sessionState = new SessionState.Builder()
.setLoadRequestData(mediaLoadRequestData)
.build();
return sessionState;
}
The SessionState
class contains:
- A
MediaLoadRequestData
field, indicating the current media status, including the media, the current playback state, and the queue. - An optional
customData
field, where you can put additional information into aJSONObject
.
The SessionState
class should be encapsulated into a
StoreSessionResponseData
object, and it will be sent to the transferee in a ResumeSessionRequestData
.