英文:
Insert Intro Jingle at Amazon Alexa with node.js
问题
我已经创建了一个使用node.js的Amazon Alexa技能,它可以播放MP3流。现在我遇到了在流开始之前播放一个固定URL的音乐的问题。我应该如何继续实现这个项目?
以下是简单播放器代码的最重要部分:
const LaunchRequestHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest'
|| (Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'PlayStationIntent');
},
handle(handlerInput) {
const speakOutput = messages.welcome;
return handlerInput.responseBuilder
.speak(speakOutput)
.addAudioPlayerPlayDirective("REPLACE_ALL", url, token(), 0)
.getResponse();
}
};
请注意,你需要将url
和token()
替换为实际的URL和令牌,以便在流开始之前播放音乐。
英文:
I have created a skill for Amazon Alexa using node.js, which plays an MP3 stream.
Now I have problems to play a jingle with a fixed URL before the stream starts.
How do I have to proceed to realize this project?
Below is the most important part of the code of the simple player:
const LaunchRequestHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest'
|| (Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'PlayStationIntent');
},
handle(handlerInput) {
const speakOutput = messages.welcome;
return handlerInput.responseBuilder
.speak(speakOutput)
.addAudioPlayerPlayDirective("REPLACE_ALL", url, token(), 0)
.getResponse();
}
};
答案1
得分: 1
有多种实现此功能的选项:
-
SSML 如果提示音非常短并且符合某些编码规范,您可以使用SSML和音频标签将其包含在
speakOutput
中。 -
M3U 与其直接在AudioPlayerPlayDirective中包含流的URL,您可以在其中包含M3U的URL,然后该M3U包含提示音的URL和流的URL的播放列表。
-
PlayBackNearlyFinished Intent 只需将提示音的URL作为第一个播放指令发送,并为PlayBackNearlyFinished Intent添加支持,当播放提示音即将完成时,音频播放器本身将调用该Intent,然后在该Intent中发送一个音频播放指令(不带speak),但带有流的URL。但要注意,如果文件即将完成,将调用相同的PlayBackNearlyFinished Intent,因此您需要识别它已被调用以避免创建无限循环。最好的方法是在两个播放指令上都使用token属性(第一个使用“Jingle”,第二个使用“Stream”或token()),因此如果调用了PlayBackFinished Intent,请检查请求中的token,并仅在token为“Jingle”时发送第二个播放指令,从而识别提示音已结束。
最后一个选项会改变您的代码,类似于以下内容:
const LaunchRequestHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest'
|| (Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'PlayStationIntent');
},
handle(handlerInput) {
const speakOutput = messages.welcome;
return handlerInput.responseBuilder
.speak(speakOutput)
.addAudioPlayerPlayDirective("REPLACE_ALL", url_jingle, "jingle", 0)
.getResponse();
}
};
const PlayBackFinishedHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'AudioPlayer.PlaybackNearlyFinished';
},
handle(handlerInput) {
if (handlerInput.requestEnvelope.request.token === 'jingle') {
return handlerInput.responseBuilder
.addAudioPlayerPlayDirective("REPLACE_ALL", url, token(), 0)
.getResponse();
}
}
};
此外,您需要激活AudioPlayer Interface并在之后重新构建模型,以便这些控制事件能够传递给您。
英文:
There are multiple options for implementing this:
- SSML if the jingle is very short and comply to some encodings, you may include it in the speakOutput by using SSML and the audio tag.
- M3U Instead of the including the URL of the stream directly in the AudioPlayerPlayDirective, you can include there the URL to an M3U, which then includes a playlist of the Jingle URL and the stream URL.
- PlayBackNearlyFinished Intent Just sent as first play directive the url of the Jingle and add support for the PlayBackNearlyFinished Intent, which will be invoked by the AudioPlayer itself when playing Jingle is nearly finished and then send inside this intent an audio player play directive (without a speak) but with the URL of the stream. But be aware if that file gets nearly finished, the same PlayBackNearlyFinished Intent will get called, so you need to identify that it already has been called to avoid making an infinity loop. Best way would to use token attribute on both play commands with (first with "Jingle" and second with "Stream" or token()) so if PlayBackFinished Intent is called, check token in the request and only send the second play command, if token is "Jingle" and so identifying the Jingle has ended.
The last option would change your code to something like:
const LaunchRequestHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest'
|| (Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'PlayStationIntent');
},
handle(handlerInput) {
const speakOutput = messages.welcome;
return handlerInput.responseBuilder
.speak(speakOutput)
.addAudioPlayerPlayDirective("REPLACE_ALL", url_jingle, "jingle", 0)
.getResponse();
}
};
const PlayBackFinishedHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'AudioPlayer.PlaybackNearlyFinished';
},
handle(handlerInput) {
if (handlerInput.requestEnvelope.request.token === 'jingle') {
return handlerInput.responseBuilder
.addAudioPlayerPlayDirective("REPLACE_ALL", url, token(), 0)
.getResponse();
}
}
};
Additionally you would need to activate the AudioPlayer Interface and rebuild the model afterwards, so that those controls events will reach you.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论