この連載のLXCの構築・活用のシリーズが、今回で3回目を迎えました。目的に合わせたパッケージ構成で、システムコンテナを作成・構築することに、だいぶ慣れてきたかと思います。皆さまは、作成・構築したコンテナをどのように利用されているでしょうか。
LXCでコンテナを使うときは、たいていサーバ用途のアプリケーションを導入して運用することが多く、これまでコンテナ内でサウンドを使う手法は、あまり知られていませんでした。しかし、コンテナ上でサウンドを使うアプリケーションの利用や評価を行ったり、多数のコンテナを起動して、利用者向けにリモートコンソール環境やリモートデスクトップ環境を提供するなど、サウンドを必要とする場面も考えられ、このような使い方に興味をお持ちの方も多いのではないかと思います。今回は、コンテナ内でサウンドを取り扱うにはどうすれば良いのかを紹介していきます。
Linuxにおける主なサウンドシステム・サウンドサーバ
まず、Linuxにおける主なサウンドシステム・サウンドサーバについて、簡単に整理しておきましょう。
- Open Sound System(OSS)
- UNIXベースのプラットフォームで使うことができるサウンドシステムで、ハードウェアを直接制御するOSSドライバを含んでいます。
- Advanced Linux Sound Architecture(ALSA)
- OSSを置き換えるために開発されたLinuxにおける高機能なサウンドシステムで、現在はALSAが主流となっています。ALSAドライバとOSSエミュレーション機能を含んでいます。
- Enlightened Sound Daemon(ESD、EsounD)
- GNOMEで使われていたサウンドサーバで、実行中の各種アプリケーションが出力するサウンドを取りまとめて、ローカルデバイスやネットワーク先のデバイスに送り出します。
- PulseAudio
- ESDの置き換えとして、クロスプラットフォームでネットワークに対応したサウンドサーバで、現在はPulseAudioが主流となっています。ESDエミュレーション機能を含んでいます。
これらのサウンドシステム・サウンドサーバの関係は、図1のようになっています。基本的に、OSS APIを使用したアプリケーションは/dev/dsp
、/dev/audio
など(OSS互換デバイスファイル)を通じてデバイスにアクセスし、ALSA APIを使用したアプリケーションは/dev/snd/*
(ALSAデバイスファイル)を通じてデバイスにアクセスします。Plamo Linuxでは、aplay
コマンドなどのALSA APIを使用したアプリケーションやesdplay
コマンドなどのESD APIを使用したアプリケーションは、paplay
コマンドなどのPulseAudio APIを使用したアプリケーションとともに、PulseAudioを経由して処理されるように設定されており、またOSS APIを使用したアプリケーションについても、padsp
コマンド(ラッパープログラム)使って、PulseAudioで一元的に管理することができます。
OSSを経由してサウンドを出力する
まず、ホスト上で音を出すことを考えてみましょう。OSS互換オーディオデバイスファイルを経由してサウンドを出力する仕組みはとても簡単です。Sunオーディオファイルであれば、以下のように/dev/audio
にリダイレクトすることにより、音を出すことができます。
一般的なWAVファイルのような、Sunオーディオファイル以外の音声ファイルについては、/dev/dsp
を使います。このとき、音声ファイルをそのままリダイレクトするのではなく、/dev/dsp
をオープンしてから音声ファイル形式を設定し、そこに音声データを流し込むことにより、音を出ことができます。
ここで、16ビット/ステレオ/44.1kHzの音声ファイルを再生するサンプルプログラム(dsptest.c
)を紹介します。わかりやすさ優先で、ファイル名は決め打ち、エラー処理は必要最小限に止めた簡単なプログラムです。
以下のようにコンパイルして実行することにより、音を出すことができます。このプログラムは後で使いますので、残しておいてください。
コンテナ内でサウンドを出力する(OSS)
それでは、いよいよコンテナ内で音を出すことを試してみましょう。あらかじめ、taro
ユーザがroot権限でdefault
バリアントのPlamoコンテナct01
を作成し、そのコンテナ内で作成したhanako
ユーザが音を出すことを試みます。
コンテナ内に/dev/audio
や/dev/dsp
が存在しないため、音が出ませんね。そこで、ホストにいるtaro
ユーザが以下のコマンドを実行して、OSS互換オーディオデバイスファイルを作成します。
また、オーディオデバイスにアクセスできるように、以下の設定をコンテナの設定ファイル(/var/lib/lxc/ct01/config
)に追加して、コンテナを再起動します。
これらの設定により、音が出るかどうか再び試みます。
これで音が出るようになりました。
コンテナ内でサウンドを出力する(ALSA)
次に、ALSA APIを使用したaplay
コマンドを使って音を出してみましょう。実行したところ、以下のエラーが出てしまいました。
はい、コンテナ内に/dev/snd/*
が存在しないためですね。ホストにいるtaro
ユーザが以下のコマンドを実行して、/dev/snd
ディレクトリを作成します。
また、/dev/snd
をバインドマウントする処理を含めた以下の設定を、コンテナの設定ファイル(/var/lib/lxc/ct01/config
)に追加して、コンテナを再起動します。
これらの設定により、音が出るかどうか再び試みます。
これで音が出るようになりました。
非特権コンテナ内でサウンドを出力する
一般ユーザ権限で利用するコンテナ(非特権コンテナ)で音を出すための設定は、ここまでの節で説明してきたroot権限で利用するコンテナで音を出すための設定とほぼ同じです。ただし、デバイスファイルを作成する代わりにバインドマウントを行い、デバイスファイルのパーミッションを変更する必要があります。
あらかじめ、taro
ユーザが一般ユーザ権限でdefault
バリアントのPlamoコンテナct01
(非特権コンテナ)を作成し、そのコンテナ内でhanako
ユーザを作成しておきます。非特権コンテナでは、キャラクタデバイスやブロックデバイスを作成するmknod
は実行できないので、代わりにOSS互換オーディオデバイスファイルをバインドマウントする処理を含めた以下の設定を、コンテナの設定ファイル(/var/lib/lxc/ct01/config
)に追加して、コンテナを再起動します。
また、コンテナ内のhanako
ユーザは、ホストOSのaudio
グループ権限を持っていないので、ホスト上でオーディオデバイスファイルのパーミッションを変更して、コンテナ内のhanako
ユーザが、オーディオデバイスファイルにアクセスできるようにする必要があります。
これらの設定により、音が出るようになります。
これで、root権限で利用するコンテナ、一般ユーザ権限で利用するコンテナ(非特権コンテナ)ともに、コンテナ内から音を出すことができました。
サウンドサーバを使ってコンテナ内のサウンドを出力する
ここまでの節で説明した方法は、ホストOSで管理しているサウンドデバイスを、コンテナが使いたいときに、早いもの勝ちで利用する仕組みです。すなわち、あるアプリケーションがサウンドデバイスを使っている間、他のアプリケーションはサウンドデバイスを使用できなくなります。ホストにいるtaro
ユーザとコンテナ内のhanako
ユーザが、あらかじめサウンドデバイスを使う割り当て時間を決めておき、ルールを守って仲良くシェアしているうちは良いのですが、多数のコンテナを起動して、多くの利用者が同時に使うような状況では、かなり難しい運用であることが想像できると思います。
そこで、ネットワークに対応したサウンドサーバ(PulseAudio)を使って、コンテナ内のサウンドを出力することを考えてみましょう。PulseAudioは、default
バリアントのPlamoコンテナに含まれていないので、pulseaudio
パッケージを追加するか、PulseAudioを含むバリアントのPlamoコンテナを用意する必要があります。ここでは、手っ取り早くlarge
バリアントのPlamoコンテナを作成して、PulseAudioを使った方法を試してみましょう。
あらかじめ、以下のコマンドでtaro
ユーザが一般ユーザ権限でlarge
バリアントのPlamoコンテナct02
(非特権コンテナ)を作成し、そのコンテナ内でhanako
ユーザを作成しておきます。
なお、lxc-1.0.6以前の安定版で作成したPlamoコンテナでは、/dev/shm
ディレクトリが存在せず、PulseAudioが必要とするshm_open()
システムコールが使えない状態になっているので、lxc-1.0.7以降の安定版※にアップデートするか、LXCの修正パッチを参考に、お手元の/usr/share/lxc/templates/lxc-plamo
と/usr/share/lxc/config/plamo.common.conf
を修正してから、コンテナを作成するようにしてください。
さて、準備ができたようなので、PulseAudioの設定を行いましょう。
ホストOSと同一セグメント(192.168.1.0/24
)にあるコンテナからの音声データの受け付けを許可するため、ホストにいるtaro
ユーザは、/etc/pulse/default.pa
を~/.config/pulse/default.pa
にコピーしてから、以下の行を編集します。
ESDとPulseAudioのサウンドサーバが同居する場合、ESDの機能はPulseAudioがエミュレートするため、module-native-protocol-tcp
のモジュールだけでなく、module-esound-protocol-tcp
のモジュールもロードしておく必要があります。
また、ホストOSのIPアドレス(192.168.1.2
)に音声データを送信するため、コンテナ内のhanako
ユーザは、/etc/pulse/client.conf
を~/.config/pulse/client.conf
にコピーしてから、以下の行を編集します。
このように設定すると、図2のようにコンテナからホストのPulseAudioサウンドサーバが透過的に見え、コンテナ内のアプリケーションにとって、あたかもホスト上でサウンドデバイスにアクセスしているような状態になります。
それでは、実際に動かしてみましょう。
以下は、PulseAudio APIを使用したアプリケーションとして、paplay
コマンドを実行する例です。
以下は、ALSA APIを使用したアプリケーションとして、aplay
コマンドを実行する例です。PulseAudioを経由して処理されています。
以下は、ESD APIを使用したアプリケーションとして、esdplay
コマンドを実行する例です。ホストOSのIPアドレス(192.168.1.2
)に音声データを送信するため、あらかじめESPEAKER
の環境変数を設定しておきます。
以下は、OSS APIを使用したアプリケーションとして、あらかじめ作成しておいたdsptest
コマンドを実行する例です。dsptest
コマンドを、padsp
コマンド(ラッパープログラム)の引数として実行することにより、PulseAudioを経由して処理されます。
このように、どのサウンドAPIを使用したアプリケーションでも、PulseAudioで一元的に管理して、コンテナ内でサウンドを出力できることが、おわかりいただけたかと思います。
また、多数のコンテナを起動して、利用者向けにリモートコンソール環境やリモートデスクトップ環境を提供するような適用例では、それぞれの利用者の端末側に音声データを送るように設定すれば良いでしょう。
まとめ
今回は、コンテナ内でサウンドの取り扱いについて紹介しました。これにより、LXCを使ったコンテナの用途の幅が、大きく広がったことと思います。
コンテナ内でサウンドを出力する方法として、前半ではホストOSで管理しているサウンドデバイスを共有する方法を紹介し、後半ではサウンドサーバ(PulseAudio)を使う方法を紹介しました。PulseAudioが含まれないdefault
バリアントやmini
バリアントのPlamoコンテナでは、前半で紹介した方法を使い、PulseAudioが含まれるlarge
バリアントやfull
バリアントのPlamoコンテナでは、後半で紹介した方法を使うことになります。
前々回から3回にわたって連載したLXCの構築・活用のシリーズが、今回で一区切りついたので、次回からは加藤さんに一旦バトンを戻しまして、ユーザネームスペースの利用について紹介する予定です。