Alexa Skills Kit for Node.js (alexa-sdk) で音楽ファイルを鳴らす (2018/3/21 追記)


追記(2018/3/21)

Alexa Skills Kit Sound Libraryというものが公開されました。
Alexaスキル開発用に、効果音や背景音などのアセットを準備したようです。日本語環境でも使えます。
こちらを使えば、音楽ファイルを準備することなくSkillを作れちゃいますね!
もちろん、Sound Libraryの音を組み合わせて何か作る、ということもできそうです。

sample.js
let speechOut = '用意されている奴をコピペするだけ!簡単!';
speechOutput += "<audio src='https://s3.amazonaws.com/ask-soundlibrary/nature/amzn_sfx_rain_01.mp3'/>";

this.emit(':tell', speechOut);

前置き

これ、あんまり探しても分かりやすい情報がなかったので書いてみます。

対象者:
 ・JavaScript、Node.js初心者
 ・とりあえずサンプルなどでスキルを動かしてみた人

Sample Code

sample.js
let speechOut = '音楽はこのように鳴らします。';
speechOut += "<break time ='1s' />";
speechOut += "<audio src='https://xxx.mp3' />";
speechOut += "<break time ='1s' />";
speechOut += 'ね、簡単でしょ?';

this.emit(':tell', speechOut);

説明

SSMLについて

Alexa本体が文字を音声に変換する際、SSMLという言語を使用します。
Alexaの公式リファレンスに解説が載っています。
音声合成マークアップ言語(SSML)のリファレンス

SSMLには単純な出力以外にも、合成音声に装飾を加えることもできます。
HTMLの<h1><\h1>←みたいな奴の音声版ですね。

Alexaのレスポンスで音を鳴らす

上記の公式リファレンスにAlexaでのレスポンス方法が載っています。

"outputSpeech": {
    "type": "SSML",
    "ssml": "<speak>This output speech uses SSML.</speak>"
}

Alexa SDKで音を鳴らす

え...でもこれとサンプル等にあるthis.emitとかってどう繋がってるんだ?
SDKのReadmeにもなんか書いてあるけど・・・
全然わからん!(〇ャガー)

そこで、this.emitで使う場合の使い方を調べてみました。
つまりSDKの中身を追ってみます。

まず、emitというのはEventEmitterというNode.jsの機能です。
emit(イベント名, [arg1], [arg2], [...])という感じで、
Emitterに引数を渡して処理させます。

では、Alexa sdkでこのEmitter処理部はどこにいるのか、というと、
response.jsにいます。

response.js
        ':tell': function (speechOutput) {
            if(this.isOverridden()) {
                return;
            }

            this.handler.response = buildSpeechletResponse({
                sessionAttributes: this.attributes,
                output: getSSMLResponse(speechOutput),
                shouldEndSession: true
            });
            this.emit(':responseReady');
        },

さらにoutputを形成しているgetSSMLResponse関数を確認します。

response.js
function getSSMLResponse(message) {
    if (message == null) { // jshint ignore:line
        return null;
    } else {
        return {
            type: 'SSML',
            speech: `<speak> ${message} </speak>`
        };
    }
}

つまり、this.emitの引数に指定した言葉は
SSML形式でまるっと<speak>で囲って出力していることがわかりました。

ここまでわかれば、単純にemitで指定する単語にタグをはめこむだけか!というのがわかりますね。

sample.js
let speechOut = '音楽はこのように鳴らします。'; //なんか喋りたい文字
speechOut += "<break time ='1s' />"; //1秒休止
speechOut += "<audio src='https://xxx.mp3' />"; //音楽ファイルをはめこむ
speechOut += "<break time ='1s' />"; //1秒休止
speechOut += 'ね、簡単でしょ?'; //なんか喋りたい文字

this.emit(':tell', speechOut);

ちなみに、ReadMeによると、
this.emit(':tell', speechOut);

this.response.speak(speechOut);
this.emit(':responseReady');
の2つでも書けるみたいですね。
(自分もあまり詳しく調べていないが、SDKの中を見ればだいたい同じことをやってると思う。)

mp3について

Amazonが指定する形式に合わせる必要があります。
公式リファレンスに記載されていますが、ここにも書いておきます。

必要に応じて、変換ソフトウェアを使用してMP3ファイルを必要なコーデックバージョン(MPEGバージョン2)とビットレート(48 kbps)に変換してください。

Audacityとffmpegを使って変換すれば楽勝ですね。

音声を提供するために使用するMP3ファイルは、HTTPSを使用するエンドポイント上でホストされている必要があります。このエンドポイントでは、Amazon認定の認証局が署名したSSL証明書を提供する必要があります。

特にこだわりなければS3にupすれば問題ないでしょう。

また、音声ファイルを用意するのがめんどい・・という人は、Alexa Skills Kit Sound Libraryを使うと簡単にお試しできます。

おわりに

Alexa-sdkで音楽ファイルを鳴らす方法を書いてみました。
誰かの参考になれば幸いです。
筆者もかなり初心者なので、間違ってる点などありましたらお知らせください。