ALSA:要素の情報

要素の情報
前回は要素のリストを取得したので、今回は、要素の情報を取得してみます。

情報と言っても、要素の値は含まれません。
今回扱うのは、値のタイプや、読み書き可能かなどの情報です。
確保
要素の情報は、snd_ctl_elem_info_t に格納されます。

今までと同じように、まずは snd_ctl_elem_info_t を確保します。

//サイズの取得
size_t snd_ctl_elem_info_sizeof(void);

//確保
int snd_ctl_elem_info_malloc(snd_ctl_elem_info_t **ptr);

//解放
void snd_ctl_elem_info_free(snd_ctl_elem_info_t *obj);
要素の識別子をセット
情報を取得する前に、まず、取得したい要素の識別子を、snd_ctl_elem_info_t にセットします。

//snd_ctl_elem_id_t をセット
void snd_ctl_elem_info_set_id(snd_ctl_elem_info_t *obj, const snd_ctl_elem_id_t *ptr);

//numid をセット
void snd_ctl_elem_info_set_numid(snd_ctl_elem_info_t *obj, unsigned int val);

//各値のセット (5つをセットで扱う)
void snd_ctl_elem_info_set_interface(snd_ctl_elem_info_t *obj, snd_ctl_elem_iface_t val);
void snd_ctl_elem_info_set_device(snd_ctl_elem_info_t *obj, unsigned int val);
void snd_ctl_elem_info_set_subdevice(snd_ctl_elem_info_t *obj, unsigned int val);
void snd_ctl_elem_info_set_name(snd_ctl_elem_info_t *obj, const char *val);
void snd_ctl_elem_info_set_index(snd_ctl_elem_info_t *obj, unsigned int val);

上記の3通りの方法で、識別子をセットします。

一番簡単なのは、numid を指定する方法です。
snd_ctl_elem_list_get_numid() を使うと、要素リストから numid を取得できます。

インターフェイスタイプやデバイスは、5つの値をセットにして識別するので、5つすべてセットする必要があります。
情報を取得
識別子をセットできたら、その要素の情報を取得します。

int snd_ctl_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info);

後は、snd_ctl_elem_info_* の関数を使って、各情報を取得します。

数が多いので、関数の一覧は 要素:情報 を参照してください。
プログラム
引数で指定したサウンドカード (省略で "default") の、すべての要素の、各情報を出力します。

$ cc -o 03_eleminfo 03_eleminfo.c -lasound

#include <stdio.h>
#include <alsa/asoundlib.h>

int main(int argc,char **argv)
{
    snd_ctl_t *ctl;
    snd_ctl_elem_list_t *list;
    snd_ctl_elem_info_t *info;
    uint32_t i,cnt,tp;

    //開く

    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);

    snd_ctl_elem_list_alloc_space(list, cnt);
    snd_ctl_elem_list(ctl, list);

    //情報取得

    snd_ctl_elem_info_malloc(&info);

    for(i = 0; i < cnt; i++)
    {
        snd_ctl_elem_info_set_numid(info, snd_ctl_elem_list_get_numid(list, i));
        snd_ctl_elem_info(ctl, info);

        printf("-- [%d] --\n", i);
        printf("<name> %s\n", snd_ctl_elem_list_get_name(list, i));

        tp = snd_ctl_elem_info_get_type(info);
        printf("type: (%d) %s\n", tp, snd_ctl_elem_type_name(tp));

        printf("readable: %d\n", snd_ctl_elem_info_is_readable(info));
        printf("writable: %d\n", snd_ctl_elem_info_is_writable(info));
        printf("volatile: %d\n", snd_ctl_elem_info_is_volatile(info));
        printf("inactive: %d\n", snd_ctl_elem_info_is_inactive(info));
        printf("locked: %d\n", snd_ctl_elem_info_is_locked(info));
        printf("tlv_readable: %d\n", snd_ctl_elem_info_is_tlv_readable(info));
        printf("tlv_writable: %d\n", snd_ctl_elem_info_is_tlv_writable(info));
        printf("tlv_commandable: %d\n", snd_ctl_elem_info_is_tlv_commandable(info));
        printf("owner: %d\n", snd_ctl_elem_info_is_owner(info));
        printf("user: %d\n", snd_ctl_elem_info_is_user(info));

        printf("count: %d\n", snd_ctl_elem_info_get_count(info));

        switch(tp)
        {
            case SND_CTL_ELEM_TYPE_INTEGER:
                printf("(int) min:%ld, max:%ld, step:%ld\n",
                    snd_ctl_elem_info_get_min(info), snd_ctl_elem_info_get_max(info),
                    snd_ctl_elem_info_get_step(info));
                break;
            case SND_CTL_ELEM_TYPE_INTEGER64:
                printf("(int64) min:%lld, max:%lld, step:%lld\n",
                    snd_ctl_elem_info_get_min64(info), snd_ctl_elem_info_get_max64(info),
                    snd_ctl_elem_info_get_step64(info));
                break;
            case SND_CTL_ELEM_TYPE_ENUMERATED:
                printf("(enum) items:%d, name:'%s'\n",
                    snd_ctl_elem_info_get_items(info),
                    snd_ctl_elem_info_get_item_name(info));
                break;
        }
    }

    snd_ctl_elem_info_free(info);

    //

    snd_ctl_elem_list_free_space(list);
    snd_ctl_elem_list_free(list);

    snd_ctl_close(ctl);

    return 0;
}
実行結果
-- [0] --
<name> Channel Mode
type: (3) ENUMERATED
readable: 1
writable: 1
volatile: 0
inactive: 0
locked: 0
tlv_readable: 0
tlv_writable: 0
tlv_commandable: 0
owner: 0
user: 0
count: 1
(enum) items:3, name:'2ch'
-- [1] --
<name> Front Playback Volume
type: (2) INTEGER
readable: 1
writable: 1
volatile: 0
inactive: 0
locked: 0
tlv_readable: 1
tlv_writable: 0
tlv_commandable: 0
owner: 0
user: 0
count: 2
(int) min:0, max:64, step:0

...

-- [59] --
<name> PCM Playback Volume
type: (2) INTEGER
readable: 1
writable: 1
volatile: 0
inactive: 0
locked: 0
tlv_readable: 1
tlv_writable: 1
tlv_commandable: 0
owner: 0
user: 1
count: 2
(int) min:0, max:255, step:0
-- [60] --
<name> Digital Capture Volume
type: (2) INTEGER
readable: 1
writable: 1
volatile: 0
inactive: 0
locked: 0
tlv_readable: 1
tlv_writable: 1
tlv_commandable: 0
owner: 0
user: 1
count: 2
(int) min:0, max:120, step:0

TLV については、後述します。
ロック
一つのアプリケーションが、各要素をロックすることができます。
その場合、他のアプリによって値が変更されなくなります。

int snd_ctl_elem_lock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id);
int snd_ctl_elem_unlock(snd_ctl_t *ctl, snd_ctl_elem_id_t *id);

locked は、他のアプリによって、要素がロックされているかどうかです。
owner は、自身がロックしたことによって、その要素を所有しているかどうかです。
要素の値
要素の値は、同じタイプで複数の値が格納されており、snd_ctl_elem_info_get_count() で値の個数を取得できます。
(一部のタイプは、単体の値のみ)

タイプが INTEGER で個数が2なら、整数の値が2個あるということです。