mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-23 03:45:31 +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
|
## Roadmap
|
||||||
|
|
||||||
0. implement JACK backend, get examples working
|
0. JACK: input
|
||||||
0. Steal PulseAudio's default channel maps per channel count
|
0. Steal PulseAudio's default channel maps per channel count
|
||||||
0. Ability to parse PulseAudio's "front-left" "front-right" channel label strings
|
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
|
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. Support PulseAudio proplist properties for main context and streams
|
||||||
0. custom allocator support
|
0. custom allocator support
|
||||||
0. mlock memory which is accessed in the real time path
|
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. 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
|
0. write detailed docs on buffer underflows explaining when they occur, what state
|
||||||
changes are related to them, and how to recover from them.
|
changes are related to them, and how to recover from them.
|
||||||
|
0. Consider testing on FreeBSD
|
||||||
|
|
||||||
## Planned Uses for libsoundio
|
## Planned Uses for libsoundio
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@ int main(int argc, char **argv) {
|
||||||
if (!device)
|
if (!device)
|
||||||
panic("out of memory");
|
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);
|
struct SoundIoOutStream *outstream = soundio_outstream_create(device);
|
||||||
outstream->format = SoundIoFormatFloat32NE;
|
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>();
|
SoundIoDevicePrivate *dev = create<SoundIoDevicePrivate>();
|
||||||
if (!device) {
|
if (!dev) {
|
||||||
free(name);
|
free(name);
|
||||||
free(descr);
|
free(descr);
|
||||||
destroy(devices_info);
|
destroy(devices_info);
|
||||||
snd_device_name_free_hint(hints);
|
snd_device_name_free_hint(hints);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
SoundIoDevice *device = &dev->pub;
|
||||||
device->ref_count = 1;
|
device->ref_count = 1;
|
||||||
device->soundio = soundio;
|
device->soundio = soundio;
|
||||||
device->is_raw = false;
|
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);
|
const char *device_name = snd_pcm_info_get_name(pcm_info);
|
||||||
|
|
||||||
SoundIoDevice *device = create<SoundIoDevice>();
|
SoundIoDevicePrivate *dev = create<SoundIoDevicePrivate>();
|
||||||
if (!device) {
|
if (!dev) {
|
||||||
snd_ctl_close(handle);
|
snd_ctl_close(handle);
|
||||||
destroy(devices_info);
|
destroy(devices_info);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
SoundIoDevice *device = &dev->pub;
|
||||||
device->ref_count = 1;
|
device->ref_count = 1;
|
||||||
device->soundio = soundio;
|
device->soundio = soundio;
|
||||||
device->name = soundio_alloc_sprintf(nullptr, "hw:%d,%d", card_index, device_index);
|
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;
|
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
|
// create output device
|
||||||
{
|
{
|
||||||
SoundIoDevice *device = create<SoundIoDevice>();
|
SoundIoDevicePrivate *dev = create<SoundIoDevicePrivate>();
|
||||||
if (!device) {
|
if (!dev) {
|
||||||
destroy_dummy(si);
|
destroy_dummy(si);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
SoundIoDevice *device = &dev->pub;
|
||||||
|
|
||||||
device->ref_count = 1;
|
device->ref_count = 1;
|
||||||
device->soundio = soundio;
|
device->soundio = soundio;
|
||||||
|
@ -482,11 +483,12 @@ int soundio_dummy_init(SoundIoPrivate *si) {
|
||||||
|
|
||||||
// create input device
|
// create input device
|
||||||
{
|
{
|
||||||
SoundIoDevice *device = create<SoundIoDevice>();
|
SoundIoDevicePrivate *dev = create<SoundIoDevicePrivate>();
|
||||||
if (!device) {
|
if (!dev) {
|
||||||
destroy_dummy(si);
|
destroy_dummy(si);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
SoundIoDevice *device = &dev->pub;
|
||||||
|
|
||||||
device->ref_count = 1;
|
device->ref_count = 1;
|
||||||
device->soundio = soundio;
|
device->soundio = soundio;
|
||||||
|
|
155
src/jack.cpp
155
src/jack.cpp
|
@ -15,8 +15,11 @@
|
||||||
static atomic_flag global_msg_callback_flag = ATOMIC_FLAG_INIT;
|
static atomic_flag global_msg_callback_flag = ATOMIC_FLAG_INIT;
|
||||||
|
|
||||||
struct SoundIoJackPort {
|
struct SoundIoJackPort {
|
||||||
|
const char *full_name;
|
||||||
|
int full_name_len;
|
||||||
const char *name;
|
const char *name;
|
||||||
int name_len;
|
int name_len;
|
||||||
|
SoundIoChannelId channel_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoJackClient {
|
struct SoundIoJackClient {
|
||||||
|
@ -24,8 +27,8 @@ struct SoundIoJackClient {
|
||||||
int name_len;
|
int name_len;
|
||||||
bool is_physical;
|
bool is_physical;
|
||||||
SoundIoDevicePurpose purpose;
|
SoundIoDevicePurpose purpose;
|
||||||
SoundIoJackPort ports[SOUNDIO_MAX_CHANNELS];
|
|
||||||
int port_count;
|
int port_count;
|
||||||
|
SoundIoJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
static void flush_events_jack(struct SoundIoPrivate *si) {
|
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);
|
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) {
|
static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
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->buffer_duration = 0.0; // TODO
|
||||||
outstream->period_duration = 0.0; // TODO
|
outstream->period_duration = 0.0; // TODO
|
||||||
outstream->prebuf_duration = 0.0; // TODO
|
outstream->prebuf_duration = 0.0; // TODO
|
||||||
|
|
||||||
outstream->layout_error = SoundIoErrorIncompatibleBackend;
|
|
||||||
|
|
||||||
jack_status_t status;
|
jack_status_t status;
|
||||||
osj->client = jack_client_open(outstream->name, JackNoStartServer, &status);
|
osj->client = jack_client_open(outstream->name, JackNoStartServer, &status);
|
||||||
if (!osj->client) {
|
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
|
// 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) {
|
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;
|
unsigned long flags = JackPortIsOutput;
|
||||||
if (!outstream->non_terminal_hint)
|
if (!outstream->non_terminal_hint)
|
||||||
flags |= JackPortIsTerminal;
|
flags |= JackPortIsTerminal;
|
||||||
jack_port_t *port = jack_port_register(osj->client, channel_name, JACK_DEFAULT_AUDIO_TYPE, flags, 0);
|
jack_port_t *jport = jack_port_register(osj->client, channel_name, JACK_DEFAULT_AUDIO_TYPE, flags, 0);
|
||||||
if (!port) {
|
if (!jport) {
|
||||||
outstream_destroy_jack(si, os);
|
outstream_destroy_jack(si, os);
|
||||||
return SoundIoErrorOpeningDevice;
|
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;
|
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) {
|
static int outstream_pause_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
||||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
|
// TODO SoundIoDevice *device = outstream->device;
|
||||||
|
// TODO SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
||||||
|
// TODO SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
||||||
int err;
|
int err;
|
||||||
if (pause) {
|
if (pause) {
|
||||||
if ((err = jack_deactivate(osj->client)))
|
if ((err = jack_deactivate(osj->client)))
|
||||||
|
@ -140,9 +183,14 @@ static int outstream_pause_jack(struct SoundIoPrivate *si, struct SoundIoOutStre
|
||||||
return SoundIoErrorStreaming;
|
return SoundIoErrorStreaming;
|
||||||
|
|
||||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||||
// TODO figure out source port name and dest port name
|
SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
||||||
//if ((err = jack_connect(osj->client, source_port, dest_port)))
|
const char *dest_port_name = osjp->dest_port_name;
|
||||||
// return SoundIoErrorStreaming;
|
// 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);
|
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)
|
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) {
|
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 *) {
|
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;
|
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) {
|
static int refresh_devices(SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
SoundIo *soundio = &si->pub;
|
||||||
SoundIoJack *sij = &si->backend_data.jack;
|
SoundIoJack *sij = &si->backend_data.jack;
|
||||||
|
@ -270,6 +342,7 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
const char **port_name_ptr = port_names;
|
const char **port_name_ptr = port_names;
|
||||||
while (*port_name_ptr) {
|
while (*port_name_ptr) {
|
||||||
const char *client_and_port_name = *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);
|
jack_port_t *jport = jack_port_by_name(sij->client, client_and_port_name);
|
||||||
int flags = jack_port_flags(jport);
|
int flags = jack_port_flags(jport);
|
||||||
|
|
||||||
|
@ -287,7 +360,7 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
const char *port_name = nullptr;
|
const char *port_name = nullptr;
|
||||||
int client_name_len;
|
int client_name_len;
|
||||||
int port_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);
|
&client_name, &client_name_len, &port_name, &port_name_len);
|
||||||
if (!client_name || !port_name) {
|
if (!client_name || !port_name) {
|
||||||
// device does not have colon, skip it
|
// device does not have colon, skip it
|
||||||
|
@ -305,9 +378,11 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SoundIoJackPort *port = &client->ports[client->port_count++];
|
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 = port_name;
|
||||||
port->name_len = port_name_len;
|
port->name_len = port_name_len;
|
||||||
|
port->channel_id = soundio_parse_channel_id(port_name, port_name_len);
|
||||||
|
|
||||||
port_name_ptr += 1;
|
port_name_ptr += 1;
|
||||||
}
|
}
|
||||||
|
@ -317,18 +392,22 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
if (client->port_count <= 0)
|
if (client->port_count <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SoundIoDevice *device = create<SoundIoDevice>();
|
SoundIoDevicePrivate *dev = create<SoundIoDevicePrivate>();
|
||||||
if (!device) {
|
if (!dev) {
|
||||||
jack_free(port_names);
|
jack_free(port_names);
|
||||||
destroy(devices_info);
|
destroy(devices_info);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
|
SoundIoDevice *device = &dev->pub;
|
||||||
|
SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
||||||
int description_len = client->name_len + 3 + 2 * client->port_count;
|
int description_len = client->name_len + 3 + 2 * client->port_count;
|
||||||
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
||||||
SoundIoJackPort *port = &client->ports[port_index];
|
SoundIoJackPort *port = &client->ports[port_index];
|
||||||
description_len += port->name_len;
|
description_len += port->name_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev->destruct = destruct_device;
|
||||||
|
|
||||||
device->ref_count = 1;
|
device->ref_count = 1;
|
||||||
device->soundio = soundio;
|
device->soundio = soundio;
|
||||||
device->is_raw = false;
|
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_min = sij->buffer_size / (double) sij->sample_rate;
|
||||||
device->buffer_duration_max = device->buffer_duration_min;
|
device->buffer_duration_max = device->buffer_duration_min;
|
||||||
device->buffer_duration_current = 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);
|
jack_free(port_names);
|
||||||
soundio_device_unref(device);
|
soundio_device_unref(device);
|
||||||
destroy(devices_info);
|
destroy(devices_info);
|
||||||
return SoundIoErrorNoMem;
|
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, client->name_len);
|
||||||
memcpy(&device->description[client->name_len], ": ", 2);
|
memcpy(&device->description[client->name_len], ": ", 2);
|
||||||
int index = client->name_len + 2;
|
int index = client->name_len + 2;
|
||||||
|
@ -367,12 +463,19 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
const struct SoundIoChannelLayout *layout = soundio_channel_layout_get_default(client->port_count);
|
||||||
if (layout) {
|
if (layout)
|
||||||
device->current_layout = *layout;
|
device->current_layout = *layout;
|
||||||
} else {
|
} else {
|
||||||
for (int port_index = 0; port_index < client->port_count; port_index += 1)
|
soundio_channel_layout_detect_builtin(&device->current_layout);
|
||||||
device->current_layout.channels[port_index] = SoundIoChannelIdInvalid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
device->layouts[0] = 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO
|
||||||
static int xrun_callback(void *arg) {
|
static int xrun_callback(void *arg) {
|
||||||
//SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
|
||||||
soundio_panic("TODO xrun callback");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
static void port_registration_callback(jack_port_id_t port_id, int reg, void *arg) {
|
static void port_registration_callback(jack_port_id_t port_id, int reg, void *arg) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
||||||
|
@ -529,10 +632,12 @@ int soundio_jack_init(struct SoundIoPrivate *si) {
|
||||||
destroy_jack(si);
|
destroy_jack(si);
|
||||||
return SoundIoErrorInitAudioBackend;
|
return SoundIoErrorInitAudioBackend;
|
||||||
}
|
}
|
||||||
|
/* TODO
|
||||||
if ((err = jack_set_xrun_callback(sij->client, xrun_callback, si))) {
|
if ((err = jack_set_xrun_callback(sij->client, xrun_callback, si))) {
|
||||||
destroy_jack(si);
|
destroy_jack(si);
|
||||||
return SoundIoErrorInitAudioBackend;
|
return SoundIoErrorInitAudioBackend;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if ((err = jack_set_port_registration_callback(sij->client, port_registration_callback, si))) {
|
if ((err = jack_set_port_registration_callback(sij->client, port_registration_callback, si))) {
|
||||||
destroy_jack(si);
|
destroy_jack(si);
|
||||||
return SoundIoErrorInitAudioBackend;
|
return SoundIoErrorInitAudioBackend;
|
||||||
|
|
18
src/jack.hpp
18
src/jack.hpp
|
@ -15,8 +15,15 @@
|
||||||
|
|
||||||
int soundio_jack_init(struct SoundIoPrivate *si);
|
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 {
|
struct SoundIoJack {
|
||||||
|
@ -30,9 +37,16 @@ struct SoundIoJack {
|
||||||
int buffer_size;
|
int buffer_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SoundIoOutStreamJackPort {
|
||||||
|
jack_port_t *source_port;
|
||||||
|
const char *dest_port_name;
|
||||||
|
int dest_port_name_len;
|
||||||
|
};
|
||||||
|
|
||||||
struct SoundIoOutStreamJack {
|
struct SoundIoOutStreamJack {
|
||||||
jack_client_t *client;
|
jack_client_t *client;
|
||||||
jack_port_t *ports[SOUNDIO_MAX_CHANNELS];
|
SoundIoOutStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||||
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoInStreamJack {
|
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;
|
sipa->have_sink_list = true;
|
||||||
finish_device_query(si);
|
finish_device_query(si);
|
||||||
} else {
|
} else {
|
||||||
SoundIoDevice *device = create<SoundIoDevice>();
|
SoundIoDevicePrivate *dev = create<SoundIoDevicePrivate>();
|
||||||
if (!device)
|
if (!dev)
|
||||||
soundio_panic("out of memory");
|
soundio_panic("out of memory");
|
||||||
|
SoundIoDevice *device = &dev->pub;
|
||||||
|
|
||||||
device->ref_count = 1;
|
device->ref_count = 1;
|
||||||
device->soundio = soundio;
|
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;
|
sipa->have_source_list = true;
|
||||||
finish_device_query(si);
|
finish_device_query(si);
|
||||||
} else {
|
} else {
|
||||||
SoundIoDevice *device = create<SoundIoDevice>();
|
SoundIoDevicePrivate *dev = create<SoundIoDevicePrivate>();
|
||||||
if (!device)
|
if (!dev)
|
||||||
soundio_panic("out of memory");
|
soundio_panic("out of memory");
|
||||||
|
SoundIoDevice *device = &dev->pub;
|
||||||
|
|
||||||
device->ref_count = 1;
|
device->ref_count = 1;
|
||||||
device->soundio = soundio;
|
device->soundio = soundio;
|
||||||
|
|
|
@ -295,11 +295,16 @@ void soundio_device_unref(struct SoundIoDevice *device) {
|
||||||
assert(device->ref_count >= 0);
|
assert(device->ref_count >= 0);
|
||||||
|
|
||||||
if (device->ref_count == 0) {
|
if (device->ref_count == 0) {
|
||||||
|
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
||||||
|
if (dev->destruct)
|
||||||
|
dev->destruct(dev);
|
||||||
|
|
||||||
free(device->name);
|
free(device->name);
|
||||||
free(device->description);
|
free(device->description);
|
||||||
deallocate(device->formats, device->format_count);
|
deallocate(device->formats, device->format_count);
|
||||||
deallocate(device->layouts, device->layout_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 struct SoundIoChannelLayout *b);
|
||||||
|
|
||||||
const char *soundio_get_channel_name(enum SoundIoChannelId id);
|
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);
|
int soundio_channel_layout_builtin_count(void);
|
||||||
const struct SoundIoChannelLayout *soundio_channel_layout_get_builtin(int index);
|
const struct SoundIoChannelLayout *soundio_channel_layout_get_builtin(int index);
|
||||||
|
|
|
@ -129,6 +129,7 @@ struct SoundIoPrivate {
|
||||||
struct SoundIoDevicePrivate {
|
struct SoundIoDevicePrivate {
|
||||||
SoundIoDevice pub;
|
SoundIoDevice pub;
|
||||||
SoundIoDeviceBackendData backend_data;
|
SoundIoDeviceBackendData backend_data;
|
||||||
|
void (*destruct)(SoundIoDevicePrivate *);
|
||||||
};
|
};
|
||||||
|
|
||||||
void soundio_destroy_devices_info(struct SoundIoDevicesInfo *devices_info);
|
void soundio_destroy_devices_info(struct SoundIoDevicesInfo *devices_info);
|
||||||
|
|
Loading…
Reference in a new issue