#topicpath
 * sndio - OpenBSDの音声フレームワーク [#t571d65f]
 RIGHT:EBUG 第66回会合 ~
 2018年 8月25日、長岡市 ながおか市民センター ~
 川俣吉広、kaw@on.rim.or.jp
 
 **概要 [#xbc2884e]
 sndioはOpenBSDで開発された音声を扱うための仕組みで、2008年にAlexandre RatchovらによってOpenBSD 4.5に導入された。
 [[sndio(7)>https://man.openbsd.org/sndio.7]]はOpenBSDで音声を統一的に扱うための仕組みで、Alexandre Ratchovらによって2008年リリースのOpenBSD 4.5に導入された。
 現在は、FreeBSD/NetBSD/Linuxにも移植されている。
 
 sndioは他のオーディオフレームワーク(ALSA, JACK, OSS, PulseAudioなど)と同様、音声を扱うハードウェアとアプリケーションとの橋渡しをする。
 具体的には、以下のような機能を持っている。
 ALSA, JACK, OSS, PulseAudioなどの音声フレームワークと同様、sndioは音声を扱うハードウェアとアプリケーションとの橋渡しをする。
 具体的には、sndioは以下のような機能を持っている。
 
 -音声デバイスを直接アクセスした場合、デバイスにアクセスできるは単一のアプリケーションだけ。
 -音声デバイスの共有
 音声アプリケーションがデバイスに直接アクセスした場合単一のアプリケーションだけがアクセスできる。
 sndioを介在させることで複数のアプリケーションが同時に音声を再生・収録できることを可能にする。
 
 -音声のフォーマット変換を行う。
 音声データの形式、サンプルレート、量子化ビット深度、チャンネル数などのパラメータが音声デバイスとアプリケーションとで異っていても、sndioで変換を行うことで支障なく使用できる。
 
 -音源の制御を可能にする。
 sndioは音声データそのもの以外に、起動・停止、音量制御、タイムコードなどををMIDIプロトコルを使用して伝送することができる。これにより、音源の制御を行うことができる。
 sndioは音声データそのもの以外に、起動・停止、音量制御、タイムコードなどをMIDIプロトコルを使用して伝送することができる。これにより、音源の制御を行うことができる。
 
 -信号のルーティングを行う。
 sndioサウンドサーバでは複数の音源をミックスしたり、あるいは複数の音声アプリケーションへ送出するなどのルーティング行う。
 これらの伝送はネットワークを経由して、他ホストで稼動している音声デバイスやアプリケーションを使用することもできる。
 
 **構成 [#z972347e]
 以下に、OpenBSDでsndioフレームワークが動作している例を示す。
 #ref(sndio.png);
 
 :ハードウェア|様々な音声機器は、PC内の音声コーデックに接続される。コーデックはアナログ機器とのA/D, D/A変換や複数入出力のミキシングやファンアウト、そして各信号のレベル制御などをおこなう。
 
 :デバイスドライバ|カーネル内には、コーデックに対応したデバイスドライバがあり、コーデックの機種毎の機能に対応した制御を行う。
 例えばIntelのICHxxチップはHD Audio規格に準拠しており、これに対応するドライバは、azalia(4)である。
 各コーデックに対応したドライバの上にはaudio(4)があり、これがユーザプロセスに対して一貫したAPIを提供する。
 このレイヤーを参照・操作するツールとしてaudioctl(1)やmixerctl(1)が提供されている。
 例えばIntelのICH8 I/Oコントローラ・ハブは[[Intel(R) HD Audio規格のコーデック>http://www.vitalsparks.com/hdaudio.html]]を搭載しており、これに対応するドライバは、[[azalia(4)>https://man.openbsd.org/azalia.4]]である。
 各コーデックに対応したドライバの上には[[audio(4)>https://man.openbsd.org/audio.4]]があり、これがユーザプロセスに対して一貫したAPIを提供する。
 このレイヤーを参照・操作するツールとして[[audioctl(1)>https://man.openbsd.org/audioctl.1]]や[[mixerctl(1)>https://man.openbsd.org/mixerctl.1]]が提供されている。
  $ audioctl
  name=azalia0
  mode=play,record
  pause=0
  active=1
  nblks=8
  blksz=960
  rate=48000
  encoding=s16le
  play.channels=2
  play.bytes=3796930560
  play.errors=883200
  record.channels=2
  record.bytes=3796930560
  record.errors=552960
  
 ~
  $ mixerctl -v | sort
  inputs.dac-0:1=234,234 
  inputs.beep=119 
  inputs.beep_mute=off  [ off on ]
  inputs.dac-2:3=234,234 
  inputs.hp_source=sel6,mix6  { sel6 mix6 }
  inputs.mic2=0,0 
  inputs.mic3=0,0 
  inputs.mic3_source=sel7,mix6  { sel7 mix6 }
  inputs.mic=0,0 
  inputs.mix4_source=sel3,mix6  { sel3 mix6 }
  inputs.mix6_mic2=0,0 
  inputs.mix6_mic=0,0 
  inputs.mix6_source=mic,mic2  { mic mic2 }
  inputs.sel3_source=dac-0:1  [ dac-0:1 dac-2:3 ]
  inputs.sel4_source=dac-0:1  [ dac-0:1 dac-2:3 ]
  inputs.sel6_source=dac-0:1  [ dac-0:1 dac-2:3 ]
  inputs.sel7_source=dac-0:1  [ dac-0:1 dac-2:3 ]
  inputs.spkr_source=dac-2:3,mix6  { dac-2:3 mix6 }
  outputs.hp_boost=off  [ off on ]
  outputs.hp_mute=off  [ off on ]
  outputs.hp_sense=plugged  [ unplugged plugged ]
  outputs.master.mute=off  [ off on ]
  outputs.master.slaves=dac-0:1,dac-2:3,hp,spkr  { dac-0:1 dac-2:3 beep hp spkr mic3 mix6 mic3 }
  outputs.master=255,255 
  outputs.mic2_dir=input-vr80  [ none input input-vr0 input-vr50 input-vr80 input-vr100 ]
  outputs.mic3_dir=input-vr80  [ none output input input-vr0 input-vr50 input-vr80 input-vr100 ]
  outputs.mic3_mute=off  [ off on ]
  outputs.mic3_sense=unplugged  [ unplugged plugged ]
  outputs.mic_dir=input-vr80  [ none input input-vr0 input-vr50 input-vr80 input-vr100 ]
  outputs.mic_sense=plugged  [ unplugged plugged ]
  outputs.mix6=0,0 
  outputs.mix6_mute=off  [ off on ]
  outputs.spkr_boost=off  [ off on ]
  outputs.spkr_eapd=on  [ off on ]
  outputs.spkr_mute=on  [ off on ]
  outputs.spkr_muters=hp,mic3  { hp mic3 }
  record.adc-0:1=200,200 
  record.adc-0:1_mute=off  [ off on ]
  record.adc-0:1_source=mic  [ mic mic2 ]
  record.adc-2:3=200,200 
  record.adc-2:3_mute=off  [ off on ]
  record.adc-2:3_source=mic2  [ mic mic2 ]
  record.volume.mute=off  [ off on ]
  record.volume.slaves=adc-2:3,adc-0:1  { adc-2:3 adc-0:1 mic mic2 }
  record.volume=200,200 
 
 :音声サーバ - [[sndiod(8)>https://man.openbsd.org/sndiod.8]]|sndioフレームワークの中核で、OpenBSDブート時に起動され、デフォルトの音声デバイス/dev/audio0へのアクセスを提供する。前節の「概要」で述べた機能の殆どは、このsndiodが持っている。
 
 :ユーザコマンド - [[aucat(1)>https://man.openbsd.org/aucat.1]]|コマンドレベルでsndioにアクセスするためのツール。
 aucatもsndiod同様、sndioの機能の殆どを提供する。
 sndiodがデーモンとしてバックグラウンドで機能を提供するのに対し、aucatはユーザが直接オンライン、あるいはオフラインでsndioの機能を利用することを意図して作成されている。
 例えば、aucatには処理を行う音声データをファイルから入力したり、ファイルへ出力したりする機能がある。
 aucatコマンド自体はOpenBSD 2.0から存在し、sndioフレームワークが登場する以前のOpenBSD 4.3までは単に複数の音声ファイルを連結して再生する(concatenate and play audio files)コマンドだった。
 OpenBSD 4.5でsndioフレームワークが登場した時点ではsndiodはなくaucatがデーモンの役目を追っていたが、OpenBSD 5.1以降はsndiodとaucatとに役割が分割された。
 
 :オーディオサーバ - sndiod|
 
 :ユーザコマンド - aucat|
 
 :音声アプリケーション|
 
 **API [#ba4463c8]
 
 **使用例 [#x7ebf0e4]
 
 **情報源 [#fcd638e8]
 
 ----
 #topicpath
Top Index Search Recent Backups  Help  RSS