The powerful combination of voice and Fire TV allows your customers to use speech to interact with their living room environment and enjoy a new level of convenience. In this blog post, we’ll introduce you to the Media Session API to enable voice control on media apps on Fire TV. With MediaSession, your customers can play, pause, skip forward, or rewind content with their voice.
Step 1
Start by adding the following permission in your Android manifest file:
<uses-permission android:name="com.amazon.permission.media.session.voicecommandcontrol" />
Step 2
Create and initialize a Media Session. See Using a media session for more details.
Step 3
Broadcast the actions supported by your app’s media session. Here is a sample implementation:
PlaybackStateCompat state = new PlaybackStateCompat.Builder()
.setActions(PlaybackState.ACTION_PLAY_PAUSE
| PlaybackState.ACTION_PLAY
| PlaybackState.ACTION_PAUSE
| PlaybackState.ACTION_FAST_FORWARD
| PlaybackState.ACTION_REWIND
| PlaybackState.ACTION_SKIP_TO_NEXT
| PlaybackState.ACTION_SKIP_TO_PREVIOUS)
Tip: Android also recommends tracking the current state of the playback at all times along with the current position and current time. This helps address a lag between the last updated position and the time when the voice command was issued. It also becomes important in case of SeekTo, where the playback needs to remember the last position it was paused and then accurately needs to calculate how much further it needs to move based on the last updated location and considering the delta time lapse. Additionally, whenever the app state changes, it should call setPlaybackState() to update its latest state:
.setState(curState, PLAYBACK_POSITION_UNKNOWN, 1.0f)
.build();
mMediaSession.setPlaybackState(state);
Step 4
Implement the Media Session Callback methods. Here is a sample implementation:
private MediaSession.Callback getMediaSessionCallback() {
return new MediaSession.Callback() {
@Override
public void onPlay() {
logState("Received Play command through voice directive");
//boolean to check if the command was issued through voice
resumeVideo(true);
}
@Override
public void onPause() {
logState("Received Pause command through voice directive");
//boolean to check if the command was issued through voice
pauseVideo(true);
}
/**
* This method keeps track of whether a play/resume command was assigned through
* the media session.
* @param onResumeMediaSessionCommand boolean which determines
* whether the resume command came through the media session
*/
private void resumeVideo(boolean onResumeMediaSessionCommand) {
if (onResumeMediaSessionCommand) {
mPauseStateAssigned = false;
}
mPlaybackState = PlaybackState.STATE_PLAYING;
Log.i(TAG, "resumeVideo: this method is triggered as a directive is given");
mVideo.start();
startPlaybackReportingService();
}
/* Keeps track of whether a pause command was assigned through
* the media session.
*
*@param onPauseMediaSessionCommand boolean which determines
* whether the pause command came through the media session
*/
private void pauseVideo(boolean onPauseMediaSessionCommand) {
if (onPauseMediaSessionCommand) {
mPauseStateAssigned = true;
}
Log.i(TAG, "pause Video - This is pause directive passed through voice");
// Pause the video player
mPlaybackState = PlaybackState.STATE_PAUSED;
mVideo.pause();
stopPlaybackReportingService();
updatePlaybackState(mPlaybackState, mVideo.getCurrentPosition(),1.0f );
}
Tip: Alexa responds to SeekTo for rewind and fast-forward actions, like fast-forward/rewind by 10 seconds (the default) or fast-forward/rewind by duration. In addition to SeekTo, if your app has separate callback methods for fast-forward/rewind, you can still continue to use it in the app.
Here is a sample implementation:
/*Implements fast forward and rewind scenarios for Alexa */
@Override
public void onSeekTo(int time) {
logState("Current position is "
+ mVideo.getCurrentPosition() +
" milliseconds. Received SEEK_TO to " + time + " milliseconds.");
seekTo(time);
}
private void seekTo(int time) {
if (!mIsActivityForeground) {
log("Seek event dropped as activity is not in foreground");
return;
}
int targetTime = mMediaPlayer.getCurrentPosition() + time;
targetTime = Math.max(0, targetTime);
mMediaPlayer.seekTo(targetTime);
log("Seeking to: " + targetTime);
}
Methods such as onSkipToNext() and onSkipToPrevious() are optional, but good to have in case you have episodic or rows of video content in your app. Your customer can use utterances like “skip to next/preview” to move through the list of videos.
Step 5: Run and test the sample app
You can download the sample app from here (you need a Fire TV and a Fire TV remote to test this app). Once installed, open the app and use the connected remote to test the utterances below.
What to test
Test for the following playback directives by using the following – “Alexa....”
Additional notes
As per Android’s best practices, all the media streaming apps must adhere to the audio focus guidelines at all times. Please refer to Managing audio focus and Multimedia app guidelines for more details.
Reference reading