mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-22 17:55:37 +00:00
sine example works with JACK
This commit is contained in:
parent
70decb39f5
commit
6df84096f3
|
@ -232,7 +232,7 @@ view `coverage/index.html` in a browser.
|
|||
|
||||
## Roadmap
|
||||
|
||||
0. implement JACK backend, get examples working
|
||||
0. JACK: input
|
||||
0. Steal PulseAudio's default channel maps per channel count
|
||||
0. Ability to parse PulseAudio's "front-left" "front-right" channel label strings
|
||||
0. When two soundio clients are talking to each other, use port names to
|
||||
|
@ -280,10 +280,10 @@ view `coverage/index.html` in a browser.
|
|||
0. Support PulseAudio proplist properties for main context and streams
|
||||
0. custom allocator support
|
||||
0. mlock memory which is accessed in the real time path
|
||||
0. Consider testing on FreeBSD
|
||||
0. make rtprio warning a callback and have existing behavior be the default callback
|
||||
0. write detailed docs on buffer underflows explaining when they occur, what state
|
||||
changes are related to them, and how to recover from them.
|
||||
0. Consider testing on FreeBSD
|
||||
|
||||
## Planned Uses for libsoundio
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ int main(int argc, char **argv) {
|
|||
if (!device)
|
||||
panic("out of memory");
|
||||
|
||||
fprintf(stderr, "Output device: %s: %s\n", device->name, device->description);
|
||||
fprintf(stderr, "Output device: %s\n", device->description);
|
||||
|
||||
struct SoundIoOutStream *outstream = soundio_outstream_create(device);
|
||||
outstream->format = SoundIoFormatFloat32NE;
|
||||
|
|
10
src/alsa.cpp
10
src/alsa.cpp
|
@ -530,14 +530,15 @@ static int refresh_devices(SoundIoPrivate *si) {
|
|||
}
|
||||
|
||||
|
||||
SoundIoDevice *device = create<SoundIoDevice>();
|
||||
if (!device) {
|
||||
SoundIoDevicePrivate *dev = create<SoundIoDevicePrivate>();
|
||||
if (!dev) {
|
||||
free(name);
|
||||
free(descr);
|
||||
destroy(devices_info);
|
||||
snd_device_name_free_hint(hints);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
SoundIoDevice *device = &dev->pub;
|
||||
device->ref_count = 1;
|
||||
device->soundio = soundio;
|
||||
device->is_raw = false;
|
||||
|
@ -647,12 +648,13 @@ static int refresh_devices(SoundIoPrivate *si) {
|
|||
|
||||
const char *device_name = snd_pcm_info_get_name(pcm_info);
|
||||
|
||||
SoundIoDevice *device = create<SoundIoDevice>();
|
||||
if (!device) {
|
||||
SoundIoDevicePrivate *dev = create<SoundIoDevicePrivate>();
|
||||
if (!dev) {
|
||||
snd_ctl_close(handle);
|
||||
destroy(devices_info);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
SoundIoDevice *device = &dev->pub;
|
||||
device->ref_count = 1;
|
||||
device->soundio = soundio;
|
||||
device->name = soundio_alloc_sprintf(nullptr, "hw:%d,%d", card_index, device_index);
|
||||
|
|
|
@ -410,3 +410,8 @@ const struct SoundIoChannelLayout *soundio_channel_layout_get_default(int channe
|
|||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
enum SoundIoChannelId soundio_parse_channel_id(const char *str, int str_len) {
|
||||
// TODO actually parse
|
||||
return SoundIoChannelIdInvalid;
|
||||
}
|
||||
|
|
|
@ -434,11 +434,12 @@ int soundio_dummy_init(SoundIoPrivate *si) {
|
|||
|
||||
// create output device
|
||||
{
|
||||
SoundIoDevice *device = create<SoundIoDevice>();
|
||||
if (!device) {
|
||||
SoundIoDevicePrivate *dev = create<SoundIoDevicePrivate>();
|
||||
if (!dev) {
|
||||
destroy_dummy(si);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
SoundIoDevice *device = &dev->pub;
|
||||
|
||||
device->ref_count = 1;
|
||||
device->soundio = soundio;
|
||||
|
@ -482,11 +483,12 @@ int soundio_dummy_init(SoundIoPrivate *si) {
|
|||
|
||||
// create input device
|
||||
{
|
||||
SoundIoDevice *device = create<SoundIoDevice>();
|
||||
if (!device) {
|
||||
SoundIoDevicePrivate *dev = create<SoundIoDevicePrivate>();
|
||||
if (!dev) {
|
||||
destroy_dummy(si);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
SoundIoDevice *device = &dev->pub;
|
||||
|
||||
device->ref_count = 1;
|
||||
device->soundio = soundio;
|
||||
|
|
159
src/jack.cpp
159
src/jack.cpp
|
@ -15,8 +15,11 @@
|
|||
static atomic_flag global_msg_callback_flag = ATOMIC_FLAG_INIT;
|
||||
|
||||
struct SoundIoJackPort {
|
||||
const char *full_name;
|
||||
int full_name_len;
|
||||
const char *name;
|
||||
int name_len;
|
||||
SoundIoChannelId channel_id;
|
||||
};
|
||||
|
||||
struct SoundIoJackClient {
|
||||
|
@ -24,8 +27,8 @@ struct SoundIoJackClient {
|
|||
int name_len;
|
||||
bool is_physical;
|
||||
SoundIoDevicePurpose purpose;
|
||||
SoundIoJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||
int port_count;
|
||||
SoundIoJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
static void flush_events_jack(struct SoundIoPrivate *si) {
|
||||
|
@ -80,17 +83,31 @@ static void outstream_destroy_jack(struct SoundIoPrivate *is, struct SoundIoOutS
|
|||
jack_client_close(osj->client);
|
||||
}
|
||||
|
||||
static SoundIoDeviceJackPort *find_port_matching_channel(SoundIoDevice *device, SoundIoChannelId id) {
|
||||
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
||||
SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
||||
|
||||
for (int ch = 0; ch < device->current_layout.channel_count; ch += 1) {
|
||||
SoundIoChannelId chan_id = device->current_layout.channels[ch];
|
||||
if (chan_id == id)
|
||||
return &dj->ports[ch];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||
SoundIoOutStream *outstream = &os->pub;
|
||||
//TODO SoundIoDevice *device = outstream->device;
|
||||
SoundIoDevice *device = outstream->device;
|
||||
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
||||
SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
||||
|
||||
|
||||
outstream->buffer_duration = 0.0; // TODO
|
||||
outstream->period_duration = 0.0; // TODO
|
||||
outstream->prebuf_duration = 0.0; // TODO
|
||||
|
||||
outstream->layout_error = SoundIoErrorIncompatibleBackend;
|
||||
|
||||
jack_status_t status;
|
||||
osj->client = jack_client_open(outstream->name, JackNoStartServer, &status);
|
||||
if (!osj->client) {
|
||||
|
@ -111,18 +128,41 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
|
|||
// TODO register the other callbacks and emit a stream error if they're called
|
||||
|
||||
|
||||
// register ports
|
||||
// register ports and map channels
|
||||
int connected_count = 0;
|
||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||
const char *channel_name = soundio_get_channel_name(outstream->layout.channels[ch]);
|
||||
SoundIoChannelId my_channel_id = outstream->layout.channels[ch];
|
||||
const char *channel_name = soundio_get_channel_name(my_channel_id);
|
||||
unsigned long flags = JackPortIsOutput;
|
||||
if (!outstream->non_terminal_hint)
|
||||
flags |= JackPortIsTerminal;
|
||||
jack_port_t *port = jack_port_register(osj->client, channel_name, JACK_DEFAULT_AUDIO_TYPE, flags, 0);
|
||||
if (!port) {
|
||||
jack_port_t *jport = jack_port_register(osj->client, channel_name, JACK_DEFAULT_AUDIO_TYPE, flags, 0);
|
||||
if (!jport) {
|
||||
outstream_destroy_jack(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
osj->ports[ch] = port;
|
||||
SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
||||
osjp->source_port = jport;
|
||||
// figure out which dest port this connects to
|
||||
SoundIoDeviceJackPort *djp = find_port_matching_channel(device, my_channel_id);
|
||||
if (djp) {
|
||||
osjp->dest_port_name = djp->full_name;
|
||||
osjp->dest_port_name_len = djp->full_name_len;
|
||||
connected_count += 1;
|
||||
}
|
||||
}
|
||||
// If nothing got connected, channel layouts aren't working. Just send the
|
||||
// data in the order of the ports.
|
||||
if (connected_count == 0) {
|
||||
outstream->layout_error = SoundIoErrorIncompatibleDevice;
|
||||
|
||||
int ch_count = min(outstream->layout.channel_count, dj->port_count);
|
||||
for (int ch = 0; ch < ch_count; ch += 1) {
|
||||
SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
||||
SoundIoDeviceJackPort *djp = &dj->ports[ch];
|
||||
osjp->dest_port_name = djp->full_name;
|
||||
osjp->dest_port_name_len = djp->full_name_len;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -131,6 +171,9 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
|
|||
static int outstream_pause_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||
SoundIoOutStream *outstream = &os->pub;
|
||||
// TODO SoundIoDevice *device = outstream->device;
|
||||
// TODO SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
||||
// TODO SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
||||
int err;
|
||||
if (pause) {
|
||||
if ((err = jack_deactivate(osj->client)))
|
||||
|
@ -140,9 +183,14 @@ static int outstream_pause_jack(struct SoundIoPrivate *si, struct SoundIoOutStre
|
|||
return SoundIoErrorStreaming;
|
||||
|
||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||
// TODO figure out source port name and dest port name
|
||||
//if ((err = jack_connect(osj->client, source_port, dest_port)))
|
||||
// return SoundIoErrorStreaming;
|
||||
SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
||||
const char *dest_port_name = osjp->dest_port_name;
|
||||
// allow unconnected ports
|
||||
if (!dest_port_name)
|
||||
continue;
|
||||
const char *source_port_name = jack_port_name(osjp->source_port);
|
||||
if ((err = jack_connect(osj->client, source_port_name, dest_port_name)))
|
||||
return SoundIoErrorStreaming;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,14 +201,29 @@ static int outstream_start_jack(struct SoundIoPrivate *si, struct SoundIoOutStre
|
|||
return outstream_pause_jack(si, os, false);
|
||||
}
|
||||
|
||||
static int outstream_begin_write_jack(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *,
|
||||
static int outstream_begin_write_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
||||
SoundIoChannelArea **out_areas, int *frame_count)
|
||||
{
|
||||
soundio_panic("TODO begin write");
|
||||
SoundIoOutStream *outstream = &os->pub;
|
||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||
SoundIoJack *sij = &si->backend_data.jack;
|
||||
assert(*frame_count <= sij->buffer_size);
|
||||
|
||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||
SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
||||
if (!(osj->areas[ch].ptr = (char*)jack_port_get_buffer(osjp->source_port, *frame_count)))
|
||||
return SoundIoErrorStreaming;
|
||||
|
||||
osj->areas[ch].step = outstream->bytes_per_sample;
|
||||
}
|
||||
|
||||
*out_areas = osj->areas;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outstream_end_write_jack(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, int frame_count) {
|
||||
soundio_panic("TODO end write");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outstream_clear_buffer_jack(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *) {
|
||||
|
@ -250,6 +313,15 @@ static char *dupe_str(const char *str, int str_len) {
|
|||
return out;
|
||||
}
|
||||
|
||||
static void destruct_device(SoundIoDevicePrivate *dp) {
|
||||
SoundIoDeviceJack *dj = &dp->backend_data.jack;
|
||||
for (int i = 0; i < dj->port_count; i += 1) {
|
||||
SoundIoDeviceJackPort *djp = &dj->ports[i];
|
||||
destroy(djp->full_name);
|
||||
}
|
||||
deallocate(dj->ports, dj->port_count);
|
||||
}
|
||||
|
||||
static int refresh_devices(SoundIoPrivate *si) {
|
||||
SoundIo *soundio = &si->pub;
|
||||
SoundIoJack *sij = &si->backend_data.jack;
|
||||
|
@ -270,6 +342,7 @@ static int refresh_devices(SoundIoPrivate *si) {
|
|||
const char **port_name_ptr = port_names;
|
||||
while (*port_name_ptr) {
|
||||
const char *client_and_port_name = *port_name_ptr;
|
||||
int client_and_port_name_len = strlen(client_and_port_name);
|
||||
jack_port_t *jport = jack_port_by_name(sij->client, client_and_port_name);
|
||||
int flags = jack_port_flags(jport);
|
||||
|
||||
|
@ -287,7 +360,7 @@ static int refresh_devices(SoundIoPrivate *si) {
|
|||
const char *port_name = nullptr;
|
||||
int client_name_len;
|
||||
int port_name_len;
|
||||
split_str(client_and_port_name, strlen(client_and_port_name), ':',
|
||||
split_str(client_and_port_name, client_and_port_name_len, ':',
|
||||
&client_name, &client_name_len, &port_name, &port_name_len);
|
||||
if (!client_name || !port_name) {
|
||||
// device does not have colon, skip it
|
||||
|
@ -305,9 +378,11 @@ static int refresh_devices(SoundIoPrivate *si) {
|
|||
continue;
|
||||
}
|
||||
SoundIoJackPort *port = &client->ports[client->port_count++];
|
||||
port->full_name = client_and_port_name;
|
||||
port->full_name_len = client_and_port_name_len;
|
||||
port->name = port_name;
|
||||
port->name_len = port_name_len;
|
||||
|
||||
port->channel_id = soundio_parse_channel_id(port_name, port_name_len);
|
||||
|
||||
port_name_ptr += 1;
|
||||
}
|
||||
|
@ -317,18 +392,22 @@ static int refresh_devices(SoundIoPrivate *si) {
|
|||
if (client->port_count <= 0)
|
||||
continue;
|
||||
|
||||
SoundIoDevice *device = create<SoundIoDevice>();
|
||||
if (!device) {
|
||||
SoundIoDevicePrivate *dev = create<SoundIoDevicePrivate>();
|
||||
if (!dev) {
|
||||
jack_free(port_names);
|
||||
destroy(devices_info);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
SoundIoDevice *device = &dev->pub;
|
||||
SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
||||
int description_len = client->name_len + 3 + 2 * client->port_count;
|
||||
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
||||
SoundIoJackPort *port = &client->ports[port_index];
|
||||
description_len += port->name_len;
|
||||
}
|
||||
|
||||
dev->destruct = destruct_device;
|
||||
|
||||
device->ref_count = 1;
|
||||
device->soundio = soundio;
|
||||
device->is_raw = false;
|
||||
|
@ -346,14 +425,31 @@ static int refresh_devices(SoundIoPrivate *si) {
|
|||
device->buffer_duration_min = sij->buffer_size / (double) sij->sample_rate;
|
||||
device->buffer_duration_max = device->buffer_duration_min;
|
||||
device->buffer_duration_current = device->buffer_duration_min;
|
||||
dj->port_count = client->port_count;
|
||||
dj->ports = allocate<SoundIoDeviceJackPort>(dj->port_count);
|
||||
|
||||
if (!device->name || !device->description || !device->layouts || !device->formats) {
|
||||
if (!device->name || !device->description || !device->layouts || !device->formats || !dj->ports) {
|
||||
jack_free(port_names);
|
||||
soundio_device_unref(device);
|
||||
destroy(devices_info);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
|
||||
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
||||
SoundIoJackPort *port = &client->ports[port_index];
|
||||
SoundIoDeviceJackPort *djp = &dj->ports[port_index];
|
||||
djp->full_name = dupe_str(port->full_name, port->full_name_len);
|
||||
djp->full_name_len = port->full_name_len;
|
||||
djp->channel_id = port->channel_id;
|
||||
|
||||
if (!djp->full_name) {
|
||||
jack_free(port_names);
|
||||
soundio_device_unref(device);
|
||||
destroy(devices_info);
|
||||
return SoundIoErrorNoMem;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(device->description, client->name, client->name_len);
|
||||
memcpy(&device->description[client->name_len], ": ", 2);
|
||||
int index = client->name_len + 2;
|
||||
|
@ -367,12 +463,19 @@ static int refresh_devices(SoundIoPrivate *si) {
|
|||
}
|
||||
}
|
||||
|
||||
const struct SoundIoChannelLayout *layout = soundio_channel_layout_get_default(client->port_count);
|
||||
if (layout) {
|
||||
device->current_layout = *layout;
|
||||
device->current_layout.channel_count = client->port_count;
|
||||
bool any_invalid = false;
|
||||
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
||||
SoundIoJackPort *port = &client->ports[port_index];
|
||||
device->current_layout.channels[port_index] = port->channel_id;
|
||||
any_invalid = any_invalid || (port->channel_id == SoundIoChannelIdInvalid);
|
||||
}
|
||||
if (any_invalid) {
|
||||
const struct SoundIoChannelLayout *layout = soundio_channel_layout_get_default(client->port_count);
|
||||
if (layout)
|
||||
device->current_layout = *layout;
|
||||
} else {
|
||||
for (int port_index = 0; port_index < client->port_count; port_index += 1)
|
||||
device->current_layout.channels[port_index] = SoundIoChannelIdInvalid;
|
||||
soundio_channel_layout_detect_builtin(&device->current_layout);
|
||||
}
|
||||
|
||||
device->layouts[0] = device->current_layout;
|
||||
|
@ -434,11 +537,11 @@ static int sample_rate_callback(jack_nframes_t nframes, void *arg) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* TODO
|
||||
static int xrun_callback(void *arg) {
|
||||
//SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
||||
soundio_panic("TODO xrun callback");
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
static void port_registration_callback(jack_port_id_t port_id, int reg, void *arg) {
|
||||
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
||||
|
@ -529,10 +632,12 @@ int soundio_jack_init(struct SoundIoPrivate *si) {
|
|||
destroy_jack(si);
|
||||
return SoundIoErrorInitAudioBackend;
|
||||
}
|
||||
/* TODO
|
||||
if ((err = jack_set_xrun_callback(sij->client, xrun_callback, si))) {
|
||||
destroy_jack(si);
|
||||
return SoundIoErrorInitAudioBackend;
|
||||
}
|
||||
*/
|
||||
if ((err = jack_set_port_registration_callback(sij->client, port_registration_callback, si))) {
|
||||
destroy_jack(si);
|
||||
return SoundIoErrorInitAudioBackend;
|
||||
|
|
18
src/jack.hpp
18
src/jack.hpp
|
@ -15,8 +15,15 @@
|
|||
|
||||
int soundio_jack_init(struct SoundIoPrivate *si);
|
||||
|
||||
struct SoundIoDeviceJack {
|
||||
struct SoundIoDeviceJackPort {
|
||||
char *full_name;
|
||||
int full_name_len;
|
||||
SoundIoChannelId channel_id;
|
||||
};
|
||||
|
||||
struct SoundIoDeviceJack {
|
||||
int port_count;
|
||||
SoundIoDeviceJackPort *ports;
|
||||
};
|
||||
|
||||
struct SoundIoJack {
|
||||
|
@ -30,9 +37,16 @@ struct SoundIoJack {
|
|||
int buffer_size;
|
||||
};
|
||||
|
||||
struct SoundIoOutStreamJackPort {
|
||||
jack_port_t *source_port;
|
||||
const char *dest_port_name;
|
||||
int dest_port_name_len;
|
||||
};
|
||||
|
||||
struct SoundIoOutStreamJack {
|
||||
jack_client_t *client;
|
||||
jack_port_t *ports[SOUNDIO_MAX_CHANNELS];
|
||||
SoundIoOutStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct SoundIoInStreamJack {
|
||||
|
|
|
@ -256,9 +256,10 @@ static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *in
|
|||
sipa->have_sink_list = true;
|
||||
finish_device_query(si);
|
||||
} else {
|
||||
SoundIoDevice *device = create<SoundIoDevice>();
|
||||
if (!device)
|
||||
SoundIoDevicePrivate *dev = create<SoundIoDevicePrivate>();
|
||||
if (!dev)
|
||||
soundio_panic("out of memory");
|
||||
SoundIoDevice *device = &dev->pub;
|
||||
|
||||
device->ref_count = 1;
|
||||
device->soundio = soundio;
|
||||
|
@ -306,9 +307,10 @@ static void source_info_callback(pa_context *pulse_context, const pa_source_info
|
|||
sipa->have_source_list = true;
|
||||
finish_device_query(si);
|
||||
} else {
|
||||
SoundIoDevice *device = create<SoundIoDevice>();
|
||||
if (!device)
|
||||
SoundIoDevicePrivate *dev = create<SoundIoDevicePrivate>();
|
||||
if (!dev)
|
||||
soundio_panic("out of memory");
|
||||
SoundIoDevice *device = &dev->pub;
|
||||
|
||||
device->ref_count = 1;
|
||||
device->soundio = soundio;
|
||||
|
|
|
@ -295,11 +295,16 @@ void soundio_device_unref(struct SoundIoDevice *device) {
|
|||
assert(device->ref_count >= 0);
|
||||
|
||||
if (device->ref_count == 0) {
|
||||
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
||||
if (dev->destruct)
|
||||
dev->destruct(dev);
|
||||
|
||||
free(device->name);
|
||||
free(device->description);
|
||||
deallocate(device->formats, device->format_count);
|
||||
deallocate(device->layouts, device->layout_count);
|
||||
destroy(device);
|
||||
|
||||
destroy(dev);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -494,6 +494,10 @@ bool soundio_channel_layout_equal(
|
|||
const struct SoundIoChannelLayout *b);
|
||||
|
||||
const char *soundio_get_channel_name(enum SoundIoChannelId id);
|
||||
// Given UTF-8 encoded text which is the name of a channel such as
|
||||
// "Front Left", "FL", or "front-left", return the corresponding
|
||||
// SoundIoChannelId. Returns SoundIoChannelIdInvalid for no match.
|
||||
enum SoundIoChannelId soundio_parse_channel_id(const char *str, int str_len);
|
||||
|
||||
int soundio_channel_layout_builtin_count(void);
|
||||
const struct SoundIoChannelLayout *soundio_channel_layout_get_builtin(int index);
|
||||
|
|
|
@ -129,6 +129,7 @@ struct SoundIoPrivate {
|
|||
struct SoundIoDevicePrivate {
|
||||
SoundIoDevice pub;
|
||||
SoundIoDeviceBackendData backend_data;
|
||||
void (*destruct)(SoundIoDevicePrivate *);
|
||||
};
|
||||
|
||||
void soundio_destroy_devices_info(struct SoundIoDevicesInfo *devices_info);
|
||||
|
|
Loading…
Reference in a new issue