ALSA backend determines what formats a device supports

This commit is contained in:
Andrew Kelley 2015-07-10 02:21:47 -07:00
parent 8887a528ef
commit 3b8d896c8e
9 changed files with 361 additions and 182 deletions

View file

@ -43,10 +43,15 @@ static void print_device(struct SoundIoDevice *device, bool is_default) {
} }
raw_str = device->is_raw ? "(raw) " : ""; raw_str = device->is_raw ? "(raw) " : "";
const char *description = soundio_device_description(device); const char *description = soundio_device_description(device);
int sample_rate = soundio_device_sample_rate(device); int sample_rate = device->sample_rate_max;
fprintf(stderr, "%s%s device: ", raw_str, purpose_str); fprintf(stderr, "%s%s device: ", raw_str, purpose_str);
print_channel_layout(soundio_device_channel_layout(device)); if (device->probe_error) {
fprintf(stderr, " %d Hz %s%s\n", sample_rate, description, default_str); fprintf(stderr, "[%s] %s%s\n", soundio_strerror(device->probe_error),
description, default_str);
} else {
print_channel_layout(soundio_device_channel_layout(device));
fprintf(stderr, " %d Hz %s%s\n", sample_rate, description, default_str);
}
} }
static int list_devices(struct SoundIo *soundio) { static int list_devices(struct SoundIo *soundio) {
@ -97,7 +102,7 @@ int main(int argc, char **argv) {
int err; int err;
if ((err = soundio_connect(soundio))) { if ((err = soundio_connect(soundio))) {
fprintf(stderr, "%s\n", soundio_error_string(err)); fprintf(stderr, "%s\n", soundio_strerror(err));
return err; return err;
} }

View file

@ -46,7 +46,7 @@ int main(int argc, char **argv) {
int err; int err;
if ((err = soundio_connect(soundio))) if ((err = soundio_connect(soundio)))
panic("error connecting: %s", soundio_error_string(err)); panic("error connecting: %s", soundio_strerror(err));
int default_out_device_index = soundio_get_default_output_device_index(soundio); int default_out_device_index = soundio_get_default_output_device_index(soundio);
if (default_out_device_index < 0) if (default_out_device_index < 0)
@ -73,24 +73,21 @@ int main(int argc, char **argv) {
if (!soundio_channel_layout_equal(in_layout, out_layout)) if (!soundio_channel_layout_equal(in_layout, out_layout))
panic("channel layouts not compatible"); panic("channel layouts not compatible");
if (soundio_device_sample_rate(in_device) != soundio_device_sample_rate(out_device))
panic("sample rates not compatible");
double latency = 0.1; double latency = 0.1;
struct SoundIoInputDevice *input_device; struct SoundIoInputDevice *input_device;
soundio_input_device_create(in_device, SoundIoSampleFormatFloat32NE, 48000, latency, NULL, soundio_input_device_create(in_device, SoundIoFormatFloat32NE, 48000, latency, NULL,
read_callback, &input_device); read_callback, &input_device);
struct SoundIoOutputDevice *output_device; struct SoundIoOutputDevice *output_device;
soundio_output_device_create(out_device, SoundIoSampleFormatFloat32NE, 48000, latency, NULL, soundio_output_device_create(out_device, SoundIoFormatFloat32NE, 48000, latency, NULL,
write_callback, underrun_callback, &output_device); write_callback, underrun_callback, &output_device);
if ((err = soundio_input_device_start(input_device))) if ((err = soundio_input_device_start(input_device)))
panic("unable to start input device: %s", soundio_error_string(err)); panic("unable to start input device: %s", soundio_strerror(err));
if ((err = soundio_output_device_start(output_device))) if ((err = soundio_output_device_start(output_device)))
panic("unable to start output device: %s", soundio_error_string(err)); panic("unable to start output device: %s", soundio_strerror(err));
for (;;) for (;;)
soundio_wait_events(soundio); soundio_wait_events(soundio);

View file

@ -75,7 +75,7 @@ int main(int argc, char **argv) {
int err; int err;
if ((err = soundio_connect(soundio))) if ((err = soundio_connect(soundio)))
panic("error connecting: %s", soundio_error_string(err)); panic("error connecting: %s", soundio_strerror(err));
int default_out_device_index = soundio_get_default_output_device_index(soundio); int default_out_device_index = soundio_get_default_output_device_index(soundio);
if (default_out_device_index < 0) if (default_out_device_index < 0)
@ -90,11 +90,11 @@ int main(int argc, char **argv) {
soundio_device_description(device)); soundio_device_description(device));
struct SoundIoOutputDevice *output_device; struct SoundIoOutputDevice *output_device;
soundio_output_device_create(device, SoundIoSampleFormatFloat32NE, 48000, soundio_output_device_create(device, SoundIoFormatFloat32NE, 48000,
0.1, NULL, write_callback, underrun_callback, &output_device); 0.1, NULL, write_callback, underrun_callback, &output_device);
if ((err = soundio_output_device_start(output_device))) if ((err = soundio_output_device_start(output_device)))
panic("unable to start device: %s", soundio_error_string(err)); panic("unable to start device: %s", soundio_strerror(err));
for (;;) for (;;)
soundio_wait_events(soundio); soundio_wait_events(soundio);

View file

@ -15,8 +15,6 @@
static snd_pcm_stream_t stream_types[] = {SND_PCM_STREAM_PLAYBACK, SND_PCM_STREAM_CAPTURE}; static snd_pcm_stream_t stream_types[] = {SND_PCM_STREAM_PLAYBACK, SND_PCM_STREAM_CAPTURE};
static const int MAX_SAMPLE_RATE = 48000;
struct SoundIoAlsa { struct SoundIoAlsa {
SoundIoOsMutex *mutex; SoundIoOsMutex *mutex;
SoundIoOsCond *cond; SoundIoOsCond *cond;
@ -158,6 +156,40 @@ static void handle_channel_maps(SoundIoDevice *device, snd_pcm_chmap_query_t **m
snd_pcm_free_chmaps(maps); snd_pcm_free_chmaps(maps);
} }
static snd_pcm_format_t to_alsa_fmt(SoundIoFormat fmt) {
switch (fmt) {
case SoundIoFormatS8: return SND_PCM_FORMAT_S8;
case SoundIoFormatU8: return SND_PCM_FORMAT_U8;
case SoundIoFormatS16LE: return SND_PCM_FORMAT_S16_LE;
case SoundIoFormatS16BE: return SND_PCM_FORMAT_S16_BE;
case SoundIoFormatU16LE: return SND_PCM_FORMAT_U16_LE;
case SoundIoFormatU16BE: return SND_PCM_FORMAT_U16_BE;
case SoundIoFormatS24LE: return SND_PCM_FORMAT_S24_LE;
case SoundIoFormatS24BE: return SND_PCM_FORMAT_S24_BE;
case SoundIoFormatU24LE: return SND_PCM_FORMAT_U24_LE;
case SoundIoFormatU24BE: return SND_PCM_FORMAT_U24_BE;
case SoundIoFormatS32LE: return SND_PCM_FORMAT_S32_LE;
case SoundIoFormatS32BE: return SND_PCM_FORMAT_S32_BE;
case SoundIoFormatU32LE: return SND_PCM_FORMAT_U32_LE;
case SoundIoFormatU32BE: return SND_PCM_FORMAT_U32_BE;
case SoundIoFormatFloat32LE: return SND_PCM_FORMAT_FLOAT_LE;
case SoundIoFormatFloat32BE: return SND_PCM_FORMAT_FLOAT_BE;
case SoundIoFormatFloat64LE: return SND_PCM_FORMAT_FLOAT64_LE;
case SoundIoFormatFloat64BE: return SND_PCM_FORMAT_FLOAT64_BE;
case SoundIoFormatInvalid:
return SND_PCM_FORMAT_UNKNOWN;
}
return SND_PCM_FORMAT_UNKNOWN;
}
static void test_fmt_mask(SoundIoDevice *device, const snd_pcm_format_mask_t *fmt_mask, SoundIoFormat fmt) {
if (snd_pcm_format_mask_test(fmt_mask, to_alsa_fmt(fmt))) {
device->formats[device->format_count] = fmt;
device->format_count += 1;
}
}
static int probe_device(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) { static int probe_device(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
int err; int err;
snd_pcm_t *handle; snd_pcm_t *handle;
@ -176,23 +208,27 @@ static int probe_device(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
} }
if ((err = snd_pcm_hw_params_any(handle, hwparams)) < 0) { if ((err = snd_pcm_hw_params_any(handle, hwparams)) < 0) {
handle_channel_maps(device, maps);
snd_pcm_close(handle); snd_pcm_close(handle);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
// disable hardware resampling because we're trying to probe // disable hardware resampling because we're trying to probe
if ((err = snd_pcm_hw_params_set_rate_resample(handle, hwparams, 0)) < 0) { if ((err = snd_pcm_hw_params_set_rate_resample(handle, hwparams, 0)) < 0) {
handle_channel_maps(device, maps);
snd_pcm_close(handle); snd_pcm_close(handle);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
if ((err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { if ((err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
handle_channel_maps(device, maps);
snd_pcm_close(handle); snd_pcm_close(handle);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
unsigned int channel_count; unsigned int channel_count;
if ((err = snd_pcm_hw_params_set_channels_last(handle, hwparams, &channel_count)) < 0) { if ((err = snd_pcm_hw_params_set_channels_last(handle, hwparams, &channel_count)) < 0) {
handle_channel_maps(device, maps);
snd_pcm_close(handle); snd_pcm_close(handle);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
@ -203,6 +239,7 @@ static int probe_device(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
int max_dir; int max_dir;
if ((err = snd_pcm_hw_params_get_rate_max(hwparams, &max_sample_rate, &max_dir)) < 0) { if ((err = snd_pcm_hw_params_get_rate_max(hwparams, &max_sample_rate, &max_dir)) < 0) {
handle_channel_maps(device, maps);
snd_pcm_close(handle); snd_pcm_close(handle);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
@ -210,12 +247,68 @@ static int probe_device(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
max_sample_rate -= 1; max_sample_rate -= 1;
if ((err = snd_pcm_hw_params_get_rate_min(hwparams, &min_sample_rate, &min_dir)) < 0) { if ((err = snd_pcm_hw_params_get_rate_min(hwparams, &min_sample_rate, &min_dir)) < 0) {
handle_channel_maps(device, maps);
snd_pcm_close(handle); snd_pcm_close(handle);
return SoundIoErrorOpeningDevice; return SoundIoErrorOpeningDevice;
} }
if (min_dir > 0) if (min_dir > 0)
min_sample_rate += 1; min_sample_rate += 1;
snd_pcm_format_mask_t *fmt_mask;
snd_pcm_format_mask_alloca(&fmt_mask);
snd_pcm_format_mask_none(fmt_mask);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_S8);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_U8);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_S16_LE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_S16_BE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_U16_LE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_U16_BE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_S24_LE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_S24_BE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_U24_LE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_U24_BE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_S32_LE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_S32_BE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_U32_LE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_U32_BE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_FLOAT_LE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_FLOAT_BE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_FLOAT64_LE);
snd_pcm_format_mask_set(fmt_mask, SND_PCM_FORMAT_FLOAT64_BE);
if ((err = snd_pcm_hw_params_set_format_mask(handle, hwparams, fmt_mask)) < 0) {
handle_channel_maps(device, maps);
snd_pcm_close(handle);
return SoundIoErrorOpeningDevice;
}
snd_pcm_hw_params_get_format_mask(hwparams, fmt_mask);
device->formats = allocate<SoundIoFormat>(18);
if (!device->formats) {
handle_channel_maps(device, maps);
snd_pcm_close(handle);
return SoundIoErrorNoMem;
}
device->format_count = 0;
test_fmt_mask(device, fmt_mask, SoundIoFormatS8);
test_fmt_mask(device, fmt_mask, SoundIoFormatU8);
test_fmt_mask(device, fmt_mask, SoundIoFormatS16LE);
test_fmt_mask(device, fmt_mask, SoundIoFormatS16BE);
test_fmt_mask(device, fmt_mask, SoundIoFormatU16LE);
test_fmt_mask(device, fmt_mask, SoundIoFormatU16BE);
test_fmt_mask(device, fmt_mask, SoundIoFormatS24LE);
test_fmt_mask(device, fmt_mask, SoundIoFormatS24BE);
test_fmt_mask(device, fmt_mask, SoundIoFormatU24LE);
test_fmt_mask(device, fmt_mask, SoundIoFormatU24BE);
test_fmt_mask(device, fmt_mask, SoundIoFormatS32LE);
test_fmt_mask(device, fmt_mask, SoundIoFormatS32BE);
test_fmt_mask(device, fmt_mask, SoundIoFormatU32LE);
test_fmt_mask(device, fmt_mask, SoundIoFormatU32BE);
test_fmt_mask(device, fmt_mask, SoundIoFormatFloat32LE);
test_fmt_mask(device, fmt_mask, SoundIoFormatFloat32BE);
test_fmt_mask(device, fmt_mask, SoundIoFormatFloat64LE);
test_fmt_mask(device, fmt_mask, SoundIoFormatFloat64BE);
snd_pcm_chmap_t *chmap = snd_pcm_get_chmap(handle); snd_pcm_chmap_t *chmap = snd_pcm_get_chmap(handle);
@ -229,16 +322,14 @@ static int probe_device(SoundIoDevice *device, snd_pcm_chmap_query_t **maps) {
device->sample_rate_min = min_sample_rate; device->sample_rate_min = min_sample_rate;
device->sample_rate_min = max_sample_rate; device->sample_rate_max = max_sample_rate;
device->sample_rate_default = // TODO can we figure out what sample rate dmix is currently playing at,
(min_sample_rate <= MAX_SAMPLE_RATE && // if dmix applies to this device?
MAX_SAMPLE_RATE <= max_sample_rate) ? MAX_SAMPLE_RATE : max_sample_rate; device->sample_rate_current = 0;
snd_pcm_close(handle); snd_pcm_close(handle);
return 0; return 0;
// TODO: device->default_sample_format
// TODO: device->default_latency // TODO: device->default_latency
} }
@ -352,7 +443,7 @@ static int refresh_devices(SoundIo *soundio) {
devices_info->default_input_index = device_list->length; devices_info->default_input_index = device_list->length;
} }
probe_device(device, nullptr); device->probe_error = probe_device(device, nullptr);
if (device_list->append(device)) { if (device_list->append(device)) {
soundio_device_unref(device); soundio_device_unref(device);
@ -461,7 +552,7 @@ static int refresh_devices(SoundIo *soundio) {
} }
snd_pcm_chmap_query_t **maps = snd_pcm_query_chmaps_from_hw(card_index, device_index, -1, stream); snd_pcm_chmap_query_t **maps = snd_pcm_query_chmaps_from_hw(card_index, device_index, -1, stream);
probe_device(device, maps); device->probe_error = probe_device(device, maps);
if (device_list->append(device)) { if (device_list->append(device)) {
soundio_device_unref(device); soundio_device_unref(device);
@ -575,7 +666,7 @@ static void device_thread_run(void *arg) {
} }
if (got_rescan_event) { if (got_rescan_event) {
if ((err = refresh_devices(soundio))) if ((err = refresh_devices(soundio)))
soundio_panic("error refreshing devices: %s", soundio_error_string(err)); soundio_panic("error refreshing devices: %s", soundio_strerror(err));
} }
} }
} }

View file

@ -245,6 +245,34 @@ static void input_device_clear_buffer_dummy(SoundIo *soundio,
soundio_panic("TODO"); soundio_panic("TODO");
} }
static int set_all_device_formats(SoundIoDevice *device) {
device->format_count = 18;
device->formats = allocate<SoundIoFormat>(device->format_count);
if (!device->formats)
return SoundIoErrorNoMem;
device->formats[0] = SoundIoFormatS8;
device->formats[1] = SoundIoFormatU8;
device->formats[2] = SoundIoFormatS16LE;
device->formats[3] = SoundIoFormatS16BE;
device->formats[4] = SoundIoFormatU16LE;
device->formats[5] = SoundIoFormatU16BE;
device->formats[6] = SoundIoFormatS24LE;
device->formats[7] = SoundIoFormatS24BE;
device->formats[8] = SoundIoFormatU24LE;
device->formats[9] = SoundIoFormatU24BE;
device->formats[10] = SoundIoFormatS32LE;
device->formats[11] = SoundIoFormatS32BE;
device->formats[12] = SoundIoFormatU32LE;
device->formats[13] = SoundIoFormatU32BE;
device->formats[14] = SoundIoFormatFloat32LE;
device->formats[15] = SoundIoFormatFloat32BE;
device->formats[16] = SoundIoFormatFloat64LE;
device->formats[17] = SoundIoFormatFloat64BE;
return 0;
}
int soundio_dummy_init(SoundIo *soundio) { int soundio_dummy_init(SoundIo *soundio) {
assert(!soundio->backend_data); assert(!soundio->backend_data);
SoundIoDummy *sid = create<SoundIoDummy>(); SoundIoDummy *sid = create<SoundIoDummy>();
@ -287,17 +315,24 @@ int soundio_dummy_init(SoundIo *soundio) {
device->ref_count = 1; device->ref_count = 1;
device->soundio = soundio; device->soundio = soundio;
device->name = strdup("dummy-out"); device->name = strdup("dummy-out");
device->description = strdup("Dummy output device"); device->description = strdup("Dummy Output Device");
if (!device->name || !device->description) { if (!device->name || !device->description) {
free(device->name); soundio_device_unref(device);
free(device->description);
destroy_dummy(soundio); destroy_dummy(soundio);
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
device->channel_layout = *soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdMono); device->channel_layout = *soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdMono);
device->default_sample_format = SoundIoSampleFormatFloat32NE; int err;
if ((err = set_all_device_formats(device))) {
soundio_device_unref(device);
destroy_dummy(soundio);
return err;
}
device->default_latency = 0.01; device->default_latency = 0.01;
device->sample_rate_default = 48000; device->sample_rate_min = 2;
device->sample_rate_max = 5644800;
device->sample_rate_current = 48000;
device->purpose = SoundIoDevicePurposeOutput; device->purpose = SoundIoDevicePurposeOutput;
if (soundio->safe_devices_info->output_devices.append(device)) { if (soundio->safe_devices_info->output_devices.append(device)) {
@ -325,9 +360,16 @@ int soundio_dummy_init(SoundIo *soundio) {
return SoundIoErrorNoMem; return SoundIoErrorNoMem;
} }
device->channel_layout = *soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdMono); device->channel_layout = *soundio_channel_layout_get_builtin(SoundIoChannelLayoutIdMono);
device->default_sample_format = SoundIoSampleFormatFloat32NE; int err;
if ((err = set_all_device_formats(device))) {
soundio_device_unref(device);
destroy_dummy(soundio);
return err;
}
device->default_latency = 0.01; device->default_latency = 0.01;
device->sample_rate_default = 48000; device->sample_rate_min = 2;
device->sample_rate_max = 5644800;
device->sample_rate_current = 48000;
device->purpose = SoundIoDevicePurposeInput; device->purpose = SoundIoDevicePurposeInput;
if (soundio->safe_devices_info->input_devices.append(device)) { if (soundio->safe_devices_info->input_devices.append(device)) {

View file

@ -139,17 +139,17 @@ static double usec_to_sec(pa_usec_t usec) {
} }
static SoundIoSampleFormat sample_format_from_pulseaudio(pa_sample_spec sample_spec) { static SoundIoFormat format_from_pulseaudio(pa_sample_spec sample_spec) {
switch (sample_spec.format) { switch (sample_spec.format) {
case PA_SAMPLE_U8: return SoundIoSampleFormatU8; case PA_SAMPLE_U8: return SoundIoFormatU8;
case PA_SAMPLE_S16LE: return SoundIoSampleFormatS16LE; case PA_SAMPLE_S16LE: return SoundIoFormatS16LE;
case PA_SAMPLE_S16BE: return SoundIoSampleFormatS16BE; case PA_SAMPLE_S16BE: return SoundIoFormatS16BE;
case PA_SAMPLE_FLOAT32LE: return SoundIoSampleFormatFloat32LE; case PA_SAMPLE_FLOAT32LE: return SoundIoFormatFloat32LE;
case PA_SAMPLE_FLOAT32BE: return SoundIoSampleFormatFloat32BE; case PA_SAMPLE_FLOAT32BE: return SoundIoFormatFloat32BE;
case PA_SAMPLE_S32LE: return SoundIoSampleFormatS32LE; case PA_SAMPLE_S32LE: return SoundIoFormatS32LE;
case PA_SAMPLE_S32BE: return SoundIoSampleFormatS32BE; case PA_SAMPLE_S32BE: return SoundIoFormatS32BE;
case PA_SAMPLE_S24_32LE: return SoundIoSampleFormatS24LE; case PA_SAMPLE_S24_32LE: return SoundIoFormatS24LE;
case PA_SAMPLE_S24_32BE: return SoundIoSampleFormatS24BE; case PA_SAMPLE_S24_32BE: return SoundIoFormatS24BE;
case PA_SAMPLE_MAX: case PA_SAMPLE_MAX:
case PA_SAMPLE_INVALID: case PA_SAMPLE_INVALID:
@ -157,9 +157,9 @@ static SoundIoSampleFormat sample_format_from_pulseaudio(pa_sample_spec sample_s
case PA_SAMPLE_ULAW: case PA_SAMPLE_ULAW:
case PA_SAMPLE_S24LE: case PA_SAMPLE_S24LE:
case PA_SAMPLE_S24BE: case PA_SAMPLE_S24BE:
return SoundIoSampleFormatInvalid; return SoundIoFormatInvalid;
} }
return SoundIoSampleFormatInvalid; return SoundIoFormatInvalid;
} }
static int sample_rate_from_pulseaudio(pa_sample_spec sample_spec) { static int sample_rate_from_pulseaudio(pa_sample_spec sample_spec) {
@ -280,9 +280,10 @@ static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *in
if (!device->name || !device->description) if (!device->name || !device->description)
soundio_panic("out of memory"); soundio_panic("out of memory");
set_from_pulseaudio_channel_map(info->channel_map, &device->channel_layout); set_from_pulseaudio_channel_map(info->channel_map, &device->channel_layout);
device->default_sample_format = sample_format_from_pulseaudio(info->sample_spec); // TODO determine the list of supported formats and the min and max sample rate
device->current_format = format_from_pulseaudio(info->sample_spec);
device->default_latency = usec_to_sec(info->configured_latency); device->default_latency = usec_to_sec(info->configured_latency);
device->sample_rate_default = sample_rate_from_pulseaudio(info->sample_spec); device->sample_rate_current = sample_rate_from_pulseaudio(info->sample_spec);
device->purpose = SoundIoDevicePurposeOutput; device->purpose = SoundIoDevicePurposeOutput;
if (sipa->current_devices_info->output_devices.append(device)) if (sipa->current_devices_info->output_devices.append(device))
@ -309,9 +310,10 @@ static void source_info_callback(pa_context *pulse_context, const pa_source_info
if (!device->name || !device->description) if (!device->name || !device->description)
soundio_panic("out of memory"); soundio_panic("out of memory");
set_from_pulseaudio_channel_map(info->channel_map, &device->channel_layout); set_from_pulseaudio_channel_map(info->channel_map, &device->channel_layout);
device->default_sample_format = sample_format_from_pulseaudio(info->sample_spec); // TODO determine the list of supported formats and the min and max sample rate
device->current_format = format_from_pulseaudio(info->sample_spec);
device->default_latency = usec_to_sec(info->configured_latency); device->default_latency = usec_to_sec(info->configured_latency);
device->sample_rate_default = sample_rate_from_pulseaudio(info->sample_spec); device->sample_rate_current = sample_rate_from_pulseaudio(info->sample_spec);
device->purpose = SoundIoDevicePurposeInput; device->purpose = SoundIoDevicePurposeInput;
if (sipa->current_devices_info->input_devices.append(device)) if (sipa->current_devices_info->input_devices.append(device))
@ -437,28 +439,28 @@ static void wakeup(SoundIo *soundio) {
pa_threaded_mainloop_signal(sipa->main_loop, 0); pa_threaded_mainloop_signal(sipa->main_loop, 0);
} }
static pa_sample_format_t to_pulseaudio_sample_format(SoundIoSampleFormat sample_format) { static pa_sample_format_t to_pulseaudio_format(SoundIoFormat format) {
switch (sample_format) { switch (format) {
case SoundIoSampleFormatU8: return PA_SAMPLE_U8; case SoundIoFormatU8: return PA_SAMPLE_U8;
case SoundIoSampleFormatS16LE: return PA_SAMPLE_S16LE; case SoundIoFormatS16LE: return PA_SAMPLE_S16LE;
case SoundIoSampleFormatS16BE: return PA_SAMPLE_S16BE; case SoundIoFormatS16BE: return PA_SAMPLE_S16BE;
case SoundIoSampleFormatS24LE: return PA_SAMPLE_S24_32LE; case SoundIoFormatS24LE: return PA_SAMPLE_S24_32LE;
case SoundIoSampleFormatS24BE: return PA_SAMPLE_S24_32BE; case SoundIoFormatS24BE: return PA_SAMPLE_S24_32BE;
case SoundIoSampleFormatS32LE: return PA_SAMPLE_S32LE; case SoundIoFormatS32LE: return PA_SAMPLE_S32LE;
case SoundIoSampleFormatS32BE: return PA_SAMPLE_S32BE; case SoundIoFormatS32BE: return PA_SAMPLE_S32BE;
case SoundIoSampleFormatFloat32LE: return PA_SAMPLE_FLOAT32LE; case SoundIoFormatFloat32LE: return PA_SAMPLE_FLOAT32LE;
case SoundIoSampleFormatFloat32BE: return PA_SAMPLE_FLOAT32BE; case SoundIoFormatFloat32BE: return PA_SAMPLE_FLOAT32BE;
case SoundIoSampleFormatInvalid: case SoundIoFormatInvalid:
case SoundIoSampleFormatS8: case SoundIoFormatS8:
case SoundIoSampleFormatU16LE: case SoundIoFormatU16LE:
case SoundIoSampleFormatU16BE: case SoundIoFormatU16BE:
case SoundIoSampleFormatU24LE: case SoundIoFormatU24LE:
case SoundIoSampleFormatU24BE: case SoundIoFormatU24BE:
case SoundIoSampleFormatU32LE: case SoundIoFormatU32LE:
case SoundIoSampleFormatU32BE: case SoundIoFormatU32BE:
case SoundIoSampleFormatFloat64LE: case SoundIoFormatFloat64LE:
case SoundIoSampleFormatFloat64BE: case SoundIoFormatFloat64BE:
return PA_SAMPLE_INVALID; return PA_SAMPLE_INVALID;
} }
return PA_SAMPLE_INVALID; return PA_SAMPLE_INVALID;
@ -600,7 +602,7 @@ static int output_device_init_pa(SoundIo *soundio,
pa_threaded_mainloop_lock(sipa->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_format(output_device->format);
sample_spec.rate = output_device->sample_rate; sample_spec.rate = output_device->sample_rate;
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);
@ -766,7 +768,7 @@ static int input_device_init_pa(SoundIo *soundio,
pa_threaded_mainloop_lock(sipa->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_format(input_device->format);
sample_spec.rate = input_device->sample_rate; sample_spec.rate = input_device->sample_rate;
sample_spec.channels = device->channel_layout.channel_count; sample_spec.channels = device->channel_layout.channel_count;

View file

@ -22,7 +22,7 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
const char *soundio_error_string(int error) { const char *soundio_strerror(int error) {
switch ((enum SoundIoError)error) { switch ((enum SoundIoError)error) {
case SoundIoErrorNone: return "(no error)"; case SoundIoErrorNone: return "(no error)";
case SoundIoErrorNoMem: return "out of memory"; case SoundIoErrorNoMem: return "out of memory";
@ -33,52 +33,56 @@ const char *soundio_error_string(int error) {
soundio_panic("invalid error enum value: %d", error); soundio_panic("invalid error enum value: %d", error);
} }
int soundio_get_bytes_per_sample(enum SoundIoSampleFormat sample_format) { int soundio_get_bytes_per_sample(enum SoundIoFormat format) {
switch (sample_format) { switch (format) {
case SoundIoSampleFormatInvalid: soundio_panic("invalid sample format"); case SoundIoFormatU8: return 1;
case SoundIoSampleFormatU8: return 1; case SoundIoFormatS8: return 1;
case SoundIoSampleFormatS8: return 1; case SoundIoFormatS16LE: return 2;
case SoundIoSampleFormatS16LE: return 2; case SoundIoFormatS16BE: return 2;
case SoundIoSampleFormatS16BE: return 2; case SoundIoFormatU16LE: return 2;
case SoundIoSampleFormatU16LE: return 2; case SoundIoFormatU16BE: return 2;
case SoundIoSampleFormatU16BE: return 2; case SoundIoFormatS24LE: return 4;
case SoundIoSampleFormatS24LE: return 4; case SoundIoFormatS24BE: return 4;
case SoundIoSampleFormatS24BE: return 4; case SoundIoFormatU24LE: return 4;
case SoundIoSampleFormatU24LE: return 4; case SoundIoFormatU24BE: return 4;
case SoundIoSampleFormatU24BE: return 4; case SoundIoFormatS32LE: return 4;
case SoundIoSampleFormatS32LE: return 4; case SoundIoFormatS32BE: return 4;
case SoundIoSampleFormatS32BE: return 4; case SoundIoFormatU32LE: return 4;
case SoundIoSampleFormatU32LE: return 4; case SoundIoFormatU32BE: return 4;
case SoundIoSampleFormatU32BE: return 4; case SoundIoFormatFloat32LE: return 4;
case SoundIoSampleFormatFloat32LE: return 4; case SoundIoFormatFloat32BE: return 4;
case SoundIoSampleFormatFloat32BE: return 4; case SoundIoFormatFloat64LE: return 8;
case SoundIoSampleFormatFloat64LE: return 8; case SoundIoFormatFloat64BE: return 8;
case SoundIoSampleFormatFloat64BE: return 8;
case SoundIoFormatInvalid:
soundio_panic("invalid sample format");
} }
soundio_panic("invalid sample format"); soundio_panic("invalid sample format");
} }
const char * soundio_sample_format_string(enum SoundIoSampleFormat sample_format) { const char * soundio_format_string(enum SoundIoFormat format) {
switch (sample_format) { switch (format) {
case SoundIoSampleFormatInvalid: return "(invalid sample format)"; case SoundIoFormatU8: return "signed 8-bit";
case SoundIoSampleFormatU8: return "signed 8-bit"; case SoundIoFormatS8: return "unsigned 8-bit";
case SoundIoSampleFormatS8: return "unsigned 8-bit"; case SoundIoFormatS16LE: return "signed 16-bit LE";
case SoundIoSampleFormatS16LE: return "signed 16-bit LE"; case SoundIoFormatS16BE: return "signed 16-bit BE";
case SoundIoSampleFormatS16BE: return "signed 16-bit BE"; case SoundIoFormatU16LE: return "unsigned 16-bit LE";
case SoundIoSampleFormatU16LE: return "unsigned 16-bit LE"; case SoundIoFormatU16BE: return "unsigned 16-bit LE";
case SoundIoSampleFormatU16BE: return "unsigned 16-bit LE"; case SoundIoFormatS24LE: return "signed 24-bit LE";
case SoundIoSampleFormatS24LE: return "signed 24-bit LE"; case SoundIoFormatS24BE: return "signed 24-bit BE";
case SoundIoSampleFormatS24BE: return "signed 24-bit BE"; case SoundIoFormatU24LE: return "unsigned 24-bit LE";
case SoundIoSampleFormatU24LE: return "unsigned 24-bit LE"; case SoundIoFormatU24BE: return "unsigned 24-bit BE";
case SoundIoSampleFormatU24BE: return "unsigned 24-bit BE"; case SoundIoFormatS32LE: return "signed 32-bit LE";
case SoundIoSampleFormatS32LE: return "signed 32-bit LE"; case SoundIoFormatS32BE: return "signed 32-bit BE";
case SoundIoSampleFormatS32BE: return "signed 32-bit BE"; case SoundIoFormatU32LE: return "unsigned 32-bit LE";
case SoundIoSampleFormatU32LE: return "unsigned 32-bit LE"; case SoundIoFormatU32BE: return "unsigned 32-bit BE";
case SoundIoSampleFormatU32BE: return "unsigned 32-bit BE"; case SoundIoFormatFloat32LE: return "float 32-bit LE";
case SoundIoSampleFormatFloat32LE: return "float 32-bit LE"; case SoundIoFormatFloat32BE: return "float 32-bit BE";
case SoundIoSampleFormatFloat32BE: return "float 32-bit BE"; case SoundIoFormatFloat64LE: return "float 64-bit LE";
case SoundIoSampleFormatFloat64LE: return "float 64-bit LE"; case SoundIoFormatFloat64BE: return "float 64-bit BE";
case SoundIoSampleFormatFloat64BE: return "float 64-bit BE";
case SoundIoFormatInvalid:
return "(invalid sample format)";
} }
return "(invalid sample format)"; return "(invalid sample format)";
} }
@ -250,10 +254,6 @@ const struct SoundIoChannelLayout *soundio_device_channel_layout(const struct So
return &device->channel_layout; return &device->channel_layout;
} }
int soundio_device_sample_rate(const struct SoundIoDevice *device) {
return device->sample_rate_default;
}
void soundio_device_unref(struct SoundIoDevice *device) { void soundio_device_unref(struct SoundIoDevice *device) {
if (!device) if (!device)
return; return;
@ -264,6 +264,7 @@ void soundio_device_unref(struct SoundIoDevice *device) {
if (device->ref_count == 0) { if (device->ref_count == 0) {
free(device->name); free(device->name);
free(device->description); free(device->description);
deallocate(device->formats, device->format_count);
destroy(device); destroy(device);
} }
} }
@ -313,7 +314,7 @@ void soundio_output_device_write(struct SoundIoOutputDevice *output_device,
int soundio_output_device_create(struct SoundIoDevice *device, int soundio_output_device_create(struct SoundIoDevice *device,
enum SoundIoSampleFormat sample_format, int sample_rate, enum SoundIoFormat format, int sample_rate,
double latency, void *userdata, double latency, void *userdata,
void (*write_callback)(struct SoundIoOutputDevice *, int frame_count), void (*write_callback)(struct SoundIoOutputDevice *, int frame_count),
void (*underrun_callback)(struct SoundIoOutputDevice *), void (*underrun_callback)(struct SoundIoOutputDevice *),
@ -332,10 +333,10 @@ int soundio_output_device_create(struct SoundIoDevice *device,
output_device->userdata = userdata; output_device->userdata = userdata;
output_device->write_callback = write_callback; output_device->write_callback = write_callback;
output_device->underrun_callback = underrun_callback; output_device->underrun_callback = underrun_callback;
output_device->sample_format = sample_format; output_device->format = format;
output_device->sample_rate = sample_rate; output_device->sample_rate = sample_rate;
output_device->latency = latency; output_device->latency = latency;
output_device->bytes_per_frame = soundio_get_bytes_per_frame(sample_format, output_device->bytes_per_frame = soundio_get_bytes_per_frame(format,
device->channel_layout.channel_count); device->channel_layout.channel_count);
SoundIo *soundio = device->soundio; SoundIo *soundio = device->soundio;
@ -368,7 +369,7 @@ int soundio_output_device_start(struct SoundIoOutputDevice *output_device) {
} }
int soundio_input_device_create(struct SoundIoDevice *device, int soundio_input_device_create(struct SoundIoDevice *device,
enum SoundIoSampleFormat sample_format, int sample_rate, enum SoundIoFormat format, int sample_rate,
double latency, void *userdata, double latency, void *userdata,
void (*read_callback)(struct SoundIoInputDevice *), void (*read_callback)(struct SoundIoInputDevice *),
struct SoundIoInputDevice **out_input_device) struct SoundIoInputDevice **out_input_device)
@ -385,10 +386,10 @@ int soundio_input_device_create(struct SoundIoDevice *device,
sid->device = device; sid->device = device;
sid->userdata = userdata; sid->userdata = userdata;
sid->read_callback = read_callback; sid->read_callback = read_callback;
sid->sample_format = sample_format; sid->format = format;
sid->latency = latency; sid->latency = latency;
sid->sample_rate = sample_rate; sid->sample_rate = sample_rate;
sid->bytes_per_frame = soundio_get_bytes_per_frame(sample_format, sid->bytes_per_frame = soundio_get_bytes_per_frame(format,
device->channel_layout.channel_count); device->channel_layout.channel_count);
SoundIo *soundio = device->soundio; SoundIo *soundio = device->soundio;

View file

@ -140,74 +140,115 @@ enum SoundIoDevicePurpose {
SoundIoDevicePurposeOutput, SoundIoDevicePurposeOutput,
}; };
enum SoundIoSampleFormat { enum SoundIoFormat {
SoundIoSampleFormatInvalid, SoundIoFormatInvalid,
SoundIoSampleFormatU8, // Signed 8 bit SoundIoFormatS8, // Signed 8 bit
SoundIoSampleFormatS8, // Unsigned 8 bit SoundIoFormatU8, // Unsigned 8 bit
SoundIoSampleFormatS16LE, // Signed 16 bit Little Endian SoundIoFormatS16LE, // Signed 16 bit Little Endian
SoundIoSampleFormatS16BE, // Signed 16 bit Big Endian SoundIoFormatS16BE, // Signed 16 bit Big Endian
SoundIoSampleFormatU16LE, // Unsigned 16 bit Little Endian SoundIoFormatU16LE, // Unsigned 16 bit Little Endian
SoundIoSampleFormatU16BE, // Unsigned 16 bit Little Endian SoundIoFormatU16BE, // Unsigned 16 bit Little Endian
SoundIoSampleFormatS24LE, // Signed 24 bit Little Endian using low three bytes in 32-bit word SoundIoFormatS24LE, // Signed 24 bit Little Endian using low three bytes in 32-bit word
SoundIoSampleFormatS24BE, // Signed 24 bit Big Endian using low three bytes in 32-bit word SoundIoFormatS24BE, // Signed 24 bit Big Endian using low three bytes in 32-bit word
SoundIoSampleFormatU24LE, // Unsigned 24 bit Little Endian using low three bytes in 32-bit word SoundIoFormatU24LE, // Unsigned 24 bit Little Endian using low three bytes in 32-bit word
SoundIoSampleFormatU24BE, // Unsigned 24 bit Big Endian using low three bytes in 32-bit word SoundIoFormatU24BE, // Unsigned 24 bit Big Endian using low three bytes in 32-bit word
SoundIoSampleFormatS32LE, // Signed 32 bit Little Endian SoundIoFormatS32LE, // Signed 32 bit Little Endian
SoundIoSampleFormatS32BE, // Signed 32 bit Big Endian SoundIoFormatS32BE, // Signed 32 bit Big Endian
SoundIoSampleFormatU32LE, // Unsigned 32 bit Little Endian SoundIoFormatU32LE, // Unsigned 32 bit Little Endian
SoundIoSampleFormatU32BE, // Unsigned 32 bit Big Endian SoundIoFormatU32BE, // Unsigned 32 bit Big Endian
SoundIoSampleFormatFloat32LE, // Float 32 bit Little Endian, Range -1.0 to 1.0 SoundIoFormatFloat32LE, // Float 32 bit Little Endian, Range -1.0 to 1.0
SoundIoSampleFormatFloat32BE, // Float 32 bit Big Endian, Range -1.0 to 1.0 SoundIoFormatFloat32BE, // Float 32 bit Big Endian, Range -1.0 to 1.0
SoundIoSampleFormatFloat64LE, // Float 64 bit Little Endian, Range -1.0 to 1.0 SoundIoFormatFloat64LE, // Float 64 bit Little Endian, Range -1.0 to 1.0
SoundIoSampleFormatFloat64BE, // Float 64 bit Big Endian, Range -1.0 to 1.0 SoundIoFormatFloat64BE, // Float 64 bit Big Endian, Range -1.0 to 1.0
}; };
#if defined(SOUNDIO_OS_BIG_ENDIAN) #if defined(SOUNDIO_OS_BIG_ENDIAN)
#define SoundIoSampleFormatS16NE SoundIoSampleFormatS16BE #define SoundIoFormatS16NE SoundIoFormatS16BE
#define SoundIoSampleFormatU16NE SoundIoSampleFormatU16BE #define SoundIoFormatU16NE SoundIoFormatU16BE
#define SoundIoSampleFormatS24NE SoundIoSampleFormatS24BE #define SoundIoFormatS24NE SoundIoFormatS24BE
#define SoundIoSampleFormatU24NE SoundIoSampleFormatU24BE #define SoundIoFormatU24NE SoundIoFormatU24BE
#define SoundIoSampleFormatS32NE SoundIoSampleFormatS32BE #define SoundIoFormatS32NE SoundIoFormatS32BE
#define SoundIoSampleFormatU32NE SoundIoSampleFormatU32BE #define SoundIoFormatU32NE SoundIoFormatU32BE
#define SoundIoSampleFormatFloat32NE SoundIoSampleFormatFloat32BE #define SoundIoFormatFloat32NE SoundIoFormatFloat32BE
#define SoundIoSampleFormatFloat64NE SoundIoSampleFormatFloat64BE #define SoundIoFormatFloat64NE SoundIoFormatFloat64BE
#elif defined(SOUNDIO_OS_LITTLE_ENDIAN) #elif defined(SOUNDIO_OS_LITTLE_ENDIAN)
#define SoundIoSampleFormatS16NE SoundIoSampleFormatS16LE #define SoundIoFormatS16NE SoundIoFormatS16LE
#define SoundIoSampleFormatU16NE SoundIoSampleFormatU16LE #define SoundIoFormatU16NE SoundIoFormatU16LE
#define SoundIoSampleFormatS24NE SoundIoSampleFormatS24LE #define SoundIoFormatS24NE SoundIoFormatS24LE
#define SoundIoSampleFormatU24NE SoundIoSampleFormatU24LE #define SoundIoFormatU24NE SoundIoFormatU24LE
#define SoundIoSampleFormatS32NE SoundIoSampleFormatS32LE #define SoundIoFormatS32NE SoundIoFormatS32LE
#define SoundIoSampleFormatU32NE SoundIoSampleFormatU32LE #define SoundIoFormatU32NE SoundIoFormatU32LE
#define SoundIoSampleFormatFloat32NE SoundIoSampleFormatFloat32LE #define SoundIoFormatFloat32NE SoundIoFormatFloat32LE
#define SoundIoSampleFormatFloat64NE SoundIoSampleFormatFloat64LE #define SoundIoFormatFloat64NE SoundIoFormatFloat64LE
#endif #endif
struct SoundIoDevice { struct SoundIoDevice {
struct SoundIo *soundio; struct SoundIo *soundio;
// `name` uniquely identifies this device. `description` is user-friendly
// text to describe the device.
char *name; char *name;
char *description; char *description;
// If this information is missing due to a `probe_error`, the number of
// channels will be zero.
struct SoundIoChannelLayout channel_layout; struct SoundIoChannelLayout channel_layout;
// these values might not actually matter. audio hardware has a set of // A device is either a raw device or it is a virtual device that is
// {sample format, sample rate} that they support. you can't know // provided by a software mixing service such as dmix or PulseAudio (see
// whether something worked until you try it. // `is_raw`). If it is a raw device, `current_format` is meaningless;
// these values can be unknown // the device has no current format until you open it. On the other hand,
enum SoundIoSampleFormat default_sample_format; // if it is a virtual device, `current_format` describes the destination
// sample format that your audio will be converted to. Or, if you're the
// lucky first application to open the device, you might cause the
// `current_format` to change to your format. Generally, you want to
// ignore `current_format` and use whatever format is most convenient
// for you which is supported by the device, because when you are the only
// application left, the mixer might decide to switch `current_format` to
// yours. You can learn the supported formats via `formats` and
// `format_count`. If this information is missing due to a probe error,
// `formats` will be `NULL`. If `current_format` is unavailable, it will be
// set to `SoundIoFormatInvalid`.
enum SoundIoFormat *formats;
int format_count;
enum SoundIoFormat current_format;
// Sample rate is handled very similar to sample format; see those docs.
// If sample rate information is missing due to a probe error, the field
// will be set to zero.
int sample_rate_min; int sample_rate_min;
int sample_rate_max; int sample_rate_max;
int sample_rate_default; int sample_rate_current;
double default_latency; double default_latency;
// Tells whether this device is an input device or an output device.
enum SoundIoDevicePurpose purpose; enum SoundIoDevicePurpose purpose;
int ref_count;
// raw means that you are directly opening the hardware device and not
// going through a proxy such as dmix or PulseAudio. When you open a raw
// device, other applications on the computer are not able to
// simultaneously access the device. Raw devices do not perform automatic
// resampling and thus tend to have fewer formats available.
bool is_raw; bool is_raw;
// Devices are reference counted. See `soundio_device_ref` and
// `soundio_device_unref`.
int ref_count;
// This is set to a SoundIoError representing the result of the device
// probe. Ideally this will be SoundIoErrorNone in which case all the
// fields of the device will be populated. If there is an error code here
// then information about formats, sample rates, and channel layouts might
// be missing.
int probe_error;
}; };
// TODO rename this to SoundIoOutStream
struct SoundIoOutputDevice { struct SoundIoOutputDevice {
void *backend_data; void *backend_data;
struct SoundIoDevice *device; struct SoundIoDevice *device;
enum SoundIoSampleFormat sample_format; enum SoundIoFormat format;
int sample_rate; int sample_rate;
double latency; double latency;
int bytes_per_frame; int bytes_per_frame;
@ -217,10 +258,11 @@ struct SoundIoOutputDevice {
void (*write_callback)(struct SoundIoOutputDevice *, int frame_count); void (*write_callback)(struct SoundIoOutputDevice *, int frame_count);
}; };
// TODO rename this to SoundIoInStream
struct SoundIoInputDevice { struct SoundIoInputDevice {
void *backend_data; void *backend_data;
struct SoundIoDevice *device; struct SoundIoDevice *device;
enum SoundIoSampleFormat sample_format; enum SoundIoFormat format;
int sample_rate; int sample_rate;
double latency; double latency;
int bytes_per_frame; int bytes_per_frame;
@ -276,7 +318,7 @@ void soundio_destroy(struct SoundIo *soundio);
int soundio_connect(struct SoundIo *soundio); int soundio_connect(struct SoundIo *soundio);
void soundio_disconnect(struct SoundIo *soundio); void soundio_disconnect(struct SoundIo *soundio);
const char *soundio_error_string(int error); const char *soundio_strerror(int error);
const char *soundio_backend_name(enum SoundIoBackend backend); const char *soundio_backend_name(enum SoundIoBackend backend);
// when you call this, the on_devices_change and on_events_signal callbacks // when you call this, the on_devices_change and on_events_signal callbacks
@ -315,19 +357,19 @@ bool soundio_channel_layout_detect_builtin(struct SoundIoChannelLayout *layout);
// Sample Formats // Sample Formats
int soundio_get_bytes_per_sample(enum SoundIoSampleFormat sample_format); int soundio_get_bytes_per_sample(enum SoundIoFormat format);
static inline int soundio_get_bytes_per_frame(enum SoundIoSampleFormat sample_format, int channel_count) { static inline int soundio_get_bytes_per_frame(enum SoundIoFormat format, int channel_count) {
return soundio_get_bytes_per_sample(sample_format) * channel_count; return soundio_get_bytes_per_sample(format) * channel_count;
} }
static inline int soundio_get_bytes_per_second(enum SoundIoSampleFormat sample_format, static inline int soundio_get_bytes_per_second(enum SoundIoFormat format,
int channel_count, int sample_rate) int channel_count, int sample_rate)
{ {
return soundio_get_bytes_per_frame(sample_format, channel_count) * sample_rate; return soundio_get_bytes_per_frame(format, channel_count) * sample_rate;
} }
const char * soundio_sample_format_string(enum SoundIoSampleFormat sample_format); const char * soundio_format_string(enum SoundIoFormat format);
@ -359,7 +401,6 @@ const char *soundio_device_name(const struct SoundIoDevice *device);
const char *soundio_device_description(const struct SoundIoDevice *device); const char *soundio_device_description(const struct SoundIoDevice *device);
const struct SoundIoChannelLayout *soundio_device_channel_layout(const struct SoundIoDevice *device); const struct SoundIoChannelLayout *soundio_device_channel_layout(const struct SoundIoDevice *device);
int soundio_device_sample_rate(const struct SoundIoDevice *device);
bool soundio_device_equal( bool soundio_device_equal(
const struct SoundIoDevice *a, const struct SoundIoDevice *a,
@ -371,7 +412,7 @@ enum SoundIoDevicePurpose soundio_device_purpose(const struct SoundIoDevice *dev
// Output Devices // Output Devices
int soundio_output_device_create(struct SoundIoDevice *device, int soundio_output_device_create(struct SoundIoDevice *device,
enum SoundIoSampleFormat sample_format, int sample_rate, enum SoundIoFormat format, int sample_rate,
double latency, void *userdata, double latency, void *userdata,
void (*write_callback)(struct SoundIoOutputDevice *, int frame_count), void (*write_callback)(struct SoundIoOutputDevice *, int frame_count),
void (*underrun_callback)(struct SoundIoOutputDevice *), void (*underrun_callback)(struct SoundIoOutputDevice *),
@ -397,7 +438,7 @@ void soundio_output_device_clear_buffer(struct SoundIoOutputDevice *output_devic
// Input Devices // Input Devices
int soundio_input_device_create(struct SoundIoDevice *device, int soundio_input_device_create(struct SoundIoDevice *device,
enum SoundIoSampleFormat sample_format, int sample_rate, enum SoundIoFormat format, int sample_rate,
double latency, void *userdata, double latency, void *userdata,
void (*read_callback)(struct SoundIoInputDevice *), void (*read_callback)(struct SoundIoInputDevice *),
struct SoundIoInputDevice **out_input_device); struct SoundIoInputDevice **out_input_device);

View file

@ -11,7 +11,7 @@
static inline void ok_or_panic(int err) { static inline void ok_or_panic(int err) {
if (err) if (err)
soundio_panic("%s", soundio_error_string(err)); soundio_panic("%s", soundio_strerror(err));
} }
static void test_os_get_time(void) { static void test_os_get_time(void) {
@ -37,7 +37,7 @@ static void test_create_output_device(void) {
soundio_device_name(device); soundio_device_name(device);
soundio_device_description(device); soundio_device_description(device);
struct SoundIoOutputDevice *output_device; struct SoundIoOutputDevice *output_device;
soundio_output_device_create(device, SoundIoSampleFormatFloat32NE, 48000, 0.1, NULL, soundio_output_device_create(device, SoundIoFormatFloat32NE, 48000, 0.1, NULL,
write_callback, underrun_callback, &output_device); write_callback, underrun_callback, &output_device);
soundio_output_device_destroy(output_device); soundio_output_device_destroy(output_device);
soundio_device_unref(device); soundio_device_unref(device);