[Alexa] 動画を再生するスキルを作ってみました

VideoApp.Launchディレクティブを使用すると、Echo Showや、Echo Spotのように画面を有するデバイスでビデオファイルをストリーミングすることができます。
2018.05.13

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

1 はじめに

VideoApp.Launchディレクティブを使用すると、Echo Showや、Echo Spotのように画面を有するデバイスでビデオファイルをストリーミングすることができます。

Echo ShowEcho Spotは、日本語では利用できないため、今回作成したサンプルのロケーションは、英語(米国)となっています。 最初に、サンプルが動作している様子です。

2 ビデオ形式と解像度

再生が可能なビデオの形式は以下のとおりです。

拡張子 .mp4、.m3u8、.ts
コーディック MPEG4、H.264
推奨解像度(フレームサイズ) 640x480または1280x720
最大解像度 1280x720

※Echo Spotは4Kビデオをサポートしていません。

3 コントロール

ビデオ再生中は、下記のようなコントロールが利用可能で、画面サイズの変更、ポーズ、早送りなどの基本的な操作は、特にスキルで作り込む必要はありません。

4 スキル作成

カスタムスキルを作成し、インターフェースで 画面インターフェースViewAppを有効にします。

画面インターフェースは、ビデオのリストをテンプレートで表示するために追加しましたが、このインターフェースを有効にすることで下記のインテントが必須インテントとして自動的に追加されます。しかし、これらについては、デフォルトの動作で良ければ特に実装の必要は無いようです。

  • AMAZON.NavigateHomeIntent
  • AMAZON.NavigateSettingsIntent
  • AMAZON.NextIntent
  • AMAZON.PageUpIntent
  • AMAZON.PageDownIntent
  • AMAZON.PreviousIntent
  • AMAZON.ScrollUpIntent
  • AMAZON.MoreIntent
  • AMAZON.ScrollLeftIntent
  • AMAZON.ScrollDownIntent
  • AMAZON.ScrollRightIntent

5 VideoApp.Launch

ビデオ再生のためのVideoApp.Launchは、Alexa SDKでは、ResponseBuilderaddVideoAppLaunchDirective()を利用することで、一発でレスポンスを作成できます。

/**
  * Adds a VideoApp play directive to play a video
  *
  * @param {string} source Identifies the location of video content at a remote HTTPS location.
  * The video file must be hosted at an Internet-accessible HTTPS endpoint.
  * @param {string} title (optional) title that can be displayed on VideoApp.
  * @param {string} subtitle (optional) subtitle that can be displayed on VideoApp.
  * @returns {ResponseBuilder}
  */
addVideoAppLaunchDirective(source: string, title?: string, subtitle?: string): this;
const url = 'https://exsample.com/sample.mp4;
return handlerInput.responseBuilder
  .speak('hello')
  .addVideoAppLaunchDirective(url, 'title', 'subtitle')
  .getResponse();

上記のコードで生成されるレスポンスは、次のようになります。

"response": {
  "outputSpeech": {
    "type": "SSML",
    "ssml": "<speak>hello</speak>"
  },
  "directives": [
    {
      "type": "VideoApp.Launch",
      "videoItem": {
          "source": "https://exsample.com/sample.mp4",
          "metadata": {
              "title": "title",
              "subtitle": "subtitle"
          }
      }
    }
  ]
},

6 実装

今回作成したサンプルのコードは以下のとおりです。LaunchRequestで、再生きるビデオのリストをListTemplate1テンプレートで作成しています。

ListTemplate1の使用方法については、下記をご参照下さい。
[日本語Alexa] Alexa-SDK Ver2(その7) ディスプレイ表示

※ 必須スロットなどは省略されています。Display.ElementSelectedしか処理していません。

const Alexa = require('ask-sdk');

let skill;
exports.handler = async function (event, context) {
  if (!skill) {
    skill = Alexa.SkillBuilders.custom()
      .addRequestHandlers(LaunchRequestHandler, SelectVideoHandler)
      .addErrorHandlers(ErrorHandler)
      .create();
  }
  return skill.invoke(event);
}

const baseUrl = 'https://s3.amazonaws.com/xxxxxxxxxvideo-sample/';
const titles = [
  {
    token:'001', 
    author: 'eso observatory',
    filename: '001.mp4'
  },
  {
    token:'002', 
    author: 'kenji kawasawa',
    filename: '002.mp4'
  },
  {
    token:'003', 
    author: 'Ricardo Mantilla',
    filename: '003.mp4'

  },
  {
    token:'004', 
    author: 'Mikah',
    filename: '004.mp4'
  }
];

const LaunchRequestHandler = {
  canHandle(handlerInput) {
      return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
  },
  handle(handlerInput) {
    const speechText = 'Welcome to Video Sample.';
    const reprompt = 'Please select video.'
    const title = 'Please select video.';
    const backgroundImage = new Alexa.ImageHelper()
      .addImageInstance(baseUrl + 'background.jpg')
      .getImage();
    let listItems = [];
    titles.forEach( title => {
      const textContent = new Alexa.RichTextContentHelper()
        .withPrimaryText(title.author)
        .getTextContent();
      const listItem = {
          token : title.token,
          textContent : textContent
      }
      listItems.push(listItem);
    })

    return handlerInput.responseBuilder
      .speak(speechText)
      .reprompt(reprompt)
      .addRenderTemplateDirective({
        type: 'ListTemplate1',
        backButton: 'HIDDEN',
        backgroundImage: backgroundImage,
        listItems:  listItems,
        title: title,
        token : 'TOKEN',
      })
      .getResponse();
  }
};

const SelectVideoHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'Display.ElementSelected';
  },
  handle(handlerInput) {
    var index = titles.map( title => title.token )
                  .indexOf(handlerInput.requestEnvelope.request.token);
    if (index != -1) {
      const url = baseUrl + titles[index].filename;
      return handlerInput.responseBuilder
        .speak(titles[index].author)
        .addVideoAppLaunchDirective(url, titles[index].author)
        .getResponse();
    } else {
      return handlerInput.responseBuilder
        .speak('ERROR Token not found.')
        .getResponse();
    }
  }
};

const ErrorHandler = {
  canHandle(handlerInput, error) {
    return true;
  },
  handle(handlerInput, error) {
    return handlerInput.responseBuilder
        .speak('Error')
        .getResponse();
  }
}

7 最後に

今回はビデオの再生を試してみました。Alexa SDK V2では、たったの1行でビデオ再生のディレクティブが送れてしまいます。後は、コンテンツのビデオ形式と解像度を対応させてS3などに配置するだけです。

あまりに簡単でちょっとビックリしました。

動画は、http://mazwai.com/#/ で ATTRIBUTION LICENSE 3.0 で公開されている下記のものを利用させて頂いています。

8 参考リンク


How to Control Your Content with the Video Skill API
Introducing the Video Skill API
VideoApp Interface Reference
Understand the Video Skill API
[日本語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) ディスプレイ表示