PulseAudio
インクルードファイル
インクルードファイルは、/usr/include/pulse/ ディレクトリにあり、カテゴリごとにファイルが分かれています。
pulse/pulseaudio.h をインクルードすると、メインの各ファイルをインクルードできます。
ただし、simple.h と glib-mainloop.h に関しては、必要に応じて別途インクルードする必要があります。
pulse/pulseaudio.h をインクルードすると、メインの各ファイルをインクルードできます。
ただし、simple.h と glib-mainloop.h に関しては、必要に応じて別途インクルードする必要があります。
#include <pulse/pulseaudio.h>
ライブラリ
ライブラリは複数あります。
libpulse は必須で、他は必要に応じて追加します。
libpulse.so | メイン |
---|---|
libpulse-simple.so | シンプル API |
libpulse-mainloop-glib.so | GLIB 2.x メインループのバインド |
libpulse は必須で、他は必要に応じて追加します。
文字列
PulseAudio では、すべての文字列は UTF-8 として扱われます。
pulse/utf8.h に、文字列変換の関数があるので、ロケール文字列と UTF-8 文字列を変換したい場合は、そちらを使うこともできます。
pulse/utf8.h に、文字列変換の関数があるので、ロケール文字列と UTF-8 文字列を変換したい場合は、そちらを使うこともできます。
シンプル API
PulseAudio を簡単に扱うために、ごくシンプルな API が用意されているので、まずはそちらを使ってみます。
複雑な操作はせず、単純に再生または録音だけしたい時に使えます。
pulse/simple.h のインクルードと、libpulse, libpulse-simple のリンクが必要になります。
シンプル API の関数一覧は、こちら。
終了時は、pa_simple オブジェクトを解放します。
再生時、書き込み済みのデータが、実際にすべて再生し終わるまで待ちます(ブロックする)。
再生/録音バッファをフラッシュします。
再生用にすでに書き込まれたデータ、または、録音用で読み込み待ちになっているデータを破棄します。
複雑な操作はせず、単純に再生または録音だけしたい時に使えます。
pulse/simple.h のインクルードと、libpulse, libpulse-simple のリンクが必要になります。
シンプル API の関数一覧は、こちら。
作成
まずは、pa_simple_new() を使って、PulseAudio サーバーに接続します。
色々とパラメータを指定できますが、NULL でデフォルトを指定できるものは、基本的に NULL で構いません。
再生 or 録音と、名前の文字列、サンプルスペックだけは指定します。
pa_simple *pa_simple_new(const char *server, const char *name, pa_stream_direction_t dir, const char *dev, const char *stream_name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_buffer_attr *attr, int *error);
server | 接続するサーバー名。NULL でデフォルト。 |
---|---|
name | クライアントの名前 (アプリケーション名など)。 pavucontrol などの音量調節アプリで表示される。 |
dir | 再生と録音、どちらで開くか。 PA_STREAM_PLAYBACK : 再生 PA_STREAM_RECORD : 録音 |
dev | 接続するシンク名(出力)、または、ソース名(入力)。 NULL でデフォルト。 普通に再生/録音をするなら、通常は NULL を指定します。 |
stream_name | ストリームを説明するための名前。 これも、pavucontrol などの音量調節アプリで表示される。 再生中の曲名や、クライアントの名前などを指定する。 |
ss | サンプルスペック |
map | チャンネルマップ。NULL でデフォルト。 |
attr | バッファ情報。NULL でデフォルト。 |
error | NULL 以外の場合、関数が失敗したときに、エラーコードが格納される。 |
戻り値 | NULL で失敗 |
色々とパラメータを指定できますが、NULL でデフォルトを指定できるものは、基本的に NULL で構いません。
再生 or 録音と、名前の文字列、サンプルスペックだけは指定します。
サンプルスペック
pa_sample_spec 構造体で、再生/録音するサンプルの情報を指定します。
再生なら、書き込む時のデータ、録音なら、読み込む時のデータになります。
PA_SAMPLE_S16LE (16bit 符号付き, LE)、48000 (Hz)、2チャンネル、というように指定します。
再生なら、書き込む時のデータ、録音なら、読み込む時のデータになります。
typedef struct pa_sample_spec { pa_sample_format_t format; uint32_t rate; uint8_t channels; } pa_sample_spec;
format | サンプルのフォーマットタイプ。 PA_SAMPLE_U8 PA_SAMPLE_ALAW PA_SAMPLE_ULAW PA_SAMPLE_S16LE PA_SAMPLE_S16BE PA_SAMPLE_FLOAT32LE PA_SAMPLE_FLOAT32BE PA_SAMPLE_S32LE PA_SAMPLE_S32BE PA_SAMPLE_S24LE PA_SAMPLE_S24BE PA_SAMPLE_S24_32LE (32bit 幅の中の 24bit) PA_SAMPLE_S24_32BE |
---|---|
rate | サンプリングレート (Hz) |
channels | チャンネル数 |
PA_SAMPLE_S16LE (16bit 符号付き, LE)、48000 (Hz)、2チャンネル、というように指定します。
解放
void pa_simple_free(pa_simple *s);
終了時は、pa_simple オブジェクトを解放します。
再生/録音
再生用にデータを書き込む時は、pa_simple_write()。
録音用にデータを取得する時は、pa_simple_read() を使います。
戻り値は、成功時 0、エラー時は負の値です(シンプル API の他の関数も同様)。
error 引数で、エラー時に、エラーコードを取得できます(NULL 指定可)。
書き込み時は、data で指定されたバッファのデータは内部にコピーされるので、pa_simple_write() の実行後は、すぐにバッファを解放したり、別の値を書き込んでも問題ありません。
書き込みを行うと、自動的に再生が始まります。
再生の場合、バッファのデータがある程度再生されてから、戻ってくる場合があります。
関数内部では、再生バッファ内で、常に一定程度のサイズまでの未再生データを保持するようにしているため、書き込み済みで未再生のデータが多い場合(一度の書き込みでサイズが多い場合)は、再生を行いつつ、バッファに新しいデータを書き込めるようになるまで、ブロックして待ちます。
そのようにして再生しつつ、すべてのデータがサーバーに送信できたら、関数は戻ってきます。
録音用にデータを取得する時は、pa_simple_read() を使います。
int pa_simple_write(pa_simple *s, const void *data, size_t bytes, int *error); int pa_simple_read(pa_simple *s, void *data, size_t bytes, int *error);
戻り値は、成功時 0、エラー時は負の値です(シンプル API の他の関数も同様)。
error 引数で、エラー時に、エラーコードを取得できます(NULL 指定可)。
書き込み時は、data で指定されたバッファのデータは内部にコピーされるので、pa_simple_write() の実行後は、すぐにバッファを解放したり、別の値を書き込んでも問題ありません。
書き込みを行うと、自動的に再生が始まります。
ブロック
なお、これらの関数は、実行後すぐに戻ってくるとは限りません。再生の場合、バッファのデータがある程度再生されてから、戻ってくる場合があります。
関数内部では、再生バッファ内で、常に一定程度のサイズまでの未再生データを保持するようにしているため、書き込み済みで未再生のデータが多い場合(一度の書き込みでサイズが多い場合)は、再生を行いつつ、バッファに新しいデータを書き込めるようになるまで、ブロックして待ちます。
そのようにして再生しつつ、すべてのデータがサーバーに送信できたら、関数は戻ってきます。
再生が終わるまで待つ
int pa_simple_drain(pa_simple *s, int *error);
再生時、書き込み済みのデータが、実際にすべて再生し終わるまで待ちます(ブロックする)。
オーディオデータを破棄
int pa_simple_flush(pa_simple *s, int *error);
再生/録音バッファをフラッシュします。
再生用にすでに書き込まれたデータ、または、録音用で読み込み待ちになっているデータを破棄します。
ソースコード
シンプル API を使って、正弦波の 'ドレミ' を1秒ずつ、合計3秒再生するプログラムです。
16bit LE、48000 Hz、モノラルで出力します。
16bit LE、48000 Hz、モノラルで出力します。
$ cc -o 01-simple 01-simple.c -lpulse -lpulse-simple -lm
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <pulse/simple.h> #define SAMPRATE 48000 #define PI 3.141592653 //正弦波 1秒 書き込み static void _write_audio(pa_simple *ps,uint8_t *buf,double freq) { int i; int16_t n; double d; uint8_t *ptr = (uint8_t *)buf; for(i = 0; i < SAMPRATE; i++, ptr += 2) { d = sin(2 * PI * freq * ((double)i / SAMPRATE)) * 0.8; n = (int16_t)round(d * 32767); //16bit LE ptr[0] = (uint8_t)n; ptr[1] = n >> 8; } printf("write.."); fflush(stdout); pa_simple_write(ps, buf, SAMPRATE * 2, NULL); printf("done\n"); } int main(void) { pa_simple *ps; pa_sample_spec ss; int err; uint8_t *buf; //作成 ss.format = PA_SAMPLE_S16LE; ss.rate = SAMPRATE; ss.channels = 1; ps = pa_simple_new(NULL, "pulse-test", PA_STREAM_PLAYBACK, NULL, "pulse-test-stream", &ss, NULL, NULL, &err); if(!ps) { printf("error: %d\n", err); return 1; } //書き込み buf = (uint8_t *)malloc(SAMPRATE * 2); _write_audio(ps, buf, 261.626); //ド _write_audio(ps, buf, 293.665); //レ _write_audio(ps, buf, 329.628); //ミ free(buf); //再生が終わるまで待つ pa_simple_drain(ps, NULL); //解放 pa_simple_free(ps); return 0; }
解説
pa_simple の作成時、name は "pulse-test"、stream_name は "pulse-test-stream" に指定しています。
プログラムの実行中に pavucontrol の「再生」タブを見てみると、以下のように表示されます。

このように、PulseAudio で再生/録音中のストリームの情報を、UI で表示するために使用されます。
プログラムの実行中に pavucontrol の「再生」タブを見てみると、以下のように表示されます。

このように、PulseAudio で再生/録音中のストリームの情報を、UI で表示するために使用されます。
再生
pa_simple_write() の実行前に "write.." が表示され、関数が戻ると "done" が表示されます。
実際に実行してみると、pa_simple_write() が実行された後は、しばらく再生されてから、関数が戻ってくるのがわかります。
最後の pa_simple_write() で書き込んだデータは、まだ再生されていない部分が残っている可能性があるので、pa_simple_drain() で、すべてのデータが再生されるまで待ちます。
実際に実行してみると、pa_simple_write() が実行された後は、しばらく再生されてから、関数が戻ってくるのがわかります。
最後の pa_simple_write() で書き込んだデータは、まだ再生されていない部分が残っている可能性があるので、pa_simple_drain() で、すべてのデータが再生されるまで待ちます。