PulseAudio:サーバー情報

サーバー情報
前回までで、サーバーとの接続が出来たので、まずは、サーバーの情報を取得してみます。

サーバーから情報を取得する際も非同期になるので、情報の取得には、コールバック関数を使います。
サーバーの情報を取得
pa_operation *pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata);

//コールバック関数
typedef void (*pa_server_info_cb_t)(pa_context *c, const pa_server_info *i, void *userdata);

現在接続されているサーバーの情報を取得します。
cb で、コールバック関数を指定します。

サーバーから情報が来た場合は、指定されたコールバック関数が実行されるので、引数の構造体ポインタから、情報を参照します。
※このデータは、コールバック関数の実行中のみ有効。
サーバー情報構造体
typedef struct pa_server_info {
    const char *user_name;
    const char *host_name;
    const char *server_version;
    const char *server_name;
    pa_sample_spec sample_spec;
    const char *default_sink_name;
    const char *default_source_name;
    uint32_t cookie;
    pa_channel_map channel_map;
} pa_server_info;

user_nameユーザー名
host_nameホスト名
server_versionサーバーのバージョン文字列
server_nameサーバー名
sample_specデフォルトのサンプルスペック情報
default_sink_nameデフォルトのシンク名
default_source_nameデフォルトのソース名
cookiePulseAudio インスタンスのランダムクッキー
channel_mapデフォルトのチャンネルマップ情報
pa_operation
pa_context_get_server_info() の戻り値が、pa_operation * になっていることに注意してください。
これは、非同期の操作の状態を、監視するためのオブジェクトです。

これにより、現在の状態を取得したり、操作をキャンセルしたりすることができます。

pa_operation 関連の詳細はこちら
参照カウント
pa_operation *pa_operation_ref(pa_operation *o);
void pa_operation_unref(pa_operation *o);

pa_operation は参照カウントされるので、解放関数はありません。

戻り値で pa_operation が返る関数の場合は、実際に pa_operation を使わなかったとしても、常に pa_operation_unref() を使って、カウンタを -1 する必要があります。
状態を取得
pa_operation_state_t pa_operation_get_state(const pa_operation *o);

現在の操作の状態を取得します。

PA_OPERATION_RUNNING操作がまだ実行中
PA_OPERATION_DONE操作が完了した
PA_OPERATION_CANCELLEDキャンセルされた。
アプリケーションによってキャンセルされた、または、操作の保留中にコンテキストが切断された。
使い方
戻り値で pa_operation * を返す関数を使った後、操作が完了するまで待ちたい場合は、スレッドメインループなら、以下のような形になります。

pa_operation *op;

pa_threaded_mainloop_lock(mainloop);

op = pa_context_get_server_info(ctx, callback, NULL);

while(pa_operation_get_state(op) == PA_OPERATION_RUNNING)
    pa_threaded_mainloop_wait(mainloop);

pa_operation_unref(op);

pa_threaded_mainloop_unlock(mainloop);

まず、pa_threaded_mainloop_lock() で、イベントループをロックするのを忘れないでください。
ロックした後に、情報取得の関数を実行します。

サーバーの接続時と同じように、pa_operation_get_state() で現在の状態を確認して、まだ実行中であれば、イベントが来るのを待ちます。

コールバック関数が来て、処理が終わったら、pa_threaded_mainloop_signal() を実行して、wait から抜けます。

最後に、pa_operation_unref() で、pa_operation の参照カウンタを -1 した後、ロックを解除します。
プログラム
接続したサーバーの情報を取得して、出力するプログラムです。

なお、PulseAudio の共通処理は、util.c にまとめておいたので、以降はこの関数を使います。
ソースコードをダウンロードして、util.c も一緒にコンパイルしてください。

メインループは、スレッドの方を使っています。

$ cc -o 04-serverinfo 04-serverinfo.c util.c -lpulse

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

PulseData *pulse;

static void _callback(pa_context *c,const pa_server_info *i,void *userdata)
{
    int j;
    char m[64];

    printf("user_name: %s\n", i->user_name);
    printf("host_name: %s\n", i->host_name);
    printf("server_version: %s\n", i->server_version);
    printf("server_name: %s\n", i->server_name);
    printf("default_sink_name: %s\n", i->default_sink_name);
    printf("default_source_name: %s\n", i->default_source_name);
    printf("cookie: 0x%08x\n", i->cookie);

    //sample_spec

    printf("\n[sample_spec]\n");
    printf("format: (%d) '%s'\n", i->sample_spec.format,
        pa_sample_format_to_string(i->sample_spec.format));

    printf("rate: %u\n", i->sample_spec.rate);
    printf("channels: %d\n", i->sample_spec.channels);

    pa_sample_spec_snprint(m, 64, &i->sample_spec);
    printf("<snprint> '%s'\n", m);

    //channel_map

    printf("\n[channel_map]\n");

    for(j = 0; j < i->channel_map.channels; j++)
        printf("[%d] '%s'\n", j, pa_channel_position_to_pretty_string(i->channel_map.map[j]));

    pa_channel_map_snprint(m, 64, &i->channel_map);
    printf("<snprint> '%s'\n", m);

    printf("<to_name> '%s'\n", pa_channel_map_to_name(&i->channel_map));
    printf("<to_pretty_name> '%s'\n", pa_channel_map_to_pretty_name(&i->channel_map));

    pa_threaded_mainloop_signal(pulse->mainloop, 0);
}

int main(void)
{
    pa_operation *op;

    pulse = pulse_connect(0);
    if(!pulse) return 1;

    //

    pa_threaded_mainloop_lock(pulse->mainloop);

    op = pa_context_get_server_info(pulse->ctx, _callback, NULL);

    while(pa_operation_get_state(op) == PA_OPERATION_RUNNING)
        pa_threaded_mainloop_wait(pulse->mainloop);

    pa_operation_unref(op);
    
    pa_threaded_mainloop_unlock(pulse->mainloop);

    //
    
    pulse_free(pulse);

    return 0;
}
実行結果
user_name: ****(環境による)
host_name: ****(環境による)
server_version: 17.0
server_name: pulseaudio
default_sink_name: alsa_output.pci-0000_00_1f.3.analog-stereo
default_source_name: alsa_output.pci-0000_00_1f.3.analog-stereo.monitor
cookie: 0x64d2ba68

[sample_spec]
format: (3) 's16le'
rate: 44100
channels: 2
<snprint> 's16le 2ch 44100Hz'

[channel_map]
[0] 'Front Left'
[1] 'Front Right'
<snprint> 'front-left,front-right'
<to_name> 'stereo'
<to_pretty_name> 'Stereo'

default_sink_name は、デフォルトのオーディオ出力先を意味します。
default_source_name は、デフォルトとのオーディオ入力元です。

サンプルスペックとチャンネルマップは、値を元に、文字列を取得する関数があるので、それらを使って表示しています。

チャンネルマップは、各チャンネルが、どの位置にあるかという情報です。
ステレオなら、「(前方) 左」と「(前方) 右」の、2つのチャンネルがあります。

サンプルスペックの詳細はこちら
チャンネルマップの詳細はこちら