Build your own music streaming service with Amazon Alexa (2023)

Do you own a huge MP3 collection and you want to be able to listen it on your Alexa device? Are you an aspiring band and want to share your music with your fans for free? Or maybe you are just curious about how the Alexa Music Skill works.

Build your own music streaming service with Amazon Alexa (1)

In the following article I will try to explain how to build a simple music streaming service. You can find the complete source code here: https://github.com/andrei-ace/music-cloud

Your Amazon Alexa will be able to respond to commands like:

  • “Alexa, play music on skill name.”
  • “Alexa, play songs by artist name on skill name.”
  • “Alexa, play the song name on skill name.”

The songs are from your own private collection, no need to buy them again or pay a subscription. Sure, you can connect and stream from your phone like with any other bluetooth speakers, but where is the fun in that? You will miss all the vocal commands you can use with Alexa Music Skill.

Prerequisites

Step 1 — install all the tools you need

Step 2 — DynamoDB

Go to AWS Console and create a new table named cloud-music with primary key id of type String and a secondary index named artist_id-id-index with primary key artist_id and a Sort key named id:

Build your own music streaming service with Amazon Alexa (2)
Build your own music streaming service with Amazon Alexa (3)

Provision read and write capacity to not exceed 5 read and 5 write units. This will keep you in the AWS free tier.

Build your own music streaming service with Amazon Alexa (4)

Go to IAM and add “dynamodb:*” permissions for the ask user.

Step 3 — upload your MP3 files to Dropbox and create your music catalog

$ git clone https://github.com/andrei-ace/music-cloud
$ cd music-cloud/dropbox-catalog/
$ npm install
#edit .env.template with your Dropbox access token$ node index upload -d ./mp3/
$ node index.js catalog

You should see the list of your MP3 files:

Build your own music streaming service with Amazon Alexa (5)

The first command, for each MP3 file from the ./mp3/ directory it will:

  • read the ID3 tags — please make sure each file has at least the artist and the title
  • upload the file to Dropbox
  • create a shareable link
  • save the ID3 tags and the shareable link to the cloud-music table

The second command will create two files: artists.json and songs.json. These two files represent the catalogs which will be uploaded to Alexa and make it understand your music collection.

Step 4 — create your Alexa Skill

Go to Alexa Developer Console and create a new skill named “Music Cloud”. Choose the Music model and press Create skill button. Go to Build tab and press the Endpoint menu (left). Copy the skill id.

Step 5 — create your Lambda function

Go to AWS Lambda functions and create a new function named MusicCloudLambda as described here. Make sure your execution role contains permissions for accessing DynamoDB:

"Action": [
"dynamodb:BatchGetItem",
"dynamodb:PutItem",
"dynamodb:DeleteItem",
"dynamodb:GetItem",
"dynamodb:Scan",
"dynamodb:Query"
],
"Resource": "*"

It should look like this:

Build your own music streaming service with Amazon Alexa (7)

Copy the Lambda’s ARN (from the upper right corner: ARN — arn:aws:lambda:us-east-1:*:function:MusicCloudLambda) and go back to your Alexa Skill -> Build -> Endpoint and paste it into the Default endpoint field. Save.

Step 6 — deploy the skill code

Edit the .ask/config.template file with your skill id and lambda ARN. Rename the file to .ask/config. Deploy:

$ ask-cli deploy

Step 7 — upload the catalog files to Alexa

First, let’s create the artists catalog:

$ ask api create-catalog --catalog-type AMAZON.MusicGroup --catalog-title catalog-artists --catalog-usage AlexaMusic.Catalog.MusicGroup

Save the catalog id and associate it to your Alexa Skill.

$ ask api associate-catalog-with-skill -s YOUR-SKILL-ID-HERE -c YOUR-ARTISTS-CATALOG-ID-HERE

Replace the YOUR-SKILL-ID-HERE and YOUR-ARTISTS-CATALOG-ID-HERE with your skill and artist catalog id values.

Now let’s upload the artists.json file:

$ ask api upload-catalog -c YOUR-ARTISTS-CATALOG-ID-HERE -f ./artists.json

Save the upload id, you’ll need it later to check the status of the upload.

Build better voice apps. Get more articles & interviews from voice technology experts at voicetechpodcast.com

Now do the same for the song catalog:

$ ask api create-catalog --catalog-type AMAZON.MusicRecording --catalog-title catalog-songs --catalog-usage AlexaMusic.Catalog.MusicRecording$ ask api associate-catalog-with-skill -s YOUR-SKILL-ID-HERE -c YOUR-SONGS-CATALOG-ID-HERE$ ask api upload-catalog -c YOUR-SONGS-CATALOG-ID-HERE -f ./songs.json

Save the upload id, you’ll need it later.

Step 8 — wait for the catalogs to be processed

Use the upload ids for both artist and song catalog to query for the upload status.

$ ask api get-catalog-upload -c YOUR-SONGS-CATALOG-ID-HERE -u YOUR-SONGS-UPLOAD-ID-HERE$ ask api get-catalog-upload -c YOUR-ARTISTS-CATALOG-ID-HERE -u YOUR-ARTISTS-UPLOAD-ID-HERE

Only after the ER_INGESTION step succeeds you can issue commands in the Test Console.

Build your own music streaming service with Amazon Alexa (8)

You can find more about catalogs here.

Step 9— test your Alexa Skill

Go to Alexa Developer Console -> Music Cloud skill -> Test tab and issue some test commands. If everything worked you should see something like this:

Don’t worry if you see the warning: “AudioPlayer is currently an unsupported namespace.” in the test console, that is normal. You will be able to listen to your songs on a real device like an Amazon Echo (or similar) that is linked with your developer account.

Catalog

There are 6 types of catalogs:

Build your own music streaming service with Amazon Alexa (10)

In our example we created catalogs just for the first two types — artists and songs.

An artist catalog looks like:

{...
"entities":[
{
"id":"g5NYvQMbvrqv76x+ItEErv5MJpE=",
"names":[
{
"language":"en",
"value":"SemMueL"
}
],
"popularity":{
"default":100
},
"lastUpdatedTime":"2019-10-08T14:51:23.326Z",
"deleted":false
}
]
}

A song catalog looks like:

{...
"entities":[
{
"id":"wuoQvgudnob9GJeKtqQxrAovVtY=",
"names":[
{
"language":"en",
"value":"Back in Time (Feat: Dylan Anthony Clark, Breanne Ponack)"
}
],
"popularity":{
"default":100
},
"lastUpdatedTime":"2019-10-08T14:51:18.849Z",
"artists":[
{
"id":"g5NYvQMbvrqv76x+ItEErv5MJpE=",
"names":[
{
"language":"en",
"value":"SemMueL"
}
]
}
],
"albums":[],
"deleted":false
}
]
}

Alexa Music Skill API

There are 4 types of requests that are mandatory for any music skill:

  • GetPlayableContent — this request is sent when a user requests content to be played from your skill. If a user says: “Alexa, play It’s my life by Bon Jovi on music skill name” your skill will need to return the ContentId of that track as listed in your Amazon.MusicRecording catalog. If no entry can be found, an error message needs to be returned.
  • Initiate — is sent when Alexa is ready for immediate playback of content obtained using a GetPlayableContent request. Alexa will send the ContentId and the skill responds with the stream URI.
  • GetNextItem — is sent when a content queue was created, playback has started and Alexa needs the next item to buffer/enqueue for smooth song transition or if the user skipped the current item.
  • GetPreviousItem — is sent when the content is playing and the user requests for the previous item.

GetPlayableContent

The skill needs to respond to three types of requests:

  • “Alexa, play music on Music Cloud”
  • “Alexa, play songs by artist name on Music Cloud”
  • “Alexa, play song name on Music Cloud”

For the first type of request the selection criteria will look like:

"selectionCriteria": {
"attributes": [
{
"type": "MEDIA_TYPE",
"value": "TRACK"
}
]
}

The Music Cloud skill will return a random item from the DynamoDB table.

For the second type the selection criteria will look like:

"selectionCriteria": {
"attributes": [
{
"type": "ARTIST",
"entityId": "A2"
},
{
"type": "MEDIA_TYPE",
"value": "TRACK"
}
]
}

The Music Cloud skill will return a random song by the requested artist.

And lastly:

"selectionCriteria": {
"attributes": [
{
"type": "TRACK",
"entityId": "138545995"
},
{
"type": "MEDIA_TYPE",
"value": "TRACK"
}
]
}

The skill will return the exact song with the ContendId equal with the requested entityId.

Initiate

The important part from the Initiate request is:

"payload": {
"filters": {
"explicitLanguageAllowed": true
},
"contentId": "1021012f-12bb-4938-9723-067a4338b6d0",
"playbackModes": {
"shuffle": false,
"loop": false
}
}

The skill will need to respond with a playable stream:

"playbackMethod": {
"type": "ALEXA_AUDIO_PLAYER_QUEUE",
"id": "Queue-Id",
"rules": {
"feedback": {
"type": "PREFERENCE",
"enabled": true
}
},
"firstItem": {
"id": "1021012f-12bb-4938-9723-067a4338b6d0",
"playbackInfo": {
"type": "DEFAULT"
},
"metadata": {
"type": "TRACK",
"name": {
"speech": {
"type": "PLAIN_TEXT",
"text": "jeremy"
},
"display": "Jeremy"
},
"art": {}
},
"controls": [
{
"type": "COMMAND",
"name": "NEXT",
"enabled": true
}
],
"rules": {
"feedbackEnabled": true
},
"stream": {
"id": "STREAMID_92_14629004",
"uri": "https://cdn.example.com/api/1/a2f318467fbf2829996adc0880e0abd03d03b1ba6ac.mp3",
"offsetInMilliseconds": 0,
"validUntil": "2020-05-10T19:11:35Z"
},
"feedback": {
"type": "PREFERENCE",
"value": "POSITIVE"
}
}
}

GetNextItem

This will return a random song. The response data is similar with the Initiate response.

GetPreviousItem

This will return an error as the queue is not persisted by the skill at this point.

Some ideas for improvement:

  • Add other types of catalogs (genre, playlists like: top 100 songs this week, etc)
  • Improve the voice modelling by adding more and better data in the catalogs. An example would be to provide alternative names for artists, spell out numbers and non-alphabetic characters
  • Track user playlists and song popularity
  • Create a music recommendation system (maybe using TensorFlow)
Top Articles
Latest Posts
Article information

Author: Tish Haag

Last Updated: 03/04/2023

Views: 6107

Rating: 4.7 / 5 (67 voted)

Reviews: 82% of readers found this page helpful

Author information

Name: Tish Haag

Birthday: 1999-11-18

Address: 30256 Tara Expressway, Kutchburgh, VT 92892-0078

Phone: +4215847628708

Job: Internal Consulting Engineer

Hobby: Roller skating, Roller skating, Kayaking, Flying, Graffiti, Ghost hunting, scrapbook

Introduction: My name is Tish Haag, I am a excited, delightful, curious, beautiful, agreeable, enchanting, fancy person who loves writing and wants to share my knowledge and understanding with you.