14

I'm trying to get the new streaming audio API going. Is the following response valid? I'm getting a "there was a problem with the skill" error when I test it on my device.

Here is the code for my AWS-lambda function:

def lambda_handler(event, context):
    return {
        "response": {
            "directives": [
                {
                    "type": "AudioPlayer.Play",
                    "playBehavior": "REPLACE_ALL",
                    "audioItem": {
                        "stream": {
                            "token": "12345",
                            "url": "http://emit-media-production.s3.amazonaws.com/pbs/the-afterglow/2016/08/24/1700/201608241700_the-afterglow_64.m4a",
                            "offsetInMilliseconds": 0
                        }
                    }
                }
            ],
            "shouldEndSession": True
        }
    }
Paul R
  • 208,748
  • 37
  • 389
  • 560
maxymoo
  • 35,286
  • 11
  • 92
  • 119
  • Hey, I looked at the API. They have a sample message that *appears* to be very similar to what you want, but there are more fields to identify `header` and `payload`. The API is [here](https://developer.amazon.com/public/solutions/alexa/alexa-voice-service/reference/audioplayer) and the message is in the 'sample message section'. If you use that formating, do you still get the error? – Liam Kelly Aug 29 '16 at 00:10
  • just tried that, didn't seem to help – maxymoo Aug 30 '16 at 05:38
  • 1
    This does work with HTTPS, however, how do you get it to stop? Cancel and Stop commands do not work once the stream is started. – Fastmover Jun 12 '17 at 21:27
  • Stop works for me (i think it just quits the skill), if you want to handle other intents you'll have to write custom handlers for them – maxymoo Jun 12 '17 at 23:20

3 Answers3

19

The following code worked for me:

def lambda_handler(event, context):
    return {
        "response": {
            "directives": [
                {
                    "type": "AudioPlayer.Play",
                    "playBehavior": "REPLACE_ALL",
                    "audioItem": {
                        "stream": {
                            "token": "12345",
                            "url": "https://emit-media-production.s3.amazonaws.com/pbs/the-afterglow/2016/08/24/1700/201608241700_the-afterglow_64.m4a",
                            "offsetInMilliseconds": 0
                        }
                    }
                }
            ],
            "shouldEndSession": True
        }
    }
]

The only difference is that the URL is https rather than http.

Don't be put off if it doesn't work in the skill simulator. That hasn't been upgraded yet to work with streaming audio. You won't even see your directives there. But it should work when used with your device.

maxymoo
  • 35,286
  • 11
  • 92
  • 119
Joseph Jaquinta
  • 2,118
  • 17
  • 15
  • This is great thank you so much! How did you know to try this? – maxymoo Sep 03 '16 at 22:38
  • 1
    Well, at first I thought it was because it was missing the normal header, output text, and stuff like that. So I went through a lot of cycles before I eventually got a message on the hardware device saying something about it needing to be https. Once that worked, I took out, step by step, all the other stuff I added in until I was left with this. So it looks like I just added one character. But it took me a long time to work out which character. :-) Thanks for the points! – Joseph Jaquinta Sep 04 '16 at 00:08
  • where did you see the message on the hardware device? this would help me so much if I could see errors logged somewhere! – maxymoo Sep 18 '16 at 03:18
  • Alexa is extremely poor about communicating errors. I think I mispoke when I said "*on* the hardward device". What I should have said is "displayed in the companion app". Occasionally it puts something useful there. But, since it is a consumer device, the messages are more often vague and non-technocal. – Joseph Jaquinta Sep 18 '16 at 13:06
  • ah cool, i'll keep an eye on that, yeah it makes development a real challenge eh! – maxymoo Sep 18 '16 at 22:50
  • @JosephJaquinta, i tried this piece of code and testing it on simulator as well as https://echosim.io/ It didn't work on both. As you mentioned, it'll not work on simulator but is it the same case with echoism? – Fayza Nawaz Oct 19 '16 at 09:04
  • It will not work on echoism either, hence it being a simulator. – Fastmover Jun 12 '17 at 21:26
  • Does anyone know if this code is valid for .m3u8 HLS audio stream? – neowinston Jul 27 '17 at 14:06
4

We created a really simple project on Github that shows the easiest possible way to use the AudioPlayer:
https://github.com/bespoken/super-simple-audio-player

We also created a writeup for it here:
https://bespoken.tools/blog/2017/02/27/super-simple-audioplayer

The project shows how to play a track, as well pausing and resuming.

Here is the code that shows the actual playing of an audio file:

SimplePlayer.prototype.play = function (audioURL, offsetInMilliseconds) {
    var response = {
        version: "1.0",
        response: {
            shouldEndSession: true,
            directives: [{
                type: "AudioPlayer.Play",
                playBehavior: "REPLACE_ALL", // Setting to REPLACE_ALL means that this track will start playing immediately
                audioItem: {
                    stream: {
                        url: audioURL,
                        token: "0", // Unique token for the track - needed when queueing multiple tracks
                        expectedPreviousToken: null, // The expected previous token - when using queues, ensures safety
                        offsetInMilliseconds: offsetInMilliseconds
                    }
                }
            }]
        }
    }

    this.context.succeed(response);
};
John Kelvie
  • 858
  • 1
  • 7
  • 16
0

A program should return some response on "LaunchRequest" and "SessionEndedRequest" otherwise you will get "There was a problem with the requested skills repsonse".

You need to add intent "PlayMusic" and change url of the file.

P.S. I am not sure which version should be in build_audio_response function, I got the json from here

def build_audio_response(url):
    return {
        "version": "1.01",
        "response": {
            "directives": [
                {
                    "type": "AudioPlayer.Play",
                    "playBehavior": "REPLACE_ALL",
                    "audioItem": {
                        "stream": {
                            "token": "12345",
                            "url": url,
                            "offsetInMilliseconds": 0
                        }
                    }
                }
            ],
            "shouldEndSession": True
        }
    }

def handle_session_end_request():
    return {
        "version": "1.0",
        "response": {
            "shouldEndSession": True
        }
    }

def play_music(intent, session):
    url = "https://s3-eu-west-1.amazonaws.com/bucket/filename.mp3"
    return build_audio_response(url, should_end_session=True)

def on_intent(intent_request, session):
    """ Called when the user specifies an intent for this skill """

    intent = intent_request['intent']
    intent_name = intent_request['intent']['name']

    if intent_name == "PlayMusic":
        return play_music(intent, session)
    elif intent_name == "AMAZON.CancelIntent" or intent_name == "AMAZON.StopIntent":
        return handle_session_end_request()
    else:
        raise ValueError("Invalid intent")

def lambda_handler(event, context):
    if event['request']['type'] == "LaunchRequest":
        return {
            "version": "1.0",
            "response": {
                "shouldEndSession": False
            }
        }
    elif event['request']['type'] == "IntentRequest":
        return on_intent(event['request'], event['session'])
    elif event['request']['type'] == "SessionEndedRequest":
        return handle_session_end_request()
armicron
  • 289
  • 2
  • 7