Docker for Mac で動いているコンテナでホスト側のサウンドカードを使う

自分でスマートスピーカーを作りたくなり、音声認識のところで Julius をいじってるなう。Julius を含む音声認識部分をコンテナで切り出しているところでホスト側 (macOS) のサウンドカードを使わせるようにしたかったのでやり方をメモっておく。

macOS ではなく ALSA の使える Linux 環境であれば Docker の --device オプションで --device=/dev/snd:/dev/snd としたりすれば動くらしい。VirtualBox だとオーディオ設定からホスト側のサウンドカードを利用できるので、コンテナを VirtualBox 上で動かすことで Docker の device オプションによりホスト側サウンドカードを利用できる。VirtualBox を経由するのではなく別のやり方が無いか調べていたら PulseAudio 経由で音声を再生するやり方も見つかったので、これをベースに音声入力もできないか試してみた。

audio - Record Sound on Ubuntu Docker Image - Stack Overflow

大まかな説明

  • コンテナ側
    • PulseAudio の設定で音声データの入力元を /dev/audio とかにしておく
    • socat の tcp-listen で port に流れてきた音声データを /dev/audio に流し込む準備をしておく
  • ホスト側 (macOS)
    • SoX (Sound exhange) でマイクからの音声データを socat で待ち受けているポートに流し込む
  • コンテナ側で録音できる

検証作業

  • Dockerfile
FROM ubuntu

RUN apt-get update && apt-get install -y pulseaudio socat alsa-utils
  • コンテナ側
bash-3.2$ docker build -t mictest . && docker run -p 127.0.0.1:3000:3000 -v `pwd`:/mictest -it mictest
...
root@bf3b26a44c0e:/# pulseaudio -D --exit-idle-time=-1
W: [pulseaudio] main.c: This program is not intended to be run as root (unless --system is specified).
root@bf3b26a44c0e:/# pacmd load-module module-pipe-source file=/dev/audio format=s16 rate=44100 channels=2
root@bf3b26a44c0e:/# socat tcp-listen:3000 file:/dev/audio &
  • ホスト側
bash-3.2$rec --encoding signed-integer -traw --bits 16 --channels 2 --rate 44100 - | nc 127.0.0.1 3000 > /dev/null

rec は SoX の録音用ラッパー。

  • コンテナに戻って
root@8c421891ff69:/# arecord /mictest/test.wav
Recording WAVE 'test.wav' : Unsigned 8 bit, Rate 8000 Hz, Mono
// この後めちゃくちゃ音を鳴らして Ctrl-C
  • test.wav を聞くと録音できているよかった

おわり

  • ネットワーク経由で PulseAudio 使ったことなかったけど具体的な使い方が見えてきたのでよかった
  • SoX は音量の閾値を超えたら録音開始したり、色々できるようで便利
    • 音声処理ツールのスイスアーミーナイフとトップページに書かれているだけある
  • 実際は Raspbian にのっけたいので実機で確認したいところだが開発中は手元の MacBook Pro で音声入力でやっていきたい