[日本語Alexa] Audioスキルを止める方法 〜再生が止まらない問題への対策〜

2018.10.27

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

1 はじめに

Audioインターフェースでは、最後にオーディオを再生したスキルに対して、いくつかの標準インテントを送ります。このため、Audioスキルでは、終了した後も、予想外の動作を引き起こすことがあります。

次の動画は、Audioスキルを終了させたのに、また、再生が始まってしまう様子です。

再開する事が期待通りだったら問題ないのですが、もし、終了後の再開が想定されていないとしたら、これは、予想外の動作となります。また、「次へ」や「もう一回」という発話で、エラーが発生してしまっている症状も確認できます。

今回は、Audioスキルを「止める」方法について確認してみました。

Audioスキルは、「再生は非常に簡単だけど、停止は予想以上に難しい」というのが、現在の感想です。

2 AMAZON.CancelIntent

AMAZON.CancelIntentは、オーディオ再生中にも利用が可能であるため、このインテントでAudioを停止させる処理を記述する方法が最初に考えられます。

標準ビルトインインテントより

下記のコードは、AMAZON.CancelIntentaddAudioPlayerStopDirective()を送ることでオーディオ再生を停止しています。

// 終了
const StopCancelIntentHandler = {
    canHandle(h) {
        return isMatch(h ,'AMAZON.CancelIntent', 'AMAZON.StopIntent');
    },
    handle(h) {
        return h.responseBuilder
          .addAudioPlayerStopDirective()
          .speak('オーディオ・サンプルを終了します')
          .getResponse();
    }
};

完全なコードは、下記に置きました。
https://gist.github.com/furuya02/7553721b79ee6e54864878270af22cc3

しかし、これだけでは、先のビデオのように、「再開して」と言うと、ゾンビのようにオーディオ再生が始まってしまいます。

3 終了ステータス

ゾンビのように再生が始まってしまう原因は、最後にオーディオを再生したスキルに対して送られる標準インテントに対する実装にあります。

下記では、AMAZON.ResumeIntent(再開)で、最後に停止したオーディオの再開が実装されています。このような実装では、別のスキルがオーディオ再生をしない限り、このインテントが呼ばれたとき、いつまでもオーデイオ再生が「再開」されてしまいます。

このソンビのような現象は、AMAZON.LoopOnIntent(ループ再生して)、AMAZON.NextIntent(次)、AMAZON.RepeatIntent(もう一度)、AMAZON.StartOverIntent(最初から)などをきめ細かく処理している場合、より発生しやすくなるでしょう。

対策は、永続化情報で、スキルのステータス(再生中・停止中)を保持して、上記のような標準インテントの処理を、ステータスに応じたものにする方法が考えられます。

// 再生
const PlayIntentHandler = {
    canHandle(h) {
        return isMatch(h,'PlayIntent');
    },
    async handle(h) {
        setStatus('playing'); // 永続化情報に「再生中」を記録する
        return h.responseBuilder
            .addAudioPlayerPlayDirective('REPLACE_ALL', url, token, 0, null)
            .getResponse();
    }
};

// 停止
const StopCancelIntentHandler = {
    canHandle(h) {
        return isMatch(h ,'AMAZON.CancelIntent');
    },
    handle(h) {
        setStatue('stopped') // 永続化情報に「停止中」を記録する
        return h.responseBuilder
          .addAudioPlayerStopDirective()
          .getResponse();
    }
};

// 再開
const ResumeIntentHandler = {
    canHandle(h) {
        return isMatch(h, 'AMAZON.ResumeIntent');
    },
    async handle(h) {
        // 「停止中」の場合は、処理なし
        if(getStatus() == 'stopped') {
            return h.responseBuilder.getResponse();
        }
        // 「再生中」の場合は、再開の処理
        return h.responseBuilder
            .addAudioPlayerPlayDirective('REPLACE_ALL', url, token, offset, null)
            .getResponse();
  }
};

永続化の要領等については、下記の「4 Persistent attributes(セッションを跨いで永続化する DynamoDB等が必要)」をご参照下さい。
参考:[日本語Alexa] Alexa-SDK Ver2(その4) スキル属性

4 サンプル発話の追加

(1) AMAZON.CancelIntent

AMAZON.CancelIntentを呼び出す場合は「アレクサ、キャンセルして」とか「アレクサ、取り消し」となるのですが、それよりも、「アレクサ、停止して」みたな方が良いと思っても、AMAZON.CancelIntentで追加したサンプル発話は、この状況ではうまく機能しませんでした。

(2) AMAZON.PauseIntent/AMAZON.ResumeIntent

また、実装が必須となっている、AMAZON.PauseIntent及び、AMAZON.ResumeIntentに関しては、サンプル発話を追加することもできません。

5 停止方法の考察

ここまでの状況を踏まえて、Audioを停止する方法を考察してみたい思います。

(1) レジューム「中断」機能の停止

この情報は、あくまで、手元で私が試した結果なのですが、オーディオ再生中に入るインテントは以下のような感じでした。

発話例 インテント 備考
アレクサ、キャンセル AMAZON.CancelIntent たまに、入らない場合もある
アレクサ、取り消し AMAZON.CancelIntent たまに、入らない場合もある
アレクサ、とめて AMAZON.PauseIntent 入りやすい
アレクサ、停止して AMAZON.PauseIntent 入りやすい
アレクサ、中断して AMAZON.PauseIntent 入りやすい
アレクサ、一時停止 AMAZON.PauseIntent 入りやすい

AMAZON.StopIntentや、カスタムインテントは、「呼び出し名」無しで呼ぶことは出来ません。

上記の状況から考えると、AMAZON.CancelIntentが、少し呼び出しにくいため、AMAZON.CancelIntentと、AMAZON.PauseIntentに停止の処理を入れるのが、一番、気持ちよく停まるような気がします。なお、この場合は、「中断して」「一時停止」を使用した、レジューム機能は、実装しない仕様になります。

(2) 呼び出し名を使用する

オーデイオ再生中にも、スキルを呼び出すことは可能です。そこで、下記のようなカスタムインテントを作成して、停止の処理を実装することもできます。

この場合、オーディオ再生中に下記のように話しかけることになります。

  • ♬ オーディオ再生中
  • 「アレクサ、(呼び出し名)を使用してオーディオの再生を止めて」
  • 「オーディオを停止します」

LaunchRequestを有効にすると、次のような利用方法になるでしょうか。

  • ♬ オーディオ再生中
  • 「アレクサ、(呼び出し名)をスタートして」
  • 「どうしましょう?」<=LaunchRequestに対する反応
  • 「オーディオの再生を止めて」
  • 「オーディオを停止します」

ちょっと、使いにくいですが、レジューム機能を活かしたい場合は、AMAZON.CancelIntentが、少し入りにくい問題に対応するため、このような実装も必要かもしれません。

6 最後に

期待していないスキルが、いきなり返事すると、ユーザーに大きな違和感を与えてしまいます。特に、最後にオーディオを使用したスキルに送られる標準インテントは、呼び出し名が必要ないために、余計に奇妙さを感じさせてしまうかも知れません。

少なくとも、永続情報を使用して「再生中」「停止中」のステータスをしっかりと実装し、スキルで「スキルを終了します。また、呼んで下さいね!」などと返事した後は、確実にオーディオ再生が再開しないようにする必要があると思います。

7 参考リンク


AudioPlayer の概要
[Alexaスキル] AudioPlayerでハローワールド
[Alexaスキル] AudioPlayerスキルのセッションとイベント
AudioPlayerの再生キューの活用
AudioPlayerインターフェースのリファレンス
AudioPlayer インターフェース(v1.0)
[日本語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) ディスプレイ表示
[日本語Alexa] Alexa-SDK Ver2(その8) AudioPlayer
[日本語Alexa] Alexa-SDK Ve2 (その9) Audio の連続再生