mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-22 22:55:28 +00:00
ability to pause and resume streams
and some cleanup
This commit is contained in:
parent
cee134eee8
commit
3999f57698
24
README.md
24
README.md
|
@ -13,23 +13,25 @@ exposed.
|
|||
## Alternatives
|
||||
|
||||
* [PortAudio](http://www.portaudio.com/)
|
||||
- It does not support [PulseAudio](http://www.freedesktop.org/wiki/Software/PulseAudio/).
|
||||
- It logs messages to stdio and you can't turn that off.
|
||||
- It does not support channel layouts / channel maps.
|
||||
- It is not written by me.
|
||||
- Does not support [PulseAudio](http://www.freedesktop.org/wiki/Software/PulseAudio/).
|
||||
- Logs messages to stdio and you can't turn that off.
|
||||
- Does not support channel layouts / channel maps.
|
||||
- Does not support emitting an event when available devices change.
|
||||
- Not written by me.
|
||||
* [rtaudio](https://www.music.mcgill.ca/~gary/rtaudio/)
|
||||
- It is not a C library.
|
||||
- It uses [exceptions](http://stackoverflow.com/questions/1736146/why-is-exception-handling-bad).
|
||||
- It does not support channel layouts / channel maps.
|
||||
- It is not written by me.
|
||||
- Does not support emitting an event when available devices change.
|
||||
- Not written by me.
|
||||
* [SDL](https://www.libsdl.org/)
|
||||
- It comes with a bunch of other baggage - display, windowing, input
|
||||
handling, and lots more.
|
||||
- It is not designed with real-time low latency audio in mind.
|
||||
- Comes with baggage: display, windowing, input handling, and lots more.
|
||||
- Not designed with real-time low latency audio in mind.
|
||||
- Listing audio devices is [broken](https://github.com/andrewrk/node-groove/issues/13).
|
||||
- It does not support recording devices.
|
||||
- It does not support channel layouts / channel maps.
|
||||
- It is not written by me.
|
||||
- Does not support recording devices.
|
||||
- Does not support channel layouts / channel maps.
|
||||
- Does not support emitting an event when available devices change.
|
||||
- Not written by me.
|
||||
|
||||
## How It Works
|
||||
|
||||
|
|
27
src/alsa.cpp
27
src/alsa.cpp
|
@ -40,6 +40,10 @@ struct SoundIoOutStreamAlsa {
|
|||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct SoundIoInStreamAlsa {
|
||||
snd_pcm_t *handle;
|
||||
};
|
||||
|
||||
static void wakeup_device_poll(SoundIoAlsa *sia) {
|
||||
ssize_t amt = write(sia->notify_pipe_fd[1], "a", 1);
|
||||
if (amt == -1) {
|
||||
|
@ -1013,9 +1017,8 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
|||
|
||||
// write the hardware parameters to device
|
||||
if ((err = snd_pcm_hw_params(osa->handle, hwparams)) < 0) {
|
||||
//assert(err != -EINVAL);
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
return (err == -EINVAL) ? SoundIoErrorIncompatibleDevice : SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
// set channel map
|
||||
|
@ -1050,7 +1053,7 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
|||
// write the software parameters to device
|
||||
if ((err = snd_pcm_sw_params(osa->handle, swparams)) < 0) {
|
||||
outstream_destroy_alsa(si, os);
|
||||
return SoundIoErrorOpeningDevice;
|
||||
return (err == -EINVAL) ? SoundIoErrorIncompatibleDevice : SoundIoErrorOpeningDevice;
|
||||
}
|
||||
|
||||
if ((err = snd_async_add_pcm_handler(&osa->ahandler, osa->handle, async_direct_callback, os)) < 0) {
|
||||
|
@ -1122,6 +1125,14 @@ static void outstream_clear_buffer_alsa(SoundIoPrivate *si,
|
|||
soundio_panic("TODO");
|
||||
}
|
||||
|
||||
static int outstream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
||||
SoundIoOutStreamAlsa *osa = (SoundIoOutStreamAlsa *) os->backend_data;
|
||||
int err;
|
||||
if ((err = snd_pcm_pause(osa->handle, pause)) < 0)
|
||||
return SoundIoErrorIncompatibleDevice;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||
soundio_panic("TODO");
|
||||
}
|
||||
|
@ -1148,6 +1159,14 @@ static void instream_clear_buffer_alsa(SoundIoPrivate *si, SoundIoInStreamPrivat
|
|||
soundio_panic("TODO");
|
||||
}
|
||||
|
||||
static int instream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
|
||||
SoundIoInStreamAlsa *isa = (SoundIoInStreamAlsa *) is->backend_data;
|
||||
int err;
|
||||
if ((err = snd_pcm_pause(isa->handle, pause)) < 0)
|
||||
return SoundIoErrorIncompatibleDevice;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int soundio_alsa_init(SoundIoPrivate *si) {
|
||||
int err;
|
||||
|
||||
|
@ -1234,6 +1253,7 @@ int soundio_alsa_init(SoundIoPrivate *si) {
|
|||
si->outstream_begin_write = outstream_begin_write_alsa;
|
||||
si->outstream_write = outstream_write_alsa;
|
||||
si->outstream_clear_buffer = outstream_clear_buffer_alsa;
|
||||
si->outstream_pause = outstream_pause_alsa;
|
||||
|
||||
si->instream_open = instream_open_alsa;
|
||||
si->instream_destroy = instream_destroy_alsa;
|
||||
|
@ -1241,6 +1261,7 @@ int soundio_alsa_init(SoundIoPrivate *si) {
|
|||
si->instream_peek = instream_peek_alsa;
|
||||
si->instream_drop = instream_drop_alsa;
|
||||
si->instream_clear_buffer = instream_clear_buffer_alsa;
|
||||
si->instream_pause = instream_pause_alsa;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -115,12 +115,10 @@ static void outstream_destroy_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate
|
|||
return;
|
||||
|
||||
if (osd->thread) {
|
||||
if (osd->thread) {
|
||||
osd->abort_flag.clear();
|
||||
soundio_os_cond_signal(osd->cond, nullptr);
|
||||
soundio_os_thread_destroy(osd->thread);
|
||||
osd->thread = nullptr;
|
||||
}
|
||||
osd->abort_flag.clear();
|
||||
soundio_os_cond_signal(osd->cond, nullptr);
|
||||
soundio_os_thread_destroy(osd->thread);
|
||||
osd->thread = nullptr;
|
||||
}
|
||||
soundio_os_cond_destroy(osd->cond);
|
||||
osd->cond = nullptr;
|
||||
|
@ -210,6 +208,10 @@ static void outstream_clear_buffer_dummy(SoundIoPrivate *si, SoundIoOutStreamPri
|
|||
soundio_ring_buffer_clear(&osd->ring_buffer);
|
||||
}
|
||||
|
||||
static int outstream_pause_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
||||
soundio_panic("TODO");
|
||||
}
|
||||
|
||||
static int instream_open_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||
soundio_panic("TODO");
|
||||
}
|
||||
|
@ -236,6 +238,10 @@ static void instream_clear_buffer_dummy(SoundIoPrivate *si, SoundIoInStreamPriva
|
|||
soundio_panic("TODO");
|
||||
}
|
||||
|
||||
static int instream_pause_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is, bool pause) {
|
||||
soundio_panic("TODO");
|
||||
}
|
||||
|
||||
static int set_all_device_formats(SoundIoDevice *device) {
|
||||
device->format_count = 18;
|
||||
device->formats = allocate<SoundIoFormat>(device->format_count);
|
||||
|
@ -411,6 +417,7 @@ int soundio_dummy_init(SoundIoPrivate *si) {
|
|||
si->outstream_begin_write = outstream_begin_write_dummy;
|
||||
si->outstream_write = outstream_write_dummy;
|
||||
si->outstream_clear_buffer = outstream_clear_buffer_dummy;
|
||||
si->outstream_pause = outstream_pause_dummy;
|
||||
|
||||
si->instream_open = instream_open_dummy;
|
||||
si->instream_destroy = instream_destroy_dummy;
|
||||
|
@ -418,6 +425,7 @@ int soundio_dummy_init(SoundIoPrivate *si) {
|
|||
si->instream_peek = instream_peek_dummy;
|
||||
si->instream_drop = instream_drop_dummy;
|
||||
si->instream_clear_buffer = instream_clear_buffer_dummy;
|
||||
si->instream_pause = instream_pause_dummy;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -734,6 +734,10 @@ static void outstream_clear_buffer_pa(SoundIoPrivate *si,
|
|||
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||
}
|
||||
|
||||
static int outstream_pause_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, bool pause) {
|
||||
soundio_panic("TODO");
|
||||
}
|
||||
|
||||
static void recording_stream_state_callback(pa_stream *stream, void *userdata) {
|
||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate*)userdata;
|
||||
SoundIoInStreamPulseAudio *ispa = (SoundIoInStreamPulseAudio *)is->backend_data;
|
||||
|
@ -898,6 +902,10 @@ static void instream_clear_buffer_pa(SoundIoPrivate *si, SoundIoInStreamPrivate
|
|||
pa_threaded_mainloop_unlock(sipa->main_loop);
|
||||
}
|
||||
|
||||
static int instream_pause_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is, bool pause) {
|
||||
soundio_panic("TODO");
|
||||
}
|
||||
|
||||
int soundio_pulseaudio_init(SoundIoPrivate *si) {
|
||||
assert(!si->backend_data);
|
||||
SoundIoPulseAudio *sipa = create<SoundIoPulseAudio>();
|
||||
|
@ -968,6 +976,7 @@ int soundio_pulseaudio_init(SoundIoPrivate *si) {
|
|||
si->outstream_begin_write = outstream_begin_write_pa;
|
||||
si->outstream_write = outstream_write_pa;
|
||||
si->outstream_clear_buffer = outstream_clear_buffer_pa;
|
||||
si->outstream_pause = outstream_pause_pa;
|
||||
|
||||
si->instream_open = instream_open_pa;
|
||||
si->instream_destroy = instream_destroy_pa;
|
||||
|
@ -975,6 +984,7 @@ int soundio_pulseaudio_init(SoundIoPrivate *si) {
|
|||
si->instream_peek = instream_peek_pa;
|
||||
si->instream_drop = instream_drop_pa;
|
||||
si->instream_clear_buffer = instream_clear_buffer_pa;
|
||||
si->instream_pause = instream_pause_pa;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -430,6 +430,13 @@ int soundio_outstream_start(struct SoundIoOutStream *outstream) {
|
|||
return si->outstream_start(si, os);
|
||||
}
|
||||
|
||||
int soundio_outstream_pause(struct SoundIoOutStream *outstream, bool pause) {
|
||||
SoundIo *soundio = outstream->device->soundio;
|
||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)outstream;
|
||||
return si->outstream_pause(si, os, pause);
|
||||
}
|
||||
|
||||
struct SoundIoInStream *soundio_instream_create(struct SoundIoDevice *device) {
|
||||
SoundIoInStreamPrivate *is = create<SoundIoInStreamPrivate>();
|
||||
if (!is)
|
||||
|
@ -490,6 +497,13 @@ void soundio_instream_destroy(struct SoundIoInStream *instream) {
|
|||
destroy(is);
|
||||
}
|
||||
|
||||
int soundio_instream_pause(struct SoundIoInStream *instream, bool pause) {
|
||||
SoundIo *soundio = instream->device->soundio;
|
||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)instream;
|
||||
return si->instream_pause(si, is, pause);
|
||||
}
|
||||
|
||||
void soundio_destroy_devices_info(SoundIoDevicesInfo *devices_info) {
|
||||
if (!devices_info)
|
||||
return;
|
||||
|
|
|
@ -304,7 +304,7 @@ struct SoundIoOutStream {
|
|||
// Defaults to `buffer_duration / 2` (and then clamped into range).
|
||||
double period_duration;
|
||||
|
||||
// Defaults to NULL.
|
||||
// Defaults to NULL. Put whatever you want here.
|
||||
void *userdata;
|
||||
// `err` is SoundIoErrorUnderflow or SoundIoErrorStreaming.
|
||||
// SoundIoErrorUnderflow means that the sound device ran out of buffered
|
||||
|
@ -312,8 +312,7 @@ struct SoundIoOutStream {
|
|||
// SoundIoErrorStreaming is an unrecoverable error. The stream is in an
|
||||
// invalid state and must be destroyed.
|
||||
void (*error_callback)(struct SoundIoOutStream *, int err);
|
||||
// `frame_count` is the number of requested frames to write.
|
||||
void (*write_callback)(struct SoundIoOutStream *, int frame_count);
|
||||
void (*write_callback)(struct SoundIoOutStream *, int requested_frame_count);
|
||||
|
||||
// computed automatically when you call soundio_outstream_open
|
||||
int bytes_per_frame;
|
||||
|
@ -344,6 +343,7 @@ struct SoundIoInStream {
|
|||
// Defaults to `buffer_duration / 8`.
|
||||
double period_duration;
|
||||
|
||||
// Defaults to NULL. Put whatever you want here.
|
||||
void *userdata;
|
||||
void (*read_callback)(struct SoundIoInStream *);
|
||||
|
||||
|
@ -354,6 +354,7 @@ struct SoundIoInStream {
|
|||
|
||||
// The size of this struct is not part of the API or ABI.
|
||||
struct SoundIo {
|
||||
// Defaults to NULL. Put whatever you want here.
|
||||
void *userdata;
|
||||
void (*on_devices_change)(struct SoundIo *);
|
||||
void (*on_events_signal)(struct SoundIo *);
|
||||
|
@ -380,7 +381,7 @@ const char *soundio_backend_name(enum SoundIoBackend backend);
|
|||
|
||||
// return the number of available backends
|
||||
int soundio_backend_count(struct SoundIo *soundio);
|
||||
// get the backend at the specified index (0 <= index < soundio_backend_count)
|
||||
// get the available backend at the specified index (0 <= index < soundio_backend_count)
|
||||
enum SoundIoBackend soundio_get_backend(struct SoundIo *soundio, int index);
|
||||
|
||||
// when you call this, the on_devices_change and on_events_signal callbacks
|
||||
|
@ -515,6 +516,12 @@ int soundio_outstream_write(struct SoundIoOutStream *outstream, int frame_count)
|
|||
|
||||
void soundio_outstream_clear_buffer(struct SoundIoOutStream *outstream);
|
||||
|
||||
// If the underyling device supports pausing, this pauses the stream and
|
||||
// prevents `write_callback` from being called. Otherwise this returns
|
||||
// `SoundIoErrorIncompatibleDevice`.
|
||||
int soundio_outstream_pause(struct SoundIoOutStream *outstream, bool pause);
|
||||
|
||||
|
||||
|
||||
|
||||
// Input Streams
|
||||
|
@ -534,6 +541,11 @@ void soundio_instream_drop(struct SoundIoInStream *instream);
|
|||
|
||||
void soundio_instream_clear_buffer(struct SoundIoInStream *instream);
|
||||
|
||||
// If the underyling device supports pausing, this pauses the stream and
|
||||
// prevents `read_callback` from being called. Otherwise this returns
|
||||
// `SoundIoErrorIncompatibleDevice`.
|
||||
int soundio_instream_pause(struct SoundIoInStream *instream, bool pause);
|
||||
|
||||
|
||||
// Ring Buffer
|
||||
struct SoundIoRingBuffer;
|
||||
|
|
|
@ -51,6 +51,7 @@ struct SoundIoPrivate {
|
|||
SoundIoChannelArea **out_areas, int *frame_count);
|
||||
int (*outstream_write)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, int frame_count);
|
||||
void (*outstream_clear_buffer)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *);
|
||||
int (*outstream_pause)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, bool pause);
|
||||
|
||||
|
||||
int (*instream_open)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
||||
|
@ -60,6 +61,7 @@ struct SoundIoPrivate {
|
|||
const char **data, int *frame_count);
|
||||
void (*instream_drop)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
||||
void (*instream_clear_buffer)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *);
|
||||
int (*instream_pause)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *, bool pause);
|
||||
};
|
||||
|
||||
void soundio_destroy_devices_info(struct SoundIoDevicesInfo *devices_info);
|
||||
|
|
Loading…
Reference in a new issue