シンク入力
「シンク入力 (sink input)」は、各クライアントが再生用に作成したそれぞれのストリームを、サーバーが識別するためのものです。
クライアントが作成した再生用のストリームを、サーバーと接続すると、サーバー上で1つのシンク入力が作成されます。
このシンク入力を、サーバー上の1つのシンクに接続することによって、オーディオが出力されます。
シンクから見れば、オーディオデータが与えられることになるので、「シンク入力」という名前になっています。
「ソース出力 (source output)」の場合は、録音用のストリームを、サーバーが識別するためのもので、ソース出力が作成された後、サーバー上の1つのソースに接続されます。
ソースから見れば、入力したデータを各ストリームに送る形になるので、「ソース出力」となります。
ここでは、サーバーから、シンク入力の情報を取得してみます。
なお、ソース出力についてはやりませんが、構造体の値も含めて、基本的にはシンク入力と同じです。
シンク入力にもインデックスが割り振られるので、特定のシンク入力の情報を取得する場合は、pa_context_get_sink_input_info() を使います。
pa_context_get_sink_input_info_list() で、すべてのシンク入力の情報を取得します。
クライアントが作成した再生用のストリームを、サーバーと接続すると、サーバー上で1つのシンク入力が作成されます。
このシンク入力を、サーバー上の1つのシンクに接続することによって、オーディオが出力されます。
シンクから見れば、オーディオデータが与えられることになるので、「シンク入力」という名前になっています。
「ソース出力 (source output)」の場合は、録音用のストリームを、サーバーが識別するためのもので、ソース出力が作成された後、サーバー上の1つのソースに接続されます。
ソースから見れば、入力したデータを各ストリームに送る形になるので、「ソース出力」となります。
ここでは、サーバーから、シンク入力の情報を取得してみます。
なお、ソース出力についてはやりませんが、構造体の値も含めて、基本的にはシンク入力と同じです。
シンク入力の情報を取得
pa_operation *pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata); pa_operation *pa_context_get_sink_input_info_list(pa_context *c, pa_sink_input_info_cb_t cb, void *userdata); //コールバック関数 typedef void (*pa_sink_input_info_cb_t)(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata);
シンク入力にもインデックスが割り振られるので、特定のシンク入力の情報を取得する場合は、pa_context_get_sink_input_info() を使います。
pa_context_get_sink_input_info_list() で、すべてのシンク入力の情報を取得します。
pa_sink_input_info 構造体
typedef struct pa_sink_input_info { uint32_t index; const char *name; uint32_t owner_module; uint32_t client; uint32_t sink; pa_sample_spec sample_spec; pa_channel_map channel_map; pa_cvolume volume; pa_usec_t buffer_usec; pa_usec_t sink_usec; const char *resample_method; const char *driver; int mute; pa_proplist *proplist; int corked; int has_volume; int volume_writable; pa_format_info *format; } pa_sink_input_info;
index | シンク入力のインデックス |
---|---|
name | シンク入力の名前。 (クライアントが設定したストリームの名前) |
client | このシンク入力が属するクライアントの、インデックス。 どのクライアントにも属していない場合は PA_INVALID_INDEX。 |
sink | 接続されているシンクのインデックス |
volume | このシンク入力の音量 |
buffer_usec | シンク入力のバッファのレイテンシ(マイクロ秒) |
sink_usec | シンクデバイスのレイテンシ(マイクロ秒) |
resample_method | このシンク入力で使用される、再サンプリング方法の文字列 |
corked | 再生が停止中か |
has_volume | volume の音量を使うか |
volume_writable | volume の音量を適用できるか |
プログラム
サーバーから、シンク入力の情報を取得して、出力するプログラムです。
$ cc -o 10-sinkinput 10-sinkinput.c util.c -lpulse
#include <stdio.h> #include <pulse/pulseaudio.h> #include "util.h" PulseData *pulse; static void _sinkinput_callback(pa_context *c,const pa_sink_input_info *i,int eol,void *userdata) { char m[64]; if(!i) { pa_threaded_mainloop_signal(pulse->mainloop, 0); return; } printf("=== [%d] ===\n", i->index); printf("name: %s\n", i->name); printf("owner_module: %u\n", i->owner_module); printf("client: %u\n", i->client); printf("sink: %u\n", i->sink); pa_sample_spec_snprint(m, 64, &i->sample_spec); printf("sample_spcec: %s\n", m); pa_channel_map_snprint(m, 64, &i->channel_map); printf("channel_map: '%s'\n", m); pa_cvolume_snprint(m, 64, &i->volume); printf("volume: '%s'\n", m); printf("buffer_usec: %lu\n", i->buffer_usec); printf("sink_usec: %lu\n", i->sink_usec); printf("resample_method: %s\n", i->resample_method); printf("driver: %s\n", i->driver); printf("mute: %d\n", i->mute); printf("corked: %d\n", i->corked); printf("has_volume: %d\n", i->has_volume); printf("volume_writable: %d\n", i->volume_writable); printf("format: encoding(%d)\n", i->format->encoding); pulse_put_proplist(i->proplist); printf("\n"); } static pa_operation *_get_info(PulseData *p,void *data) { return pa_context_get_sink_input_info_list(pulse->ctx, _sinkinput_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; }
実行結果
※何かしらのアプリで、オーディオを再生している状態で、実行してください。
以下は、SMPlayer で test.mp4 のファイルを再生している時の、出力結果です。
このシンク入力は、SMPlayer が、"test.mp4" の名前で作成したストリームによって、作成されたものです。
index = 16 のシンクに接続されています。
サーバー情報のデフォルトのサンプルスペックは "s16le 2ch 44100Hz" で、シンクのサンプルスペックは "s16le 2ch 48000Hz" でしたが、このストリームは、"float32le 2ch 48000Hz" で出力されています。
再生中にシンク情報を見ても、"s16le 2ch 48000Hz" でした。
つまり、ストリームには float32le 2ch 48000Hz のデータが書き込まれ、そのデータがシンクに送られる時に、s16le 2ch 48000Hz のデータに変換されます。
サーバー上の音量とは別に、各ストリームには、個別の音量を設定することができます。
以下は、SMPlayer で test.mp4 のファイルを再生している時の、出力結果です。
=== [13] === name: test.mp4 owner_module: 8 client: 36 sink: 16 sample_spcec: float32le 2ch 48000Hz channel_map: 'front-left,front-right' volume: '0: 100% 1: 100%' buffer_usec: 74666 sink_usec: 60368 resample_method: copy driver: protocol-native.c mute: 0 corked: 0 has_volume: 1 volume_writable: 1 format: encoding(1) <proplist> media.icon_name = "SMPlayer" media.name = "test.mp4" application.name = "SMPlayer" native-protocol.peer = "UNIX socket client" native-protocol.version = "35" application.process.id = "***" application.process.user = "***" application.process.host = "***" application.process.binary = "mpv" application.language = "C" window.x11.display = ":0" application.process.machine_id = "***" application.process.session_id = "2" application.icon_name = "mpv" module-stream-restore.id = "sink-input-by-application-name:SMPlayer"
このシンク入力は、SMPlayer が、"test.mp4" の名前で作成したストリームによって、作成されたものです。
index = 16 のシンクに接続されています。
サーバー情報のデフォルトのサンプルスペックは "s16le 2ch 44100Hz" で、シンクのサンプルスペックは "s16le 2ch 48000Hz" でしたが、このストリームは、"float32le 2ch 48000Hz" で出力されています。
再生中にシンク情報を見ても、"s16le 2ch 48000Hz" でした。
つまり、ストリームには float32le 2ch 48000Hz のデータが書き込まれ、そのデータがシンクに送られる時に、s16le 2ch 48000Hz のデータに変換されます。
サーバー上の音量とは別に、各ストリームには、個別の音量を設定することができます。
2つのシンク入力
2つのアプリで同時に再生を行った場合、以下のようになります(一部省略)。
Audacious は 16bit で出力、SMPlayer は 32bit float で出力されています。
この場合、再生中にシンクの情報を見てみると、サンプルスペックは "s16le 2ch 44100Hz" になっていました。
Audacious の方が先に再生されているので、こちらの 44100Hz が優先されているようです。
後から再生した SMPlayer の再サンプリング方法は、"speex-float-1" になっています。
float32le 2ch 48000Hz で書き込まれたデータは、現在のシンクのサンプルスペックである、"s16le 2ch 44100Hz" に再サンプリングされます。
ちなみに、24000Hz のストリームを単独で再生すると、シンクは 48000Hz になり、22500Hz のストリームを再生すると、シンクは 44100Hz となります。
低いサンプリングレートの場合は、一番値が高くて、倍数になるような値に補正されます。
このように、シンクのサンプルスペックは、最初に再生されたストリームによって、動的に変更されることがわかります。
その後、新しいシンク入力が増えた場合は、現在のシンクのサンプルスペックに合わせて、再サンプリングされます。
=== [6] === name: Audacious client: 13 sink: 4 sample_spcec: s16le 2ch 44100Hz channel_map: 'front-left,front-right' volume: '0: 100% 1: 100%' buffer_usec: 465668 sink_usec: 60322 resample_method: (null) === [7] === name: test.mp4 - mpv client: 15 sink: 4 sample_spcec: float32le 2ch 48000Hz channel_map: 'front-left,front-right' volume: '0: 100% 1: 100%' buffer_usec: 77170 sink_usec: 60127 resample_method: speex-float-1
Audacious は 16bit で出力、SMPlayer は 32bit float で出力されています。
この場合、再生中にシンクの情報を見てみると、サンプルスペックは "s16le 2ch 44100Hz" になっていました。
Audacious の方が先に再生されているので、こちらの 44100Hz が優先されているようです。
後から再生した SMPlayer の再サンプリング方法は、"speex-float-1" になっています。
float32le 2ch 48000Hz で書き込まれたデータは、現在のシンクのサンプルスペックである、"s16le 2ch 44100Hz" に再サンプリングされます。
ちなみに、24000Hz のストリームを単独で再生すると、シンクは 48000Hz になり、22500Hz のストリームを再生すると、シンクは 44100Hz となります。
低いサンプリングレートの場合は、一番値が高くて、倍数になるような値に補正されます。
このように、シンクのサンプルスペックは、最初に再生されたストリームによって、動的に変更されることがわかります。
その後、新しいシンク入力が増えた場合は、現在のシンクのサンプルスペックに合わせて、再サンプリングされます。
シンク入力の操作
特定のシンク入力の音量を変更したり、ミュートにしたり、削除したりすることができます。
これにより、外部のアプリから、現在再生中のストリームの音量を変更したり、ストリームを終了させることができます。
また、特定のシンク入力を、別のシンクに接続することもできます。
これにより、外部のアプリから、現在再生中のストリームの音量を変更したり、ストリームを終了させることができます。
また、特定のシンク入力を、別のシンクに接続することもできます。