Alexa-SDK Ver2(その8) AudioPlayer

今回は、Alexa SDK V2による、AudioPlayerインターフェースを使用したスキルの作成についてまとめてみました。 AudioPlayerインターフェースは、完全に、ResponseBuilderにラップされているため、非常に簡単に利用可能です。
2018.10.18

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

AudioPlayerの利用方法については、既に、ここDevelopers.IOでも紹介されています。
[Alexaスキル] AudioPlayerでハローワールド
[Alexaスキル] AudioPlayerスキルのセッションとイベント
AudioPlayerの再生キューの活用

しかし、上記の記事のサンプルコードは、当時のAlexa SDK V1で書かれています。そこで、本記事では、内容はかなりの部分被りますが、サンプルコードをAlexa SDK V2に変更して書かせていただきました。

なお、Alexa SDK V2については、色々とまとめてきましたので、その流れに乗せ(その8)とさせて頂きました。
[日本語Alexa] Alexa SDK for Node.js Ver2入門(その1)はじめの一歩
[日本語Alexa] Alexa SDK for Node.js Ver2入門(その2)ハンドラの登録
[日本語Alexa] Alexa SDK for Node.js Ver2入門(その3)レスポンスの作成
[日本語Alexa] Alexa-SDK Ver2(その4)スキル属性
[日本語Alexa] Alexa-SDK Ver2(その5)ダイアログモード
[日本語Alexa] Alexa-SDK Ver2(その6) 所在地情報
[日本語Alexa] Alexa-SDK Ver2(その7) ディスプレイ表示

2 AudioPlayerの有効化

AudioPlayerを使用するには、スキルの作成持に、開発者コンソールのインターフェースでAudioPlayerをONにする必要があります。

AudioPlayerをONにすると、デフォルトで追加されるインテントに AMAZON.PauseIntent(一時停止)AMAZON.ResumeIntent(再開) が追加されます。

3 オーディオ再生

オーディオ再生は、ResponseBuilderaddAudioPlayerPlayDirectiveを使用します。

PlayerIntentを定義して、sample.mp3を再生する簡単なサンプルは、以下のようになります。

「音楽をかけて」と話しかけると、PlayIntentが呼ばれます。

PlayIntentを処理するハンドラの例です。https://exsample.com/sample.mp3を再生するように指定しています。 なお、ResponseBuilderに、speakを指定すると、再生の直前に発話することも可能です。

const PlayIntentHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        return (request.type === 'IntentRequest' && request.intent.name === 'PlayIntent');
    },
    async handle(handlerInput) {
        const url = "https://exsample.com/sample.mp3";
        const token = "sample";
        return handlerInput.responseBuilder
            .addAudioPlayerPlayDirective('REPLACE_ALL', url, token, 0, null)
            //.speak('サンプルを再生します。')
            .getResponse();
    }
};

4 addAudioPlayerPlayDirective

ここで、addAudioPlayerPlayDirectiveの定義は以下のとおりです。

addAudioPlayerPlayDirective (
    playBehavior: interfaces.audioplayer.PlayBehavior, 
    url: string, 
    token: string, 
    offsetInMilliseconds: number, 
    expectedPreviousToken?: string, 
    audioItemMetadata? : AudioItemMetadata): this;

(1) playBehavior: interfaces.audioplayer.PlayBehavior

指定したオーディオの再生方法を指定します。

  • REPLACE_ALL: 再生中のストリーム及び、キューを置き換えて、すぐに再生を開始します。
  • ENQUEUE: 現在のキューの最後に追加します。再生中のストリームには影響しません。
  • REPLACE_ENQUEUED: キューを置き換えます。再生中のストリームには影響しません。

(2) url: string

オーディオコンテンツのURLを指定します。

使用可能なファイルの形式はAAC/MP4、MP3、HLSなどでビットレートは、16kbps~384kbpsです。HTTPSは必須で、ドメインには有効なSSL証明書が必要です。(オレオレ証明は使用できません)

(3) token: string

オーディオストリームを識別するためのトークンで、1024文字以内の文字列が指定できます。(自由に設定できます)

(4) offsetInMilliseconds: number

再生を開始するタイムスタンプです。最初から再生する場合は0を指定します。

(5) expectedPreviousToken?: string

前のストリームを指定します。playBehaviorENQUEUE の場合に必須の指定となります。

(6) audioItemMetadata? : AudioItemMetadata

オーディオに関連するメタデータを指定します。Echo ShowEcho Spot で表示されます。(Alexaアプリには表示されません)

5 Amazon.PauseIntent「中断して」

AudioPlayerインターフェースで、実装が必須となっているAmazon.PauseIntentの実装例は以下のとおりです。

const PauseIntentHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        return (request.type === 'IntentRequest' && request.intent.name === 'AMAZON.PauseIntent');
    },
    async handle(handlerInput) {
        return handlerInput.responseBuilder
        //.speak('サンプルを中断します。')
        .getResponse();
    }
};

ユーザーによる「中断して」などのリクエストに答えるものですが、ここでは、空のレスポンスを返しても、再生中のオーディオは停止します。なお、Amazon.PauseIntentは、通常のインテントと同じなので、speakで発話させる事も可能です。

6 Amazon.ResumeIntent「再開して」

実装が必須となっている、もう一つのインテントであるAmazon.ResumeIntentの実装例は以下のとおりです。

const ResumeIntentHandler = {
    canHandle(handlerInput) {
        const request = handlerInput.requestEnvelope.request;
        return (request.type === 'IntentRequest' && request.intent.name === 'AMAZON.ResumeIntent');
    },
    async handle(handlerInput) {
        const url = "https://exsample.com/sample.mp3";
        const AudioPlayer = handlerInput.requestEnvelope.context.AudioPlayer;
        const token = AudioPlayer.token;
        const offset = AudioPlayer.offsetInMilliseconds;
        return handlerInput.responseBuilder
            .addAudioPlayerPlayDirective('REPLACE_ALL', url, token, offset, null)
            //.speak('サンプルを再開します。')
            .getResponse();
  }
};

オーディオ再生を開始した時と同じで、ResponseBuilderaddAudioPlayerPlayDirectiveを使用していますが、今度は、再開なので、中断している位置(オフセット)からのスタートとします。

オフセット(及び、トークン)については、Alexaからのコンテキストに含まれていますので、これを利用しています。(urlについては、Contentに含まれませんので、スキル側で記憶する仕組みが必要です)

{
    "context": {
        "AudioPlayer": {
            "offsetInMilliseconds": 3578,
            "token": "sample",
            "playerActivity": "STOPPED"
        },
        ・・・略・・・
    },
    "request": {
        "type": "IntentRequest",
        "intent": {
            "name": "AMAZON.ResumeIntent",
        ・・・略・・・
    }
}

7 AudioPlayerのイベント

AudioPlayerを使用すると、オーディオの「再生開始」や「終了」又、「もうすぐ終了する」などのリクエストがスキルに送られます。 特に必要がなければ無視しても良いのですが、スキルに実装がないとLambdaでエラーとなってしまいますので、下記のように処理しておくことをお勧めします。

こちらのイベントで送られてきているリクエストのタイプはIntentRequestではなく、また、Alexaへの指示ができません。そのため、誤って、ResponseBuilderspeakなどを追加すると、エラーとなりますので注意が必要です。

const PlaybackHandler = {
  canHandle(h) {
      const type = h.requestEnvelope.request.type;
      return (type == 'AudioPlayer.PlaybackStarted' || // 再生開始
              type == 'AudioPlayer.PlaybackFinished' || // 再生終了
              type == 'AudioPlayer.PlaybackStopped' || // 再生停止
              type == 'AudioPlayer.PlaybackNearlyFinished' || // もうすぐ再生終了
              type == 'AudioPlayer.PlaybackFailed'); // 再生失敗
  },
  async handle(handlerInput) {
      return handlerInput.responseBuilder
      .getResponse();
  }
};

8 テストできない

オーディオ再生は、開発者コンソールのテストで確認することはできません。

デバイスのログを確認すると、AudioPlayer.Playディレクティブが、端末側に返っていることまでは、確認できますが、未対応である旨のポップアップと共にスキルは終了してしまいます。

9 最後に

今回は、Alexa SDK V2による、AudioPlayerインターフェースを使用したスキルの作成についてまとめてみました。

AudioPlayerインターフェースは、完全に、ResponseBuilderにラップされているため、非常に簡単に利用可能です。次回は、AudioPlayerのイベントを処理し、オーディオの連続再生について扱いたいと思います。

10 参考リンク


AudioPlayer の概要
[Alexaスキル] AudioPlayerでハローワールド
[Alexaスキル] AudioPlayerスキルのセッションとイベント
AudioPlayerの再生キューの活用
AudioPlayerインターフェースのリファレンス
AudioPlayer インターフェース(v1.0)