PulseAudio:カード情報

カード情報の取得
次に、カード情報を取得します。
カードとは、ハードウェア構成のことです。
関数
pa_operation *pa_context_get_card_info_by_index(pa_context *c,
    uint32_t idx, pa_card_info_cb_t cb, void *userdata);

pa_operation *pa_context_get_card_info_by_name(pa_context *c,
    const char *name, pa_card_info_cb_t cb, void *userdata);

pa_operation *pa_context_get_card_info_list(pa_context *c,
    pa_card_info_cb_t cb, void *userdata);

//コールバック関数
typedef void (*pa_card_info_cb_t)(pa_context *c, const pa_card_info *i, int eol, void *userdata);

カード情報を取得するには、3つの方法があります。

by_index はインデックス番号から、by_name はカード名から、単体の情報を取得します。
list は、すべてのカード情報を取得します。
プログラム
情報が多いので、まずはプログラムを提示します。
すべてのカード情報を取得して、出力します。

$ cc -o 06-card 06-card.c util.c -lpulse

#include <stdio.h>
#include <pulse/pulseaudio.h>
#include "util.h"

PulseData *pulse;

static void _card_callback(pa_context *c,const pa_card_info *i,int eol,void *userdata)
{
    int j,k;
    pa_card_profile_info2 *prof;
    pa_card_port_info *port;

    if(!i)
    {
        pa_threaded_mainloop_signal(pulse->mainloop, 0);
        return;
    }
    
    printf("[index:%u]\n", i->index);
    printf("name: %s\n", i->name);
    printf("owner_module: %u\n", i->owner_module);
    printf("driver: %s\n", i->driver);
    printf("n_profiles: %u\n", i->n_profiles);
    printf("n_ports: %u\n", i->n_ports);

    pulse_put_proplist(i->proplist);

    //profile

    printf("\n=== profile ===\n");

    for(j = 0; j < i->n_profiles; j++)
    {
        prof = i->profiles2[j];
        printf("---[%d](%c)---\n", j,
            (prof == i->active_profile2)? '*': '-');
        printf(" name: '%s'\n", prof->name);
        printf(" description: '%s'\n", prof->description);
        printf(" n_sinks: %u\n", prof->n_sinks);
        printf(" n_sources: %u\n", prof->n_sources);
        printf(" priority: %u\n", prof->priority);
        printf(" available: %d\n", prof->available);
    }

    //ports

    printf("\n=== ports ===\n");

    for(j = 0; j < i->n_ports; j++)
    {
        port = i->ports[j];
        printf("---[%d]---\n", j);
        printf(" name: '%s'\n", port->name);
        printf(" description: '%s'\n", port->description);
        printf(" priority: %u\n", port->priority);
        printf(" available: %d\n", port->available);
        printf(" direction: %s\n",
            (port->direction == PA_DIRECTION_OUTPUT)? "OUT": "IN");
        printf(" n_profiles: %u\n", port->n_profiles);
        printf(" latency_offset: %ld\n", port->latency_offset);
        printf(" availability_group: %s\n", port->availability_group);
        printf(" type: %u\n", port->type);

        printf(" <profiles>\n");
        for(k = 0; k < port->n_profiles; k++)
            printf("  [%d] %s\n", k, (port->profiles2[k])->description);

        pulse_put_proplist(port->proplist);
    }

    printf("\n");
}

static pa_operation *_get_info(PulseData *p,void *data)
{
    return pa_context_get_card_info_list(pulse->ctx, _card_callback, NULL);
}

int main(void)
{
    pulse = pulse_connect(0);
    if(!pulse) return 1;

    pulse_wait_operation(pulse, _get_info, NULL);

    pulse_free(pulse);

    return 0;
}
カード情報 (pa_card_info)
まずは、struct pa_card_info のカード情報です。

typedef struct pa_card_info {
    uint32_t index;
    const char *name;
    uint32_t owner_module;
    const char *driver;
    uint32_t n_profiles;
    pa_card_profile_info *profiles; //廃止
    pa_card_profile_info *active_profile; //廃止
    pa_proplist *proplist;
    uint32_t n_ports;
    pa_card_port_info **ports;
    pa_card_profile_info2 **profiles2;
    pa_card_profile_info2 *active_profile2;
} pa_card_info;

profiles と active_profile は、現在廃止されています。
代わりに、profiles2 と active_profile2 を使います。

indexサーバー上で認識されるインデックス番号
nameカード名
owner_module所有モジュールのインデックス、または PA_INVALID_INDEX
driverドライバ名
n_profilesプロファイルの数
proplistプロパティリスト
n_portsポートの数
ports利用可能なポートのポインタの配列、または NULL
profiles2利用可能なプロファイルのポインタの配列、または NULL
active_profile2現在アクティブなプロファイル。
profiles2 配列内の一つのポインタ、または NULL。
実行結果
[index:0]
name: alsa_card.pci-0000_00_1f.3
owner_module: 6
driver: module-alsa-card.c
n_profiles: 18
n_ports: 8
<proplist>
alsa.card = "0"
alsa.card_name = "HDA Intel PCH"
alsa.long_card_name = "HDA Intel PCH at 0xdf140000 irq 130"
alsa.driver_name = "snd_hda_intel"
device.bus_path = "pci-0000:00:1f.3"
sysfs.path = "/devices/pci0000:00/0000:00:1f.3/sound/card0"
device.bus = "pci"
device.vendor.id = "8086"
device.vendor.name = "Intel Corporation"
device.product.id = "a170"
device.product.name = "100 Series/C230 Series Chipset Family HD Audio Controller"
device.form_factor = "internal"
device.string = "0"
device.description = "内部オーディオ"
module-udev-detect.discovered = "1"
device.icon_name = "audio-card-pci"

サウンドカードが1つなら、基本的にカード情報は1つです。

プロパティリストには、ハードウェアの情報などが格納されています。
プロファイル情報 (pa_card_profile_info2)
pa_card_info 構造体の profiles2 メンバは、このカードで利用できるプロファイル情報の、ポインタの配列です。
n_profiles の個数分あります。

typedef struct pa_card_profile_info2 {
    const char *name;
    const char *description;
    uint32_t n_sinks;
    uint32_t n_sources;
    uint32_t priority;
    int available;
} pa_card_profile_info2;

nameプロファイル名
descriptionプロファイルの詳細説明
n_sinksこのプロファイルが作成するシンクの数。
シンクは、出力のことです。
n_sourcesこのプロファイルが作成するソースの数。
ソースは、入力のことです。
PulseAudio が仮想的に作成するソースの数は含まれません。
priority優先度。
値が高いほど、デフォルトに近くなる。
availableこのプロファイルが利用できるか。

0 の場合、使用不可。
0 以外であっても、このプロファイルを有効しても、意味がない場合もある。
実行結果
=== profile ===
---[0](-)---
 name: 'input:analog-stereo'
 description: 'アナログステレオ 入力'
 n_sinks: 0
 n_sources: 1
 priority: 65
 available: 0
---[1](-)---
 name: 'output:analog-stereo'
 description: 'アナログステレオ 出力'
 n_sinks: 1
 n_sources: 0
 priority: 39268
 available: 1
---[2](*)---
 name: 'output:analog-stereo+input:analog-stereo'
 description: 'アナログステレオデュプレックス'
 n_sinks: 1
 n_sources: 1
 priority: 6565
 available: 1
---[3](-)---
 name: 'output:hdmi-stereo'
 description: 'Digital Stereo (HDMI) 出力'
 n_sinks: 1
 n_sources: 0
 priority: 38668
 available: 1
---[4](-)---
 name: 'output:hdmi-stereo+input:analog-stereo'
 description: 'Digital Stereo (HDMI) 出力 + アナログステレオ 入力'
 n_sinks: 1
 n_sources: 1
 priority: 5965
 available: 1
---[5](-)---
 name: 'output:hdmi-stereo-extra1'
 description: 'Digital Stereo (HDMI 2) 出力'
 n_sinks: 1
 n_sources: 0
 priority: 5700
 available: 0
---[6](-)---
 name: 'output:hdmi-stereo-extra1+input:analog-stereo'
 description: 'Digital Stereo (HDMI 2) 出力 + アナログステレオ 入力'
 n_sinks: 1
 n_sources: 1
 priority: 5765
 available: 0
---[7](-)---
 name: 'output:hdmi-surround-extra1'
 description: 'Digital Surround 5.1 (HDMI 2) 出力'
 n_sinks: 1
 n_sources: 0
 priority: 600
 available: 0
---[8](-)---
 name: 'output:hdmi-surround-extra1+input:analog-stereo'
 description: 'Digital Surround 5.1 (HDMI 2) 出力 + アナログステレオ 入力'
 n_sinks: 1
 n_sources: 1
 priority: 665
 available: 0
---[9](-)---
 name: 'output:hdmi-surround71-extra1'
 description: 'Digital Surround 7.1 (HDMI 2) 出力'
 n_sinks: 1
 n_sources: 0
 priority: 600
 available: 0
---[10](-)---
 name: 'output:hdmi-surround71-extra1+input:analog-stereo'
 description: 'Digital Surround 7.1 (HDMI 2) 出力 + アナログステレオ 入力'
 n_sinks: 1
 n_sources: 1
 priority: 665
 available: 0
---[11](-)---
 name: 'output:hdmi-stereo-extra2'
 description: 'Digital Stereo (HDMI 3) 出力'
 n_sinks: 1
 n_sources: 0
 priority: 5700
 available: 0
---[12](-)---
 name: 'output:hdmi-stereo-extra2+input:analog-stereo'
 description: 'Digital Stereo (HDMI 3) 出力 + アナログステレオ 入力'
 n_sinks: 1
 n_sources: 1
 priority: 5765
 available: 0
---[13](-)---
 name: 'output:hdmi-surround-extra2'
 description: 'Digital Surround 5.1 (HDMI 3) 出力'
 n_sinks: 1
 n_sources: 0
 priority: 600
 available: 0
---[14](-)---
 name: 'output:hdmi-surround-extra2+input:analog-stereo'
 description: 'Digital Surround 5.1 (HDMI 3) 出力 + アナログステレオ 入力'
 n_sinks: 1
 n_sources: 1
 priority: 665
 available: 0
---[15](-)---
 name: 'output:hdmi-surround71-extra2'
 description: 'Digital Surround 7.1 (HDMI 3) 出力'
 n_sinks: 1
 n_sources: 0
 priority: 600
 available: 0
---[16](-)---
 name: 'output:hdmi-surround71-extra2+input:analog-stereo'
 description: 'Digital Surround 7.1 (HDMI 3) 出力 + アナログステレオ 入力'
 n_sinks: 1
 n_sources: 1
 priority: 665
 available: 0
---[17](-)---
 name: 'off'
 description: 'オフ'
 n_sinks: 0
 n_sources: 0
 priority: 0
 available: 1
解説
プロファイルとは、ハードウェア上のどの端子を組み合わせて、出力と入力を行うか、という構成です。

HDMI 端子でモニタが繋がっていて、アナログオーディオ端子にも接続がある場合は、どちらに出力を行うかを、選択する必要があります。

それぞれの priority の数値を見ると、値が一番高いのは「アナログステレオ 出力」なので、ユーザーによる選択がなければ、このプロファイルが優先されます。

アナログステレオ 出力
---[1](-)---
 name: 'output:analog-stereo'
 description: 'アナログステレオ 出力'
 n_sinks: 1
 n_sources: 0
 priority: 39268
 available: 1

index = 1 の「アナログステレオ 出力」を見てみると、n_sinks は 1 で、シンク(出力)は1つだけ作成されます。
n_sources は 0 なので、ソース(入力)は使用されません。つまり、ハードウェアからの録音はできないということです。
available が 1 なので、このプロファイルは利用可能です。

アナログステレオデュプレックス
---[2](*)---
 name: 'output:analog-stereo+input:analog-stereo'
 description: 'アナログステレオデュプレックス'
 n_sinks: 1
 n_sources: 1
 priority: 6565
 available: 1

「アナログステレオデュプレックス」は、アナログオーディオの出力と入力を使います。
アナログ端子への出力と、アナログ端子からの入力が可能になります。
この場合、HDMI へのオーディオ出力は行われません。

なお、サーバー上では、このプロファイルが現在アクティブになっているので、profiles2[2] == active_profile2 となります。

HDMI
---[3](-)---
 name: 'output:hdmi-stereo'
 description: 'Digital Stereo (HDMI) 出力'
 n_sinks: 1
 n_sources: 0
 priority: 38668
 available: 1
---[4](-)---
 name: 'output:hdmi-stereo+input:analog-stereo'
 description: 'Digital Stereo (HDMI) 出力 + アナログステレオ 入力'
 n_sinks: 1
 n_sources: 1
 priority: 5965
 available: 1

HDMI で繋がっているモニタのスピーカー、あるいは、モニタのヘッドホン端子に出力する場合は、HDMI 出力のプロファイルを使います。

この場合、PC 本体のアナログ端子への出力は行われません。
ただし、「+アナログステレオ入力」の場合は、入力として、本体のアナログ入力端子を使います。

他にも、HDMI2 や HDMI3 がありますが、この PC には HDMI 端子が1つしかないので、これらは利用不可の状態になっています。
ポート情報 (pa_card_port_info)
pa_card_info 構造体の ports メンバは、このカードで利用可能なポート情報の、ポインタの配列です。
n_ports の個数分あります。

ポートは、ハードウェア上の端子を意味します。

typedef struct pa_card_port_info {
    const char *name;
    const char *description;
    uint32_t priority;
    int available;
    int direction;
    uint32_t n_profiles;
    pa_card_profile_info **profiles; //廃止
    pa_proplist *proplist;
    int64_t latency_offset;
    pa_card_profile_info2 **profiles2;
    const char *availability_group; //ver 14.0
    uint32_t type; //ver 14.0
} pa_card_port_info;

nameポート名
descriptionポートの詳細説明
priority優先度。値が高いほどデフォルトに近い。
availableこのポートが実際に使用できるかを示す、pa_port_available 列挙型。

PA_PORT_AVAILABLE_UNKNOWN (0) : 端子の接続判定をサポートしていない。
PA_PORT_AVAILABLE_NO (1) : 使用できない。端子が接続されていない可能性がある。
PA_PORT_AVAILABLE_YES (2) : 使用可能。
directionこのポートの方向を示す、pa_direction 列挙型。

PA_DIRECTION_OUTPUT : 出力
PA_DIRECTION_INPUT : 入力
n_profilesプロファイルの配列の数
proplistプロパティリスト
latency_offsetポートがアクティブなときに、シンク/ソースの遅延に追加されるオフセット
profiles2このポートを利用できるプロファイルの、ポインタの配列
availability_groupポートのグループ識別子名。
available の状態を相互に共有する。
typeポートタイプ (pa_device_port_type 列挙型)
実行結果
=== ports ===
---[0]---
 name: 'analog-input-front-mic'
 description: 'フロントマイクロフォン'
 priority: 8500
 available: 1
 direction: IN
 n_profiles: 9
 latency_offset: 0
 availability_group: (null)
 type: 5
 <profiles>
  [0] アナログステレオ 入力
  [1] アナログステレオデュプレックス
  [2] Digital Stereo (HDMI) 出力 + アナログステレオ 入力
  [3] Digital Stereo (HDMI 2) 出力 + アナログステレオ 入力
  [4] Digital Surround 5.1 (HDMI 2) 出力 + アナログステレオ 入力
  [5] Digital Surround 7.1 (HDMI 2) 出力 + アナログステレオ 入力
  [6] Digital Stereo (HDMI 3) 出力 + アナログステレオ 入力
  [7] Digital Surround 5.1 (HDMI 3) 出力 + アナログステレオ 入力
  [8] Digital Surround 7.1 (HDMI 3) 出力 + アナログステレオ 入力
<proplist>
device.icon_name = "audio-input-microphone"

---[1]---
 name: 'analog-input-rear-mic'
 description: 'リアマイクロフォン'
 priority: 8200
 available: 1
 direction: IN
 n_profiles: 9
 latency_offset: 0
 availability_group: (null)
 type: 5
 <profiles>
  [0] アナログステレオ 入力
  [1] アナログステレオデュプレックス
  [2] Digital Stereo (HDMI) 出力 + アナログステレオ 入力
  [3] Digital Stereo (HDMI 2) 出力 + アナログステレオ 入力
  [4] Digital Surround 5.1 (HDMI 2) 出力 + アナログステレオ 入力
  [5] Digital Surround 7.1 (HDMI 2) 出力 + アナログステレオ 入力
  [6] Digital Stereo (HDMI 3) 出力 + アナログステレオ 入力
  [7] Digital Surround 5.1 (HDMI 3) 出力 + アナログステレオ 入力
  [8] Digital Surround 7.1 (HDMI 3) 出力 + アナログステレオ 入力
<proplist>
device.icon_name = "audio-input-microphone"

---[2]---
 name: 'analog-input-linein'
 description: 'ラインイン'
 priority: 8100
 available: 1
 direction: IN
 n_profiles: 9
 latency_offset: 0
 availability_group: (null)
 type: 4
 <profiles>
  [0] アナログステレオ 入力
  [1] アナログステレオデュプレックス
  [2] Digital Stereo (HDMI) 出力 + アナログステレオ 入力
  [3] Digital Stereo (HDMI 2) 出力 + アナログステレオ 入力
  [4] Digital Surround 5.1 (HDMI 2) 出力 + アナログステレオ 入力
  [5] Digital Surround 7.1 (HDMI 2) 出力 + アナログステレオ 入力
  [6] Digital Stereo (HDMI 3) 出力 + アナログステレオ 入力
  [7] Digital Surround 5.1 (HDMI 3) 出力 + アナログステレオ 入力
  [8] Digital Surround 7.1 (HDMI 3) 出力 + アナログステレオ 入力
<proplist>

---[3]---
 name: 'analog-output-lineout'
 description: 'ライン出力'
 priority: 9000
 available: 1
 direction: OUT
 n_profiles: 2
 latency_offset: 0
 availability_group: (null)
 type: 4
 <profiles>
  [0] アナログステレオ 出力
  [1] アナログステレオデュプレックス
<proplist>

---[4]---
 name: 'analog-output-headphones'
 description: 'アナログヘッドフォン'
 priority: 9900
 available: 2
 direction: OUT
 n_profiles: 2
 latency_offset: 0
 availability_group: (null)
 type: 3
 <profiles>
  [0] アナログステレオ 出力
  [1] アナログステレオデュプレックス
<proplist>
device.icon_name = "audio-headphones"

---[5]---
 name: 'hdmi-output-0'
 description: 'HDMI / DisplayPort'
 priority: 5900
 available: 2
 direction: OUT
 n_profiles: 2
 latency_offset: 0
 availability_group: (null)
 type: 10
 <profiles>
  [0] Digital Stereo (HDMI) 出力
  [1] Digital Stereo (HDMI) 出力 + アナログステレオ 入力
<proplist>
device.icon_name = "video-display"
device.product.name = "PHL 224E5"

---[6]---
 name: 'hdmi-output-1'
 description: 'HDMI / DisplayPort 2'
 priority: 5800
 available: 1
 direction: OUT
 n_profiles: 6
 latency_offset: 0
 availability_group: (null)
 type: 10
 <profiles>
  [0] Digital Stereo (HDMI 2) 出力
  [1] Digital Stereo (HDMI 2) 出力 + アナログステレオ 入力
  [2] Digital Surround 5.1 (HDMI 2) 出力
  [3] Digital Surround 5.1 (HDMI 2) 出力 + アナログステレオ 入力
  [4] Digital Surround 7.1 (HDMI 2) 出力
  [5] Digital Surround 7.1 (HDMI 2) 出力 + アナログステレオ 入力
<proplist>
device.icon_name = "video-display"

---[7]---
 name: 'hdmi-output-2'
 description: 'HDMI / DisplayPort 3'
 priority: 5700
 available: 1
 direction: OUT
 n_profiles: 6
 latency_offset: 0
 availability_group: (null)
 type: 10
 <profiles>
  [0] Digital Stereo (HDMI 3) 出力
  [1] Digital Stereo (HDMI 3) 出力 + アナログステレオ 入力
  [2] Digital Surround 5.1 (HDMI 3) 出力
  [3] Digital Surround 5.1 (HDMI 3) 出力 + アナログステレオ 入力
  [4] Digital Surround 7.1 (HDMI 3) 出力
  [5] Digital Surround 7.1 (HDMI 3) 出力 + アナログステレオ 入力
<proplist>
device.icon_name = "video-display"

「マイクロフォン」はマイク端子のことです。

PC 前面に「マイク端子」「ヘッドホン端子」、PC 背面に「マイク端子」「ラインイン」「ラインアウト」「HDMI」があります。
「フロント」は PC 前面を意味し、「リア」は PC 背面を意味します。

プロパティリストには、その端子を表示するためのアイコン名や、HDMI に接続されているモニタ名が格納されています。
プロファイルの変更
現在接続されているサーバー上で、アクティブになっているプロファイルを変更したい場合は、以下の関数を使います。
そのサーバーに接続されている、他のクライアントも影響を受けるので、注意してください。

pa_operation *pa_context_set_card_profile_by_index(pa_context *c, uint32_t idx,
    const char *profile, pa_context_success_cb_t cb, void *userdata);

pa_operation *pa_context_set_card_profile_by_name(pa_context *c, const char *name,
    const char *profile, pa_context_success_cb_t cb, void *userdata);

//コールバック関数
typedef void (*pa_context_success_cb_t)(pa_context *c, int success, void *userdata);

by_index は、設定を変更したいカードのインデックス番号を指定し、by_name はカードの名前を指定します。
profile 引数に、変更するプロファイルの名前を指定します。

コールバック関数の success 引数で、操作が成功したか失敗したかが判断できます。