mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-23 07:25:33 +00:00
SoundIoOutStream, SoundIoInStream: void * -> union
For better cache locality and lower mlock requirements.
This commit is contained in:
parent
db1195877a
commit
70decb39f5
|
@ -280,8 +280,6 @@ 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. instead of `void *backend_data` use a union for better cache locality
|
|
||||||
and smaller mlock requirements
|
|
||||||
0. Consider testing on FreeBSD
|
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
|
||||||
|
|
104
src/alsa.cpp
104
src/alsa.cpp
|
@ -8,7 +8,6 @@
|
||||||
#include "alsa.hpp"
|
#include "alsa.hpp"
|
||||||
#include "soundio.hpp"
|
#include "soundio.hpp"
|
||||||
|
|
||||||
#include <alsa/asoundlib.h>
|
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
#include <math.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) {
|
static void wakeup_device_poll(SoundIoAlsa *sia) {
|
||||||
ssize_t amt = write(sia->notify_pipe_fd[1], "a", 1);
|
ssize_t amt = write(sia->notify_pipe_fd[1], "a", 1);
|
||||||
if (amt == -1) {
|
if (amt == -1) {
|
||||||
|
@ -881,9 +847,7 @@ static void wakeup(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void outstream_destroy_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static void outstream_destroy_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamAlsa *osa = (SoundIoOutStreamAlsa *) os->backend_data;
|
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
if (!osa)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (osa->thread) {
|
if (osa->thread) {
|
||||||
osa->thread_exit_flag.clear();
|
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->chmap, osa->chmap_size);
|
||||||
|
|
||||||
deallocate(osa->sample_buffer, osa->sample_buffer_size);
|
deallocate(osa->sample_buffer, osa->sample_buffer_size);
|
||||||
|
|
||||||
destroy(osa);
|
|
||||||
os->backend_data = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xrun_recovery(SoundIoOutStreamPrivate *os, int err) {
|
static int xrun_recovery(SoundIoOutStreamPrivate *os, int err) {
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamAlsa *osa = (SoundIoOutStreamAlsa *)os->backend_data;
|
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
if (err == -EPIPE) {
|
if (err == -EPIPE) {
|
||||||
err = snd_pcm_prepare(osa->handle);
|
err = snd_pcm_prepare(osa->handle);
|
||||||
if (err >= 0)
|
if (err >= 0)
|
||||||
|
@ -924,7 +885,7 @@ static int xrun_recovery(SoundIoOutStreamPrivate *os, int err) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_xrun_recovery(SoundIoInStreamPrivate *is, 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) {
|
if (err == -EPIPE) {
|
||||||
err = snd_pcm_prepare(isa->handle);
|
err = snd_pcm_prepare(isa->handle);
|
||||||
} else if (err == -ESTRPIPE) {
|
} else if (err == -ESTRPIPE) {
|
||||||
|
@ -977,7 +938,7 @@ static int instream_wait_for_poll(SoundIoInStreamAlsa *isa) {
|
||||||
void outstream_thread_run(void *arg) {
|
void outstream_thread_run(void *arg) {
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *) arg;
|
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *) arg;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamAlsa *osa = (SoundIoOutStreamAlsa *) os->backend_data;
|
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -1046,37 +1007,37 @@ void outstream_thread_run(void *arg) {
|
||||||
static void instream_thread_run(void *arg) {
|
static void instream_thread_run(void *arg) {
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *) arg;
|
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *) arg;
|
||||||
SoundIoInStream *instream = &is->pub;
|
SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamAlsa *osa = (SoundIoInStreamAlsa *) is->backend_data;
|
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
snd_pcm_state_t state = snd_pcm_state(osa->handle);
|
snd_pcm_state_t state = snd_pcm_state(isa->handle);
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case SND_PCM_STATE_SETUP:
|
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);
|
instream->error_callback(instream, SoundIoErrorStreaming);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
case SND_PCM_STATE_PREPARED:
|
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);
|
instream->error_callback(instream, SoundIoErrorStreaming);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
case SND_PCM_STATE_RUNNING:
|
case SND_PCM_STATE_RUNNING:
|
||||||
{
|
{
|
||||||
if ((err = instream_wait_for_poll(osa)) < 0) {
|
if ((err = instream_wait_for_poll(isa)) < 0) {
|
||||||
if (!osa->thread_exit_flag.test_and_set())
|
if (!isa->thread_exit_flag.test_and_set())
|
||||||
return;
|
return;
|
||||||
instream->error_callback(instream, SoundIoErrorStreaming);
|
instream->error_callback(instream, SoundIoErrorStreaming);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!osa->thread_exit_flag.test_and_set())
|
if (!isa->thread_exit_flag.test_and_set())
|
||||||
return;
|
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 (avail < 0) {
|
||||||
if ((err = instream_xrun_recovery(is, avail)) < 0) {
|
if ((err = instream_xrun_recovery(is, avail)) < 0) {
|
||||||
instream->error_callback(instream, SoundIoErrorStreaming);
|
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) {
|
static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
|
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoDevice *device = outstream->device;
|
SoundIoDevice *device = outstream->device;
|
||||||
|
|
||||||
|
@ -1123,13 +1085,6 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
||||||
if (outstream->prebuf_duration == -1.0)
|
if (outstream->prebuf_duration == -1.0)
|
||||||
outstream->prebuf_duration = outstream->buffer_duration;
|
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;
|
int ch_count = outstream->layout.channel_count;
|
||||||
|
|
||||||
osa->chmap_size = sizeof(int) + sizeof(int) * ch_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) {
|
static int outstream_start_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamAlsa *osa = (SoundIoOutStreamAlsa *) os->backend_data;
|
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
|
|
||||||
assert(!osa->thread);
|
assert(!osa->thread);
|
||||||
|
|
||||||
|
@ -1302,7 +1257,7 @@ int outstream_begin_write_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os,
|
||||||
struct SoundIoChannelArea **out_areas, int *frame_count)
|
struct SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
*out_areas = nullptr;
|
*out_areas = nullptr;
|
||||||
SoundIoOutStreamAlsa *osa = (SoundIoOutStreamAlsa *) os->backend_data;
|
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
|
|
||||||
if (osa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
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) {
|
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;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
|
|
||||||
snd_pcm_sframes_t commitres;
|
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,
|
static int outstream_clear_buffer_alsa(SoundIoPrivate *si,
|
||||||
SoundIoOutStreamPrivate *os)
|
SoundIoOutStreamPrivate *os)
|
||||||
{
|
{
|
||||||
SoundIoOutStreamAlsa *osa = (SoundIoOutStreamAlsa *) os->backend_data;
|
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||||
int err;
|
int err;
|
||||||
if ((err = snd_pcm_reset(osa->handle)) < 0)
|
if ((err = snd_pcm_reset(osa->handle)) < 0)
|
||||||
return SoundIoErrorStreaming;
|
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) {
|
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;
|
int err;
|
||||||
if ((err = snd_pcm_pause(osa->handle, pause)) < 0)
|
if ((err = snd_pcm_pause(osa->handle, pause)) < 0)
|
||||||
return SoundIoErrorIncompatibleDevice;
|
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) {
|
static void instream_destroy_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamAlsa *isa = (SoundIoInStreamAlsa *) is->backend_data;
|
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
if (!isa)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (isa->thread) {
|
if (isa->thread) {
|
||||||
isa->thread_exit_flag.clear();
|
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->poll_fds, isa->poll_fd_count);
|
||||||
deallocate(isa->chmap, isa->chmap_size);
|
deallocate(isa->chmap, isa->chmap_size);
|
||||||
deallocate(isa->sample_buffer, isa->sample_buffer_size);
|
deallocate(isa->sample_buffer, isa->sample_buffer_size);
|
||||||
|
|
||||||
destroy(isa);
|
|
||||||
is->backend_data = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
|
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
SoundIoInStream *instream = &is->pub;
|
SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoDevice *device = instream->device;
|
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);
|
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;
|
int ch_count = instream->layout.channel_count;
|
||||||
|
|
||||||
isa->chmap_size = sizeof(int) + sizeof(int) * ch_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) {
|
static int instream_start_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamAlsa *isa = (SoundIoInStreamAlsa *) is->backend_data;
|
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
|
|
||||||
assert(!isa->thread);
|
assert(!isa->thread);
|
||||||
|
|
||||||
|
@ -1586,7 +1530,7 @@ static int instream_begin_read_alsa(SoundIoPrivate *si,
|
||||||
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
|
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
*out_areas = nullptr;
|
*out_areas = nullptr;
|
||||||
SoundIoInStreamAlsa *isa = (SoundIoInStreamAlsa *) is->backend_data;
|
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||||
SoundIoInStream *instream = &is->pub;
|
SoundIoInStream *instream = &is->pub;
|
||||||
|
|
||||||
if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
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) {
|
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) {
|
if (isa->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
|
||||||
return 0;
|
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) {
|
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;
|
int err;
|
||||||
if ((err = snd_pcm_pause(isa->handle, pause)) < 0)
|
if ((err = snd_pcm_pause(isa->handle, pause)) < 0)
|
||||||
return SoundIoErrorIncompatibleDevice;
|
return SoundIoErrorIncompatibleDevice;
|
||||||
|
|
36
src/alsa.hpp
36
src/alsa.hpp
|
@ -8,9 +8,12 @@
|
||||||
#ifndef SOUNDIO_ALSA_HPP
|
#ifndef SOUNDIO_ALSA_HPP
|
||||||
#define SOUNDIO_ALSA_HPP
|
#define SOUNDIO_ALSA_HPP
|
||||||
|
|
||||||
|
#include "soundio.h"
|
||||||
#include "os.hpp"
|
#include "os.hpp"
|
||||||
#include "atomics.hpp"
|
#include "atomics.hpp"
|
||||||
|
|
||||||
|
#include <alsa/asoundlib.h>
|
||||||
|
|
||||||
int soundio_alsa_init(struct SoundIoPrivate *si);
|
int soundio_alsa_init(struct SoundIoPrivate *si);
|
||||||
|
|
||||||
struct SoundIoDeviceAlsa {
|
struct SoundIoDeviceAlsa {
|
||||||
|
@ -32,4 +35,37 @@ struct SoundIoAlsa {
|
||||||
struct SoundIoDevicesInfo *ready_devices_info;
|
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
|
#endif
|
||||||
|
|
|
@ -7,41 +7,15 @@
|
||||||
|
|
||||||
#include "dummy.hpp"
|
#include "dummy.hpp"
|
||||||
#include "soundio.hpp"
|
#include "soundio.hpp"
|
||||||
#include "atomics.hpp"
|
|
||||||
#include "ring_buffer.hpp"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.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) {
|
static void playback_thread_run(void *arg) {
|
||||||
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
|
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamDummy *osd = (SoundIoOutStreamDummy *)os->backend_data;
|
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
|
|
||||||
double start_time = soundio_os_get_time();
|
double start_time = soundio_os_get_time();
|
||||||
osd->playback_start_time = start_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) {
|
static void capture_thread_run(void *arg) {
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
|
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate *)arg;
|
||||||
SoundIoInStream *instream = &is->pub;
|
SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamDummy *isd = (SoundIoInStreamDummy *)is->backend_data;
|
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||||
|
|
||||||
long frames_consumed = 0;
|
long frames_consumed = 0;
|
||||||
double start_time = soundio_os_get_time();
|
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) {
|
static void outstream_destroy_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamDummy *osd = (SoundIoOutStreamDummy *)os->backend_data;
|
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
if (!osd)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (osd->thread) {
|
if (osd->thread) {
|
||||||
osd->abort_flag.clear();
|
osd->abort_flag.clear();
|
||||||
|
@ -164,12 +136,10 @@ static void outstream_destroy_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate
|
||||||
osd->cond = nullptr;
|
osd->cond = nullptr;
|
||||||
|
|
||||||
soundio_ring_buffer_deinit(&osd->ring_buffer);
|
soundio_ring_buffer_deinit(&osd->ring_buffer);
|
||||||
|
|
||||||
destroy(osd);
|
|
||||||
os->backend_data = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_open_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static int outstream_open_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
|
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoDevice *device = outstream->device;
|
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);
|
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 err;
|
||||||
int buffer_size = outstream->bytes_per_frame * outstream->sample_rate * outstream->buffer_duration;
|
int buffer_size = outstream->bytes_per_frame * outstream->sample_rate * outstream->buffer_duration;
|
||||||
if ((err = soundio_ring_buffer_init(&osd->ring_buffer, buffer_size))) {
|
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) {
|
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 (pause) {
|
||||||
if (osd->thread) {
|
if (osd->thread) {
|
||||||
osd->abort_flag.clear();
|
osd->abort_flag.clear();
|
||||||
|
@ -242,7 +205,7 @@ static int outstream_begin_write_dummy(SoundIoPrivate *si,
|
||||||
*out_areas = nullptr;
|
*out_areas = nullptr;
|
||||||
|
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamDummy *osd = (SoundIoOutStreamDummy *)os->backend_data;
|
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||||
|
|
||||||
assert(*frame_count >= 0);
|
assert(*frame_count >= 0);
|
||||||
assert(*frame_count <= osd->buffer_frame_count);
|
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) {
|
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;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
int byte_count = frame_count * outstream->bytes_per_frame;
|
int byte_count = frame_count * outstream->bytes_per_frame;
|
||||||
soundio_ring_buffer_advance_write_ptr(&osd->ring_buffer, byte_count);
|
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) {
|
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);
|
soundio_ring_buffer_clear(&osd->ring_buffer);
|
||||||
osd->prebuf_frames_left = osd->prebuf_frame_count;
|
osd->prebuf_frames_left = osd->prebuf_frame_count;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void instream_destroy_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
static void instream_destroy_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamDummy *isd = (SoundIoInStreamDummy *)is->backend_data;
|
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||||
if (!isd)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (isd->thread) {
|
if (isd->thread) {
|
||||||
isd->abort_flag.clear();
|
isd->abort_flag.clear();
|
||||||
|
@ -300,12 +261,10 @@ static void instream_destroy_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *i
|
||||||
isd->cond = nullptr;
|
isd->cond = nullptr;
|
||||||
|
|
||||||
soundio_ring_buffer_deinit(&isd->ring_buffer);
|
soundio_ring_buffer_deinit(&isd->ring_buffer);
|
||||||
|
|
||||||
destroy(isd);
|
|
||||||
is->backend_data = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_open_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
static int instream_open_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
|
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||||
SoundIoInStream *instream = &is->pub;
|
SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoDevice *device = instream->device;
|
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);
|
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 err;
|
||||||
int buffer_size = instream->bytes_per_frame * instream->sample_rate * instream->buffer_duration;
|
int buffer_size = instream->bytes_per_frame * instream->sample_rate * instream->buffer_duration;
|
||||||
if ((err = soundio_ring_buffer_init(&isd->ring_buffer, buffer_size))) {
|
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) {
|
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 (pause) {
|
||||||
if (isd->thread) {
|
if (isd->thread) {
|
||||||
isd->abort_flag.clear();
|
isd->abort_flag.clear();
|
||||||
|
@ -372,7 +324,7 @@ static int instream_begin_read_dummy(SoundIoPrivate *si,
|
||||||
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
|
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
SoundIoInStream *instream = &is->pub;
|
SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamDummy *isd = (SoundIoInStreamDummy *)is->backend_data;
|
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||||
|
|
||||||
assert(*frame_count >= 0);
|
assert(*frame_count >= 0);
|
||||||
assert(*frame_count <= isd->buffer_frame_count);
|
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) {
|
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;
|
SoundIoInStream *instream = &is->pub;
|
||||||
|
|
||||||
if (isd->hole_size > 0) {
|
if (isd->hole_size > 0) {
|
||||||
|
|
|
@ -8,7 +8,10 @@
|
||||||
#ifndef SOUNDIO_DUMMY_HPP
|
#ifndef SOUNDIO_DUMMY_HPP
|
||||||
#define SOUNDIO_DUMMY_HPP
|
#define SOUNDIO_DUMMY_HPP
|
||||||
|
|
||||||
|
#include "soundio.h"
|
||||||
#include "os.hpp"
|
#include "os.hpp"
|
||||||
|
#include "atomics.hpp"
|
||||||
|
#include "ring_buffer.hpp"
|
||||||
|
|
||||||
int soundio_dummy_init(struct SoundIoPrivate *si);
|
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
|
#endif
|
||||||
|
|
22
src/jack.cpp
22
src/jack.cpp
|
@ -14,11 +14,6 @@
|
||||||
|
|
||||||
static atomic_flag global_msg_callback_flag = ATOMIC_FLAG_INIT;
|
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 {
|
struct SoundIoJackPort {
|
||||||
const char *name;
|
const char *name;
|
||||||
int name_len;
|
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) {
|
static void outstream_destroy_jack(struct SoundIoPrivate *is, struct SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamJack *osj = (SoundIoOutStreamJack *) os->backend_data;
|
SoundIoOutStreamJack *osj = &os->backend_data.jack;
|
||||||
if (!osj)
|
|
||||||
return;
|
|
||||||
|
|
||||||
jack_client_close(osj->client);
|
jack_client_close(osj->client);
|
||||||
|
|
||||||
destroy(osj);
|
|
||||||
os->backend_data = 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;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
//TODO SoundIoDevice *device = outstream->device;
|
//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->period_duration = 0.0; // TODO
|
||||||
outstream->prebuf_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;
|
outstream->layout_error = SoundIoErrorIncompatibleBackend;
|
||||||
|
|
||||||
jack_status_t status;
|
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) {
|
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;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
int err;
|
int err;
|
||||||
if (pause) {
|
if (pause) {
|
||||||
|
|
11
src/jack.hpp
11
src/jack.hpp
|
@ -8,6 +8,7 @@
|
||||||
#ifndef SOUNDIO_JACK_HPP
|
#ifndef SOUNDIO_JACK_HPP
|
||||||
#define SOUNDIO_JACK_HPP
|
#define SOUNDIO_JACK_HPP
|
||||||
|
|
||||||
|
#include "soundio.h"
|
||||||
#include "os.hpp"
|
#include "os.hpp"
|
||||||
|
|
||||||
#include <jack/jack.h>
|
#include <jack/jack.h>
|
||||||
|
@ -29,5 +30,13 @@ struct SoundIoJack {
|
||||||
int buffer_size;
|
int buffer_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
struct SoundIoOutStreamJack {
|
||||||
|
jack_client_t *client;
|
||||||
|
jack_port_t *ports[SOUNDIO_MAX_CHANNELS];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SoundIoInStreamJack {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -13,21 +13,6 @@
|
||||||
#include <stdio.h>
|
#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,
|
static void subscribe_callback(pa_context *context,
|
||||||
pa_subscription_event_type_t event_bits, uint32_t index, void *userdata)
|
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;
|
SoundIo *soundio = outstream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
|
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
switch (pa_stream_get_state(stream)) {
|
switch (pa_stream_get_state(stream)) {
|
||||||
case PA_STREAM_UNCONNECTED:
|
case PA_STREAM_UNCONNECTED:
|
||||||
case PA_STREAM_CREATING:
|
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) {
|
static void outstream_destroy_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
|
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
if (!ospa)
|
|
||||||
return;
|
|
||||||
|
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
pa_stream *stream = ospa->stream;
|
pa_stream *stream = ospa->stream;
|
||||||
|
@ -618,21 +601,12 @@ static void outstream_destroy_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os
|
||||||
|
|
||||||
ospa->stream = nullptr;
|
ospa->stream = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy(ospa);
|
|
||||||
os->backend_data = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
|
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
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;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
ospa->stream_ready = false;
|
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) {
|
static int outstream_start_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
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);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
|
@ -720,7 +694,7 @@ static int outstream_begin_write_pa(SoundIoPrivate *si,
|
||||||
*out_areas = nullptr;
|
*out_areas = nullptr;
|
||||||
|
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
|
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
pa_stream *stream = ospa->stream;
|
pa_stream *stream = ospa->stream;
|
||||||
size_t byte_count = *frame_count * outstream->bytes_per_frame;
|
size_t byte_count = *frame_count * outstream->bytes_per_frame;
|
||||||
if (pa_stream_begin_write(stream, (void**)&ospa->write_ptr, &byte_count))
|
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) {
|
static int outstream_end_write_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os, int frame_count) {
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
|
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
pa_stream *stream = ospa->stream;
|
pa_stream *stream = ospa->stream;
|
||||||
assert(frame_count > 0);
|
assert(frame_count > 0);
|
||||||
size_t byte_count = frame_count * outstream->bytes_per_frame;
|
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,
|
static int outstream_clear_buffer_pa(SoundIoPrivate *si,
|
||||||
SoundIoOutStreamPrivate *os)
|
SoundIoOutStreamPrivate *os)
|
||||||
{
|
{
|
||||||
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
|
SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
pa_stream *stream = ospa->stream;
|
pa_stream *stream = ospa->stream;
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
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) {
|
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;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
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) {
|
static void recording_stream_state_callback(pa_stream *stream, void *userdata) {
|
||||||
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate*)userdata;
|
SoundIoInStreamPrivate *is = (SoundIoInStreamPrivate*)userdata;
|
||||||
SoundIoInStreamPulseAudio *ispa = (SoundIoInStreamPulseAudio *)is->backend_data;
|
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
||||||
SoundIoInStream *instream = &is->pub;
|
SoundIoInStream *instream = &is->pub;
|
||||||
SoundIo *soundio = instream->device->soundio;
|
SoundIo *soundio = instream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)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);
|
instream->read_callback(instream, available_frame_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void instream_destroy_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *instream) {
|
static void instream_destroy_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStreamPulseAudio *ispa = (SoundIoInStreamPulseAudio *)instream->backend_data;
|
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
||||||
if (!ispa)
|
|
||||||
return;
|
|
||||||
|
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
pa_stream *stream = ispa->stream;
|
pa_stream *stream = ispa->stream;
|
||||||
if (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) {
|
static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
|
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
||||||
SoundIoInStream *instream = &is->pub;
|
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;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
ispa->stream_ready = false;
|
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) {
|
static int instream_start_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
SoundIoInStream *instream = &is->pub;
|
SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamPulseAudio *ispa = (SoundIoInStreamPulseAudio *)is->backend_data;
|
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
||||||
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
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)
|
SoundIoInStreamPrivate *is, SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
SoundIoInStream *instream = &is->pub;
|
SoundIoInStream *instream = &is->pub;
|
||||||
SoundIoInStreamPulseAudio *ispa = (SoundIoInStreamPulseAudio *)is->backend_data;
|
SoundIoInStreamPulseAudio *ispa = &is->backend_data.pulseaudio;
|
||||||
pa_stream *stream = ispa->stream;
|
pa_stream *stream = ispa->stream;
|
||||||
|
|
||||||
assert(ispa->stream_ready);
|
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) {
|
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;
|
pa_stream *stream = ispa->stream;
|
||||||
if (pa_stream_drop(stream))
|
if (pa_stream_drop(stream))
|
||||||
return SoundIoErrorStreaming;
|
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) {
|
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;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#ifndef SOUNDIO_PULSEAUDIO_HPP
|
#ifndef SOUNDIO_PULSEAUDIO_HPP
|
||||||
#define SOUNDIO_PULSEAUDIO_HPP
|
#define SOUNDIO_PULSEAUDIO_HPP
|
||||||
|
|
||||||
|
#include "soundio.h"
|
||||||
#include "atomics.hpp"
|
#include "atomics.hpp"
|
||||||
|
|
||||||
#include <pulse/pulseaudio.h>
|
#include <pulse/pulseaudio.h>
|
||||||
|
@ -43,4 +44,19 @@ struct SoundIoPulseAudio {
|
||||||
pa_proplist *props;
|
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
|
#endif
|
||||||
|
|
|
@ -186,8 +186,6 @@ int soundio_connect_backend(SoundIo *soundio, SoundIoBackend backend) {
|
||||||
if (!fn)
|
if (!fn)
|
||||||
return SoundIoErrorBackendUnavailable;
|
return SoundIoErrorBackendUnavailable;
|
||||||
|
|
||||||
memset(&si->backend_data, 0, sizeof(SoundIoBackendData));
|
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
if ((err = backend_init_fns[backend](si))) {
|
if ((err = backend_init_fns[backend](si))) {
|
||||||
soundio_disconnect(soundio);
|
soundio_disconnect(soundio);
|
||||||
|
@ -201,10 +199,12 @@ void soundio_disconnect(struct SoundIo *soundio) {
|
||||||
|
|
||||||
if (si->destroy)
|
if (si->destroy)
|
||||||
si->destroy(si);
|
si->destroy(si);
|
||||||
|
memset(&si->backend_data, 0, sizeof(SoundIoBackendData));
|
||||||
|
|
||||||
soundio->current_backend = SoundIoBackendNone;
|
soundio->current_backend = SoundIoBackendNone;
|
||||||
|
|
||||||
soundio_destroy_devices_info(si->safe_devices_info);
|
soundio_destroy_devices_info(si->safe_devices_info);
|
||||||
|
|
||||||
si->safe_devices_info = nullptr;
|
si->safe_devices_info = nullptr;
|
||||||
|
|
||||||
si->destroy = nullptr;
|
si->destroy = nullptr;
|
||||||
|
|
|
@ -51,6 +51,32 @@ union SoundIoDeviceBackendData {
|
||||||
SoundIoDeviceDummy dummy;
|
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 {
|
struct SoundIoDevicesInfo {
|
||||||
SoundIoList<SoundIoDevice *> input_devices;
|
SoundIoList<SoundIoDevice *> input_devices;
|
||||||
SoundIoList<SoundIoDevice *> output_devices;
|
SoundIoList<SoundIoDevice *> output_devices;
|
||||||
|
@ -60,13 +86,13 @@ struct SoundIoDevicesInfo {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoOutStreamPrivate {
|
struct SoundIoOutStreamPrivate {
|
||||||
struct SoundIoOutStream pub;
|
SoundIoOutStream pub;
|
||||||
void *backend_data;
|
SoundIoOutStreamBackendData backend_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoInStreamPrivate {
|
struct SoundIoInStreamPrivate {
|
||||||
struct SoundIoInStream pub;
|
SoundIoInStream pub;
|
||||||
void *backend_data;
|
SoundIoInStreamBackendData backend_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoPrivate {
|
struct SoundIoPrivate {
|
||||||
|
|
Loading…
Reference in a new issue