mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-22 18:45:29 +00:00
microphone example works with JACK
This commit is contained in:
parent
1eca206a24
commit
754343bba6
27
README.md
27
README.md
|
@ -1,14 +1,21 @@
|
|||
# libsoundio
|
||||
|
||||
C library which provides cross-platform audio input and output. The API is
|
||||
C99 library providing cross-platform audio input and output. The API is
|
||||
suitable for real-time software such as digital audio workstations as well
|
||||
as consumer software such as music players.
|
||||
|
||||
This library is an abstraction; however it prioritizes performance and power
|
||||
over API convenience. Features that only exist in some sound backends are
|
||||
exposed.
|
||||
This library is an abstraction; however in the delicate balance between
|
||||
performance and power, and API convenience, the scale is tipped closer to
|
||||
the former. Features that only exist in some sound backends are exposed.
|
||||
|
||||
**This library is a work-in-progress.**
|
||||
The goal of this library is to be the only resource needed to implement top
|
||||
quality audio playback and capture on desktop and laptop systems. This
|
||||
includes detailed documentation explaining how audio works on each supported
|
||||
backend, how they are abstracted to provide the libsoundio API, and what
|
||||
assumptions you can and cannot make in order to guarantee consistent, reliable
|
||||
behavior on every platform.
|
||||
|
||||
**This project is a work-in-progress.**
|
||||
|
||||
## Features and Limitations
|
||||
|
||||
|
@ -16,18 +23,20 @@ exposed.
|
|||
- [PulseAudio](http://www.freedesktop.org/wiki/Software/PulseAudio/)
|
||||
- [ALSA](http://www.alsa-project.org/)
|
||||
- Dummy (silence)
|
||||
- (planned) [JACK](http://jackaudio.org/)
|
||||
- [JACK](http://jackaudio.org/)
|
||||
- (planned) [CoreAudio](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/CoreAudioOverview/Introduction/Introduction.html)
|
||||
- (planned) [WASAPI](https://msdn.microsoft.com/en-us/library/windows/desktop/dd371455%28v=vs.85%29.aspx)
|
||||
- (planned) [ASIO](http://www.asio4all.com/)
|
||||
* C library. Depends only on the respective backend API libraries and libc.
|
||||
Does *not* depend on libstdc++, and does *not* have exceptions, run-time type
|
||||
information, or [setjmp](http://latentcontent.net/2007/12/05/libpng-worst-api-ever/).
|
||||
* Does not write anything to stdio. I'm looking at you,
|
||||
[PortAudio](http://www.portaudio.com/).
|
||||
* Errors are communicated via return codes, not logging to stdio. This is one
|
||||
of my many complaints against [PortAudio](http://www.portaudio.com/).
|
||||
* Supports channel layouts (also known as channel maps), important for
|
||||
surround sound applications.
|
||||
* Ability to monitor devices and get an event when available devices change.
|
||||
* Ability to get an event when the backend is disconnected, for example when
|
||||
the JACK server or PulseAudio server shuts down.
|
||||
* Detects which input device is default and which output device is default.
|
||||
* Ability to connect to multiple backends at once. For example you could have
|
||||
an ALSA device open and a JACK device open at the same time.
|
||||
|
@ -249,6 +258,7 @@ view `coverage/index.html` in a browser.
|
|||
If not, might need to hav xrun callback set a flag and have process callback
|
||||
call the underflow callback.
|
||||
0. Detect PulseAudio server going offline and emit `on_backend_disconnect`.
|
||||
0. Instead fo open(), start(), pause(), open() starts it and it starts paused.
|
||||
0. Create a test for clearing the playback buffer and prebuffering.
|
||||
0. Create a test for pausing and resuming input and output streams.
|
||||
0. Create a test for the latency / synchronization API.
|
||||
|
@ -258,6 +268,7 @@ view `coverage/index.html` in a browser.
|
|||
- Play the audio file, have the user press an input right at the beat. Find
|
||||
out what the frame index it thinks the user pressed it at and make sure
|
||||
that is correct.
|
||||
0. Create a test for input stream overflow handling.
|
||||
0. Expose JACK options in `jack_client_open`
|
||||
0. Allow calling functions from outside the callbacks as long as they first
|
||||
call lock and then unlock when done.
|
||||
|
|
|
@ -293,7 +293,7 @@ int main(int argc, char **argv) {
|
|||
if ((err = soundio_outstream_open(outstream)))
|
||||
panic("unable to open output stream: %s", soundio_strerror(err));
|
||||
|
||||
int capacity = instream->buffer_duration * instream->sample_rate * instream->bytes_per_frame;
|
||||
int capacity = fmax(1.0, instream->buffer_duration) * instream->sample_rate * instream->bytes_per_frame;
|
||||
ring_buffer = soundio_ring_buffer_create(soundio, capacity);
|
||||
if (!ring_buffer)
|
||||
panic("unable to create ring buffer: out of memory");
|
||||
|
|
|
@ -888,6 +888,7 @@ static int xrun_recovery(SoundIoOutStreamPrivate *os, int err) {
|
|||
|
||||
static int instream_xrun_recovery(SoundIoInStreamPrivate *is, int err) {
|
||||
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||
// TODO do something with this overflow
|
||||
if (err == -EPIPE) {
|
||||
err = snd_pcm_prepare(isa->handle);
|
||||
} else if (err == -ESTRPIPE) {
|
||||
|
|
229
src/jack.cpp
229
src/jack.cpp
|
@ -20,6 +20,7 @@ struct SoundIoJackPort {
|
|||
const char *name;
|
||||
int name_len;
|
||||
SoundIoChannelId channel_id;
|
||||
jack_latency_range_t latency_range;
|
||||
};
|
||||
|
||||
struct SoundIoJackClient {
|
||||
|
@ -113,11 +114,9 @@ static int outstream_xrun_callback(void *arg) {
|
|||
|
||||
static int outstream_buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
|
||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||
SoundIoOutStream *outstream = &os->pub;
|
||||
SoundIo *soundio = outstream->device->soundio;
|
||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
||||
SoundIoJack *sij = &si->backend_data.jack;
|
||||
if ((jack_nframes_t)sij->buffer_size == nframes) {
|
||||
if ((jack_nframes_t)osj->period_size == nframes) {
|
||||
return 0;
|
||||
} else {
|
||||
outstream->error_callback(outstream, SoundIoErrorStreaming);
|
||||
|
@ -153,9 +152,10 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
|
|||
if (sij->is_shutdown)
|
||||
return SoundIoErrorBackendDisconnected;
|
||||
|
||||
outstream->buffer_duration = device->buffer_duration_current;
|
||||
outstream->period_duration = 0.0;
|
||||
outstream->buffer_duration = 0.0;
|
||||
outstream->period_duration = device->period_duration_current;
|
||||
outstream->prebuf_duration = 0.0;
|
||||
osj->period_size = sij->period_size;
|
||||
|
||||
jack_status_t status;
|
||||
osj->client = jack_client_open(outstream->name, JackNoStartServer, &status);
|
||||
|
@ -269,7 +269,7 @@ static int outstream_begin_write_jack(struct SoundIoPrivate *si, struct SoundIoO
|
|||
SoundIoOutStream *outstream = &os->pub;
|
||||
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||
SoundIoJack *sij = &si->backend_data.jack;
|
||||
assert(*frame_count <= sij->buffer_size);
|
||||
assert(*frame_count <= sij->period_size);
|
||||
|
||||
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||
SoundIoOutStreamJackPort *osjp = &osj->ports[ch];
|
||||
|
@ -284,11 +284,13 @@ static int outstream_begin_write_jack(struct SoundIoPrivate *si, struct SoundIoO
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int outstream_end_write_jack(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, int frame_count) {
|
||||
static int outstream_end_write_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os,
|
||||
int frame_count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outstream_clear_buffer_jack(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *) {
|
||||
static int outstream_clear_buffer_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||
// JACK does not support `prebuf` which is the same as a `prebuf` value of 0,
|
||||
// which means that clearing the buffer is always successful and does nothing.
|
||||
return 0;
|
||||
|
@ -296,44 +298,199 @@ static int outstream_clear_buffer_jack(struct SoundIoPrivate *, struct SoundIoOu
|
|||
|
||||
|
||||
|
||||
static void instream_destroy_jack(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *) {
|
||||
soundio_panic("TODO destroy instream");
|
||||
static void instream_destroy_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||
|
||||
jack_client_close(isj->client);
|
||||
}
|
||||
|
||||
static int instream_xrun_callback(void *arg) {
|
||||
// SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
|
||||
// SoundIoInStream *instream = &is->pub;
|
||||
// TODO do something with this overflow
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
|
||||
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||
SoundIoInStream *instream = &is->pub;
|
||||
|
||||
if ((jack_nframes_t)isj->period_size == nframes) {
|
||||
return 0;
|
||||
} else {
|
||||
instream->error_callback(instream, SoundIoErrorStreaming);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int instream_sample_rate_callback(jack_nframes_t nframes, void *arg) {
|
||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
|
||||
SoundIoInStream *instream = &is->pub;
|
||||
if (nframes == (jack_nframes_t)instream->sample_rate) {
|
||||
return 0;
|
||||
} else {
|
||||
instream->error_callback(instream, SoundIoErrorStreaming);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void instream_shutdown_callback(void *arg) {
|
||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
|
||||
SoundIoInStream *instream = &is->pub;
|
||||
instream->error_callback(instream, SoundIoErrorStreaming);
|
||||
}
|
||||
|
||||
static int instream_process_callback(jack_nframes_t nframes, void *arg) {
|
||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
|
||||
SoundIoInStream *instream = &is->pub;
|
||||
instream->read_callback(instream, nframes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_open_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||
//SoundIoInStream *outstream = &is->pub;
|
||||
//SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||
SoundIoInStream *instream = &is->pub;
|
||||
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||
SoundIoJack *sij = &si->backend_data.jack;
|
||||
if (sij->is_shutdown) {
|
||||
instream_destroy_jack(si, is);
|
||||
SoundIoDevice *device = instream->device;
|
||||
SoundIoDevicePrivate *dev = (SoundIoDevicePrivate *)device;
|
||||
SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
||||
|
||||
if (sij->is_shutdown)
|
||||
return SoundIoErrorBackendDisconnected;
|
||||
|
||||
instream->buffer_duration = 0.0;
|
||||
instream->period_duration = device->period_duration_current;
|
||||
isj->period_size = sij->period_size;
|
||||
|
||||
jack_status_t status;
|
||||
isj->client = jack_client_open(instream->name, JackNoStartServer, &status);
|
||||
if (!isj->client) {
|
||||
instream_destroy_jack(si, is);
|
||||
assert(!(status & JackInvalidOption));
|
||||
if (status & JackShmFailure)
|
||||
return SoundIoErrorSystemResources;
|
||||
if (status & JackNoSuchClient)
|
||||
return SoundIoErrorNoSuchClient;
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
soundio_panic("TODO open instream");
|
||||
|
||||
int err;
|
||||
if ((err = jack_set_process_callback(isj->client, instream_process_callback, is))) {
|
||||
instream_destroy_jack(si, is);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
if ((err = jack_set_buffer_size_callback(isj->client, instream_buffer_size_callback, is))) {
|
||||
instream_destroy_jack(si, is);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
if ((err = jack_set_sample_rate_callback(isj->client, instream_sample_rate_callback, is))) {
|
||||
instream_destroy_jack(si, is);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
if ((err = jack_set_xrun_callback(isj->client, instream_xrun_callback, is))) {
|
||||
instream_destroy_jack(si, is);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
jack_on_shutdown(isj->client, instream_shutdown_callback, is);
|
||||
|
||||
// register ports and map channels
|
||||
int connected_count = 0;
|
||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||
SoundIoChannelId my_channel_id = instream->layout.channels[ch];
|
||||
const char *channel_name = soundio_get_channel_name(my_channel_id);
|
||||
unsigned long flags = JackPortIsInput;
|
||||
if (!instream->non_terminal_hint)
|
||||
flags |= JackPortIsTerminal;
|
||||
jack_port_t *jport = jack_port_register(isj->client, channel_name, JACK_DEFAULT_AUDIO_TYPE, flags, 0);
|
||||
if (!jport) {
|
||||
instream_destroy_jack(si, is);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
}
|
||||
SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
||||
isjp->dest_port = jport;
|
||||
// figure out which source port this connects to
|
||||
SoundIoDeviceJackPort *djp = find_port_matching_channel(device, my_channel_id);
|
||||
if (djp) {
|
||||
isjp->source_port_name = djp->full_name;
|
||||
isjp->source_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) {
|
||||
instream->layout_error = SoundIoErrorIncompatibleDevice;
|
||||
|
||||
int ch_count = min(instream->layout.channel_count, dj->port_count);
|
||||
for (int ch = 0; ch < ch_count; ch += 1) {
|
||||
SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
||||
SoundIoDeviceJackPort *djp = &dj->ports[ch];
|
||||
isjp->source_port_name = djp->full_name;
|
||||
isjp->source_port_name_len = djp->full_name_len;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_start_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||
static int instream_pause_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
|
||||
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||
SoundIoInStream *instream = &is->pub;
|
||||
SoundIoJack *sij = &si->backend_data.jack;
|
||||
if (sij->is_shutdown)
|
||||
return SoundIoErrorBackendDisconnected;
|
||||
|
||||
soundio_panic("TODO start instream");
|
||||
int err;
|
||||
if (pause) {
|
||||
if ((err = jack_deactivate(isj->client)))
|
||||
return SoundIoErrorStreaming;
|
||||
} else {
|
||||
if ((err = jack_activate(isj->client)))
|
||||
return SoundIoErrorStreaming;
|
||||
|
||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||
SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
||||
const char *source_port_name = isjp->source_port_name;
|
||||
// allow unconnected ports
|
||||
if (!source_port_name)
|
||||
continue;
|
||||
const char *dest_port_name = jack_port_name(isjp->dest_port);
|
||||
if ((err = jack_connect(isj->client, source_port_name, dest_port_name)))
|
||||
return SoundIoErrorStreaming;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_start_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||
return instream_pause_jack(si, is, false);
|
||||
}
|
||||
|
||||
static int instream_begin_read_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is,
|
||||
SoundIoChannelArea **out_areas, int *frame_count)
|
||||
{
|
||||
soundio_panic("TODO begin read");
|
||||
SoundIoInStream *instream = &is->pub;
|
||||
SoundIoInStreamJack *isj = &is->backend_data.jack;
|
||||
SoundIoJack *sij = &si->backend_data.jack;
|
||||
assert(*frame_count <= sij->period_size);
|
||||
|
||||
for (int ch = 0; ch < instream->layout.channel_count; ch += 1) {
|
||||
SoundIoInStreamJackPort *isjp = &isj->ports[ch];
|
||||
if (!(isj->areas[ch].ptr = (char*)jack_port_get_buffer(isjp->dest_port, *frame_count)))
|
||||
return SoundIoErrorStreaming;
|
||||
|
||||
isj->areas[ch].step = instream->bytes_per_sample;
|
||||
}
|
||||
|
||||
*out_areas = isj->areas;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_end_read_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is) {
|
||||
soundio_panic("TODO end read");
|
||||
}
|
||||
|
||||
static int instream_pause_jack(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
|
||||
SoundIoJack *sij = &si->backend_data.jack;
|
||||
if (sij->is_shutdown)
|
||||
return SoundIoErrorBackendDisconnected;
|
||||
soundio_panic("TODO pause");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void split_str(const char *input_str, int input_str_len, char c,
|
||||
|
@ -421,6 +578,7 @@ static int refresh_devices(SoundIoPrivate *si) {
|
|||
jack_port_t *jport = jack_port_by_name(sij->client, client_and_port_name);
|
||||
int flags = jack_port_flags(jport);
|
||||
|
||||
|
||||
const char *port_type = jack_port_type(jport);
|
||||
if (strcmp(port_type, JACK_DEFAULT_AUDIO_TYPE) != 0) {
|
||||
// we don't know how to support such a port
|
||||
|
@ -459,6 +617,10 @@ static int refresh_devices(SoundIoPrivate *si) {
|
|||
port->name_len = port_name_len;
|
||||
port->channel_id = soundio_parse_channel_id(port_name, port_name_len);
|
||||
|
||||
jack_latency_callback_mode_t latency_mode = (purpose == SoundIoDevicePurposeOutput) ?
|
||||
JackPlaybackLatency : JackCaptureLatency;
|
||||
jack_port_get_latency_range(jport, latency_mode, &port->latency_range);
|
||||
|
||||
port_name_ptr += 1;
|
||||
}
|
||||
|
||||
|
@ -476,9 +638,13 @@ static int refresh_devices(SoundIoPrivate *si) {
|
|||
SoundIoDevice *device = &dev->pub;
|
||||
SoundIoDeviceJack *dj = &dev->backend_data.jack;
|
||||
int description_len = client->name_len + 3 + 2 * client->port_count;
|
||||
jack_nframes_t max_buffer_frames = 0;
|
||||
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
||||
SoundIoJackPort *port = &client->ports[port_index];
|
||||
|
||||
description_len += port->name_len;
|
||||
|
||||
max_buffer_frames = max(max_buffer_frames, port->latency_range.max);
|
||||
}
|
||||
|
||||
dev->destruct = destruct_device;
|
||||
|
@ -497,7 +663,10 @@ static int refresh_devices(SoundIoPrivate *si) {
|
|||
device->sample_rate_min = sij->sample_rate;
|
||||
device->sample_rate_max = sij->sample_rate;
|
||||
device->sample_rate_current = sij->sample_rate;
|
||||
device->buffer_duration_min = sij->buffer_size / (double) sij->sample_rate;
|
||||
device->period_duration_min = sij->period_size / (double) sij->sample_rate;
|
||||
device->period_duration_max = device->period_duration_min;
|
||||
device->period_duration_current = device->period_duration_min;
|
||||
device->buffer_duration_min = max_buffer_frames / (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;
|
||||
|
@ -591,7 +760,7 @@ static int refresh_devices(SoundIoPrivate *si) {
|
|||
static int buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
||||
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
||||
SoundIoJack *sij = &si->backend_data.jack;
|
||||
sij->buffer_size = nframes;
|
||||
sij->period_size = nframes;
|
||||
if (sij->initialized)
|
||||
refresh_devices(si);
|
||||
return 0;
|
||||
|
@ -706,7 +875,7 @@ int soundio_jack_init(struct SoundIoPrivate *si) {
|
|||
}
|
||||
jack_on_shutdown(sij->client, shutdown_callback, si);
|
||||
|
||||
sij->buffer_size = jack_get_buffer_size(sij->client);
|
||||
sij->period_size = jack_get_buffer_size(sij->client);
|
||||
sij->sample_rate = jack_get_sample_rate(sij->client);
|
||||
|
||||
if ((err = jack_activate(sij->client))) {
|
||||
|
|
14
src/jack.hpp
14
src/jack.hpp
|
@ -34,7 +34,7 @@ struct SoundIoJack {
|
|||
struct SoundIoDevicesInfo *ready_devices_info;
|
||||
bool initialized;
|
||||
int sample_rate;
|
||||
int buffer_size;
|
||||
int period_size;
|
||||
bool is_shutdown;
|
||||
bool emitted_shutdown_cb;
|
||||
};
|
||||
|
@ -47,12 +47,22 @@ struct SoundIoOutStreamJackPort {
|
|||
|
||||
struct SoundIoOutStreamJack {
|
||||
jack_client_t *client;
|
||||
int period_size;
|
||||
SoundIoOutStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct SoundIoInStreamJack {
|
||||
struct SoundIoInStreamJackPort {
|
||||
jack_port_t *dest_port;
|
||||
const char *source_port_name;
|
||||
int source_port_name_len;
|
||||
};
|
||||
|
||||
struct SoundIoInStreamJack {
|
||||
jack_client_t *client;
|
||||
int period_size;
|
||||
SoundIoInStreamJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
struct SoundIoRingBuffer *soundio_ring_buffer_create(struct SoundIo *soundio, int requested_capacity) {
|
||||
SoundIoRingBuffer *rb = create<SoundIoRingBuffer>();
|
||||
|
||||
assert(requested_capacity > 0);
|
||||
|
||||
if (!rb) {
|
||||
soundio_ring_buffer_destroy(rb);
|
||||
return nullptr;
|
||||
|
|
|
@ -286,7 +286,8 @@ struct SoundIoDevice {
|
|||
int sample_rate_current;
|
||||
|
||||
// Buffer duration in seconds. If any values are unknown, they are set to
|
||||
// 0.0. These values are unknown for PulseAudio.
|
||||
// 0.0. These values are unknown for PulseAudio. These values are sometimes
|
||||
// unknown for JACK.
|
||||
double buffer_duration_min;
|
||||
double buffer_duration_max;
|
||||
double buffer_duration_current;
|
||||
|
@ -448,6 +449,12 @@ struct SoundIoInStream {
|
|||
// Must not contain a colon (":").
|
||||
const char *name;
|
||||
|
||||
// Optional: Hint that this input stream is nonterminal. This is used by
|
||||
// JACK and it means that the data received by the stream will be
|
||||
// passed on or made available to another stream. Defaults to `false`.
|
||||
// stream. Defaults to `false`.
|
||||
bool non_terminal_hint;
|
||||
|
||||
// computed automatically when you call soundio_instream_open
|
||||
int bytes_per_frame;
|
||||
int bytes_per_sample;
|
||||
|
|
Loading…
Reference in a new issue