AUDIO(9)

名称
audio - 低レベル - 高レベルオーディオドライバ間のインタフェース

解説
オーディオデバイスドライバは、ハードウェアに依存しない高レベル層と、 ハードウェアに依存する低レベル層に分かれています。 この間のインタフェースは audio_hw_if 構造体です。

    struct audio_hw_if {
    	int	(*open)__P((void *, int));
    	void	(*close)__P((void *));
    	int	(*drain)__P((void *));
    	int	(*query_encoding)__P((void *, struct audio_encoding *));
    	int	(*set_params)__P((void *, int, int,
    			struct audio_params *, struct audio_params *));
    	int	(*round_blocksize)__P((void *, int));
    	int	(*commit_settings)__P((void *));
    	int	(*init_output)__P((void *, void *, int));
    	int	(*init_input)__P((void *, void *, int));
    	int	(*start_output)__P((void *, void *, int,
    				    void (*)(void *), void *));
    	int	(*start_input)__P((void *, void *, int,
    				   void (*)(void *), void *));
    	int	(*halt_output)__P((void *));
    	int	(*halt_input)__P((void *));
    	int	(*speaker_ctl)__P((void *, int));
    #define SPKR_ON  1
    #define SPKR_OFF 0
    	int	(*getdev)__P((void *, struct audio_device *));
    	int	(*setfd)__P((void *, int));

    	int	(*set_port)__P((void *, mixer_ctrl_t *));
    	int	(*get_port)__P((void *, mixer_ctrl_t *));
    	int	(*query_devinfo)__P((void *, mixer_devinfo_t *));

    	void	*(*alloc)__P((void *, unsigned long, int, int));
    	void	(*free)__P((void *, void *, int));
    	u_long	(*round_buffersize)__P((void *, u_long));
    	int	(*mappage)__P((void *, void *, int, int));
    	int 	(*get_props)__P((void *));
    };
    struct audio_params {
    	u_long	sample_rate;		/* sample rate */
    	u_int	encoding;		/* ulaw, linear, etc */
    	u_int	precision;		/* bits/sample */
    	u_int	channels;		/* mono(1), stereo(2) */
    	/* Software en/decode functions, set if SW coding required by HW */
    	void	(*sw_code)__P((void *, u_char *, int));
    	int	factor;			/* coding space change */
    };

高レベルオーディオドライバは、低レベルドライバが audio_attach_mi を呼び出すことによって低レベルドライバに結びつけられます。 この呼び出し形式は、

        void
        audio_attach_mi(ahwp, mhwp, hdl, dev)
    	struct audio_hw_if *ahwp;
    	struct midi_hw_if *mhwp;
    	void *hdl;
    	struct device *dev;

です。 構造体 audio_hw_if は上記のとおりで、 midi_hw_if は (今のところ) 使用されていません。 hdl 引数は低レベルのデータ構造へのハンドルです。これは audio_hw_if 内の全ての関数で、高レベルドライバから呼び出される時に 第一引数として渡されます。 dev はハードウエアデバイスのデバイス構造体です。

上位レイヤのオーディオドライバは再生用と録音用にそれぞれ 1 つずつ バッファを割り当てます。これらは、それに含まれるユーザプロセスからの データのバッファリングに用います。それらデータは、下位レベルでは さらに小さな塊で扱い、それらはブロックといいます。再生中に、 ユーザプロセスからのデータが途切れた場合、ハードウエアのブロック要求には 無音ブロックを代わりに使います。また、録音中にユーザプロセスの データ読み取りが遅いと、データは破棄されてしまいます。

audio_hw_if の各フィールドは下に多少詳しく述べてあります。 いくつかのフィールドは省略可で、必要ない場合は 0 を設定します。
int open(void *hdl, int flags)
    はオーディオデバイスのオープンで呼び出されます。ここではハードウエアの I/O の初期化を行います。正常な各 open 呼び出しは、 close 呼び出しと対となります。 正常終了で 0、それ以外ではエラーコードを返します。
void close(void *hdl)
    はオーディオデバイスがクローズされるときに呼び出されます。
int drain(void *hdl)
    は省略可で、デバイスがクローズされるか、 AUDIO_DRAIN 呼び出しの前に呼び出されます。これは、再生されるべきデータが close 呼び出しによって喪失しないようにします。 正常終了で 0、それ以外ではエラーコードを返します。
int query_encoding(void *hdl, struct audio_encoding *ae)
    は AUDIO_GETENC が呼び出される時に使用します。これは audio_encoding 構造体を埋め、0 を返すか、引数の番号に該当するエンコード方法がなければ EINVAL を返します。
int set_params(void *hdl, int setmode, int usemode,
    struct audio_params *play, struct audio_params *rec)
    オーディオエンコーディングモードを設定するために呼び出されます。 setmode は AUMODE_RECORD と AUMODE_PLAY フラグの組合せで、どのモード (複数可) 使うかを示します。 usemode もこれらフラグの組合せですが、現在のデバイスのモードを示しています (要するに audio_info 構造体の mode の値です)。 play と rec 構造体には使用すべきエンコーディングパラメータが入っています。 ハードウエアにソフトウエアによる補助を必要とするエンコーディングがある場合 (例えば mulaw サポートのないもの)、これら構造体の sw_code と factor フィールドを埋めます。 構造体の値はハードウエアが要求されたモードに正確には設定できなかった 場合にも変更されます (例えば要求されたサンプリングレートはサポートして おらず、近似のものをサポートしている場合)。 デバイスが AUDIO_PROP_INDEPENDENT 属性を持っていない場合は、 play と rec には同じ値が渡され、また、 play でのエンコーディングパラメータは set_params 呼び出しの後 rec にコピーされます。 正常終了で 0、それ以外ではエラーコードを返します。
int round_blocksize(void *hdl, int bs)
    省略可能です。上位レイヤで計算済みのブロックサイズ bs を指定して呼び出されます。ブロックサイズを返しますが、値は ハードウエアドライバの都合により変更することができます。
int commit_settings(void *hdl)
    省略可能です。 set_params と set_port への呼び出しが完了した後に呼び出されます。 変更のたびにコマンドモードに入って出なくてはならないハードウエアの ドライバでは、ここでこれまでの変更を保存します。 正常終了で 0、それ以外ではエラーコードを返します。
int init_output(void *hdl, void *buffer, int size)
    省略可能です。 出力を開始する前に呼び出しますが、出力 buffer のトータル size を決めておきます。ルーピング DMA の必要なハードウエアの初期化に使います。 正常終了で 0、それ以外ではエラーコードを返します。
int init_input(void *hdl, void *buffer, int size)
    省略可能です。 入力を開始する前に呼び出しますが、入力 buffer のトータル size を決めておきます。ルーピング DMA の必要なハードウエアの初期化に使います。 正常終了で 0、それ以外ではエラーコードを返します。
int start_output(void *hdl, void *block, int bsize,
    void (*intr)(void*), void *intrarg)
    block から bsize バイトをオーディオハードウエアへ転送開始します。この呼び出しはデータ転送が (通常 DMA で) 開始されたら復帰します。ハードウエアが次のサンプルを 受付可能になると、 intrarg を引数として関数 intr が呼び出されます。 intr の呼び出しによって、通常は start_output がまた呼び出されることになります。 正常終了で 0、それ以外ではエラーコードを返します。
int start_input(void *hdl, void *block, int bsize,
    void (*intr)(void*), void *intrarg)
    オーディオハードウエアから bsize バイトを block へ転送開始します。この呼び出しはデータ転送が (通常 DMA で) 開始されたら復帰します。ハードウエアがさらにサンプルを 供給可能になると、 intrarg を引数として関数 intr が呼び出されます。 intr の呼び出しによって、通常は start_input がまた呼び出されることになります。 正常終了で 0、それ以外ではエラーコードを返します。
int halt_output(void *hdl)
    進行中の (start_output で開始された) 出力転送をアボートさせます。 正常終了で 0、それ以外ではエラーコードを返します。
int halt_input(void *hdl)
    進行中の (start_input で開始された) 入力転送をアボートさせます。 正常終了で 0、それ以外ではエラーコードを返します。
int speaker_ctl(void *hdl, int on)
    省略可能です。 半二重デバイスの再生と録音を切り替えるために呼び出されます。 言い替えると、スピーカの ON/OFF に使う事ができます。 正常終了で 0、それ以外ではエラーコードを返します。
int getdev(void *hdl, struct audio_device *ret)
    audio_device 構造体をドライバに関連した情報で埋めます。 正常終了で 0、それ以外ではエラーコードを返します。
int setfd(void *hdl, int fd)
    省略可能です。 AUDIO_SETFD の使用時、デバイスが AUDIO_PROP_FULLDUPLEX セットを持っている場合のみ 呼び出されます。 正常終了で 0、それ以外ではエラーコードを返します。
int set_port(void *hdl, mixer_ctl_t *mc)
    AUDIO_MIXER_WRITE の使用時に呼び出されます。 mixer_ctl_t 構造体のデータを相当するミキサの値に設定します。 正常終了で 0、それ以外ではエラーコードを返します。
int get_port(void *hdl, mixer_ctl_t *mc)
    AUDIO_MIXER_READ の使用時に呼び出されます。 mixer_ctl_t 構造体を埋めます。 正常終了で 0、それ以外ではエラーコードを返します。
int query_devinfo(void *hdl, mixer_devinfo_t *di)
    AUDIO_MIXER_DEVINFO の使用時に呼び出されます。 mixer_devinfo_t 構造体を埋めます。 正常終了で 0、それ以外ではエラーコードを返します。
void *alloc(void *hdl, u_long size, int type, int flags)
    省略可能です。 デバイスのバッファを割り当てるために呼び出されます。 定義されていなければ malloc(9) がかわりに (最初の引数を除いて同じ引数で) 呼び出されます。 malloc(9) でなく、デバイス依存のルーチンを使用するのは、DMA のために特殊な 割り当てが必要なバスがあるからです。 バッファのアドレスを返すか、失敗時には 0 を返します。
void free(void *hdl, void *addr, int type)
    省略可能です。 alloc によって割り当てられたメモリを解放します。定義されていなければ free(9) が使用されます。
u_long round_buffer(void *hdl, u_long bufsize)
    省略可能です。 スタートアップ時にオーディオバッファのサイズを決めるために 呼び出されます。上位層は推奨サイズを bufsize に入れますが、ハードウエアドライバは必要なら変更することができます。 例えば、ISA バスの DMA では 65536 を越える値にはできません。
int mappage(void *hdl, void *addr, int offs, int prot)
    省略可能です。 mmap(2) のために呼び出されます。 ページの、アドレス addr から、オフセットが offs で、保護フラグが prot というマップ値を返します。 異常終了で -1、正常終了ではマシン依存の非透過な値を返します。
int get_props(void *hdl)
    デバイスのプロパティを返します。プロパティは、AUDIO_PROP_xxx の組合せです。
query_devinfo メソッドはミキサコントロールが AUDIO_SETINFO でポートとゲインを変更できるようにします。

オーディオハードウエアが複数のソース入力を可能な場合は、 AudioCrecord クラスの AudioNsource を定義します。 このミキサコントロールは AUDIO_MIXER_ENUM または AUDIO_MIXER_SET 型で、入力可能なソースを列挙します。 ここにあげる名前付きソースは、録音レベルが設定できるなら全て AudioCinputs クラスの AUDIO_MIXER_VALUE 型のコントロールにします。 録音全体に対して (入力にかかわらず、という意味で) のレベル変更が可能な 場合は、 AudioNrecord という名前で、 AudioCinputs クラスに属すようにします。

オーディオハードウエアが複数対象に出力できる場合は、 AudioCmonitor クラスの AudioNoutput を定義します。 このミキサコントロールは AUDIO_MIXER_ENUM または AUDIO_MIXER_SET の型で、なりうる対象を列挙します。 ここでの名前付きの対象は、出力レベルを設定できるのならば AudioCoutputs クラスの AUDIO_MIXER_VALUE 型のコントロールにします。 出力全体に対して (対象にかかわらず、という意味で) のレベル変更が可能な 場合は、 AudioNmaster という名前で、 AudioCoutputs クラスに属すコントロールにします。

関連項目
audio(4)

歴史
この audio インタフェースは NetBSD 1.3 で初めて登場しました。