SoundIoOutStream, SoundIoInStream: void * -> union

For better cache locality and lower mlock requirements.
This commit is contained in:
Andrew Kelley 2015-07-27 17:06:12 -07:00
parent db1195877a
commit 70decb39f5
11 changed files with 177 additions and 220 deletions

View file

@ -280,8 +280,6 @@ 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. instead of `void *backend_data` use a union for better cache locality
and smaller mlock requirements
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

View file

@ -8,7 +8,6 @@
#include "alsa.hpp"
#include "soundio.hpp"
#include <alsa/asoundlib.h>
#include <sys/inotify.h>
#include <math.h>
@ -23,39 +22,6 @@ static snd_pcm_access_t prioritized_access_types[] = {
};
struct SoundIoOutStreamAlsa {
snd_pcm_t *handle;
snd_pcm_chmap_t *chmap;
int chmap_size;
snd_pcm_uframes_t offset;
snd_pcm_access_t access;
int sample_buffer_size;
char *sample_buffer;
int poll_fd_count;
struct pollfd *poll_fds;
SoundIoOsThread *thread;
atomic_flag thread_exit_flag;
int period_size;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
};
struct SoundIoInStreamAlsa {
snd_pcm_t *handle;
snd_pcm_chmap_t *chmap;
int chmap_size;
snd_pcm_uframes_t offset;
snd_pcm_access_t access;
int sample_buffer_size;
char *sample_buffer;
int poll_fd_count;
struct pollfd *poll_fds;
SoundIoOsThread *thread;
atomic_flag thread_exit_flag;
int period_size;
int read_frame_count;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
};
static void wakeup_device_poll(SoundIoAlsa *sia) {
ssize_t amt = write(sia->notify_pipe_fd[1], "a", 1);
if (amt == -1) {
@ -881,9 +847,7 @@ static void wakeup(SoundIoPrivate *si) {
}
static void outstream_destroy_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
SoundIoOutStreamAlsa *osa = (SoundIoOutStreamAlsa *) os->backend_data;
if (!osa)
return;
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
if (osa->thread) {
osa->thread_exit_flag.clear();
@ -898,14 +862,11 @@ static void outstream_destroy_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *
deallocate(osa->chmap, osa->chmap_size);
deallocate(osa->sample_buffer, osa->sample_buffer_size);
destroy(osa);
os->backend_data = nullptr;
}
static int xrun_recovery(SoundIoOutStreamPrivate *os, int err) {
SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamAlsa *osa = (SoundIoOutStreamAlsa *)os->backend_data;
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
if (err == -EPIPE) {
err = snd_pcm_prepare(osa->handle);
if (err >= 0)
@ -924,7 +885,7 @@ static int xrun_recovery(SoundIoOutStreamPrivate *os, int err) {
}
static int instream_xrun_recovery(SoundIoInStreamPrivate *is, int err) {
SoundIoInStreamAlsa *isa = (SoundIoInStreamAlsa *)is->backend_data;
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
if (err == -EPIPE) {
err = snd_pcm_prepare(isa->handle);
} else if (err == -ESTRPIPE) {
@ -977,7 +938,7 @@ static int instream_wait_for_poll(SoundIoInStreamAlsa *isa) {
void outstream_thread_run(void *arg) {
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *) arg;
SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamAlsa *osa = (SoundIoOutStreamAlsa *) os->backend_data;
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
int err;
@ -1046,37 +1007,37 @@ void outstream_thread_run(void *arg) {
static void instream_thread_run(void *arg) {
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *) arg;
SoundIoInStream *instream = &is->pub;
SoundIoInStreamAlsa *osa = (SoundIoInStreamAlsa *) is->backend_data;
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
int err;
for (;;) {
snd_pcm_state_t state = snd_pcm_state(osa->handle);
snd_pcm_state_t state = snd_pcm_state(isa->handle);
switch (state) {
case SND_PCM_STATE_SETUP:
if ((err = snd_pcm_prepare(osa->handle)) < 0) {
if ((err = snd_pcm_prepare(isa->handle)) < 0) {
instream->error_callback(instream, SoundIoErrorStreaming);
return;
}
continue;
case SND_PCM_STATE_PREPARED:
if ((err = snd_pcm_start(osa->handle)) < 0) {
if ((err = snd_pcm_start(isa->handle)) < 0) {
instream->error_callback(instream, SoundIoErrorStreaming);
return;
}
continue;
case SND_PCM_STATE_RUNNING:
{
if ((err = instream_wait_for_poll(osa)) < 0) {
if (!osa->thread_exit_flag.test_and_set())
if ((err = instream_wait_for_poll(isa)) < 0) {
if (!isa->thread_exit_flag.test_and_set())
return;
instream->error_callback(instream, SoundIoErrorStreaming);
return;
}
if (!osa->thread_exit_flag.test_and_set())
if (!isa->thread_exit_flag.test_and_set())
return;
snd_pcm_sframes_t avail = snd_pcm_avail_update(osa->handle);
snd_pcm_sframes_t avail = snd_pcm_avail_update(isa->handle);
if (avail < 0) {
if ((err = instream_xrun_recovery(is, avail)) < 0) {
instream->error_callback(instream, SoundIoErrorStreaming);
@ -1111,6 +1072,7 @@ static void instream_thread_run(void *arg) {
}
static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
SoundIoOutStream *outstream = &os->pub;
SoundIoDevice *device = outstream->device;
@ -1123,13 +1085,6 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
if (outstream->prebuf_duration == -1.0)
outstream->prebuf_duration = outstream->buffer_duration;
SoundIoOutStreamAlsa *osa = create<SoundIoOutStreamAlsa>();
if (!osa) {
outstream_destroy_alsa(si, os);
return SoundIoErrorNoMem;
}
os->backend_data = osa;
int ch_count = outstream->layout.channel_count;
osa->chmap_size = sizeof(int) + sizeof(int) * ch_count;
@ -1284,7 +1239,7 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
}
static int outstream_start_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
SoundIoOutStreamAlsa *osa = (SoundIoOutStreamAlsa *) os->backend_data;
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
assert(!osa->thread);
@ -1302,7 +1257,7 @@ int outstream_begin_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os,
struct SoundIoChannelArea **out_areas, int *frame_count)
{
*out_areas = nullptr;
SoundIoOutStreamAlsa *osa = (SoundIoOutStreamAlsa *) os->backend_data;
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
SoundIoOutStream *outstream = &os->pub;
if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
@ -1345,7 +1300,7 @@ int outstream_begin_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os,
}
static int outstream_end_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, int frame_count) {
SoundIoOutStreamAlsa *osa = (SoundIoOutStreamAlsa *) os->backend_data;
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
SoundIoOutStream *outstream = &os->pub;
snd_pcm_sframes_t commitres;
@ -1373,7 +1328,7 @@ static int outstream_end_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate
static int outstream_clear_buffer_alsa(SoundIoPrivate *si,
SoundIoOutStreamPrivate *os)
{
SoundIoOutStreamAlsa *osa = (SoundIoOutStreamAlsa *) os->backend_data;
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
int err;
if ((err = snd_pcm_reset(osa->handle)) < 0)
return SoundIoErrorStreaming;
@ -1381,7 +1336,7 @@ static int outstream_clear_buffer_alsa(SoundIoPrivate *si,
}
static int outstream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
SoundIoOutStreamAlsa *osa = (SoundIoOutStreamAlsa *) os->backend_data;
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
int err;
if ((err = snd_pcm_pause(osa->handle, pause)) < 0)
return SoundIoErrorIncompatibleDevice;
@ -1389,9 +1344,7 @@ static int outstream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoOutStre
}
static void instream_destroy_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
SoundIoInStreamAlsa *isa = (SoundIoInStreamAlsa *) is->backend_data;
if (!isa)
return;
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
if (isa->thread) {
isa->thread_exit_flag.clear();
@ -1404,12 +1357,10 @@ static void instream_destroy_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is
deallocate(isa->poll_fds, isa->poll_fd_count);
deallocate(isa->chmap, isa->chmap_size);
deallocate(isa->sample_buffer, isa->sample_buffer_size);
destroy(isa);
is->backend_data = nullptr;
}
static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
SoundIoInStream *instream = &is->pub;
SoundIoDevice *device = instream->device;
@ -1420,13 +1371,6 @@ static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
instream->buffer_duration / 8.0, device->period_duration_max);
}
SoundIoInStreamAlsa *isa = create<SoundIoInStreamAlsa>();
if (!isa) {
instream_destroy_alsa(si, is);
return SoundIoErrorNoMem;
}
is->backend_data = isa;
int ch_count = instream->layout.channel_count;
isa->chmap_size = sizeof(int) + sizeof(int) * ch_count;
@ -1568,7 +1512,7 @@ static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
}
static int instream_start_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
SoundIoInStreamAlsa *isa = (SoundIoInStreamAlsa *) is->backend_data;
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
assert(!isa->thread);
@ -1586,7 +1530,7 @@ static int instream_begin_read_alsa(SoundIoPrivate *si,
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
{
*out_areas = nullptr;
SoundIoInStreamAlsa *isa = (SoundIoInStreamAlsa *) is->backend_data;
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
SoundIoInStream *instream = &is->pub;
if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
@ -1646,7 +1590,7 @@ static int instream_begin_read_alsa(SoundIoPrivate *si,
}
static int instream_end_read_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
SoundIoInStreamAlsa *isa = (SoundIoInStreamAlsa *) is->backend_data;
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
return 0;
@ -1665,7 +1609,7 @@ static int instream_end_read_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is
}
static int instream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoInStreamPrivate *is, bool pause) {
SoundIoInStreamAlsa *isa = (SoundIoInStreamAlsa *) is->backend_data;
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
int err;
if ((err = snd_pcm_pause(isa->handle, pause)) < 0)
return SoundIoErrorIncompatibleDevice;

View file

@ -8,9 +8,12 @@
#ifndef SOUNDIO_ALSA_HPP
#define SOUNDIO_ALSA_HPP
#include "soundio.h"
#include "os.hpp"
#include "atomics.hpp"
#include <alsa/asoundlib.h>
int soundio_alsa_init(struct SoundIoPrivate *si);
struct SoundIoDeviceAlsa {
@ -32,4 +35,37 @@ struct SoundIoAlsa {
struct SoundIoDevicesInfo *ready_devices_info;
};
struct SoundIoOutStreamAlsa {
snd_pcm_t *handle;
snd_pcm_chmap_t *chmap;
int chmap_size;
snd_pcm_uframes_t offset;
snd_pcm_access_t access;
int sample_buffer_size;
char *sample_buffer;
int poll_fd_count;
struct pollfd *poll_fds;
SoundIoOsThread *thread;
atomic_flag thread_exit_flag;
int period_size;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
};
struct SoundIoInStreamAlsa {
snd_pcm_t *handle;
snd_pcm_chmap_t *chmap;
int chmap_size;
snd_pcm_uframes_t offset;
snd_pcm_access_t access;
int sample_buffer_size;
char *sample_buffer;
int poll_fd_count;
struct pollfd *poll_fds;
SoundIoOsThread *thread;
atomic_flag thread_exit_flag;
int period_size;
int read_frame_count;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
};
#endif

View file

@ -7,41 +7,15 @@
#include "dummy.hpp"
#include "soundio.hpp"
#include "atomics.hpp"
#include "ring_buffer.hpp"
#include <stdio.h>
#include <string.h>
#include <math.h>
struct SoundIoOutStreamDummy {
struct SoundIoOsThread *thread;
struct SoundIoOsCond *cond;
atomic_flag abort_flag;
int buffer_frame_count;
struct SoundIoRingBuffer ring_buffer;
int prebuf_frame_count;
int prebuf_frames_left;
long frames_consumed;
double playback_start_time;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
};
struct SoundIoInStreamDummy {
struct SoundIoOsThread *thread;
struct SoundIoOsCond *cond;
atomic_flag abort_flag;
int read_frame_count;
int buffer_frame_count;
struct SoundIoRingBuffer ring_buffer;
int hole_size;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
};
static void playback_thread_run(void *arg) {
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamDummy *osd = (SoundIoOutStreamDummy *)os->backend_data;
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
double start_time = soundio_os_get_time();
osd->playback_start_time = start_time;
@ -90,7 +64,7 @@ static void playback_thread_run(void *arg) {
static void capture_thread_run(void *arg) {
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
SoundIoInStream *instream = &is->pub;
SoundIoInStreamDummy *isd = (SoundIoInStreamDummy *)is->backend_data;
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
long frames_consumed = 0;
double start_time = soundio_os_get_time();
@ -150,9 +124,7 @@ static void wakeup(SoundIoPrivate *si) {
}
static void outstream_destroy_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
SoundIoOutStreamDummy *osd = (SoundIoOutStreamDummy *)os->backend_data;
if (!osd)
return;
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
if (osd->thread) {
osd->abort_flag.clear();
@ -164,12 +136,10 @@ static void outstream_destroy_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate
osd->cond = nullptr;
soundio_ring_buffer_deinit(&osd->ring_buffer);
destroy(osd);
os->backend_data = nullptr;
}
static int outstream_open_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
SoundIoOutStream *outstream = &os->pub;
SoundIoDevice *device = outstream->device;
@ -180,13 +150,6 @@ static int outstream_open_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
outstream->buffer_duration / 2.0, device->period_duration_max);
}
SoundIoOutStreamDummy *osd = create<SoundIoOutStreamDummy>();
if (!osd) {
outstream_destroy_dummy(si, os);
return SoundIoErrorNoMem;
}
os->backend_data = osd;
int err;
int buffer_size = outstream->bytes_per_frame * outstream->sample_rate * outstream->buffer_duration;
if ((err = soundio_ring_buffer_init(&osd->ring_buffer, buffer_size))) {
@ -212,7 +175,7 @@ static int outstream_open_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
}
static int outstream_pause_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
SoundIoOutStreamDummy *osd = (SoundIoOutStreamDummy *)os->backend_data;
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
if (pause) {
if (osd->thread) {
osd->abort_flag.clear();
@ -242,7 +205,7 @@ static int outstream_begin_write_dummy(SoundIoPrivate *si,
*out_areas = nullptr;
SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamDummy *osd = (SoundIoOutStreamDummy *)os->backend_data;
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
assert(*frame_count >= 0);
assert(*frame_count <= osd->buffer_frame_count);
@ -264,7 +227,7 @@ static int outstream_begin_write_dummy(SoundIoPrivate *si,
}
static int outstream_end_write_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, int frame_count) {
SoundIoOutStreamDummy *osd = (SoundIoOutStreamDummy *)os->backend_data;
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
SoundIoOutStream *outstream = &os->pub;
int byte_count = frame_count * outstream->bytes_per_frame;
soundio_ring_buffer_advance_write_ptr(&osd->ring_buffer, byte_count);
@ -279,16 +242,14 @@ static int outstream_end_write_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate
}
static int outstream_clear_buffer_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
SoundIoOutStreamDummy *osd = (SoundIoOutStreamDummy *)os->backend_data;
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
soundio_ring_buffer_clear(&osd->ring_buffer);
osd->prebuf_frames_left = osd->prebuf_frame_count;
return 0;
}
static void instream_destroy_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
SoundIoInStreamDummy *isd = (SoundIoInStreamDummy *)is->backend_data;
if (!isd)
return;
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
if (isd->thread) {
isd->abort_flag.clear();
@ -300,12 +261,10 @@ static void instream_destroy_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *i
isd->cond = nullptr;
soundio_ring_buffer_deinit(&isd->ring_buffer);
destroy(isd);
is->backend_data = nullptr;
}
static int instream_open_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
SoundIoInStream *instream = &is->pub;
SoundIoDevice *device = instream->device;
@ -316,13 +275,6 @@ static int instream_open_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
instream->buffer_duration / 8.0, instream->device->period_duration_max);
}
SoundIoInStreamDummy *isd = create<SoundIoInStreamDummy>();
if (!isd) {
instream_destroy_dummy(si, is);
return SoundIoErrorNoMem;
}
is->backend_data = isd;
int err;
int buffer_size = instream->bytes_per_frame * instream->sample_rate * instream->buffer_duration;
if ((err = soundio_ring_buffer_init(&isd->ring_buffer, buffer_size))) {
@ -344,7 +296,7 @@ static int instream_open_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
}
static int instream_pause_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is, bool pause) {
SoundIoInStreamDummy *isd = (SoundIoInStreamDummy *)is->backend_data;
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
if (pause) {
if (isd->thread) {
isd->abort_flag.clear();
@ -372,7 +324,7 @@ static int instream_begin_read_dummy(SoundIoPrivate *si,
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
{
SoundIoInStream *instream = &is->pub;
SoundIoInStreamDummy *isd = (SoundIoInStreamDummy *)is->backend_data;
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
assert(*frame_count >= 0);
assert(*frame_count <= isd->buffer_frame_count);
@ -403,7 +355,7 @@ static int instream_begin_read_dummy(SoundIoPrivate *si,
}
static int instream_end_read_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
SoundIoInStreamDummy *isd = (SoundIoInStreamDummy *)is->backend_data;
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
SoundIoInStream *instream = &is->pub;
if (isd->hole_size > 0) {

View file

@ -8,7 +8,10 @@
#ifndef SOUNDIO_DUMMY_HPP
#define SOUNDIO_DUMMY_HPP
#include "soundio.h"
#include "os.hpp"
#include "atomics.hpp"
#include "ring_buffer.hpp"
int soundio_dummy_init(struct SoundIoPrivate *si);
@ -22,4 +25,28 @@ struct SoundIoDeviceDummy {
};
struct SoundIoOutStreamDummy {
struct SoundIoOsThread *thread;
struct SoundIoOsCond *cond;
atomic_flag abort_flag;
int buffer_frame_count;
struct SoundIoRingBuffer ring_buffer;
int prebuf_frame_count;
int prebuf_frames_left;
long frames_consumed;
double playback_start_time;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
};
struct SoundIoInStreamDummy {
struct SoundIoOsThread *thread;
struct SoundIoOsCond *cond;
atomic_flag abort_flag;
int read_frame_count;
int buffer_frame_count;
struct SoundIoRingBuffer ring_buffer;
int hole_size;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
};
#endif

View file

@ -14,11 +14,6 @@
static atomic_flag global_msg_callback_flag = ATOMIC_FLAG_INIT;
struct SoundIoOutStreamJack {
jack_client_t *client;
jack_port_t *ports[SOUNDIO_MAX_CHANNELS];
};
struct SoundIoJackPort {
const char *name;
int name_len;
@ -80,17 +75,13 @@ static int outstream_process_callback(jack_nframes_t nframes, void *arg) {
}
static void outstream_destroy_jack(struct SoundIoPrivate *is, struct SoundIoOutStreamPrivate *os) {
SoundIoOutStreamJack *osj = (SoundIoOutStreamJack *) os->backend_data;
if (!osj)
return;
SoundIoOutStreamJack *osj = &os->backend_data.jack;
jack_client_close(osj->client);
destroy(osj);
os->backend_data = 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;
@ -98,13 +89,6 @@ static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStrea
outstream->period_duration = 0.0; // TODO
outstream->prebuf_duration = 0.0; // TODO
SoundIoOutStreamJack *osj = create<SoundIoOutStreamJack>();
if (!osj) {
outstream_destroy_jack(si, os);
return SoundIoErrorNoMem;
}
os->backend_data = osj;
outstream->layout_error = SoundIoErrorIncompatibleBackend;
jack_status_t status;
@ -145,7 +129,7 @@ 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 = (SoundIoOutStreamJack *) os->backend_data;
SoundIoOutStreamJack *osj = &os->backend_data.jack;
SoundIoOutStream *outstream = &os->pub;
int err;
if (pause) {

View file

@ -8,6 +8,7 @@
#ifndef SOUNDIO_JACK_HPP
#define SOUNDIO_JACK_HPP
#include "soundio.h"
#include "os.hpp"
#include <jack/jack.h>
@ -29,5 +30,13 @@ struct SoundIoJack {
int buffer_size;
};
#endif
struct SoundIoOutStreamJack {
jack_client_t *client;
jack_port_t *ports[SOUNDIO_MAX_CHANNELS];
};
struct SoundIoInStreamJack {
};
#endif

View file

@ -13,21 +13,6 @@
#include <stdio.h>
struct SoundIoOutStreamPulseAudio {
pa_stream *stream;
atomic_bool stream_ready;
pa_buffer_attr buffer_attr;
char *write_ptr;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
};
struct SoundIoInStreamPulseAudio {
pa_stream *stream;
atomic_bool stream_ready;
pa_buffer_attr buffer_attr;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
};
static void subscribe_callback(pa_context *context,
pa_subscription_event_type_t event_bits, uint32_t index, void *userdata)
{
@ -570,7 +555,7 @@ static void playback_stream_state_callback(pa_stream *stream, void *userdata) {
SoundIo *soundio = outstream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
switch (pa_stream_get_state(stream)) {
case PA_STREAM_UNCONNECTED:
case PA_STREAM_CREATING:
@ -598,9 +583,7 @@ static void playback_stream_write_callback(pa_stream *stream, size_t nbytes, voi
}
static void outstream_destroy_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
if (!ospa)
return;
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
pa_stream *stream = ospa->stream;
@ -618,21 +601,12 @@ static void outstream_destroy_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os
ospa->stream = nullptr;
}
destroy(ospa);
os->backend_data = nullptr;
}
static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamPulseAudio *ospa = create<SoundIoOutStreamPulseAudio>();
if (!ospa) {
outstream_destroy_pa(si, os);
return SoundIoErrorNoMem;
}
os->backend_data = ospa;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
ospa->stream_ready = false;
@ -686,7 +660,7 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
static int outstream_start_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
SoundIoOutStream *outstream = &os->pub;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
pa_threaded_mainloop_lock(sipa->main_loop);
@ -720,7 +694,7 @@ static int outstream_begin_write_pa(SoundIoPrivate *si,
*out_areas = nullptr;
SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
pa_stream *stream = ospa->stream;
size_t byte_count = *frame_count * outstream->bytes_per_frame;
if (pa_stream_begin_write(stream, (void**)&ospa->write_ptr, &byte_count))
@ -739,7 +713,7 @@ static int outstream_begin_write_pa(SoundIoPrivate *si,
static int outstream_end_write_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, int frame_count) {
SoundIoOutStream *outstream = &os->pub;
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
pa_stream *stream = ospa->stream;
assert(frame_count > 0);
size_t byte_count = frame_count * outstream->bytes_per_frame;
@ -752,7 +726,7 @@ static int outstream_end_write_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *o
static int outstream_clear_buffer_pa(SoundIoPrivate *si,
SoundIoOutStreamPrivate *os)
{
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
pa_stream *stream = ospa->stream;
pa_threaded_mainloop_lock(sipa->main_loop);
@ -765,7 +739,7 @@ static int outstream_clear_buffer_pa(SoundIoPrivate *si,
}
static int outstream_pause_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, bool pause) {
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
pa_threaded_mainloop_lock(sipa->main_loop);
@ -784,7 +758,7 @@ static int outstream_pause_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, b
static void recording_stream_state_callback(pa_stream *stream, void *userdata) {
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate*)userdata;
SoundIoInStreamPulseAudio *ispa = (SoundIoInStreamPulseAudio *)is->backend_data;
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
SoundIoInStream *instream = &is->pub;
SoundIo *soundio = instream->device->soundio;
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
@ -814,11 +788,8 @@ static void recording_stream_read_callback(pa_stream *stream, size_t nbytes, voi
instream->read_callback(instream, available_frame_count);
}
static void instream_destroy_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *instream) {
SoundIoInStreamPulseAudio *ispa = (SoundIoInStreamPulseAudio *)instream->backend_data;
if (!ispa)
return;
static void instream_destroy_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
pa_stream *stream = ispa->stream;
if (stream) {
@ -836,15 +807,9 @@ static void instream_destroy_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *inst
}
static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
SoundIoInStream *instream = &is->pub;
SoundIoInStreamPulseAudio *ispa = create<SoundIoInStreamPulseAudio>();
if (!ispa) {
instream_destroy_pa(si, is);
return SoundIoErrorNoMem;
}
is->backend_data = ispa;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
ispa->stream_ready = false;
@ -889,7 +854,7 @@ static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
static int instream_start_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
SoundIoInStream *instream = &is->pub;
SoundIoInStreamPulseAudio *ispa = (SoundIoInStreamPulseAudio *)is->backend_data;
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
pa_threaded_mainloop_lock(sipa->main_loop);
@ -918,7 +883,7 @@ static int instream_begin_read_pa(SoundIoPrivate *si,
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
{
SoundIoInStream *instream = &is->pub;
SoundIoInStreamPulseAudio *ispa = (SoundIoInStreamPulseAudio *)is->backend_data;
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
pa_stream *stream = ispa->stream;
assert(ispa->stream_ready);
@ -948,7 +913,7 @@ static int instream_begin_read_pa(SoundIoPrivate *si,
}
static int instream_end_read_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
SoundIoInStreamPulseAudio *ispa = (SoundIoInStreamPulseAudio *)is->backend_data;
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
pa_stream *stream = ispa->stream;
if (pa_stream_drop(stream))
return SoundIoErrorStreaming;
@ -957,7 +922,7 @@ static int instream_end_read_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is)
}
static int instream_pause_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is, bool pause) {
SoundIoInStreamPulseAudio *ispa = (SoundIoInStreamPulseAudio *)is->backend_data;
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
pa_threaded_mainloop_lock(sipa->main_loop);

View file

@ -8,6 +8,7 @@
#ifndef SOUNDIO_PULSEAUDIO_HPP
#define SOUNDIO_PULSEAUDIO_HPP
#include "soundio.h"
#include "atomics.hpp"
#include <pulse/pulseaudio.h>
@ -43,4 +44,19 @@ struct SoundIoPulseAudio {
pa_proplist *props;
};
struct SoundIoOutStreamPulseAudio {
pa_stream *stream;
atomic_bool stream_ready;
pa_buffer_attr buffer_attr;
char *write_ptr;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
};
struct SoundIoInStreamPulseAudio {
pa_stream *stream;
atomic_bool stream_ready;
pa_buffer_attr buffer_attr;
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
};
#endif

View file

@ -186,8 +186,6 @@ int soundio_connect_backend(SoundIo *soundio, SoundIoBackend backend) {
if (!fn)
return SoundIoErrorBackendUnavailable;
memset(&si->backend_data, 0, sizeof(SoundIoBackendData));
int err;
if ((err = backend_init_fns[backend](si))) {
soundio_disconnect(soundio);
@ -201,10 +199,12 @@ void soundio_disconnect(struct SoundIo *soundio) {
if (si->destroy)
si->destroy(si);
memset(&si->backend_data, 0, sizeof(SoundIoBackendData));
soundio->current_backend = SoundIoBackendNone;
soundio_destroy_devices_info(si->safe_devices_info);
si->safe_devices_info = nullptr;
si->destroy = nullptr;

View file

@ -51,6 +51,32 @@ union SoundIoDeviceBackendData {
SoundIoDeviceDummy dummy;
};
union SoundIoOutStreamBackendData {
#ifdef SOUNDIO_HAVE_JACK
SoundIoOutStreamJack jack;
#endif
#ifdef SOUNDIO_HAVE_PULSEAUDIO
SoundIoOutStreamPulseAudio pulseaudio;
#endif
#ifdef SOUNDIO_HAVE_ALSA
SoundIoOutStreamAlsa alsa;
#endif
SoundIoOutStreamDummy dummy;
};
union SoundIoInStreamBackendData {
#ifdef SOUNDIO_HAVE_JACK
SoundIoInStreamJack jack;
#endif
#ifdef SOUNDIO_HAVE_PULSEAUDIO
SoundIoInStreamPulseAudio pulseaudio;
#endif
#ifdef SOUNDIO_HAVE_ALSA
SoundIoInStreamAlsa alsa;
#endif
SoundIoInStreamDummy dummy;
};
struct SoundIoDevicesInfo {
SoundIoList<SoundIoDevice *> input_devices;
SoundIoList<SoundIoDevice *> output_devices;
@ -60,13 +86,13 @@ struct SoundIoDevicesInfo {
};
struct SoundIoOutStreamPrivate {
struct SoundIoOutStream pub;
void *backend_data;
SoundIoOutStream pub;
SoundIoOutStreamBackendData backend_data;
};
struct SoundIoInStreamPrivate {
struct SoundIoInStream pub;
void *backend_data;
SoundIoInStream pub;
SoundIoInStreamBackendData backend_data;
};
struct SoundIoPrivate {