mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2025-01-03 16:25:28 +00:00
sine wave example working with pulseaudio on linux
This commit is contained in:
parent
664c50752a
commit
93f288e8b1
|
@ -81,8 +81,7 @@ make
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
0. sine example working with dummy backend osx, windows
|
0. sine example working with dummy backend osx
|
||||||
0. sine example working with pulseaudio backend linux
|
|
||||||
0. pipe record to playback example working with dummy linux, osx, windows
|
0. pipe record to playback example working with dummy linux, osx, windows
|
||||||
0. pipe record to playback example working with pulseaudio linux
|
0. pipe record to playback example working with pulseaudio linux
|
||||||
0. implement CoreAudio (OSX) backend, get examples working
|
0. implement CoreAudio (OSX) backend, get examples working
|
||||||
|
|
|
@ -49,25 +49,25 @@ static void subscribe_callback(pa_context *context,
|
||||||
pa_subscription_event_type_t event_bits, uint32_t index, void *userdata)
|
pa_subscription_event_type_t event_bits, uint32_t index, void *userdata)
|
||||||
{
|
{
|
||||||
SoundIo *soundio = (SoundIo *)userdata;
|
SoundIo *soundio = (SoundIo *)userdata;
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
ah->device_scan_queued = true;
|
sipa->device_scan_queued = true;
|
||||||
pa_threaded_mainloop_signal(ah->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void subscribe_to_events(SoundIo *soundio) {
|
static void subscribe_to_events(SoundIo *soundio) {
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
pa_subscription_mask_t events = (pa_subscription_mask_t)(
|
pa_subscription_mask_t events = (pa_subscription_mask_t)(
|
||||||
PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE|PA_SUBSCRIPTION_MASK_SERVER);
|
PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE|PA_SUBSCRIPTION_MASK_SERVER);
|
||||||
pa_operation *subscribe_op = pa_context_subscribe(ah->pulse_context,
|
pa_operation *subscribe_op = pa_context_subscribe(sipa->pulse_context,
|
||||||
events, nullptr, soundio);
|
events, nullptr, soundio);
|
||||||
if (!subscribe_op)
|
if (!subscribe_op)
|
||||||
soundio_panic("pa_context_subscribe failed: %s", pa_strerror(pa_context_errno(ah->pulse_context)));
|
soundio_panic("pa_context_subscribe failed: %s", pa_strerror(pa_context_errno(sipa->pulse_context)));
|
||||||
pa_operation_unref(subscribe_op);
|
pa_operation_unref(subscribe_op);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void context_state_callback(pa_context *context, void *userdata) {
|
static void context_state_callback(pa_context *context, void *userdata) {
|
||||||
SoundIo *soundio = (SoundIo *)userdata;
|
SoundIo *soundio = (SoundIo *)userdata;
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
|
|
||||||
switch (pa_context_get_state(context)) {
|
switch (pa_context_get_state(context)) {
|
||||||
case PA_CONTEXT_UNCONNECTED: // The context hasn't been connected yet.
|
case PA_CONTEXT_UNCONNECTED: // The context hasn't been connected yet.
|
||||||
|
@ -79,19 +79,19 @@ static void context_state_callback(pa_context *context, void *userdata) {
|
||||||
case PA_CONTEXT_SETTING_NAME: // The client is passing its application name to the daemon.
|
case PA_CONTEXT_SETTING_NAME: // The client is passing its application name to the daemon.
|
||||||
return;
|
return;
|
||||||
case PA_CONTEXT_READY: // The connection is established, the context is ready to execute operations.
|
case PA_CONTEXT_READY: // The connection is established, the context is ready to execute operations.
|
||||||
ah->device_scan_queued = true;
|
sipa->device_scan_queued = true;
|
||||||
subscribe_to_events(soundio);
|
subscribe_to_events(soundio);
|
||||||
ah->ready_flag = true;
|
sipa->ready_flag = true;
|
||||||
pa_threaded_mainloop_signal(ah->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
return;
|
return;
|
||||||
case PA_CONTEXT_TERMINATED: // The connection was terminated cleanly.
|
case PA_CONTEXT_TERMINATED: // The connection was terminated cleanly.
|
||||||
pa_threaded_mainloop_signal(ah->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
return;
|
return;
|
||||||
case PA_CONTEXT_FAILED: // The connection failed or was disconnected.
|
case PA_CONTEXT_FAILED: // The connection failed or was disconnected.
|
||||||
{
|
{
|
||||||
int err_number = pa_context_errno(context);
|
int err_number = pa_context_errno(context);
|
||||||
if (err_number == PA_ERR_CONNECTIONREFUSED) {
|
if (err_number == PA_ERR_CONNECTIONREFUSED) {
|
||||||
ah->connection_refused = true;
|
sipa->connection_refused = true;
|
||||||
} else {
|
} else {
|
||||||
soundio_panic("pulseaudio connect failure: %s", pa_strerror(pa_context_errno(context)));
|
soundio_panic("pulseaudio connect failure: %s", pa_strerror(pa_context_errno(context)));
|
||||||
}
|
}
|
||||||
|
@ -101,55 +101,55 @@ static void context_state_callback(pa_context *context, void *userdata) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_current_devices_info(SoundIo *soundio) {
|
static void destroy_current_devices_info(SoundIo *soundio) {
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
if (ah->current_devices_info) {
|
if (sipa->current_devices_info) {
|
||||||
for (int i = 0; i < ah->current_devices_info->input_devices.length; i += 1)
|
for (int i = 0; i < sipa->current_devices_info->input_devices.length; i += 1)
|
||||||
soundio_device_unref(ah->current_devices_info->input_devices.at(i));
|
soundio_device_unref(sipa->current_devices_info->input_devices.at(i));
|
||||||
for (int i = 0; i < ah->current_devices_info->output_devices.length; i += 1)
|
for (int i = 0; i < sipa->current_devices_info->output_devices.length; i += 1)
|
||||||
soundio_device_unref(ah->current_devices_info->output_devices.at(i));
|
soundio_device_unref(sipa->current_devices_info->output_devices.at(i));
|
||||||
|
|
||||||
destroy(ah->current_devices_info);
|
destroy(sipa->current_devices_info);
|
||||||
ah->current_devices_info = nullptr;
|
sipa->current_devices_info = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_ready_devices_info(SoundIo *soundio) {
|
static void destroy_ready_devices_info(SoundIo *soundio) {
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
if (ah->ready_devices_info) {
|
if (sipa->ready_devices_info) {
|
||||||
for (int i = 0; i < ah->ready_devices_info->input_devices.length; i += 1)
|
for (int i = 0; i < sipa->ready_devices_info->input_devices.length; i += 1)
|
||||||
soundio_device_unref(ah->ready_devices_info->input_devices.at(i));
|
soundio_device_unref(sipa->ready_devices_info->input_devices.at(i));
|
||||||
for (int i = 0; i < ah->ready_devices_info->output_devices.length; i += 1)
|
for (int i = 0; i < sipa->ready_devices_info->output_devices.length; i += 1)
|
||||||
soundio_device_unref(ah->ready_devices_info->output_devices.at(i));
|
soundio_device_unref(sipa->ready_devices_info->output_devices.at(i));
|
||||||
destroy(ah->ready_devices_info);
|
destroy(sipa->ready_devices_info);
|
||||||
ah->ready_devices_info = nullptr;
|
sipa->ready_devices_info = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void destroy_pa(SoundIo *soundio) {
|
static void destroy_pa(SoundIo *soundio) {
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
if (!ah)
|
if (!sipa)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ah->main_loop)
|
if (sipa->main_loop)
|
||||||
pa_threaded_mainloop_stop(ah->main_loop);
|
pa_threaded_mainloop_stop(sipa->main_loop);
|
||||||
|
|
||||||
destroy_current_devices_info(soundio);
|
destroy_current_devices_info(soundio);
|
||||||
destroy_ready_devices_info(soundio);
|
destroy_ready_devices_info(soundio);
|
||||||
|
|
||||||
pa_context_disconnect(ah->pulse_context);
|
pa_context_disconnect(sipa->pulse_context);
|
||||||
pa_context_unref(ah->pulse_context);
|
pa_context_unref(sipa->pulse_context);
|
||||||
|
|
||||||
if (ah->main_loop)
|
if (sipa->main_loop)
|
||||||
pa_threaded_mainloop_free(ah->main_loop);
|
pa_threaded_mainloop_free(sipa->main_loop);
|
||||||
|
|
||||||
if (ah->props)
|
if (sipa->props)
|
||||||
pa_proplist_free(ah->props);
|
pa_proplist_free(sipa->props);
|
||||||
|
|
||||||
free(ah->default_sink_name);
|
free(sipa->default_sink_name);
|
||||||
free(ah->default_source_name);
|
free(sipa->default_source_name);
|
||||||
|
|
||||||
destroy(ah);
|
destroy(sipa);
|
||||||
soundio->backend_data = nullptr;
|
soundio->backend_data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,11 +215,11 @@ static void set_from_pulseaudio_channel_map(pa_channel_map channel_map, SoundIoC
|
||||||
}
|
}
|
||||||
|
|
||||||
static int perform_operation(SoundIo *soundio, pa_operation *op) {
|
static int perform_operation(SoundIo *soundio, pa_operation *op) {
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
switch (pa_operation_get_state(op)) {
|
switch (pa_operation_get_state(op)) {
|
||||||
case PA_OPERATION_RUNNING:
|
case PA_OPERATION_RUNNING:
|
||||||
pa_threaded_mainloop_wait(ah->main_loop);
|
pa_threaded_mainloop_wait(sipa->main_loop);
|
||||||
continue;
|
continue;
|
||||||
case PA_OPERATION_DONE:
|
case PA_OPERATION_DONE:
|
||||||
pa_operation_unref(op);
|
pa_operation_unref(op);
|
||||||
|
@ -232,46 +232,46 @@ static int perform_operation(SoundIo *soundio, pa_operation *op) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void finish_device_query(SoundIo *soundio) {
|
static void finish_device_query(SoundIo *soundio) {
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
|
|
||||||
if (!ah->have_sink_list ||
|
if (!sipa->have_sink_list ||
|
||||||
!ah->have_source_list ||
|
!sipa->have_source_list ||
|
||||||
!ah->have_default_sink)
|
!sipa->have_default_sink)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// based on the default sink name, figure out the default output index
|
// based on the default sink name, figure out the default output index
|
||||||
ah->current_devices_info->default_output_index = -1;
|
sipa->current_devices_info->default_output_index = -1;
|
||||||
ah->current_devices_info->default_input_index = -1;
|
sipa->current_devices_info->default_input_index = -1;
|
||||||
for (int i = 0; i < ah->current_devices_info->input_devices.length; i += 1) {
|
for (int i = 0; i < sipa->current_devices_info->input_devices.length; i += 1) {
|
||||||
SoundIoDevice *device = ah->current_devices_info->input_devices.at(i);
|
SoundIoDevice *device = sipa->current_devices_info->input_devices.at(i);
|
||||||
assert(device->purpose == SoundIoDevicePurposeInput);
|
assert(device->purpose == SoundIoDevicePurposeInput);
|
||||||
if (strcmp(device->name, ah->default_source_name) == 0) {
|
if (strcmp(device->name, sipa->default_source_name) == 0) {
|
||||||
ah->current_devices_info->default_input_index = i;
|
sipa->current_devices_info->default_input_index = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < ah->current_devices_info->output_devices.length; i += 1) {
|
for (int i = 0; i < sipa->current_devices_info->output_devices.length; i += 1) {
|
||||||
SoundIoDevice *device = ah->current_devices_info->output_devices.at(i);
|
SoundIoDevice *device = sipa->current_devices_info->output_devices.at(i);
|
||||||
assert(device->purpose == SoundIoDevicePurposeOutput);
|
assert(device->purpose == SoundIoDevicePurposeOutput);
|
||||||
if (strcmp(device->name, ah->default_sink_name) == 0) {
|
if (strcmp(device->name, sipa->default_sink_name) == 0) {
|
||||||
ah->current_devices_info->default_output_index = i;
|
sipa->current_devices_info->default_output_index = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy_ready_devices_info(soundio);
|
destroy_ready_devices_info(soundio);
|
||||||
ah->ready_devices_info = ah->current_devices_info;
|
sipa->ready_devices_info = sipa->current_devices_info;
|
||||||
ah->current_devices_info = NULL;
|
sipa->current_devices_info = NULL;
|
||||||
ah->have_devices_flag = true;
|
sipa->have_devices_flag = true;
|
||||||
pa_threaded_mainloop_signal(ah->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
soundio->on_events_signal(soundio);
|
soundio->on_events_signal(soundio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *info, int eol, void *userdata) {
|
static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *info, int eol, void *userdata) {
|
||||||
SoundIo *soundio = (SoundIo *)userdata;
|
SoundIo *soundio = (SoundIo *)userdata;
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
if (eol) {
|
if (eol) {
|
||||||
ah->have_sink_list = true;
|
sipa->have_sink_list = true;
|
||||||
finish_device_query(soundio);
|
finish_device_query(soundio);
|
||||||
} else {
|
} else {
|
||||||
SoundIoDevice *device = create<SoundIoDevice>();
|
SoundIoDevice *device = create<SoundIoDevice>();
|
||||||
|
@ -290,17 +290,17 @@ static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *in
|
||||||
device->default_sample_rate = sample_rate_from_pulseaudio(info->sample_spec);
|
device->default_sample_rate = sample_rate_from_pulseaudio(info->sample_spec);
|
||||||
device->purpose = SoundIoDevicePurposeOutput;
|
device->purpose = SoundIoDevicePurposeOutput;
|
||||||
|
|
||||||
if (ah->current_devices_info->output_devices.append(device))
|
if (sipa->current_devices_info->output_devices.append(device))
|
||||||
soundio_panic("out of memory");
|
soundio_panic("out of memory");
|
||||||
}
|
}
|
||||||
pa_threaded_mainloop_signal(ah->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void source_info_callback(pa_context *pulse_context, const pa_source_info *info, int eol, void *userdata) {
|
static void source_info_callback(pa_context *pulse_context, const pa_source_info *info, int eol, void *userdata) {
|
||||||
SoundIo *soundio = (SoundIo *)userdata;
|
SoundIo *soundio = (SoundIo *)userdata;
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
if (eol) {
|
if (eol) {
|
||||||
ah->have_source_list = true;
|
sipa->have_source_list = true;
|
||||||
finish_device_query(soundio);
|
finish_device_query(soundio);
|
||||||
} else {
|
} else {
|
||||||
SoundIoDevice *device = create<SoundIoDevice>();
|
SoundIoDevice *device = create<SoundIoDevice>();
|
||||||
|
@ -319,50 +319,50 @@ static void source_info_callback(pa_context *pulse_context, const pa_source_info
|
||||||
device->default_sample_rate = sample_rate_from_pulseaudio(info->sample_spec);
|
device->default_sample_rate = sample_rate_from_pulseaudio(info->sample_spec);
|
||||||
device->purpose = SoundIoDevicePurposeInput;
|
device->purpose = SoundIoDevicePurposeInput;
|
||||||
|
|
||||||
if (ah->current_devices_info->input_devices.append(device))
|
if (sipa->current_devices_info->input_devices.append(device))
|
||||||
soundio_panic("out of memory");
|
soundio_panic("out of memory");
|
||||||
}
|
}
|
||||||
pa_threaded_mainloop_signal(ah->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void server_info_callback(pa_context *pulse_context, const pa_server_info *info, void *userdata) {
|
static void server_info_callback(pa_context *pulse_context, const pa_server_info *info, void *userdata) {
|
||||||
SoundIo *soundio = (SoundIo *)userdata;
|
SoundIo *soundio = (SoundIo *)userdata;
|
||||||
assert(soundio);
|
assert(soundio);
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
|
|
||||||
free(ah->default_sink_name);
|
free(sipa->default_sink_name);
|
||||||
free(ah->default_source_name);
|
free(sipa->default_source_name);
|
||||||
|
|
||||||
ah->default_sink_name = strdup(info->default_sink_name);
|
sipa->default_sink_name = strdup(info->default_sink_name);
|
||||||
ah->default_source_name = strdup(info->default_source_name);
|
sipa->default_source_name = strdup(info->default_source_name);
|
||||||
|
|
||||||
if (!ah->default_sink_name || !ah->default_source_name)
|
if (!sipa->default_sink_name || !sipa->default_source_name)
|
||||||
soundio_panic("out of memory");
|
soundio_panic("out of memory");
|
||||||
|
|
||||||
ah->have_default_sink = true;
|
sipa->have_default_sink = true;
|
||||||
finish_device_query(soundio);
|
finish_device_query(soundio);
|
||||||
pa_threaded_mainloop_signal(ah->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scan_devices(SoundIo *soundio) {
|
static void scan_devices(SoundIo *soundio) {
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
|
|
||||||
ah->have_sink_list = false;
|
sipa->have_sink_list = false;
|
||||||
ah->have_default_sink = false;
|
sipa->have_default_sink = false;
|
||||||
ah->have_source_list = false;
|
sipa->have_source_list = false;
|
||||||
|
|
||||||
destroy_current_devices_info(soundio);
|
destroy_current_devices_info(soundio);
|
||||||
ah->current_devices_info = create<SoundIoDevicesInfo>();
|
sipa->current_devices_info = create<SoundIoDevicesInfo>();
|
||||||
if (!ah->current_devices_info)
|
if (!sipa->current_devices_info)
|
||||||
soundio_panic("out of memory");
|
soundio_panic("out of memory");
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(ah->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
pa_operation *list_sink_op = pa_context_get_sink_info_list(ah->pulse_context,
|
pa_operation *list_sink_op = pa_context_get_sink_info_list(sipa->pulse_context,
|
||||||
sink_info_callback, soundio);
|
sink_info_callback, soundio);
|
||||||
pa_operation *list_source_op = pa_context_get_source_info_list(ah->pulse_context,
|
pa_operation *list_source_op = pa_context_get_source_info_list(sipa->pulse_context,
|
||||||
source_info_callback, soundio);
|
source_info_callback, soundio);
|
||||||
pa_operation *server_info_op = pa_context_get_server_info(ah->pulse_context,
|
pa_operation *server_info_op = pa_context_get_server_info(sipa->pulse_context,
|
||||||
server_info_callback, soundio);
|
server_info_callback, soundio);
|
||||||
|
|
||||||
if (perform_operation(soundio, list_sink_op))
|
if (perform_operation(soundio, list_sink_op))
|
||||||
|
@ -372,32 +372,56 @@ static void scan_devices(SoundIo *soundio) {
|
||||||
if (perform_operation(soundio, server_info_op))
|
if (perform_operation(soundio, server_info_op))
|
||||||
soundio_panic("get server info failed");
|
soundio_panic("get server info failed");
|
||||||
|
|
||||||
pa_threaded_mainloop_signal(ah->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void block_until_have_devices(SoundIo *soundio) {
|
||||||
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
|
if (sipa->have_devices_flag)
|
||||||
|
return;
|
||||||
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
while (!sipa->have_devices_flag) {
|
||||||
|
pa_threaded_mainloop_wait(sipa->main_loop);
|
||||||
|
}
|
||||||
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void block_until_ready(SoundIo *soundio) {
|
||||||
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
|
if (sipa->ready_flag)
|
||||||
|
return;
|
||||||
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
while (!sipa->ready_flag) {
|
||||||
|
pa_threaded_mainloop_wait(sipa->main_loop);
|
||||||
|
}
|
||||||
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flush_events(SoundIo *soundio) {
|
static void flush_events(SoundIo *soundio) {
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
block_until_ready(soundio);
|
||||||
|
|
||||||
if (ah->device_scan_queued) {
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
ah->device_scan_queued = false;
|
|
||||||
|
if (sipa->device_scan_queued) {
|
||||||
|
sipa->device_scan_queued = false;
|
||||||
scan_devices(soundio);
|
scan_devices(soundio);
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundIoDevicesInfo *old_devices_info = nullptr;
|
SoundIoDevicesInfo *old_devices_info = nullptr;
|
||||||
bool change = false;
|
bool change = false;
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(ah->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
if (ah->ready_devices_info) {
|
if (sipa->ready_devices_info) {
|
||||||
old_devices_info = soundio->safe_devices_info;
|
old_devices_info = soundio->safe_devices_info;
|
||||||
soundio->safe_devices_info = ah->ready_devices_info;
|
soundio->safe_devices_info = sipa->ready_devices_info;
|
||||||
ah->ready_devices_info = nullptr;
|
sipa->ready_devices_info = nullptr;
|
||||||
change = true;
|
change = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
|
|
||||||
if (change)
|
if (change)
|
||||||
soundio->on_devices_change(soundio);
|
soundio->on_devices_change(soundio);
|
||||||
|
@ -409,28 +433,19 @@ static void flush_events(SoundIo *soundio) {
|
||||||
soundio_device_unref(old_devices_info->output_devices.at(i));
|
soundio_device_unref(old_devices_info->output_devices.at(i));
|
||||||
destroy(old_devices_info);
|
destroy(old_devices_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
block_until_have_devices(soundio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void block_until_ready(SoundIo *soundio) {
|
static void wait_events(SoundIo *soundio) {
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
if (ah->ready_flag)
|
flush_events(soundio);
|
||||||
return;
|
pa_threaded_mainloop_wait(sipa->main_loop);
|
||||||
pa_threaded_mainloop_lock(ah->main_loop);
|
|
||||||
while (!ah->ready_flag) {
|
|
||||||
pa_threaded_mainloop_wait(ah->main_loop);
|
|
||||||
}
|
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void block_until_have_devices(SoundIo *soundio) {
|
static void wakeup(SoundIo *soundio) {
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
if (ah->have_devices_flag)
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
return;
|
|
||||||
pa_threaded_mainloop_lock(ah->main_loop);
|
|
||||||
while (!ah->have_devices_flag) {
|
|
||||||
pa_threaded_mainloop_wait(ah->main_loop);
|
|
||||||
}
|
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static pa_sample_format_t to_pulseaudio_sample_format(SoundIoSampleFormat sample_format) {
|
static pa_sample_format_t to_pulseaudio_sample_format(SoundIoSampleFormat sample_format) {
|
||||||
|
@ -514,7 +529,7 @@ static pa_channel_map to_pulseaudio_channel_map(const SoundIoChannelLayout *chan
|
||||||
static void playback_stream_state_callback(pa_stream *stream, void *userdata) {
|
static void playback_stream_state_callback(pa_stream *stream, void *userdata) {
|
||||||
SoundIoOutputDevice *output_device = (SoundIoOutputDevice*) userdata;
|
SoundIoOutputDevice *output_device = (SoundIoOutputDevice*) userdata;
|
||||||
SoundIo *soundio = output_device->device->soundio;
|
SoundIo *soundio = output_device->device->soundio;
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
SoundIoOutputDevicePulseAudio *opd = (SoundIoOutputDevicePulseAudio *)output_device->backend_data;
|
SoundIoOutputDevicePulseAudio *opd = (SoundIoOutputDevicePulseAudio *)output_device->backend_data;
|
||||||
switch (pa_stream_get_state(stream)) {
|
switch (pa_stream_get_state(stream)) {
|
||||||
case PA_STREAM_UNCONNECTED:
|
case PA_STREAM_UNCONNECTED:
|
||||||
|
@ -523,7 +538,7 @@ static void playback_stream_state_callback(pa_stream *stream, void *userdata) {
|
||||||
break;
|
break;
|
||||||
case PA_STREAM_READY:
|
case PA_STREAM_READY:
|
||||||
opd->stream_ready = true;
|
opd->stream_ready = true;
|
||||||
pa_threaded_mainloop_signal(ah->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
break;
|
break;
|
||||||
case PA_STREAM_FAILED:
|
case PA_STREAM_FAILED:
|
||||||
soundio_panic("pulseaudio stream error: %s", pa_strerror(pa_context_errno(pa_stream_get_context(stream))));
|
soundio_panic("pulseaudio stream error: %s", pa_strerror(pa_context_errno(pa_stream_get_context(stream))));
|
||||||
|
@ -550,10 +565,10 @@ static void output_device_destroy_pa(SoundIo *soundio,
|
||||||
if (!opd)
|
if (!opd)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
pa_stream *stream = opd->stream;
|
pa_stream *stream = opd->stream;
|
||||||
if (stream) {
|
if (stream) {
|
||||||
pa_threaded_mainloop_lock(ah->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
pa_stream_set_write_callback(stream, nullptr, nullptr);
|
pa_stream_set_write_callback(stream, nullptr, nullptr);
|
||||||
pa_stream_set_state_callback(stream, nullptr, nullptr);
|
pa_stream_set_state_callback(stream, nullptr, nullptr);
|
||||||
|
@ -562,7 +577,7 @@ static void output_device_destroy_pa(SoundIo *soundio,
|
||||||
|
|
||||||
pa_stream_unref(stream);
|
pa_stream_unref(stream);
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
|
|
||||||
opd->stream = nullptr;
|
opd->stream = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -581,13 +596,13 @@ static int output_device_init_pa(SoundIo *soundio,
|
||||||
}
|
}
|
||||||
output_device->backend_data = opd;
|
output_device->backend_data = opd;
|
||||||
|
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
SoundIoDevice *device = output_device->device;
|
SoundIoDevice *device = output_device->device;
|
||||||
opd->stream_ready = false;
|
opd->stream_ready = false;
|
||||||
|
|
||||||
assert(ah->pulse_context);
|
assert(sipa->pulse_context);
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(ah->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
pa_sample_spec sample_spec;
|
pa_sample_spec sample_spec;
|
||||||
sample_spec.format = to_pulseaudio_sample_format(output_device->sample_format);
|
sample_spec.format = to_pulseaudio_sample_format(output_device->sample_format);
|
||||||
|
@ -595,9 +610,9 @@ static int output_device_init_pa(SoundIo *soundio,
|
||||||
sample_spec.channels = device->channel_layout.channel_count;
|
sample_spec.channels = device->channel_layout.channel_count;
|
||||||
pa_channel_map channel_map = to_pulseaudio_channel_map(&device->channel_layout);
|
pa_channel_map channel_map = to_pulseaudio_channel_map(&device->channel_layout);
|
||||||
|
|
||||||
opd->stream = pa_stream_new(ah->pulse_context, "SoundIo", &sample_spec, &channel_map);
|
opd->stream = pa_stream_new(sipa->pulse_context, "SoundIo", &sample_spec, &channel_map);
|
||||||
if (!opd->stream) {
|
if (!opd->stream) {
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
output_device_destroy_pa(soundio, output_device);
|
output_device_destroy_pa(soundio, output_device);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
@ -615,7 +630,7 @@ static int output_device_init_pa(SoundIo *soundio,
|
||||||
opd->buffer_attr.minreq = UINT32_MAX;
|
opd->buffer_attr.minreq = UINT32_MAX;
|
||||||
opd->buffer_attr.fragsize = UINT32_MAX;
|
opd->buffer_attr.fragsize = UINT32_MAX;
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -623,26 +638,26 @@ static int output_device_init_pa(SoundIo *soundio,
|
||||||
static int output_device_start_pa(SoundIo *soundio,
|
static int output_device_start_pa(SoundIo *soundio,
|
||||||
SoundIoOutputDevice *output_device)
|
SoundIoOutputDevice *output_device)
|
||||||
{
|
{
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
SoundIoOutputDevicePulseAudio *opd = (SoundIoOutputDevicePulseAudio *)output_device->backend_data;
|
SoundIoOutputDevicePulseAudio *opd = (SoundIoOutputDevicePulseAudio *)output_device->backend_data;
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(ah->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
|
|
||||||
int err = pa_stream_connect_playback(opd->stream,
|
int err = pa_stream_connect_playback(opd->stream,
|
||||||
output_device->device->name, &opd->buffer_attr,
|
output_device->device->name, &opd->buffer_attr,
|
||||||
PA_STREAM_ADJUST_LATENCY, nullptr, nullptr);
|
PA_STREAM_ADJUST_LATENCY, nullptr, nullptr);
|
||||||
if (err) {
|
if (err) {
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!opd->stream_ready)
|
while (!opd->stream_ready)
|
||||||
pa_threaded_mainloop_wait(ah->main_loop);
|
pa_threaded_mainloop_wait(sipa->main_loop);
|
||||||
|
|
||||||
soundio_output_device_fill_with_silence(output_device);
|
soundio_output_device_fill_with_silence(output_device);
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -659,11 +674,11 @@ static void output_device_begin_write_pa(SoundIo *soundio,
|
||||||
SoundIoOutputDevice *output_device, char **data, int *frame_count)
|
SoundIoOutputDevice *output_device, char **data, int *frame_count)
|
||||||
{
|
{
|
||||||
SoundIoOutputDevicePulseAudio *opd = (SoundIoOutputDevicePulseAudio *)output_device->backend_data;
|
SoundIoOutputDevicePulseAudio *opd = (SoundIoOutputDevicePulseAudio *)output_device->backend_data;
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
pa_stream *stream = opd->stream;
|
pa_stream *stream = opd->stream;
|
||||||
size_t byte_count = *frame_count * output_device->bytes_per_frame;
|
size_t byte_count = *frame_count * output_device->bytes_per_frame;
|
||||||
if (pa_stream_begin_write(stream, (void**)data, &byte_count))
|
if (pa_stream_begin_write(stream, (void**)data, &byte_count))
|
||||||
soundio_panic("pa_stream_begin_write error: %s", pa_strerror(pa_context_errno(ah->pulse_context)));
|
soundio_panic("pa_stream_begin_write error: %s", pa_strerror(pa_context_errno(sipa->pulse_context)));
|
||||||
|
|
||||||
*frame_count = byte_count / output_device->bytes_per_frame;
|
*frame_count = byte_count / output_device->bytes_per_frame;
|
||||||
}
|
}
|
||||||
|
@ -672,25 +687,25 @@ static void output_device_write_pa(SoundIo *soundio,
|
||||||
SoundIoOutputDevice *output_device, char *data, int frame_count)
|
SoundIoOutputDevice *output_device, char *data, int frame_count)
|
||||||
{
|
{
|
||||||
SoundIoOutputDevicePulseAudio *opd = (SoundIoOutputDevicePulseAudio *)output_device->backend_data;
|
SoundIoOutputDevicePulseAudio *opd = (SoundIoOutputDevicePulseAudio *)output_device->backend_data;
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
pa_stream *stream = opd->stream;
|
pa_stream *stream = opd->stream;
|
||||||
size_t byte_count = frame_count * output_device->bytes_per_frame;
|
size_t byte_count = frame_count * output_device->bytes_per_frame;
|
||||||
if (pa_stream_write(stream, data, byte_count, NULL, 0, PA_SEEK_RELATIVE))
|
if (pa_stream_write(stream, data, byte_count, NULL, 0, PA_SEEK_RELATIVE))
|
||||||
soundio_panic("pa_stream_write error: %s", pa_strerror(pa_context_errno(ah->pulse_context)));
|
soundio_panic("pa_stream_write error: %s", pa_strerror(pa_context_errno(sipa->pulse_context)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_device_clear_buffer_pa(SoundIo *soundio,
|
static void output_device_clear_buffer_pa(SoundIo *soundio,
|
||||||
SoundIoOutputDevice *output_device)
|
SoundIoOutputDevice *output_device)
|
||||||
{
|
{
|
||||||
SoundIoOutputDevicePulseAudio *opd = (SoundIoOutputDevicePulseAudio *)output_device->backend_data;
|
SoundIoOutputDevicePulseAudio *opd = (SoundIoOutputDevicePulseAudio *)output_device->backend_data;
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
pa_stream *stream = opd->stream;
|
pa_stream *stream = opd->stream;
|
||||||
pa_threaded_mainloop_lock(ah->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
pa_operation *op = pa_stream_flush(stream, NULL, NULL);
|
pa_operation *op = pa_stream_flush(stream, NULL, NULL);
|
||||||
if (!op)
|
if (!op)
|
||||||
soundio_panic("pa_stream_flush failed: %s", pa_strerror(pa_context_errno(ah->pulse_context)));
|
soundio_panic("pa_stream_flush failed: %s", pa_strerror(pa_context_errno(sipa->pulse_context)));
|
||||||
pa_operation_unref(op);
|
pa_operation_unref(op);
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recording_stream_state_callback(pa_stream *stream, void *userdata) {
|
static void recording_stream_state_callback(pa_stream *stream, void *userdata) {
|
||||||
|
@ -719,11 +734,11 @@ static int input_device_init_pa(SoundIo *soundio,
|
||||||
SoundIoInputDevice *input_device)
|
SoundIoInputDevice *input_device)
|
||||||
{
|
{
|
||||||
SoundIoInputDevicePulseAudio *ord = (SoundIoInputDevicePulseAudio *)input_device->backend_data;
|
SoundIoInputDevicePulseAudio *ord = (SoundIoInputDevicePulseAudio *)input_device->backend_data;
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
SoundIoDevice *device = input_device->device;
|
SoundIoDevice *device = input_device->device;
|
||||||
ord->stream_ready = false;
|
ord->stream_ready = false;
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(ah->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
pa_sample_spec sample_spec;
|
pa_sample_spec sample_spec;
|
||||||
sample_spec.format = to_pulseaudio_sample_format(input_device->sample_format);
|
sample_spec.format = to_pulseaudio_sample_format(input_device->sample_format);
|
||||||
|
@ -732,9 +747,9 @@ static int input_device_init_pa(SoundIo *soundio,
|
||||||
|
|
||||||
pa_channel_map channel_map = to_pulseaudio_channel_map(&device->channel_layout);
|
pa_channel_map channel_map = to_pulseaudio_channel_map(&device->channel_layout);
|
||||||
|
|
||||||
ord->stream = pa_stream_new(ah->pulse_context, "SoundIo", &sample_spec, &channel_map);
|
ord->stream = pa_stream_new(sipa->pulse_context, "SoundIo", &sample_spec, &channel_map);
|
||||||
if (!input_device) {
|
if (!input_device) {
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,7 +768,7 @@ static int input_device_init_pa(SoundIo *soundio,
|
||||||
ord->buffer_attr.minreq = UINT32_MAX;
|
ord->buffer_attr.minreq = UINT32_MAX;
|
||||||
ord->buffer_attr.fragsize = buffer_length;
|
ord->buffer_attr.fragsize = buffer_length;
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -762,17 +777,17 @@ static void input_device_destroy_pa(SoundIo *soundio,
|
||||||
SoundIoInputDevice *input_device)
|
SoundIoInputDevice *input_device)
|
||||||
{
|
{
|
||||||
SoundIoInputDevicePulseAudio *ord = (SoundIoInputDevicePulseAudio *)input_device->backend_data;
|
SoundIoInputDevicePulseAudio *ord = (SoundIoInputDevicePulseAudio *)input_device->backend_data;
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
pa_stream *stream = ord->stream;
|
pa_stream *stream = ord->stream;
|
||||||
if (stream) {
|
if (stream) {
|
||||||
pa_threaded_mainloop_lock(ah->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
pa_stream_set_state_callback(stream, nullptr, nullptr);
|
pa_stream_set_state_callback(stream, nullptr, nullptr);
|
||||||
pa_stream_set_read_callback(stream, nullptr, nullptr);
|
pa_stream_set_read_callback(stream, nullptr, nullptr);
|
||||||
pa_stream_disconnect(stream);
|
pa_stream_disconnect(stream);
|
||||||
pa_stream_unref(stream);
|
pa_stream_unref(stream);
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
|
|
||||||
ord->stream = nullptr;
|
ord->stream = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -782,18 +797,18 @@ static int input_device_start_pa(SoundIo *soundio,
|
||||||
SoundIoInputDevice *input_device)
|
SoundIoInputDevice *input_device)
|
||||||
{
|
{
|
||||||
SoundIoInputDevicePulseAudio *ord = (SoundIoInputDevicePulseAudio *)input_device->backend_data;
|
SoundIoInputDevicePulseAudio *ord = (SoundIoInputDevicePulseAudio *)input_device->backend_data;
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
pa_threaded_mainloop_lock(ah->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
int err = pa_stream_connect_record(ord->stream,
|
int err = pa_stream_connect_record(ord->stream,
|
||||||
input_device->device->name,
|
input_device->device->name,
|
||||||
&ord->buffer_attr, PA_STREAM_ADJUST_LATENCY);
|
&ord->buffer_attr, PA_STREAM_ADJUST_LATENCY);
|
||||||
if (err) {
|
if (err) {
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
return SoundIoErrorOpeningDevice;
|
return SoundIoErrorOpeningDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -830,9 +845,9 @@ static void input_device_clear_buffer_pa(SoundIo *soundio,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pa_stream *stream = ord->stream;
|
pa_stream *stream = ord->stream;
|
||||||
SoundIoPulseAudio *ah = (SoundIoPulseAudio *)soundio->backend_data;
|
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)soundio->backend_data;
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(ah->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const char *data;
|
const char *data;
|
||||||
|
@ -847,7 +862,7 @@ static void input_device_clear_buffer_pa(SoundIo *soundio,
|
||||||
soundio_panic("pa_stream_drop error: %s", pa_strerror(pa_context_errno(pa_stream_get_context(stream))));
|
soundio_panic("pa_stream_drop error: %s", pa_strerror(pa_context_errno(pa_stream_get_context(stream))));
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock(ah->main_loop);
|
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void refresh_devices(SoundIo *soundio) {
|
static void refresh_devices(SoundIo *soundio) {
|
||||||
|
@ -858,58 +873,58 @@ static void refresh_devices(SoundIo *soundio) {
|
||||||
|
|
||||||
int soundio_pulseaudio_init(SoundIo *soundio) {
|
int soundio_pulseaudio_init(SoundIo *soundio) {
|
||||||
assert(!soundio->backend_data);
|
assert(!soundio->backend_data);
|
||||||
SoundIoPulseAudio *ah = create<SoundIoPulseAudio>();
|
SoundIoPulseAudio *sipa = create<SoundIoPulseAudio>();
|
||||||
if (!ah) {
|
if (!sipa) {
|
||||||
destroy_pa(soundio);
|
destroy_pa(soundio);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
soundio->backend_data = ah;
|
soundio->backend_data = sipa;
|
||||||
|
|
||||||
ah->connection_refused = false;
|
sipa->connection_refused = false;
|
||||||
ah->device_scan_queued = false;
|
sipa->device_scan_queued = false;
|
||||||
ah->ready_flag = false;
|
sipa->ready_flag = false;
|
||||||
ah->have_devices_flag = false;
|
sipa->have_devices_flag = false;
|
||||||
|
|
||||||
ah->main_loop = pa_threaded_mainloop_new();
|
sipa->main_loop = pa_threaded_mainloop_new();
|
||||||
if (!ah->main_loop) {
|
if (!sipa->main_loop) {
|
||||||
destroy_pa(soundio);
|
destroy_pa(soundio);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_mainloop_api *main_loop_api = pa_threaded_mainloop_get_api(ah->main_loop);
|
pa_mainloop_api *main_loop_api = pa_threaded_mainloop_get_api(sipa->main_loop);
|
||||||
|
|
||||||
ah->props = pa_proplist_new();
|
sipa->props = pa_proplist_new();
|
||||||
if (!ah->props) {
|
if (!sipa->props) {
|
||||||
destroy_pa(soundio);
|
destroy_pa(soundio);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO let the API specify this
|
// TODO let the API specify this
|
||||||
pa_proplist_sets(ah->props, PA_PROP_APPLICATION_NAME, "libsoundio");
|
pa_proplist_sets(sipa->props, PA_PROP_APPLICATION_NAME, "libsoundio");
|
||||||
pa_proplist_sets(ah->props, PA_PROP_APPLICATION_VERSION, SOUNDIO_VERSION_STRING);
|
pa_proplist_sets(sipa->props, PA_PROP_APPLICATION_VERSION, SOUNDIO_VERSION_STRING);
|
||||||
pa_proplist_sets(ah->props, PA_PROP_APPLICATION_ID, "me.andrewkelley.libsoundio");
|
pa_proplist_sets(sipa->props, PA_PROP_APPLICATION_ID, "me.andrewkelley.libsoundio");
|
||||||
|
|
||||||
ah->pulse_context = pa_context_new_with_proplist(main_loop_api, "SoundIo", ah->props);
|
sipa->pulse_context = pa_context_new_with_proplist(main_loop_api, "SoundIo", sipa->props);
|
||||||
if (!ah->pulse_context) {
|
if (!sipa->pulse_context) {
|
||||||
destroy_pa(soundio);
|
destroy_pa(soundio);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_context_set_subscribe_callback(ah->pulse_context, subscribe_callback, soundio);
|
pa_context_set_subscribe_callback(sipa->pulse_context, subscribe_callback, soundio);
|
||||||
pa_context_set_state_callback(ah->pulse_context, context_state_callback, soundio);
|
pa_context_set_state_callback(sipa->pulse_context, context_state_callback, soundio);
|
||||||
|
|
||||||
int err = pa_context_connect(ah->pulse_context, NULL, (pa_context_flags_t)0, NULL);
|
int err = pa_context_connect(sipa->pulse_context, NULL, (pa_context_flags_t)0, NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
destroy_pa(soundio);
|
destroy_pa(soundio);
|
||||||
return SoundIoErrorInitAudioBackend;
|
return SoundIoErrorInitAudioBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ah->connection_refused) {
|
if (sipa->connection_refused) {
|
||||||
destroy_pa(soundio);
|
destroy_pa(soundio);
|
||||||
return SoundIoErrorInitAudioBackend;
|
return SoundIoErrorInitAudioBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pa_threaded_mainloop_start(ah->main_loop)) {
|
if (pa_threaded_mainloop_start(sipa->main_loop)) {
|
||||||
destroy_pa(soundio);
|
destroy_pa(soundio);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
@ -917,6 +932,8 @@ int soundio_pulseaudio_init(SoundIo *soundio) {
|
||||||
soundio->destroy = destroy_pa;
|
soundio->destroy = destroy_pa;
|
||||||
soundio->flush_events = flush_events;
|
soundio->flush_events = flush_events;
|
||||||
soundio->refresh_devices = refresh_devices;
|
soundio->refresh_devices = refresh_devices;
|
||||||
|
soundio->wait_events = wait_events;
|
||||||
|
soundio->wakeup = wakeup;
|
||||||
|
|
||||||
soundio->output_device_init = output_device_init_pa;
|
soundio->output_device_init = output_device_init_pa;
|
||||||
soundio->output_device_destroy = output_device_destroy_pa;
|
soundio->output_device_destroy = output_device_destroy_pa;
|
||||||
|
@ -935,5 +952,3 @@ int soundio_pulseaudio_init(SoundIo *soundio) {
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,7 @@ void soundio_destroy(struct SoundIo *soundio) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void default_on_devices_change(struct SoundIo *) { }
|
static void default_on_devices_change(struct SoundIo *) { }
|
||||||
|
static void default_on_events_signal(struct SoundIo *) { }
|
||||||
|
|
||||||
struct SoundIo * soundio_create(void) {
|
struct SoundIo * soundio_create(void) {
|
||||||
soundio_os_init();
|
soundio_os_init();
|
||||||
|
@ -85,6 +86,7 @@ struct SoundIo * soundio_create(void) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
soundio->on_devices_change = default_on_devices_change;
|
soundio->on_devices_change = default_on_devices_change;
|
||||||
|
soundio->on_events_signal = default_on_events_signal;
|
||||||
return soundio;
|
return soundio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +96,8 @@ int soundio_connect(struct SoundIo *soundio) {
|
||||||
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||||
soundio->current_backend = SoundIoBackendPulseAudio;
|
soundio->current_backend = SoundIoBackendPulseAudio;
|
||||||
err = soundio_pulseaudio_init(soundio);
|
err = soundio_pulseaudio_init(soundio);
|
||||||
|
if (!err)
|
||||||
|
return 0;
|
||||||
if (err != SoundIoErrorInitAudioBackend) {
|
if (err != SoundIoErrorInitAudioBackend) {
|
||||||
soundio_disconnect(soundio);
|
soundio_disconnect(soundio);
|
||||||
return err;
|
return err;
|
||||||
|
@ -149,26 +153,31 @@ void soundio_disconnect(struct SoundIo *soundio) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void soundio_flush_events(struct SoundIo *soundio) {
|
void soundio_flush_events(struct SoundIo *soundio) {
|
||||||
|
assert(soundio->flush_events);
|
||||||
if (soundio->flush_events)
|
if (soundio->flush_events)
|
||||||
soundio->flush_events(soundio);
|
soundio->flush_events(soundio);
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_get_input_device_count(struct SoundIo *soundio) {
|
int soundio_get_input_device_count(struct SoundIo *soundio) {
|
||||||
|
soundio_flush_events(soundio);
|
||||||
assert(soundio->safe_devices_info);
|
assert(soundio->safe_devices_info);
|
||||||
return soundio->safe_devices_info->input_devices.length;
|
return soundio->safe_devices_info->input_devices.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_get_output_device_count(struct SoundIo *soundio) {
|
int soundio_get_output_device_count(struct SoundIo *soundio) {
|
||||||
|
soundio_flush_events(soundio);
|
||||||
assert(soundio->safe_devices_info);
|
assert(soundio->safe_devices_info);
|
||||||
return soundio->safe_devices_info->output_devices.length;
|
return soundio->safe_devices_info->output_devices.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_get_default_input_device_index(struct SoundIo *soundio) {
|
int soundio_get_default_input_device_index(struct SoundIo *soundio) {
|
||||||
|
soundio_flush_events(soundio);
|
||||||
assert(soundio->safe_devices_info);
|
assert(soundio->safe_devices_info);
|
||||||
return soundio->safe_devices_info->default_input_index;
|
return soundio->safe_devices_info->default_input_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_get_default_output_device_index(struct SoundIo *soundio) {
|
int soundio_get_default_output_device_index(struct SoundIo *soundio) {
|
||||||
|
soundio_flush_events(soundio);
|
||||||
assert(soundio->safe_devices_info);
|
assert(soundio->safe_devices_info);
|
||||||
return soundio->safe_devices_info->default_output_index;
|
return soundio->safe_devices_info->default_output_index;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue