RaspberryPi3上のLXCコンテナでWAVファイルを再生する準備をする


# やりたいこと
[RaspberryPi3にLXC/LXDを使ってコンテナ環境を作り](https://qiita.com/hatayan1126/items/79d9ba7f3dd1d3803f49)、その中のコンテナでWAVファイルを再生し、RaspberryPi3本体に接続したスピーカーから音をだす。

# 環境
- Raspberry Pi 3 MODEL B
- Raspbian 9.4(stretch)

```shell-session
pi@raspberrypi:~ $ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 9.4 (stretch)
Release:        9.4
Codename:       stretch
pi@raspberrypi:~ $
```


# やったこと

## RaspberryPi3本体で音を出す仕組みを確認

RaspberryPi3本体のサウンドカード周りのデバイスファイルを確認
Advanced Linux Sound Architecture（ALSA）を使っているらしいので /dev/snd 以下がそれにあたる。

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ ls -l /dev/snd
合計 0
drwxr-xr-x 2 root root       60  5月 29 23:22 by-path
crw-rw---- 1 root audio 116,  0  5月 29 23:22 controlC0
crw-rw---- 1 root audio 116, 16  5月 29 23:22 pcmC0D0p
crw-rw---- 1 root audio 116, 17  5月 29 23:22 pcmC0D1p
crw-rw---- 1 root audio 116,  1  5月 29 23:22 seq
crw-rw---- 1 root audio 116, 33  5月 29 23:22 timer
pi@raspberrypi:~ $ tree  --charset=C /dev/snd/
/dev/snd/
|-- by-path
|   `-- platform-soc:audio -> ../controlC0
|-- controlC0
|-- pcmC0D0p
|-- pcmC0D1p
|-- seq
`-- timer

1 directory, 6 files
pi@raspberrypi:~ $
```

aplayコマンドでデバイスを認識しているか確認。
このとき、コマンドを実行するユーザーが audio グループに所属している必要がある。

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ id pi
uid=1000(pi) gid=1000(pi) groups=1000(pi), ・・・29(audio),・・・
pi@raspberrypi:~ $
pi@raspberrypi:~ $ aplay -l
**** ハードウェアデバイス PLAYBACK のリスト ****
カード 0: ALSA [bcm2835 ALSA], デバイス 0: bcm2835 ALSA [bcm2835 ALSA]
  サブデバイス: 7/7
  サブデバイス #0: subdevice #0
  サブデバイス #1: subdevice #1
  サブデバイス #2: subdevice #2
  サブデバイス #3: subdevice #3
  サブデバイス #4: subdevice #4
  サブデバイス #5: subdevice #5
  サブデバイス #6: subdevice #6
カード 0: ALSA [bcm2835 ALSA], デバイス 1: bcm2835 ALSA [bcm2835 IEC958/HDMI]
  サブデバイス: 1/1
  サブデバイス #0: subdevice #0
pi@raspberrypi:~ $
pi@raspberrypi:~ $ aplay -L
null
    Discard all samples (playback) or generate zero samples (capture)
default:CARD=ALSA
    bcm2835 ALSA, bcm2835 ALSA
    Default Audio Device
sysdefault:CARD=ALSA
    bcm2835 ALSA, bcm2835 ALSA
    Default Audio Device
dmix:CARD=ALSA,DEV=0
    bcm2835 ALSA, bcm2835 ALSA
    Direct sample mixing device
dmix:CARD=ALSA,DEV=1
    bcm2835 ALSA, bcm2835 IEC958/HDMI
    Direct sample mixing device
dsnoop:CARD=ALSA,DEV=0
    bcm2835 ALSA, bcm2835 ALSA
    Direct sample snooping device
dsnoop:CARD=ALSA,DEV=1
    bcm2835 ALSA, bcm2835 IEC958/HDMI
    Direct sample snooping device
hw:CARD=ALSA,DEV=0
    bcm2835 ALSA, bcm2835 ALSA
    Direct hardware device without any conversions
hw:CARD=ALSA,DEV=1
    bcm2835 ALSA, bcm2835 IEC958/HDMI
    Direct hardware device without any conversions
plughw:CARD=ALSA,DEV=0
    bcm2835 ALSA, bcm2835 ALSA
    Hardware device with all software conversions
plughw:CARD=ALSA,DEV=1
    bcm2835 ALSA, bcm2835 IEC958/HDMI
    Hardware device with all software conversions
pi@raspberrypi:~ $
```


## RaspberryPi3のデバイスファイルをコンテナに登録する

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxc config device add container1 controlC0 unix-char source=/dev/snd/controlC0 path=/dev/snd/controlC0
Device controlC0 added to container1
pi@raspberrypi:~ $ lxc config device add container1 pcmC0D0p unix-char source=/dev/snd/pcmC0D0p path=/dev/snd/pcmC0D0p
Device pcmC0D0p added to container1
pi@raspberrypi:~ $ lxc config device add container1 pcmC0D1p unix-char source=/dev/snd/pcmC0D1p path=/dev/snd/pcmC0D1p
Device pcmC0D1p added to container1
pi@raspberrypi:~ $ lxc config device add container1 seq unix-char source=/dev/snd/seq path=/dev/snd/seq
Device seq added to container1
pi@raspberrypi:~ $ lxc config device add container1 timer unix-char source=/dev/snd/timer path=/dev/snd/timer
Device timer added to container1
pi@raspberrypi:~ $
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxc config device show container1
controlC0:
  path: /dev/snd/controlC0
  source: /dev/snd/controlC0
  type: unix-char
pcmC0D0p:
  path: /dev/snd/pcmC0D0p
  source: /dev/snd/pcmC0D0p
  type: unix-char
pcmC0D1p:
  path: /dev/snd/pcmC0D1p
  source: /dev/snd/pcmC0D1p
  type: unix-char
seq:
  path: /dev/snd/seq
  source: /dev/snd/seq
  type: unix-char
timer:
  path: /dev/snd/timer
  source: /dev/snd/timer
  type: unix-char
pi@raspberrypi:~ $
```

## コンテナ側で確認

コンテナ側で /dev/snd/* が生成されているのを確認

```shell-session
pi@raspberrypi:~ $
pi@raspberrypi:~ $ lxc exec container1 /bin/bash
root@container1:~#
root@container1:~# ls -la /dev/snd
合計 0
drwxr-xr-x 2 root root     140  6月 15 15:23 .
drwxr-xr-x 9 root root     480  6月 15 15:01 ..
crw-rw---- 1 root root 116,  0  6月 15 15:22 controlC0
crw-rw---- 1 root root 116, 16  6月 15 15:22 pcmC0D0p
crw-rw---- 1 root root 116, 17  6月 15 15:23 pcmC0D1p
crw-rw---- 1 root root 116,  1  6月 15 15:23 seq
crw-rw---- 1 root root 116, 33  6月 15 15:23 timer
```

RaspberryPi3本体と同じになるようにコンテナ側で /dev/snd 以下を調整する。

```shell-session
root@container1:~#
root@container1:~# cd /dev/snd
root@container1:/dev/snd#
root@container1:/dev/snd# mkdir by-path/
root@container1:/dev/snd#
root@container1:/dev/snd# cd by-path/
root@container1:/dev/snd/by-path#
root@container1:/dev/snd/by-path# ln -s ../controlC0 platform-soc:audio
root@container1:/dev/snd/by-path#
root@container1:/dev/snd/by-path# ls -al
合計 0
drwxr-xr-x 2 root root  60  6月 15 15:25 ./
drwxr-xr-x 3 root root 160  6月 15 15:24 ../
lrwxrwxrwx 1 root root  12  6月 15 15:25 platform-soc:audio -> ../controlC0
root@container1:/dev/snd/by-path# cd ..
root@container1:/dev/snd# ls -la
合計 0
drwxr-xr-x 3 root root     160  6月 15 15:24 .
drwxr-xr-x 9 root root     480  6月 15 15:01 ..
drwxr-xr-x 2 root root      60  6月 15 15:25 by-path
crw-rw---- 1 root root 116,  0  6月 15 15:22 controlC0
crw-rw---- 1 root root 116, 16  6月 15 15:22 pcmC0D0p
crw-rw---- 1 root root 116, 17  6月 15 15:23 pcmC0D1p
crw-rw---- 1 root root 116,  1  6月 15 15:23 seq
crw-rw---- 1 root root 116, 33  6月 15 15:23 timer
root@container1:/dev/snd#
root@container1:/dev/snd# chown root.audio controlC0 pcmC0D0p pcmC0D1p seq timer
root@container1:/dev/snd#
root@container1:/dev/snd# ls -la
合計 0
drwxr-xr-x 3 root root      160  6月 15 15:24 .
drwxr-xr-x 9 root root      480  6月 15 15:01 ..
drwxr-xr-x 2 root root       60  6月 15 15:25 by-path
crw-rw---- 1 root audio 116,  0  6月 15 15:22 controlC0
crw-rw---- 1 root audio 116, 16  6月 15 15:22 pcmC0D0p
crw-rw---- 1 root audio 116, 17  6月 15 15:23 pcmC0D1p
crw-rw---- 1 root audio 116,  1  6月 15 15:23 seq
crw-rw---- 1 root audio 116, 33  6月 15 15:23 timer
root@container1:/dev/snd# 
root@container1:/dev/snd#  tree  --charset=C /dev/snd/
/dev/snd/
|-- by-path
|   `-- platform-soc:audio -> ../controlC0
|-- controlC0
|-- pcmC0D0p
|-- pcmC0D1p
|-- seq
`-- timer

1 directory, 6 files
root@container1:/dev/snd#
```

aplayコマンドでデバイスが認識しているか確認

```shell-session
root@container1:/dev/snd#
root@container1:/dev/snd# aplay -l
**** ハードウェアデバイス PLAYBACK のリスト ****
カード 0: ALSA [bcm2835 ALSA], デバイス 0: bcm2835 ALSA [bcm2835 ALSA]
  サブデバイス: 7/7
  サブデバイス #0: subdevice #0
  サブデバイス #1: subdevice #1
  サブデバイス #2: subdevice #2
  サブデバイス #3: subdevice #3
  サブデバイス #4: subdevice #4
  サブデバイス #5: subdevice #5
  サブデバイス #6: subdevice #6
カード 0: ALSA [bcm2835 ALSA], デバイス 1: bcm2835 ALSA [bcm2835 IEC958/HDMI]
  サブデバイス: 1/1
  サブデバイス #0: subdevice #0
root@container1:/dev/snd#
root@container1:/dev/snd# aplay -L
null
    Discard all samples (playback) or generate zero samples (capture)
default:CARD=ALSA
    bcm2835 ALSA, bcm2835 ALSA
    Default Audio Device
sysdefault:CARD=ALSA
    bcm2835 ALSA, bcm2835 ALSA
    Default Audio Device
dmix:CARD=ALSA,DEV=0
    bcm2835 ALSA, bcm2835 ALSA
    Direct sample mixing device
dmix:CARD=ALSA,DEV=1
    bcm2835 ALSA, bcm2835 IEC958/HDMI
    Direct sample mixing device
dsnoop:CARD=ALSA,DEV=0
    bcm2835 ALSA, bcm2835 ALSA
    Direct sample snooping device
dsnoop:CARD=ALSA,DEV=1
    bcm2835 ALSA, bcm2835 IEC958/HDMI
    Direct sample snooping device
hw:CARD=ALSA,DEV=0
    bcm2835 ALSA, bcm2835 ALSA
    Direct hardware device without any conversions
hw:CARD=ALSA,DEV=1
    bcm2835 ALSA, bcm2835 IEC958/HDMI
    Direct hardware device without any conversions
plughw:CARD=ALSA,DEV=0
    bcm2835 ALSA, bcm2835 ALSA
    Hardware device with all software conversions
plughw:CARD=ALSA,DEV=1
    bcm2835 ALSA, bcm2835 IEC958/HDMI
    Hardware device with all software conversions
root@container1:/dev/snd#
root@container1:/dev/snd#
```

これでコンテナ側でWAVファイルを再生すると、RaspberryPi3本体に接続したスピーカーから音がなるはず。

# 感想
ネットで「lxc audio」とかで検索しても解決策が見つからなかったので苦労した。

# 参考
- [Container configuration](https://github.com/lxc/lxd/blob/master/doc/containers.md)
- [RaspberryPi3上のLXCコンテナからRaspberryPi3本体のI2Cにアクセスする](https://qiita.com/hatayan1126/items/a5beb5aec1dc4a558d63)
- [第15回　LXCの構築・活用 [3] ― コンテナ内でサウンドを取り扱う](http://gihyo.jp/admin/serial/01/linux_containers/0015)