In this step, we will flesh out our podcast player and allow the user to pause and resume the audio file.
- On Amazon Alexa
- On Google Assistant
- Next Step
Currently, our podcast player can only start playing audio files, nothing else. It's time to change that. We will start with Amazon since they provide us with built-in intents, which we can use as a guideline later on.
The built-in intents for playback control are:
Two of these built-in intents,
AMAZON.ResumeIntent, are required, the other intents are technically not, but these intents can still be invoked by our user, so we should, as Amazon says, handle the situation gracefully and return a short response, explaining that the command is not supported, otherwise we will run into errors.
Before we can work with the AudioPlayer interface on an Alexa device, we have to prepare one more thing. As I said two of these intents are required, because of that, an Alexa Skill, that has the AudioPlayer interface enabled, has to have both intents in its language model as well. Instead of using the Alexa Developer Portal to add those intents, we will use the Jovo Language Model, which allows us to maintain a single file, that will be used to create the platform specific language models.
We can find the language model file in the
/models folder of our Jovo project:
Here's its default state:
Right next to the other Alexa built-in intents inside the
alexa object, which is used to add platform-specific intents and input types, we will add the
AMAZON.ResumeIntent in the same format:
The content of each platform object will be used to extend the language model defined in the platform-independent part.
We can also change the invocation name to
my podcast player:
Now that our preparation are done, we can use the Jovo Language Model to create the platform specific files and deploy them to the Amazon Developer Console right after:
This was just a small sneak peek into the Jovo Language Model. We will use the it again in one the next steps, where we will go more in depth.
After we have updated our language model, we need to add the intents to the logic of the code:
Open up the
app.js file inside your
src/ folder and add the
AMAZON.PauseIntent intent to our handler.
Every time the intent is called we want to pause the audio stream by sending out a stop directive (learn more in the official reference by Amazon):
To test it out we run our Jovo Webhook and say Alexa, start my podcast player to launch the app with our Amazon Echo. After the audio started playing, we just say Alexa, pause to invoke the
That's it. We have successfully paused the audio file.
Alright, our user can now pause the audio, but now they also have to be able to resume where they left off. That's what the second required built-in
AMAZON.ResumeIntent is for.
As we learned at the beginning of the course, we can specify the point at which the audio stream should start playing using the
offset variable. To let the user resume, we simply save the offset at the time at which they stop the audio in a database, so we can retrieve the offset and use it in our
ResumeIntent to start the audio back at the correct spot.
For this, we have to do the following steps:
- An Introduction to Databases in Jovo
- Updating the PlaybackStopped Request Handler
- Saving and Retrieving the Current Audio File
As the session is closed after the
PauseIntent, we have to find a way to persist data across sessions. This is where the Jovo Database Integrations can be helpful.
The default databse is File DB for local development and prototyping. Jovo will save the data inside a
JSON file, which we can find in our project's root folder under
db/db.json. To save and load data we use Jovo Framework's user class:
Later on, when you prepare to launch your application and host your app on e.g. AWS Lambda, you have switch to a different database, e.g. DynamoDB. Find all supported databases here.
The most convenient way to save the offset is with the help of the
The request will be sent if:
- we stop the current stream and start a new one,
- we stop the audio stream altogether,
- the user pauses the current stream,
- the user makes any type of other voice requests, which will pause the audio for the moment. It will resume after the interaction has ended.
JSON request will contain the data we need:
We save the offset to our database using one of
$audioPlayer class's built-in methods:
Now we add the
AMAZON.ResumeIntent to our handler and retrieve the
offset from the database.
But, there's one more thing missing. How do we know, which audio file to stream? We have to not only save the
offset, but the current audio files URL as well.
The first step is to save the current episode before we send out the first play directive:
Besides that, we have to remember that we enqueue the next song, which we have to save as the current episode after the first one finished playing. For that we save the audio file, which we enqueue, as the
nextEpisode and switch out
nextEpisode as soon as the audio stream finishes, which we get notified about with the
Now we can finish implementing the
AMAZON.ResumeIntent. Simply retrieve the current episode from the database and send out a play directive using that and the
To test it out, simply pause the audio stream at some point and restart it with Alexa, resume.
There are still quite many built-in intents remaining. For now we will simply tell the user that these are not implemented and revisit at least two of them at a later point:
Here's the deal: Implementing a resume and pause intent the same way won't work here. First of all, pausing an audio stream is handled by Google, so those requests don't reach our app's code. Resuming an audio stream at a certain point won't work either, because we can't specify the offset as we did with Alexa.
But, there's one thing we can do. Instead of starting with the very first audio file every time, we will automatically start playing the audio file the user last listened to.
To do that, we have to additionally save the current episode in the
Now we can check at our
LAUNCH intent if the request is from a new user, if that's the case we start with the first track, otherwise we stream the most recently listened one:
As you can see, for the Google Action we still need to find a way to use different
title parameters for different episodes. We will look into this in a later step.
Wow, that was quite a long step, but we can now successfully pause and resume episodes. Our handler should look like this:
In the next step, we will build a system to store and retrieve the episodes of our podcast.