[Alexaスキル] AudioPlayerスキルのセッションとイベント

2018.02.02

この記事は公開されてから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.newtrue となっていることで、セッションの初回リクエストと判断できます。

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や中断位置などはコンテキスト情報として取得可能です。

また、音楽再生終了時にスキルからアクション(応答)を行うことはできません。 利用者から発話がある場合、スキルのインテント関数で処理が行われるため、再生終了時のフローを整理すると良いでしょう。