この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
渡辺です。
AudioPlayerでハローワールドでは、AudioPlayerスキルの概要を解説しました。 今回は、実用レベルのスキルを作るために必要なポイントを解説します。
セッションとAudioPlayerスキル
一般的なカスタムスキルでは、スキルの起動後、ユーザの発話でリクエストが発生しインテント関数が呼び出されます。 インテント関数では、応答メッセージを返し、ユーザの応答に対し次のインテント関数が呼び出される流れです。 この時、一連のリクエストではセッションが確立され、セッション情報を利用できます。
インテント関数でイベントを確認すると次のように、セッション情報が格納されています。
{
"version": "1.0",
"session": {
"new": true,
"sessionId": "amzn1.echo-api.session.xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"user": {
"userId": "amzn1.ask.account.xxxx"
}
},
"request": {
"type": "LaunchRequest"
}
}
session.new
が true
となっていることで、セッションの初回リクエストと判断できます。
2回目のリクエストは、次のようにセッションが維持されています。
{
"version": "1.0",
"session": {
"new": false,
"sessionId": "amzn1.echo-api.session.xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"attributes": {
"repeatSpeech": "タイマースキルへようこそ。"
},
"user": {
"userId": "amzn1.ask.account.xxxx"
}
},
"request": {
"type": "IntentRequest"
}
}
セッションが維持され、セッション情報(attributes)が保持されていることが確認出来ます。
ところが、AudioPlayerスキルではセッションが維持されません。 ステートレスを前提とした設計を行う必要があります。
AudioPlayerイベントのセッション
音楽再生時に呼び出されるPlaybackStartedイベントなど、AudioPlayerスキルでは多くのイベントが発生します。 この時、すべて新しいセッションとして呼び出されます。 セッション情報(attributes)は利用できません。
{
"version": "1.0",
"session": {
"new": true,
"sessionId": "amzn1.echo-api.session.xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
},
"context": {
"AudioPlayer": {
"offsetInMilliseconds": 0,
"token": "https://s3-ap-northeast-1.amazonaws.com/xxxxxx/xxx.m4a",
"playerActivity": "STOPPED"
}
},
"request": {
"type": "AudioPlayer.PlaybackStarted",
"locale": "ja-JP",
"token": "https://s3-ap-northeast-1.amazonaws.com/xxxxxx/xxx.m4a",
"offsetInMilliseconds": 0
}
}
セッションは維持されず、session.new がtrueになっており、attributeはありません。 ただし、context.AudioPlayer から、再生された音楽ファイルのパスや再生位置などは取得可能です。
インテントでも同様です。 一時停止を行った場合に、呼び出されるPauseIntentでは、次のようなリクエストが行われます。
{
"version": "1.0",
"session": {
"new": true,
"sessionId": "amzn1.echo-api.session.xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
},
"context": {
"AudioPlayer": {
"offsetInMilliseconds": 40075,
"token": "https://s3-ap-northeast-1.amazonaws.com/xxxxxx/xxx.m4a",
"playerActivity": "STOPPED"
}
},
"request": {
"type": "IntentRequest",
"intent": {
"name": "AMAZON.PauseIntent"
}
}
}
AudioPlayerスキルで永続化情報を扱う
AudioPlayerで音楽が再生されると、セッションは維持されません。 セッション情報が利用できないため、情報は外部データベースに保存する必要があります。
AlexaのSDKを利用するならば、DyanmoDBにセッション情報を保存できるため、DynamoDBを有効にしてください。 DynamoDBを有効にすれば、同一ユーザのセッション情報は永続化されるため、イベント時にも利用できます。
exports.handler = function (event, context, callback) {
const alexa = Alexa.handler(event, context, callback);
// DynamoDBの有効化
alexa.dynamoDBTableName = 'your-dynamodb-table';
// 中略
alexa.execute();
};
例えば、スロットに含まれるタイマー時間をセッションに保存し、DynamoDBに保存します。
'StartTimerIntent': function () {
var num = this.event.request.intent.slots.Num.value;
// セッションに保存(DynamoDBに自動保存)
this.attributes['timer'] = num;
// 省略
},
再生の再開を実装する
前回の実装では、再生の再開時に曲の最初から再生を行っていました。
context.AudioPlayer
のパラメータを使用すれば、中断したところから再生可能です。
'AMAZON.PauseIntent': function () {
this.response.audioPlayerStop();
this.emit(':responseReady');
},
'AMAZON.ResumeIntent': function () {
var offset = this.event.context.AudioPlayer.offsetInMilliseconds;
var url = this.event.context.AudioPlayer.token;
this.response.audioPlayerPlay('REPLACE_ALL', url, url, null, offset);
this.emit(':responseReady');
}
再生終了時のハンドリング
AudioPlayerで音楽を再生した時、再生終了時にPlaybackFinishedイベントが発生します。 しかし、PlaybackFinishedイベントにレスポンスを返し、Alexaに発話させるようなアクションは行えません。
PlaybackFinishedイベントは、他のイベントと同様に、AudioPlayerが特定のタイミングで発生させるリクエストです。 イベントを受けてLambdaで処理は行えますが、メッセージをレスポンスに含めることができません。 Alexaでは、ユーザの発話に対するレスポンスとして応答メッセージを返すことしかできないのです。
それでは、再生終了時にどのようなステータスとなるのでしょうか?
答えは、スキルを起動していないデフォルト状態です。 ただし、Alexaは最後に起動したスキルを記憶しています。
再生終了後、利用者がAlexaに話しかけた場合、発話内容を解釈し、いずれかのアクションを取ります。
- Alexaの組み込み機能による応答
- 直前に起動していたAudioPlayerスキルによる応答
発話内容が、AudioPlayerスキルのインテントでマッチした場合、スキルのインテント関数が呼び出されます。
例えば、音楽再生完了後、「Alexa, 繰り返して」と発話するならば、スキルのAMAZON.RepeatIntent
が呼び出されるでしょう。
この時も、セッションは維持されず、新しいセッションとして処理されることは注意してください。
音楽再生終了後、「Alexa, XXを開いて」と発話するならば、XXスキルが起動します。
まとめ
AudioPlayerスキルで音楽を再生した時に発生するイベントは、セッション情報を持たないステートレスリクエストです。 セッション情報を扱いたい場合はDynamoDB機能を有効にしてください。 ただし、再生した音楽のURLや中断位置などはコンテキスト情報として取得可能です。
また、音楽再生終了時にスキルからアクション(応答)を行うことはできません。 利用者から発話がある場合、スキルのインテント関数で処理が行われるため、再生終了時のフローを整理すると良いでしょう。