question

newuser-57c12c65-9ebe-4fce-a019-f6f1f5b5df67 avatar image

Very Simple AudioPlayer Lambda Code to play a hosted MP3 on a server

Hello All

I tried for weeks to just play a MP3 file from my Amazon Echo, saying

"Alexa, launch welcome me"

I wanted Amazon Echo to play a MP3 file hosted on a https server.


I tried to find a sample code for AWS Lambda but they don't work at all,

Anyone has it already ?


Thanks

audioplayermusic skills
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Anand@Amazon avatar image
Anand@Amazon answered

Hey there,

Thanks for reaching out to us !!

We have audio player sample code which you can use to build to your skill. Remember this code uses DynamoDB database so you need to provide permission to your lambda function to use it.

You can also share the error message you are getting with your current skill with us for any help.

10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Andy Whitworth avatar image
Andy Whitworth answered

In your response the the launch intent, return the following SSML:


<speak><audio src="https://URL_OF_YOUR_MP3" /></speak>

Note:

  • The MP3 must be hosted at an Internet-accessible HTTPS endpoint. HTTPS is required, and the domain hosting the MP3 file must present a valid, trusted SSL certificate. Self-signed certificates cannot be used.
  • The MP3 must not contain any customer-specific or other sensitive information.
  • The MP3 must be a valid MP3 file (MPEG version 2).
  • The audio file cannot be longer than 240 seconds.
  • The bit rate must be 48 kbps. Note that this bit rate gives a good result when used with spoken content, but is generally not a high enough quality for music.
  • The sample rate must be 22050Hz, 24000Hz, or 16000Hz.

The last two are common reasons why audio doesn't play

From: https://developer.amazon.com/docs/custom-skills/speech-synthesis-markup-language-ssml-reference.html#audio


10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

newuser-57c12c65-9ebe-4fce-a019-f6f1f5b5df67 avatar image
newuser-57c12c65-9ebe-4fce-a019-f6f1f5b5df67 answered

Hello


Thanks for your quick answer.

I tried this code put on my index.js on my Lambda AWS folder


const Alexa = require('ask-sdk-core');

const soundURL = 'https://xxx.test.com/file.mp3';
let expectedPreviousToken = '';

const LaunchRequestHandler = {
    canHandle(handlerInput) {
      return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
    },
    handle(handlerInput) {

    expectedPreviousToken = 'sometoken' + Math.random();
    return handlerInput.responseBuilder
     .speak('start playing sound')
     .addAudioPlayerPlayDirective('REPLACE_ALL', soundURL, expectedPreviousToken, 0, null)
     .withSimpleCard('Example', 'Example')
     .getResponse();
    }
};

const StartSoundHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest'
        && handlerInput.requestEnvelope.request.intent.name === 'StartSoundHandler';
    },
    handle(handlerInput) {

     expectedPreviousToken = 'sometoken'+Math.random();
     return handlerInput.responseBuilder

     .addAudioPlayerPlayDirective
              ('REPLACE_ALL', soundURL, expectedPreviousToken, 0, null)
     .withSimpleCard('Example', 'Example')
     .getResponse();
    }
};


const ExitHandler = {
    canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;

    return request.type === 'IntentRequest' &&
        (request.intent.name === 'AMAZON.StopIntent' ||
        request.intent.name === 'AMAZON.CancelIntent');
    },
    handle(handlerInput) {
        return handlerInput.responseBuilder
        .addAudioPlayerStopDirective()
        .getResponse();
    }
};

const SessionEndedRequestHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest';
    },
    handle(handlerInput) {
        //any cleanup logic goes here
        return handlerInput.responseBuilder.getResponse();
    }
};

const PausePlaybackHandler = {
    canHandle(handlerInput) {

    const request = handlerInput.requestEnvelope.request;

    return request.type === 'IntentRequest' &&
        request.intent.name === 'AMAZON.PauseIntent';
    },
    handle(handlerInput) {
        return handlerInput.responseBuilder
            .speak('Sound is paused.')
            .addAudioPlayerStopDirective()
            .withSimpleCard('Example', 'Bye!')
            .getResponse();
    },
};


const AudioPlayerEventHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;

        return request.type === 'AudioPlayer.PlaybackStarted' ||
            request.type === 'AudioPlayer.PlaybackStopped' ||
            request.type === 'AudioPlayer.PlaybackNearlyFinished' ||
            request.type === 'AudioPlayer.PlaybackFailed';
    },
    handle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;

        switch (request.type) {

         case 'AudioPlayer.PlaybackStarted':
           expectedPreviousToken = request.token;
           return handlerInput.responseBuilder
             .getResponse();

         case 'AudioPlayer.PlaybackFinished':
          return handlerInput.responseBuilder
          .getResponse();

         case 'AudioPlayer.PlaybackStopped':
             return handlerInput.responseBuilder
             .getResponse();

         case 'AudioPlayer.PlaybackNearlyFinished':

           return handlerInput.responseBuilder
              .addAudioPlayerPlayDirective
                       ('ENQUEUE', soundURL, 'sometoken', 0, expectedPreviousToken)
               .getResponse();

         case 'AudioPlayer.PlaybackFailed':
             console.log('Playback Failed');
             break;
        }

        return handlerInput.responseBuilder.getResponse();
    },
};

const ErrorHandler = {
    canHandle() {
        return true;
    },
    handle(handlerInput, error) {
        console.log(`Error handled: ${error.message}`);

        return handlerInput.responseBuilder
            .getResponse();
    }
};


exports.handler = Alexa.SkillBuilders.custom()
    .addRequestHandlers(
        LaunchRequestHandler,
        StartSoundHandler,
        ExitHandler,
                SessionEndedRequestHandler,
        PausePlaybackHandler,
        AudioPlayerEventHandler)
    .addErrorHandlers(ErrorHandler)
    .lambda();


I tested in AWS Lambda, I receive a Success when testing with this :


{
  "version": "1.0",
  "response": {},
  "userAgent": "ask-node/2.0.0 Node/v8.10.0"
}

Request ID:
"bc1b040a-c660-42f6-b882-76065ed33aa2"

Function Logs:
START RequestId: bc1b040a-c660-42f6-b882-76065ed33aa2 Version: $LATEST
2019-09-09T10:36:27.877Z    bc1b040a-c660-42f6-b882-76065ed33aa2    Error handled: Cannot read property 'type' of undefined
END RequestId: bc1b040a-c660-42f6-b882-76065ed33aa2
REPORT RequestId: bc1b040a-c660-42f6-b882-76065ed33aa2    Duration: 428.97 ms    Billed Duration: 500 ms    Memory Size: 128 MB    Max Memory Used: 65 MB    Init Duration: 47.12 ms    
XRAY TraceId: 1-5d762b2b-c868376e2363fc99e0e960b7    SegmentId: 6269459548437ed5    Sampled: false    

And when trying to invoke it from the Alexa developper console, it doesn't work at all.


Any idea ?


What I would like to do is just play an MP3 file. I saw your sample code but it is complicated, I would like a very very simple MP3 player


Thanks



1 comment
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Andy Whitworth avatar image Andy Whitworth commented ·

AudioPlayer is complete overkill for what you have said you want to achieve. Try my SSML suggestion.

0 Likes 0 ·