ラズパイでスマートスピーカーを自作(stretch)

![myalexa.jpeg](https://qiita-image-store.s3.amazonaws.com/0/95614/9850ed3e-18b5-d34f-03ab-41ab23a49fdd.jpeg)


ポストスマホの有力候補といえばスマートスピーカーということで、とりあえずデバイス側を作ってみました。
今回は米国で既に先行しているamazon Alexaとやり取りしたいと思います。
なんか色々アレクサと対話したいので英語、米語、ドイツ語、日本語と切り替えれるようにしました。

# 用意するもの
- [ ] プロト基盤：Raspberry Pi3(2でも良いがwifiが付いているので3）
- [ ] スピーカー：USB,3.5mmでもいいしHDMIでもいい
- [ ] mircoSD:RSPIとの依存があるので[この中](https://elinux.org/RPi_SD_cards)から選ぶことを強くおすすめします。
- [ ] USBキーボード：ラズパイ操作用
- [ ] USBマウス：ラズパイ操作用
- [ ] HDMIケーブル：モニターにつなぐため
- [ ] HDMIモニタ：ラズパイ操作用
- [ ] macbook：OSダウンロード用

#大まかな流れ
**ラズパイの設定**
    1. OSインストール
    2. OSセットアップ
**AVSの構築**
    1. SDKインストールと環境設定
    2. SDKのビルド
    3. AVSの認証
    4. 実行

はい、では行ってみよう。

#   **ラズパイの設定** 
**1. OSインストール** 
まずはOS(raspbian)をインストールしましょう。
**1. 1 OSのダウンロード**
[このサイト](https://www.raspberrypi.org/downloads/)からダウンロード(https://www.raspberrypi.org/downloads/)
>今回はraspbianというDebianベースのOSを使います。
>ここにはNoobsという初心者用のインストーラーもあるけど、イケてる君は
>Bootイメージを直接扱った方が時短になるので迷わず[Rasbian stretch2017-09-07](https://www.raspberrypi.org/downloads/)を選ぼう。
>※国内外の文献ではAVSのSDKがstretchに対応していないと書いているけど、そこはクリアしているので大丈夫。

 **１.２ SDカードのフォーマット** 

- macbookにmicroSDカードを差す。
- マウントが出来たらSDカードのフォーマットを行う。
- SDカードの場所を確認
`$diskutil list`
これでSDカードのディレクトリが分かります。（ex:/dev/disk2)

- SDカードのフォーマット（FATね）
`$sudo diskutil eraseDisk FAT32 RASBIAN MBRFormat /dev/disk2`
>SDカードのサイズが30GB以下はFAT32とし、それ以上のサイズはexFATする。
>RASBIANは任意で好きな名前を付けてね

- SDカードをアンマウントし、コピーができる状態が完了
	`$sudo diskuitl unmount /dev/disk2`
	disk2をアンマウントする

 **１.３ SDカードのコピー** 

- ダウンロードしたOSを解凍
`$tar xzf 2017-09-07-raspbian-stretch.zip`

- 解凍したイメージをSDカードにコピー
`$sudo dd bs=1m if=2017-09-07-raspbian-stretch.img of=/deb/rdsik2`
>なぜデバイス名rdiskになってるの？とお気づきですか。
>それはrdiskの方が書き込む速度が早いからです。
>disk2もrdisk2も同じ場所ですが、disk2とした場合、ランダムアクセスが可能となるデバイスとして転送データがUserSpaceという4KBのバッファを経由して処理されます。
>これはマルチタスクがゆえのことなのですが、これをrdiskで指定することにより、バッファを経由せずにダイレクトでシーケンシャルに処理が進むためにdiskよりも高速になります。
>興味と時間のある方はdisk指定で４GBのコピーの旅をお楽しみ下さい。

 **２ OSセットアップ** 
いよいよラズパイを動かしましょう。

 **２.１ OSの起動** 
RSPI3にモニタ、キーボード、マウス、SDカードを入れて電源ON
![rasbian.jpeg](https://qiita-image-store.s3.amazonaws.com/0/95614/3cc5b35b-714c-20a1-6000-e7e3f45d2623.jpeg)


 **２.２ 初期セットアップ** 

- ターミナルを起動し次の設定を行う
		`sudo raspi-config`でもいいしGUIでもOK。とにかくこれを設定
			・タイムゾーンの設定
			・wifiの設定
			・SSHの設定
			・キーボード設定
			※お好みに合わせてVNCも設定

#  **AVSの構築** 
ここから本番。
**１. SDKインストールと環境設定**
**１.１ まずは最低限必要なパッケージの更新とインストール** 

- パッケージの更新
`sudo apt-get update`

- で、必要なパッケージをインストール

```
sudo apt-get -y install git gcc cmake build-essential libsqlite3-dev libcurl4-openssl-dev libfaad-dev libsoup2.4-dev libgcrypt20-dev libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-good libasound2-dev doxygen
```

**１.２ 開発環境のディレクトリを作成**

```
cd /home/pi/ && mkdir sdk-folder && cd sdk-folder && mkdir sdk-build sdk-source third-party application-necessities && cd application-necessities && mkdir sound-files
```
**１.３ フリーの音声ライブラリ(portaudio)を拝借**
ディレクトリ移動＆ダウンロード＆解凍＆configure＆makeを一気に行います

```
cd /home/pi/sdk-folder/third-party && wget -c http://www.portaudio.com/archives/pa_stable_v190600_20161030.tgz && tar zxf pa_stable_v190600_20161030.tgz && cd portaudio && ./configure --without-jack && make
```

**１.４ commentjsonのインストール**
AVS認証時に必要になるAlexaClientSDKConfig.jsonに書き込みを行うために必要
`pip install commentjson`

**１.５ タイマーとアラーム音をアマゾンのサイトからダウンロード**

```
cd /home/pi/sdk-folder/application-necessities/sound-files/ && wget -c https://images-na.ssl-images-amazon.com/images/G/01/mobile-apps/dex/alexa/alexa-voice-service/docs/audio/states/med_system_alerts_melodic_02._TTH_.mp3 && wget -c https://images-na.ssl-images-amazon.com/images/G/01/mobile-apps/dex/alexa/alexa-voice-service/docs/audio/states/med_system_alerts_melodic_02_short._TTH_.wav && wget -c https://images-na.ssl-images-amazon.com/images/G/01/mobile-apps/dex/alexa/alexa-voice-service/docs/audio/states/med_system_alerts_melodic_01._TTH_.mp3 && wget -c https://images-na.ssl-images-amazon.com/images/G/01/mobile-apps/dex/alexa/alexa-voice-service/docs/audio/states/med_system_alerts_melodic_01_short._TTH_.wav
```

	
 **２. SDKのビルド**
 **２.１ AVSのSDKをクローンします** 


```
cd /home/pi/sdk-folder/sdk-source && git clone git://github.com/alexa/avs-device-sdk.git
```

**２.２ ウェイクワードのエンジン（Sensory)もクローン**
これをすると「アレクサ！」で反応してくれるようになります。

```
cd /home/pi/sdk-folder/third-party && git clone git://github.com/Sensory/alexa-rpi.git
```
で、それの利用規約に同意します。

```
cd /home/pi/sdk-folder/third-party/alexa-rpi/bin/ && ./license.sh 
```
**２.３ 日本語化対応**
デフォルトは英語なので、これらのソースを変更し日本語に対応させます。

まずはエンドポイントを日本に変更

```cpp:/sdk-folder/sdk-source/avs-device-sdk/SampleApp/src/SampleApplication.cpp
//68行目
// Default AVS endpoint to connect to.
static const std::string DEFAULT_ENDPOINT("https://avs-alexa-fe.amazon.com");
```

アプリ実行中のメニューに日本語切り替えを追加

```cpp:/sdk-folder/sdk-source/avs-device-sdk/SampleApp/src/UIManager.cpp
//89行目のこのメニューに日本語を追加し、英語と入れ替える
static const std::string LOCALE_MESSAGE =
    "+----------------------------------------------------------------------------+\n"
    "|                          Language Options:                                 |\n"
    "|                                                                            |\n"
    "| Press '1' followed by Enter to change the language to US English.          |\n"
    "| Press '2' followed by Enter to change the language to UK English.          |\n"
    "| Press '3' followed by Enter to change the language to German.              |\n"
   "+----------------------------------------------------------------------------+\n";
//を、次の内容に変更する
static const std::string LOCALE_MESSAGE =
    "+----------------------------------------------------------------------------+\n"
    "|                          Language Options:                                 |\n"
    "|                                                                            |\n"
    "| Press '1' followed by Enter to change the language to Japan.               |\n"
    "| Press '2' followed by Enter to change the language to UK English.          |\n"
    "| Press '3' followed by Enter to change the language to German.              |\n"
    "| Press '4' followed by Enter to change the language to US English.          |\n"
    "+----------------------------------------------------------------------------+\n";
```
メニューの変更をテーブルにも反映

```cpp:/sdk-folder/sdk-source/avs-device-sdk/SampleApp/src/UIManager.cpp
//44行目　日本語を追加し、英語と入れ替える
static const std::unordered_map<char, std::string> LOCALE_VALUES({{'1', "ja-JP"}, {'2', "en-GB"}, {'3', "de-DE"},{'4', "en-US"}});

```

**２.４ AVSのSDKをビルド**
まずはcmakeを走らせます。
ウェイクワードをONやgstreamer許可なのをオプションとして設定しています。

```
cd /home/pi/sdk-folder/sdk-build && cmake /home/pi/sdk-folder/sdk-source/avs-device-sdk -DSENSORY_KEY_WORD_DETECTOR=ON -DSENSORY_KEY_WORD_DETECTOR_LIB_PATH=/home/pi/sdk-folder/third-party/alexa-rpi/lib/libsnsr.a -DSENSORY_KEY_WORD_DETECTOR_INCLUDE_DIR=/home/pi/sdk-folder/third-party/alexa-rpi/include -DGSTREAMER_MEDIA_PLAYER=ON -DPORTAUDIO=ON -DPORTAUDIO_LIB_PATH=/home/pi/sdk-folder/third-party/portaudio/lib/.libs/libportaudio.a -DPORTAUDIO_INCLUDE_DIR=/home/pi/sdk-folder/third-party/portaudio/include
```
そしてmake
`make SampleApp -j3`
>makeのjオプションは並行処理の数で多い方がより高速になるがリスクもあるので、とりあえず3程度で。安全なのはもちろんjオプションなし。

**３. AVSの認証**
**３.１ プロダクトの登録**
[amazon](https://developer.amazon.com/)へサインインして今回のプロダクトを登録します。
入力方法は[こちら](https://github.com/alexa/alexa-avs-sample-app/wiki/Create-Security-Profile)を参考に(https://github.com/alexa/alexa-avs-sample-app/wiki/Create-Security-Profile)
>この登録で設定したProductID,ClientID,ClientSecretの3つは認証時に必ず必要になるよ！

**３.２ AlexaClientSDKConfig.jsonの設定**
これは認証実行時に必要な情報を定義する設定ファイルです
>場所：/home/pi/sdk-folder/sdk-build/Integration
>ファイル名：AlexaClientSDKConfig.json

```json:AlexaClientConfig.json
{
    "authDelegate":{
        "clientSecret”:”Amazonへ設定したClientSecret”,
        "deviceSerialNumber":"123456”,（適当でいい）
        "refreshToken”:”{デフォルトの状態にしておく、認証後に自動的に追加されるため}”,
        "clientId”:”Amazonへ設定したclientID”,
        "productId”:”Amazonへ設定したproductID”
    },
    "alertsCapabilityAgent":{
        "databaseFilePath":"/home/pi/sdk-folder/application-necessities/alerts.db",
        "alarmSoundFilePath":"/home/pi/sdk-folder/application-necessities/sound-files/med_system_alerts_melodic_01._TTH_.mp3",
        "alarmShortSoundFilePath":"/home/pi/sdk-folder/application-necessities/sound-files/med_system_alerts_melodic_01_short._TTH_.wav",
        "timerSoundFilePath":"/home/pi/sdk-folder/application-necessities/sound-files/med_system_alerts_melodic_02._TTH_.mp3",
        "timerShortSoundFilePath":"/home/pi/sdk-folder/application-necessities/sound-files/med_system_alerts_melodic_02_short._TTH_.wav"
    },
    "settings":{
        "databaseFilePath":"/home/pi/sdk-folder/application-necessities/settings.db",
        "defaultAVSClientSettings":{
            "locale":"ja-JP"
        }
    },
    "certifiedSender":{
        "databaseFilePath":"/home/pi/sdk-folder/application-necessities/certifiedSender.db
    }
}
```

**３.３ 認証**
認証用プログラムを起動、3000ポートで待ち受けます
`cd /home/pi/sdk-folder/sdk-build && python AuthServer/AuthServer.py`
	
ブラウザを立ち上げ[http://localhost:3000](http://localhost:3000)へアクセス
Developer用のアカウントを聞かれるのでログイン
ログインが成功するとWindowを閉じろというメッセージが出て認証完了
>※AlexaClientSDKConfig.jsonのrefreshTokenに新たなトークンが追加されていることが確認できます。

**４ 実行**
**４.１ マイクのテスト**
テストの前にpiのカレントに設定ファイルを用意します。
>ファイル名：.asoundrc
>場所：ユーザーカレントディレクトリ

```bash:.asoundrc
pcm.!default{
    type asym
    playback.pcm {
        type plug
        slave.pcm "hw:0,0"
    }
    capture.pcm {
        type plug
        slave.pcm "hw:1,0"
    }
}
```
>※playbackは再生、captureは入力の設定ブロックになっている。
>slave.pcmの値hw:はa,b　a=カード b=デバイス番号となっている。
>ラズパイに差したスピーカーとマイクの値を確認し設定すること。
>`aplay -l`で確認できる。

**４.２ soxのインストール**
音声の加工や編集が出来るコマンドですー。
`sudo apt-get install sox -y `

**４.３ マイクとスピーカーの入出力テスト**
`rec test.wav`
>実行したら何か話してみよう。
>声に合わせて入力ボリュームが変化している様子がコマンドから分かると思う。
>それが確認できたらControl+Cで終了

`aplay /usr/share/sounds/alsa/Front_Center.wav'
>「フロントセンタ〜」っていう女性の声が聞こえたらOK
>もし聞こえない場合はスピーカーの接続種別により次の設定を行って下さい

`sudo amixer cset numid=3 x`
>ｘは接続の種類です。
>０：自動判別
>１：ライン入力(3.5mm)
>２：HDMI
>自動判別の場合はHDMIが優先されます。

**４.４ いよいよAlexa起動**
srcに移動
`cd /home/pi/sdk-folder/sdk-build/SampleApp/src`
SampleAPPを起動

```
TZ=UTC ./SampleApp /home/pi/sdk-folder/sdk-build/Integration/AlexaClientSDKConfig.json /home/pi/sdk-folder/third-party/alexa-rpi/models
```
SampleAPPの引数に設定ファイルであるAlexaClientSDKConfig.jsonとmodelsを指定

**４.５ 「Alexa! こんにちは!」と話しかけてみよう。**
あとは、スマホにAlexa APPを追加するか[ここ](https://alexa.amazon.co.jp/)から好きなスキルを追加してみましょう。

カスタムスキルの作り方(Alexa Skills KitとLambda）はいろんな人が書いてるのでそちらを見てください。