カードの要素のリスト
コントロールインターフェイスでは、音量などの値を取得したり、設定したりすることができます。
これらは、それぞれ「要素 (element)」として格納されています。
まずは、カードが持っている要素のリストを取得してみます。
要素のリストを取得します。
この関数を実行する前に、snd_ctl_elem_list_t のメモリを確保する必要があります。
実際にセットされた要素の個数を取得します。
スペースを確保していない状態で実行すると、0 になります。
snd_ctl_elem_list() は、スペースが足りない場合は、確保されている分のデータだけをセットし、余分なスペースがある場合は、その部分を未使用の状態にします。
snd_ctl_elem_list() を複数回実行するような場合は、同じスペースを使いまわすことができます。
これらは、それぞれ「要素 (element)」として格納されています。
まずは、カードが持っている要素のリストを取得してみます。
要素のリストを取得
int snd_ctl_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list);
要素のリストを取得します。
この関数を実行する前に、snd_ctl_elem_list_t のメモリを確保する必要があります。
snd_ctl_elem_list_t の確保
//サイズの取得 size_t snd_ctl_elem_list_sizeof(void); //確保 int snd_ctl_elem_list_malloc(snd_ctl_elem_list_t **ptr); //解放 void snd_ctl_elem_list_free(snd_ctl_elem_list_t *obj);
スペースの確保
要素のリストを取得する場合、注意しなければならない点があります。
それは、snd_ctl_elem_list_t を確保しても、実際の各要素のスペースは確保されないということです。
要素は可変個数なので、固定のメモリ領域で取得できないというのは、当然といえば当然です。
そのため、実際に要素のデータを読み込むためには、snd_ctl_elem_list_t 内に、読み込みに必要な要素数分のスペースを確保する必要があります。
snd_ctl_elem_list_free() で snd_ctl_elem_list_t を解放しても、要素用に確保したスペースは解放されません。
snd_ctl_elem_list_free() を実行する前に、snd_ctl_elem_list_free_space() で解放する必要があります。
それは、snd_ctl_elem_list_t を確保しても、実際の各要素のスペースは確保されないということです。
要素は可変個数なので、固定のメモリ領域で取得できないというのは、当然といえば当然です。
そのため、実際に要素のデータを読み込むためには、snd_ctl_elem_list_t 内に、読み込みに必要な要素数分のスペースを確保する必要があります。
//指定個数の要素スペースを確保 int snd_ctl_elem_list_alloc_space(snd_ctl_elem_list_t *obj, unsigned int entries); //要素スペースを解放 void snd_ctl_elem_list_free_space(snd_ctl_elem_list_t *obj);
snd_ctl_elem_list_free() で snd_ctl_elem_list_t を解放しても、要素用に確保したスペースは解放されません。
snd_ctl_elem_list_free() を実行する前に、snd_ctl_elem_list_free_space() で解放する必要があります。
要素数の取得
要素スペースを確保するためには、カードが実際に持っている要素数が必要になります。
しかし、要素数だけを取得する関数は存在しません。
そこで、まずは要素スペースを確保していない状態で、一度 snd_ctl_elem_list() を実行します。
※スペースが確保されていないので、要素のデータは取得されません。
これにより、snd_ctl_elem_list_t に、カードが持っている要素数がセットされるので、その情報を取得します。
デバイスに存在する要素の数を取得します。
この情報は、snd_ctl_elem_list() の実行後にセットされます。
これで、必要な要素数が取得できるので、snd_ctl_elem_list_alloc_space() でスペースを確保した後、再度 snd_ctl_elem_list() を実行します。
確保したスペースに、実際に要素データがセットされます。
しかし、要素数だけを取得する関数は存在しません。
そこで、まずは要素スペースを確保していない状態で、一度 snd_ctl_elem_list() を実行します。
※スペースが確保されていないので、要素のデータは取得されません。
これにより、snd_ctl_elem_list_t に、カードが持っている要素数がセットされるので、その情報を取得します。
unsigned int snd_ctl_elem_list_get_count(const snd_ctl_elem_list_t *obj);
デバイスに存在する要素の数を取得します。
この情報は、snd_ctl_elem_list() の実行後にセットされます。
これで、必要な要素数が取得できるので、snd_ctl_elem_list_alloc_space() でスペースを確保した後、再度 snd_ctl_elem_list() を実行します。
確保したスペースに、実際に要素データがセットされます。
実際にセットされた個数を取得
unsigned int snd_ctl_elem_list_get_used(const snd_ctl_elem_list_t *obj);
実際にセットされた要素の個数を取得します。
スペースを確保していない状態で実行すると、0 になります。
snd_ctl_elem_list() は、スペースが足りない場合は、確保されている分のデータだけをセットし、余分なスペースがある場合は、その部分を未使用の状態にします。
snd_ctl_elem_list() を複数回実行するような場合は、同じスペースを使いまわすことができます。
要素の識別子
各要素には、その要素を識別するための ID がセットされています。
snd_ctl_elem_list() は、実際には、要素の値などは読み込まず、要素の識別子のリストだけを読み込みます。
snd_ctl_elem_list() は、実際には、要素の値などは読み込まず、要素の識別子のリストだけを読み込みます。
構成
要素の識別子は、以下の複数の値で構成されています。
1つの要素は、「numid」、または、「インターフェイスタイプ、デバイス、サブデバイス、名前、インデックス」の5つセットのいずれかで識別されます。
基本的には、numid を使って識別した方がいいでしょう。
- numid (数値の識別子)
サウンドカードが接続されている間は不変の値。 - インターフェイスタイプ
- デバイス
- サブデバイス
- 名前
- インデックス
1つの要素は、「numid」、または、「インターフェイスタイプ、デバイス、サブデバイス、名前、インデックス」の5つセットのいずれかで識別されます。
基本的には、numid を使って識別した方がいいでしょう。
snd_ctl_elem_id_t
要素の識別子は、snd_ctl_elem_id_t 型で表現されます。
ここには、上記の複数の値が格納されているので、他の情報と同じように、まずはメモリを確保する必要があります。
その他の関数は、要素:識別子 で確認してください。
ここには、上記の複数の値が格納されているので、他の情報と同じように、まずはメモリを確保する必要があります。
//サイズの取得 size_t snd_ctl_elem_id_sizeof(void); //確保 int snd_ctl_elem_id_malloc(snd_ctl_elem_id_t **ptr); //解放 void snd_ctl_elem_id_free(snd_ctl_elem_id_t *obj); //ASCII文字列にして返す //戻り値: strdup で複製された文字列 char *snd_ctl_ascii_elem_id_get(snd_ctl_elem_id_t *id); //ASCII文字列から解析して値をセット int snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str);
その他の関数は、要素:識別子 で確認してください。
リストから情報取得
snd_ctl_elem_list() で取得したリストは、「要素の識別子」のリストです。
snd_ctl_elem_list_get_* 関数を使うことで、リストから、ぞれぞれの要素の識別子の情報を取得することができます。
idx 引数は、要素スペース内の、項目のインデックス番号 (0〜) です。
snd_ctl_elem_list_get_* 関数を使うことで、リストから、ぞれぞれの要素の識別子の情報を取得することができます。
idx 引数は、要素スペース内の、項目のインデックス番号 (0〜) です。
//項目のインデックスのオフセットをセット void snd_ctl_elem_list_set_offset(snd_ctl_elem_list_t *obj, unsigned int val); //snd_ctl_elem_id_t の情報を取得 //(あらかじめ確保しておくこと) void snd_ctl_elem_list_get_id(const snd_ctl_elem_list_t *obj, unsigned int idx, snd_ctl_elem_id_t *ptr); //numid を取得 unsigned int snd_ctl_elem_list_get_numid(const snd_ctl_elem_list_t *obj, unsigned int idx); //インターフェイスのタイプを取得 snd_ctl_elem_iface_t snd_ctl_elem_list_get_interface(const snd_ctl_elem_list_t *obj, unsigned int idx); //デバイスを取得 unsigned int snd_ctl_elem_list_get_device(const snd_ctl_elem_list_t *obj, unsigned int idx); //サブデバイスを取得 unsigned int snd_ctl_elem_list_get_subdevice(const snd_ctl_elem_list_t *obj, unsigned int idx); //名前を取得 const char *snd_ctl_elem_list_get_name(const snd_ctl_elem_list_t *obj, unsigned int idx); //インデックスを取得 //(項目のインデックスとは異なる) unsigned int snd_ctl_elem_list_get_index(const snd_ctl_elem_list_t *obj, unsigned int idx);
プログラム
引数で指定したサウンドカード (デフォルトは "default") の、要素のリストを取得し、情報を出力するプログラムです。
$ cc -o 02_elemlist 02_elemlist.c -lasound
#include <stdio.h> #include <alsa/asoundlib.h> int main(int argc,char **argv) { snd_ctl_t *ctl; char *str; snd_ctl_elem_list_t *list; snd_ctl_elem_id_t *eid; uint32_t i,cnt,n; //開く if(snd_ctl_open(&ctl, (argc >= 2)? argv[1]: "default", 0)) return 1; //要素のリスト取得 (個数のみ) snd_ctl_elem_list_malloc(&list); snd_ctl_elem_list(ctl, list); //必要な個数 cnt = snd_ctl_elem_list_get_count(list); printf("count:%u, used:%u\n", cnt, snd_ctl_elem_list_get_used(list)); //個数分を確保して、取得 snd_ctl_elem_list_alloc_space(list, cnt); snd_ctl_elem_list(ctl, list); printf("used:%u\n", snd_ctl_elem_list_get_used(list)); //各要素の識別子 snd_ctl_elem_id_malloc(&eid); for(i = 0; i < cnt; i++) { printf("--- [%d] ---\n", i); printf("numid: %u\n", snd_ctl_elem_list_get_numid(list, i)); n = snd_ctl_elem_list_get_interface(list, i); printf("interface: (%d) %s\n", n, snd_ctl_elem_iface_name(n)); printf("device: %u\n", snd_ctl_elem_list_get_device(list, i)); printf("subdevice: %u\n", snd_ctl_elem_list_get_subdevice(list, i)); printf("name: '%s'\n", snd_ctl_elem_list_get_name(list, i)); printf("index: %u\n", snd_ctl_elem_list_get_index(list, i)); //ASCII文字列で表現 snd_ctl_elem_list_get_id(list, i, eid); str = snd_ctl_ascii_elem_id_get(eid); printf("<ascii> %s\n", str); free(str); } snd_ctl_elem_id_free(eid); // snd_ctl_elem_list_free_space(list); snd_ctl_elem_list_free(list); snd_ctl_close(ctl); return 0; }
実行結果
count:61, used:0 used:61 --- [0] --- numid: 1 interface: (2) MIXER device: 0 subdevice: 0 name: 'Channel Mode' index: 0 <ascii> numid=1,iface=MIXER,name='Channel Mode' --- [1] --- numid: 2 interface: (2) MIXER device: 0 subdevice: 0 name: 'Front Playback Volume' index: 0 <ascii> numid=2,iface=MIXER,name='Front Playback Volume' --- [2] --- numid: 3 interface: (2) MIXER device: 0 subdevice: 0 name: 'Front Playback Switch' index: 0 <ascii> numid=3,iface=MIXER,name='Front Playback Switch' --- [3] --- numid: 4 interface: (2) MIXER device: 0 subdevice: 0 name: 'Surround Playback Volume' index: 0 <ascii> numid=4,iface=MIXER,name='Surround Playback Volume' ... --- [59] --- numid: 60 interface: (2) MIXER device: 0 subdevice: 0 name: 'PCM Playback Volume' index: 0 <ascii> numid=60,iface=MIXER,name='PCM Playback Volume' --- [60] --- numid: 61 interface: (2) MIXER device: 0 subdevice: 0 name: 'Digital Capture Volume' index: 0 <ascii> numid=61,iface=MIXER,name='Digital Capture Volume'
解説
スペースの確保に必要な個数を調べるため、スペースを確保していない状態で、snd_ctl_elem_list() を実行します。
実行後に snd_ctl_elem_list_get_count() を使用すると、61 が返ります。これが要素の個数です。
snd_ctl_elem_list_get_used() を実行すると、0 が返ります。
スペースが確保されていないので、実際には読み込まれたデータがありません。
その後、61 個のスペースを確保して、再度 snd_ctl_elem_list() を行うと、used は 61 になっています。
実際に 61 個のデータが読み込まれたということです。
あとは、各関数を使って、要素の識別子の情報を取得します。
snd_ctl_elem_id_t から、ASCII 文字列形式で取得した場合、"<name>=<val>,..." という形式になります。
識別子の各値が 0 (デフォルト) の場合は、項目が省略されるようです。
終了時は、snd_ctl_elem_list_free() の前に、snd_ctl_elem_list_free_space() でスペースを解放することを忘れないでください。
count:61, used:0
実行後に snd_ctl_elem_list_get_count() を使用すると、61 が返ります。これが要素の個数です。
snd_ctl_elem_list_get_used() を実行すると、0 が返ります。
スペースが確保されていないので、実際には読み込まれたデータがありません。
その後、61 個のスペースを確保して、再度 snd_ctl_elem_list() を行うと、used は 61 になっています。
実際に 61 個のデータが読み込まれたということです。
あとは、各関数を使って、要素の識別子の情報を取得します。
snd_ctl_elem_id_t から、ASCII 文字列形式で取得した場合、"<name>=<val>,..." という形式になります。
識別子の各値が 0 (デフォルト) の場合は、項目が省略されるようです。
終了時は、snd_ctl_elem_list_free() の前に、snd_ctl_elem_list_free_space() でスペースを解放することを忘れないでください。
snd_ctl_elem_list_free_space(list); snd_ctl_elem_list_free(list);
インターフェイスタイプ
音量関連の要素は、インターフェイスタイプが MIXER になります。
他に、CARD や PCM のタイプがあります。
他に、CARD や PCM のタイプがあります。