When developing on the Alexa, using:
var audioUrl = Util.getS3PreSignedUrl("Media/001.mp3").replace(/&/g,'&');`
I can play an mp3 audio clip using an SSML tag and yet keep the mp3 private, by storing it in an Alexa-hosted S3 bucket (and locking down the permissions to it):
output1+=audio001[currentTrack]+<audio src="${audioUrl1}"/>
+moreInstructions; // AND
return handlerInput.responseBuilder .speak(output1) .reprompt(moreInstructions) .getResponse();
However, I can't seem to follow the same approach for an mp4 / video format. It seems that using Alexa Presentation Language (APL), you have to store your videos publically on the internet. I have tried to use the pre-signed Utility function for the Mp4 video, but it doesn't seem to work ...
I tried the following:
const Alexa = require('ask-sdk-core');
const Util = require('./util.js');
const DOCUMENT_ID = "VideoDocument";
var videoUrl = Util.getS3PreSignedUrl("Media/safari.mp4").replace(/&/g,'&');
const datasource = {
"videoPlayerTemplateData": {
"type": "object",
"properties": {
"backgroundImage": "https://d2o906d8ln7ui1.cloudfront.net/images/response_builder/background-green.png",
"displayFullscreen": true,
"headerTitle": "xxx",
"headerSubtitle": "xxx",
"logoUrl": "xxx,
"videoControlType": "skip",
"videoSources": [
// "https://d2o906d8ln7ui1.cloudfront.net/videos/AdobeStock_277864451.mov", "https://d2o906d8ln7ui1.cloudfront.net/videos/AdobeStock_292807382.mov", videoUrl ], "sliderType": "determinate" } } };
const LaunchRequestHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest';
},
handle(handlerInput) {
const speakOutput = 'Welcome, you can say Hello or Help. Which would you like to try?';
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakOutput)
.getResponse();
}
};
const createDirectivePayload = (aplDocumentId, dataSources = {}, tokenId = "documentToken") => {
return {
type: "Alexa.Presentation.APL.RenderDocument",
token: tokenId,
document: {
type: "Link",
src: "doc://alexa/apl/documents/" + aplDocumentId
},
datasources: dataSources
}
};
const SampleAPLRequestHandler = {
canHandle(handlerInput) {
// handle named intent
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'HelloWorldIntent';
},
handle(handlerInput) {
if (Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)['Alexa.Presentation.APL']) {
// generate the APL RenderDocument directive that will be returned from your skill
const aplDirective = createDirectivePayload(DOCUMENT_ID, datasource);
// add the RenderDocument directive to the responseBuilder
handlerInput.responseBuilder.addDirective(aplDirective);
}
// send out skill response
return handlerInput.responseBuilder.getResponse();
}
};
It works if videoURL is set to a string or a URL of a publically hosted mp4 video, but not if it points to the pre-signed URL for an mp4 video from an S3 bucket.
The
.replace(/&/g,'&')
is only used for URLs which will be included in SSML, since this is an XML syntax within a json, so two parsers apply and will correct this when they are invoked inside each other.If you get a file URL directly in json (what APL is), then you just can use
var videoUrl = Util.getS3PreSignedUrl("Media/safari.mp4");
and it should work.