mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2025-01-03 15:25:42 +00:00
ALSA: expose pcm devices and introduce is_raw
This commit is contained in:
parent
fe61322b23
commit
c39c1ab9f4
|
@ -75,7 +75,7 @@ make
|
|||
sudo make install
|
||||
```
|
||||
|
||||
### Building With MXE
|
||||
### Building for Windows
|
||||
|
||||
You can build libsoundio with [mxe](http://mxe.cc/). Follow the
|
||||
[requirements](http://mxe.cc/#requirements) section to install the
|
||||
|
@ -115,6 +115,8 @@ view `coverage/index.html` in a browser.
|
|||
|
||||
## Roadmap
|
||||
|
||||
0. ALSA `list_devices` should list default, dmix, etc.
|
||||
0. ALSA default devices are "default" and "default" respectively
|
||||
0. implement ALSA (Linux) backend, get examples working
|
||||
0. pipe record to playback example working with dummy linux, osx, windows
|
||||
0. pipe record to playback example working with pulseaudio linux
|
||||
|
|
|
@ -33,6 +33,7 @@ static void print_channel_layout(const struct SoundIoChannelLayout *layout) {
|
|||
static void print_device(struct SoundIoDevice *device, bool is_default) {
|
||||
const char *purpose_str;
|
||||
const char *default_str;
|
||||
const char *raw_str;
|
||||
if (soundio_device_purpose(device) == SoundIoDevicePurposeOutput) {
|
||||
purpose_str = "playback";
|
||||
default_str = is_default ? " (default)" : "";
|
||||
|
@ -40,9 +41,10 @@ static void print_device(struct SoundIoDevice *device, bool is_default) {
|
|||
purpose_str = "recording";
|
||||
default_str = is_default ? " (default)" : "";
|
||||
}
|
||||
raw_str = device->is_raw ? "(raw) " : "";
|
||||
const char *description = soundio_device_description(device);
|
||||
int sample_rate = soundio_device_sample_rate(device);
|
||||
fprintf(stderr, "%s device: ", purpose_str);
|
||||
fprintf(stderr, "%s%s device: ", raw_str, purpose_str);
|
||||
print_channel_layout(soundio_device_channel_layout(device));
|
||||
fprintf(stderr, " %d Hz %s%s\n", sample_rate, description, default_str);
|
||||
}
|
||||
|
|
144
src/alsa.cpp
144
src/alsa.cpp
|
@ -70,8 +70,145 @@ static void destroy_alsa(SoundIo *soundio) {
|
|||
soundio->backend_data = nullptr;
|
||||
}
|
||||
|
||||
static char * str_partition_on_char(char *str, char c) {
|
||||
while (*str) {
|
||||
if (*str == c) {
|
||||
*str = 0;
|
||||
return str + 1;
|
||||
}
|
||||
str += 1;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static int refresh_devices(SoundIo *soundio) {
|
||||
SoundIoAlsa *sia = (SoundIoAlsa *)soundio->backend_data;
|
||||
|
||||
SoundIoDevicesInfo *devices_info = create<SoundIoDevicesInfo>();
|
||||
if (!devices_info)
|
||||
return SoundIoErrorNoMem;
|
||||
|
||||
void **hints;
|
||||
if (snd_device_name_hint(-1, "pcm", &hints) < 0) {
|
||||
destroy(devices_info);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
for (void **hint_ptr = hints; *hint_ptr; hint_ptr += 1) {
|
||||
char *name = snd_device_name_get_hint(*hint_ptr, "NAME");
|
||||
// null - libsoundio has its own dummy backend. API clients should use
|
||||
// that instead of alsa null device.
|
||||
if (strcmp(name, "null") == 0 ||
|
||||
// sysdefault is confusing - the name and description is identical
|
||||
// to default, and my best guess for what it does is ignore ~/.asoundrc
|
||||
// which is just an accident waiting to happen.
|
||||
str_has_prefix(name, "sysdefault:") ||
|
||||
// all these surround devices are clutter
|
||||
str_has_prefix(name, "front:") ||
|
||||
str_has_prefix(name, "surround21:") ||
|
||||
str_has_prefix(name, "surround40:") ||
|
||||
str_has_prefix(name, "surround41:") ||
|
||||
str_has_prefix(name, "surround50:") ||
|
||||
str_has_prefix(name, "surround51:") ||
|
||||
str_has_prefix(name, "surround71:"))
|
||||
{
|
||||
free(name);
|
||||
continue;
|
||||
}
|
||||
|
||||
char *descr = snd_device_name_get_hint(*hint_ptr, "DESC");
|
||||
char *descr1 = str_partition_on_char(descr, '\n');
|
||||
|
||||
char *io = snd_device_name_get_hint(*hint_ptr, "IOID");
|
||||
bool is_playback;
|
||||
bool is_capture;
|
||||
if (io) {
|
||||
if (strcmp(io, "Input") == 0) {
|
||||
is_playback = false;
|
||||
is_capture = true;
|
||||
} else if (strcmp(io, "Output") == 0) {
|
||||
is_playback = true;
|
||||
is_capture = false;
|
||||
} else {
|
||||
soundio_panic("invalid io hint value");
|
||||
}
|
||||
free(io);
|
||||
} else {
|
||||
is_playback = true;
|
||||
is_capture = true;
|
||||
}
|
||||
|
||||
for (int stream_type_i = 0; stream_type_i < array_length(stream_types); stream_type_i += 1) {
|
||||
snd_pcm_stream_t stream = stream_types[stream_type_i];
|
||||
if (stream == SND_PCM_STREAM_PLAYBACK && !is_playback) continue;
|
||||
if (stream == SND_PCM_STREAM_CAPTURE && !is_capture) continue;
|
||||
if (stream == SND_PCM_STREAM_CAPTURE && descr1 &&
|
||||
(strstr(descr1, "Output") || strstr(descr1, "output")))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
SoundIoDevice *device = create<SoundIoDevice>();
|
||||
if (!device) {
|
||||
free(name);
|
||||
free(descr);
|
||||
destroy(devices_info);
|
||||
snd_device_name_free_hint(hints);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
device->ref_count = 1;
|
||||
device->soundio = soundio;
|
||||
device->name = strdup(name);
|
||||
device->description = descr1 ?
|
||||
soundio_alloc_sprintf(nullptr, "%s: %s", descr, descr1) : strdup(descr);
|
||||
device->is_raw = false;
|
||||
|
||||
if (!device->name || !device->description) {
|
||||
soundio_device_unref(device);
|
||||
free(name);
|
||||
free(descr);
|
||||
destroy(devices_info);
|
||||
snd_device_name_free_hint(hints);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
|
||||
// TODO: device->channel_layout
|
||||
// TODO: device->default_sample_format
|
||||
// TODO: device->default_latency
|
||||
// TODO: device->default_sample_rate
|
||||
|
||||
SoundIoList<SoundIoDevice *> *device_list;
|
||||
if (stream == SND_PCM_STREAM_PLAYBACK) {
|
||||
device->purpose = SoundIoDevicePurposeOutput;
|
||||
device_list = &devices_info->output_devices;
|
||||
if (str_has_prefix(name, "default:"))
|
||||
devices_info->default_output_index = device_list->length;
|
||||
} else {
|
||||
assert(stream == SND_PCM_STREAM_CAPTURE);
|
||||
device->purpose = SoundIoDevicePurposeInput;
|
||||
device_list = &devices_info->input_devices;
|
||||
if (str_has_prefix(name, "default:"))
|
||||
devices_info->default_input_index = device_list->length;
|
||||
}
|
||||
|
||||
if (device_list->append(device)) {
|
||||
soundio_device_unref(device);
|
||||
free(name);
|
||||
free(descr);
|
||||
destroy(devices_info);
|
||||
snd_device_name_free_hint(hints);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
}
|
||||
|
||||
free(name);
|
||||
free(descr);
|
||||
}
|
||||
|
||||
snd_device_name_free_hint(hints);
|
||||
|
||||
int card_index = -1;
|
||||
|
||||
if (snd_card_next(&card_index) < 0)
|
||||
|
@ -83,10 +220,6 @@ static int refresh_devices(SoundIo *soundio) {
|
|||
snd_pcm_info_t *pcm_info;
|
||||
snd_pcm_info_alloca(&pcm_info);
|
||||
|
||||
SoundIoDevicesInfo *devices_info = create<SoundIoDevicesInfo>();
|
||||
if (!devices_info)
|
||||
return SoundIoErrorNoMem;
|
||||
|
||||
while (card_index >= 0) {
|
||||
int err;
|
||||
snd_ctl_t *handle;
|
||||
|
@ -145,8 +278,9 @@ static int refresh_devices(SoundIo *soundio) {
|
|||
}
|
||||
device->ref_count = 1;
|
||||
device->soundio = soundio;
|
||||
device->name = soundio_alloc_sprintf(nullptr, "hw:%d,%d,%d", card_index, device_index, 0);
|
||||
device->name = soundio_alloc_sprintf(nullptr, "hw:%d,%d", card_index, device_index);
|
||||
device->description = soundio_alloc_sprintf(nullptr, "%s %s", card_name, device_name);
|
||||
device->is_raw = true;
|
||||
|
||||
if (!device->name || !device->description) {
|
||||
soundio_device_unref(device);
|
||||
|
|
|
@ -120,6 +120,7 @@ struct SoundIoDevice {
|
|||
int default_sample_rate;
|
||||
enum SoundIoDevicePurpose purpose;
|
||||
int ref_count;
|
||||
bool is_raw;
|
||||
};
|
||||
|
||||
struct SoundIoOutputDevice {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#define SOUNDIO_UTIL_HPP
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <new>
|
||||
|
||||
|
@ -103,4 +104,8 @@ static inline T min(T a, T b) {
|
|||
return (a <= b) ? a : b;
|
||||
}
|
||||
|
||||
static inline bool str_has_prefix(const char *big_str, const char *prefix) {
|
||||
return strncmp(big_str, prefix, strlen(prefix)) == 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue