mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-23 08:25:30 +00:00
SoundIo, SoundIoDevice: unions instead of void *
for better cache locality
This commit is contained in:
parent
85549b59b7
commit
db1195877a
|
@ -233,12 +233,16 @@ view `coverage/index.html` in a browser.
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
0. implement JACK backend, get examples working
|
0. implement JACK backend, get examples working
|
||||||
|
0. Steal PulseAudio's default channel maps per channel count
|
||||||
|
0. Ability to parse PulseAudio's "front-left" "front-right" channel label strings
|
||||||
|
0. When two soundio clients are talking to each other, use port names to
|
||||||
|
negotiate channel maps.
|
||||||
0. why does pulseaudio microphone use up all the CPU?
|
0. why does pulseaudio microphone use up all the CPU?
|
||||||
0. merge in/out stream structures and functions?
|
0. merge in/out stream structures and functions?
|
||||||
0. implement CoreAudio (OSX) backend, get examples working
|
0. implement CoreAudio (OSX) backend, get examples working
|
||||||
0. implement WASAPI (Windows) backend, get examples working
|
0. implement WASAPI (Windows) backend, get examples working
|
||||||
0. implement ASIO (Windows) backend, get examples working
|
0. implement ASIO (Windows) backend, get examples working
|
||||||
0. Avoid calling `panic` in PulseAudio.
|
0. Avoid calling `soundio_panic` in PulseAudio.
|
||||||
0. Figure out a way to test prebuf. I suspect prebuf not working for ALSA
|
0. Figure out a way to test prebuf. I suspect prebuf not working for ALSA
|
||||||
which is why we have to pre-fill the ring buffer with silence for
|
which is why we have to pre-fill the ring buffer with silence for
|
||||||
the microphone example.
|
the microphone example.
|
||||||
|
@ -257,6 +261,9 @@ view `coverage/index.html` in a browser.
|
||||||
0. Allow calling functions from outside the callbacks as long as they first
|
0. Allow calling functions from outside the callbacks as long as they first
|
||||||
call lock and then unlock when done.
|
call lock and then unlock when done.
|
||||||
0. Should pause/resume be callable from outside the callbacks?
|
0. Should pause/resume be callable from outside the callbacks?
|
||||||
|
0. device.name -> device.id, device.description -> device.name
|
||||||
|
0. PulseAudio: when opening a device start it corked that way we can get
|
||||||
|
accurate buffer readings
|
||||||
0. clean up API and improve documentation
|
0. clean up API and improve documentation
|
||||||
- make sure every function which can return an error documents which errors
|
- make sure every function which can return an error documents which errors
|
||||||
it can return
|
it can return
|
||||||
|
|
42
src/alsa.cpp
42
src/alsa.cpp
|
@ -7,8 +7,6 @@
|
||||||
|
|
||||||
#include "alsa.hpp"
|
#include "alsa.hpp"
|
||||||
#include "soundio.hpp"
|
#include "soundio.hpp"
|
||||||
#include "os.hpp"
|
|
||||||
#include "atomics.hpp"
|
|
||||||
|
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
|
@ -25,21 +23,6 @@ static snd_pcm_access_t prioritized_access_types[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct SoundIoAlsa {
|
|
||||||
SoundIoOsMutex *mutex;
|
|
||||||
SoundIoOsCond *cond;
|
|
||||||
|
|
||||||
struct SoundIoOsThread *thread;
|
|
||||||
atomic_flag abort_flag;
|
|
||||||
int notify_fd;
|
|
||||||
int notify_wd;
|
|
||||||
atomic_bool have_devices_flag;
|
|
||||||
int notify_pipe_fd[2];
|
|
||||||
|
|
||||||
// this one is ready to be read with flush_events. protected by mutex
|
|
||||||
struct SoundIoDevicesInfo *ready_devices_info;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SoundIoOutStreamAlsa {
|
struct SoundIoOutStreamAlsa {
|
||||||
snd_pcm_t *handle;
|
snd_pcm_t *handle;
|
||||||
snd_pcm_chmap_t *chmap;
|
snd_pcm_chmap_t *chmap;
|
||||||
|
@ -85,9 +68,7 @@ static void wakeup_device_poll(SoundIoAlsa *sia) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_alsa(SoundIoPrivate *si) {
|
static void destroy_alsa(SoundIoPrivate *si) {
|
||||||
SoundIoAlsa *sia = (SoundIoAlsa *)si->backend_data;
|
SoundIoAlsa *sia = &si->backend_data.alsa;
|
||||||
if (!sia)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (sia->thread) {
|
if (sia->thread) {
|
||||||
sia->abort_flag.clear();
|
sia->abort_flag.clear();
|
||||||
|
@ -108,9 +89,6 @@ static void destroy_alsa(SoundIoPrivate *si) {
|
||||||
close(sia->notify_pipe_fd[0]);
|
close(sia->notify_pipe_fd[0]);
|
||||||
close(sia->notify_pipe_fd[1]);
|
close(sia->notify_pipe_fd[1]);
|
||||||
close(sia->notify_fd);
|
close(sia->notify_fd);
|
||||||
|
|
||||||
destroy(sia);
|
|
||||||
si->backend_data = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char * str_partition_on_char(char *str, char c) {
|
static char * str_partition_on_char(char *str, char c) {
|
||||||
|
@ -517,7 +495,7 @@ static inline bool str_has_prefix(const char *big_str, const char *prefix) {
|
||||||
|
|
||||||
static int refresh_devices(SoundIoPrivate *si) {
|
static int refresh_devices(SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
SoundIo *soundio = &si->pub;
|
||||||
SoundIoAlsa *sia = (SoundIoAlsa *)si->backend_data;
|
SoundIoAlsa *sia = &si->backend_data.alsa;
|
||||||
|
|
||||||
SoundIoDevicesInfo *devices_info = create<SoundIoDevicesInfo>();
|
SoundIoDevicesInfo *devices_info = create<SoundIoDevicesInfo>();
|
||||||
if (!devices_info)
|
if (!devices_info)
|
||||||
|
@ -761,7 +739,7 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
|
|
||||||
static void device_thread_run(void *arg) {
|
static void device_thread_run(void *arg) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
||||||
SoundIoAlsa *sia = (SoundIoAlsa *)si->backend_data;
|
SoundIoAlsa *sia = &si->backend_data.alsa;
|
||||||
|
|
||||||
// Some systems cannot read integer variables if they are not
|
// Some systems cannot read integer variables if they are not
|
||||||
// properly aligned. On other systems, incorrect alignment may
|
// properly aligned. On other systems, incorrect alignment may
|
||||||
|
@ -864,7 +842,7 @@ static void block_until_have_devices(SoundIoAlsa *sia) {
|
||||||
|
|
||||||
static void flush_events(SoundIoPrivate *si) {
|
static void flush_events(SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
SoundIo *soundio = &si->pub;
|
||||||
SoundIoAlsa *sia = (SoundIoAlsa *)si->backend_data;
|
SoundIoAlsa *sia = &si->backend_data.alsa;
|
||||||
block_until_have_devices(sia);
|
block_until_have_devices(sia);
|
||||||
|
|
||||||
bool change = false;
|
bool change = false;
|
||||||
|
@ -888,7 +866,7 @@ static void flush_events(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wait_events(SoundIoPrivate *si) {
|
static void wait_events(SoundIoPrivate *si) {
|
||||||
SoundIoAlsa *sia = (SoundIoAlsa *)si->backend_data;
|
SoundIoAlsa *sia = &si->backend_data.alsa;
|
||||||
flush_events(si);
|
flush_events(si);
|
||||||
soundio_os_mutex_lock(sia->mutex);
|
soundio_os_mutex_lock(sia->mutex);
|
||||||
soundio_os_cond_wait(sia->cond, sia->mutex);
|
soundio_os_cond_wait(sia->cond, sia->mutex);
|
||||||
|
@ -896,7 +874,7 @@ static void wait_events(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wakeup(SoundIoPrivate *si) {
|
static void wakeup(SoundIoPrivate *si) {
|
||||||
SoundIoAlsa *sia = (SoundIoAlsa *)si->backend_data;
|
SoundIoAlsa *sia = &si->backend_data.alsa;
|
||||||
soundio_os_mutex_lock(sia->mutex);
|
soundio_os_mutex_lock(sia->mutex);
|
||||||
soundio_os_cond_signal(sia->cond, sia->mutex);
|
soundio_os_cond_signal(sia->cond, sia->mutex);
|
||||||
soundio_os_mutex_unlock(sia->mutex);
|
soundio_os_mutex_unlock(sia->mutex);
|
||||||
|
@ -1695,15 +1673,9 @@ static int instream_pause_alsa(struct SoundIoPrivate *si, struct SoundIoInStream
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_alsa_init(SoundIoPrivate *si) {
|
int soundio_alsa_init(SoundIoPrivate *si) {
|
||||||
|
SoundIoAlsa *sia = &si->backend_data.alsa;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
assert(!si->backend_data);
|
|
||||||
SoundIoAlsa *sia = create<SoundIoAlsa>();
|
|
||||||
if (!sia) {
|
|
||||||
destroy_alsa(si);
|
|
||||||
return SoundIoErrorNoMem;
|
|
||||||
}
|
|
||||||
si->backend_data = sia;
|
|
||||||
sia->notify_fd = -1;
|
sia->notify_fd = -1;
|
||||||
sia->notify_wd = -1;
|
sia->notify_wd = -1;
|
||||||
sia->have_devices_flag.store(false);
|
sia->have_devices_flag.store(false);
|
||||||
|
|
23
src/alsa.hpp
23
src/alsa.hpp
|
@ -8,7 +8,28 @@
|
||||||
#ifndef SOUNDIO_ALSA_HPP
|
#ifndef SOUNDIO_ALSA_HPP
|
||||||
#define SOUNDIO_ALSA_HPP
|
#define SOUNDIO_ALSA_HPP
|
||||||
|
|
||||||
|
#include "os.hpp"
|
||||||
|
#include "atomics.hpp"
|
||||||
|
|
||||||
int soundio_alsa_init(struct SoundIoPrivate *si);
|
int soundio_alsa_init(struct SoundIoPrivate *si);
|
||||||
|
|
||||||
#endif
|
struct SoundIoDeviceAlsa {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SoundIoAlsa {
|
||||||
|
SoundIoOsMutex *mutex;
|
||||||
|
SoundIoOsCond *cond;
|
||||||
|
|
||||||
|
struct SoundIoOsThread *thread;
|
||||||
|
atomic_flag abort_flag;
|
||||||
|
int notify_fd;
|
||||||
|
int notify_wd;
|
||||||
|
atomic_bool have_devices_flag;
|
||||||
|
int notify_pipe_fd[2];
|
||||||
|
|
||||||
|
// this one is ready to be read with flush_events. protected by mutex
|
||||||
|
struct SoundIoDevicesInfo *ready_devices_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
#include "dummy.hpp"
|
#include "dummy.hpp"
|
||||||
#include "soundio.hpp"
|
#include "soundio.hpp"
|
||||||
#include "os.hpp"
|
|
||||||
#include "atomics.hpp"
|
#include "atomics.hpp"
|
||||||
#include "ring_buffer.hpp"
|
#include "ring_buffer.hpp"
|
||||||
|
|
||||||
|
@ -39,12 +38,6 @@ struct SoundIoInStreamDummy {
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoDummy {
|
|
||||||
SoundIoOsMutex *mutex;
|
|
||||||
SoundIoOsCond *cond;
|
|
||||||
bool devices_emitted;
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
||||||
|
@ -127,23 +120,18 @@ static void capture_thread_run(void *arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_dummy(SoundIoPrivate *si) {
|
static void destroy_dummy(SoundIoPrivate *si) {
|
||||||
SoundIoDummy *sid = (SoundIoDummy *)si->backend_data;
|
SoundIoDummy *sid = &si->backend_data.dummy;
|
||||||
if (!sid)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (sid->cond)
|
if (sid->cond)
|
||||||
soundio_os_cond_destroy(sid->cond);
|
soundio_os_cond_destroy(sid->cond);
|
||||||
|
|
||||||
if (sid->mutex)
|
if (sid->mutex)
|
||||||
soundio_os_mutex_destroy(sid->mutex);
|
soundio_os_mutex_destroy(sid->mutex);
|
||||||
|
|
||||||
destroy(sid);
|
|
||||||
si->backend_data = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flush_events(SoundIoPrivate *si) {
|
static void flush_events(SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
SoundIo *soundio = &si->pub;
|
||||||
SoundIoDummy *sid = (SoundIoDummy *)si->backend_data;
|
SoundIoDummy *sid = &si->backend_data.dummy;
|
||||||
if (sid->devices_emitted)
|
if (sid->devices_emitted)
|
||||||
return;
|
return;
|
||||||
sid->devices_emitted = true;
|
sid->devices_emitted = true;
|
||||||
|
@ -151,13 +139,13 @@ static void flush_events(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wait_events(SoundIoPrivate *si) {
|
static void wait_events(SoundIoPrivate *si) {
|
||||||
SoundIoDummy *sid = (SoundIoDummy *)si->backend_data;
|
SoundIoDummy *sid = &si->backend_data.dummy;
|
||||||
flush_events(si);
|
flush_events(si);
|
||||||
soundio_os_cond_wait(sid->cond, nullptr);
|
soundio_os_cond_wait(sid->cond, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wakeup(SoundIoPrivate *si) {
|
static void wakeup(SoundIoPrivate *si) {
|
||||||
SoundIoDummy *sid = (SoundIoDummy *)si->backend_data;
|
SoundIoDummy *sid = &si->backend_data.dummy;
|
||||||
soundio_os_cond_signal(sid->cond, nullptr);
|
soundio_os_cond_signal(sid->cond, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,13 +456,7 @@ static int set_all_device_channel_layouts(SoundIoDevice *device) {
|
||||||
|
|
||||||
int soundio_dummy_init(SoundIoPrivate *si) {
|
int soundio_dummy_init(SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
SoundIo *soundio = &si->pub;
|
||||||
assert(!si->backend_data);
|
SoundIoDummy *sid = &si->backend_data.dummy;
|
||||||
SoundIoDummy *sid = create<SoundIoDummy>();
|
|
||||||
if (!sid) {
|
|
||||||
destroy_dummy(si);
|
|
||||||
return SoundIoErrorNoMem;
|
|
||||||
}
|
|
||||||
si->backend_data = sid;
|
|
||||||
|
|
||||||
sid->mutex = soundio_os_mutex_create();
|
sid->mutex = soundio_os_mutex_create();
|
||||||
if (!sid->mutex) {
|
if (!sid->mutex) {
|
||||||
|
|
|
@ -8,6 +8,18 @@
|
||||||
#ifndef SOUNDIO_DUMMY_HPP
|
#ifndef SOUNDIO_DUMMY_HPP
|
||||||
#define SOUNDIO_DUMMY_HPP
|
#define SOUNDIO_DUMMY_HPP
|
||||||
|
|
||||||
|
#include "os.hpp"
|
||||||
|
|
||||||
int soundio_dummy_init(struct SoundIoPrivate *si);
|
int soundio_dummy_init(struct SoundIoPrivate *si);
|
||||||
|
|
||||||
|
struct SoundIoDummy {
|
||||||
|
SoundIoOsMutex *mutex;
|
||||||
|
SoundIoOsCond *cond;
|
||||||
|
bool devices_emitted;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SoundIoDeviceDummy {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
203
src/jack.cpp
203
src/jack.cpp
|
@ -8,23 +8,15 @@
|
||||||
#include "jack.hpp"
|
#include "jack.hpp"
|
||||||
#include "soundio.hpp"
|
#include "soundio.hpp"
|
||||||
#include "atomics.hpp"
|
#include "atomics.hpp"
|
||||||
#include "os.hpp"
|
|
||||||
#include "list.hpp"
|
#include "list.hpp"
|
||||||
|
|
||||||
#include <jack/jack.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
static atomic_flag global_msg_callback_flag = ATOMIC_FLAG_INIT;
|
static atomic_flag global_msg_callback_flag = ATOMIC_FLAG_INIT;
|
||||||
|
|
||||||
struct SoundIoJack {
|
struct SoundIoOutStreamJack {
|
||||||
jack_client_t *client;
|
jack_client_t *client;
|
||||||
SoundIoOsMutex *mutex;
|
jack_port_t *ports[SOUNDIO_MAX_CHANNELS];
|
||||||
SoundIoOsCond *cond;
|
|
||||||
// this one is ready to be read with flush_events. protected by mutex
|
|
||||||
struct SoundIoDevicesInfo *ready_devices_info;
|
|
||||||
bool initialized;
|
|
||||||
int sample_rate;
|
|
||||||
int buffer_size;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoJackPort {
|
struct SoundIoJackPort {
|
||||||
|
@ -37,12 +29,13 @@ struct SoundIoJackClient {
|
||||||
int name_len;
|
int name_len;
|
||||||
bool is_physical;
|
bool is_physical;
|
||||||
SoundIoDevicePurpose purpose;
|
SoundIoDevicePurpose purpose;
|
||||||
SoundIoList<SoundIoJackPort> ports;
|
SoundIoJackPort ports[SOUNDIO_MAX_CHANNELS];
|
||||||
|
int port_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void flush_events_jack(struct SoundIoPrivate *si) {
|
static void flush_events_jack(struct SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
SoundIo *soundio = &si->pub;
|
||||||
SoundIoJack *sij = (SoundIoJack *)si->backend_data;
|
SoundIoJack *sij = &si->backend_data.jack;
|
||||||
|
|
||||||
bool change = false;
|
bool change = false;
|
||||||
SoundIoDevicesInfo *old_devices_info = nullptr;
|
SoundIoDevicesInfo *old_devices_info = nullptr;
|
||||||
|
@ -65,7 +58,7 @@ static void flush_events_jack(struct SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wait_events_jack(struct SoundIoPrivate *si) {
|
static void wait_events_jack(struct SoundIoPrivate *si) {
|
||||||
SoundIoJack *sij = (SoundIoJack *)si->backend_data;
|
SoundIoJack *sij = &si->backend_data.jack;
|
||||||
flush_events_jack(si);
|
flush_events_jack(si);
|
||||||
soundio_os_mutex_lock(sij->mutex);
|
soundio_os_mutex_lock(sij->mutex);
|
||||||
soundio_os_cond_wait(sij->cond, sij->mutex);
|
soundio_os_cond_wait(sij->cond, sij->mutex);
|
||||||
|
@ -73,69 +66,150 @@ static void wait_events_jack(struct SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wakeup_jack(struct SoundIoPrivate *si) {
|
static void wakeup_jack(struct SoundIoPrivate *si) {
|
||||||
SoundIoJack *sij = (SoundIoJack *)si->backend_data;
|
SoundIoJack *sij = &si->backend_data.jack;
|
||||||
soundio_os_mutex_lock(sij->mutex);
|
soundio_os_mutex_lock(sij->mutex);
|
||||||
soundio_os_cond_signal(sij->cond, sij->mutex);
|
soundio_os_cond_signal(sij->cond, sij->mutex);
|
||||||
soundio_os_mutex_unlock(sij->mutex);
|
soundio_os_mutex_unlock(sij->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int outstream_process_callback(jack_nframes_t nframes, void *arg) {
|
||||||
static int outstream_open_jack(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *) {
|
SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg;
|
||||||
soundio_panic("TODO");
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
|
outstream->write_callback(outstream, nframes);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void outstream_destroy_jack(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *) {
|
static void outstream_destroy_jack(struct SoundIoPrivate *is, struct SoundIoOutStreamPrivate *os) {
|
||||||
soundio_panic("TODO");
|
SoundIoOutStreamJack *osj = (SoundIoOutStreamJack *) os->backend_data;
|
||||||
|
if (!osj)
|
||||||
|
return;
|
||||||
|
|
||||||
|
jack_client_close(osj->client);
|
||||||
|
|
||||||
|
destroy(osj);
|
||||||
|
os->backend_data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_start_jack(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *) {
|
static int outstream_open_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
soundio_panic("TODO");
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
|
//TODO SoundIoDevice *device = outstream->device;
|
||||||
|
|
||||||
|
outstream->buffer_duration = 0.0; // TODO
|
||||||
|
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;
|
||||||
|
osj->client = jack_client_open(outstream->name, JackNoStartServer, &status);
|
||||||
|
if (!osj->client) {
|
||||||
|
outstream_destroy_jack(si, os);
|
||||||
|
assert(!(status & JackInvalidOption));
|
||||||
|
if (status & JackShmFailure)
|
||||||
|
return SoundIoErrorSystemResources;
|
||||||
|
if (status & JackNoSuchClient)
|
||||||
|
return SoundIoErrorNoSuchClient;
|
||||||
|
return SoundIoErrorOpeningDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
int err;
|
||||||
|
if ((err = jack_set_process_callback(osj->client, outstream_process_callback, os))) {
|
||||||
|
outstream_destroy_jack(si, os);
|
||||||
|
return SoundIoErrorOpeningDevice;
|
||||||
|
}
|
||||||
|
// TODO register the other callbacks and emit a stream error if they're called
|
||||||
|
|
||||||
|
|
||||||
|
// register ports
|
||||||
|
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||||
|
const char *channel_name = soundio_get_channel_name(outstream->layout.channels[ch]);
|
||||||
|
unsigned long flags = JackPortIsOutput;
|
||||||
|
if (!outstream->non_terminal_hint)
|
||||||
|
flags |= JackPortIsTerminal;
|
||||||
|
jack_port_t *port = jack_port_register(osj->client, channel_name, JACK_DEFAULT_AUDIO_TYPE, flags, 0);
|
||||||
|
if (!port) {
|
||||||
|
outstream_destroy_jack(si, os);
|
||||||
|
return SoundIoErrorOpeningDevice;
|
||||||
|
}
|
||||||
|
osj->ports[ch] = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int outstream_pause_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
||||||
|
SoundIoOutStreamJack *osj = (SoundIoOutStreamJack *) os->backend_data;
|
||||||
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
|
int err;
|
||||||
|
if (pause) {
|
||||||
|
if ((err = jack_deactivate(osj->client)))
|
||||||
|
return SoundIoErrorStreaming;
|
||||||
|
} else {
|
||||||
|
if ((err = jack_activate(osj->client)))
|
||||||
|
return SoundIoErrorStreaming;
|
||||||
|
|
||||||
|
for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
|
||||||
|
// TODO figure out source port name and dest port name
|
||||||
|
//if ((err = jack_connect(osj->client, source_port, dest_port)))
|
||||||
|
// return SoundIoErrorStreaming;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int outstream_start_jack(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os) {
|
||||||
|
return outstream_pause_jack(si, os, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_begin_write_jack(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *,
|
static int outstream_begin_write_jack(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *,
|
||||||
SoundIoChannelArea **out_areas, int *frame_count)
|
SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
soundio_panic("TODO");
|
soundio_panic("TODO begin write");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_end_write_jack(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, int frame_count) {
|
static int outstream_end_write_jack(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, int frame_count) {
|
||||||
soundio_panic("TODO");
|
soundio_panic("TODO end write");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_clear_buffer_jack(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *) {
|
static int outstream_clear_buffer_jack(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *) {
|
||||||
soundio_panic("TODO");
|
soundio_panic("TODO clear buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int outstream_pause_jack(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *, bool pause) {
|
|
||||||
soundio_panic("TODO");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int instream_open_jack(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *) {
|
static int instream_open_jack(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *) {
|
||||||
soundio_panic("TODO");
|
soundio_panic("TODO open instream");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void instream_destroy_jack(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *) {
|
static void instream_destroy_jack(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *) {
|
||||||
soundio_panic("TODO");
|
soundio_panic("TODO destroy instream");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_start_jack(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *) {
|
static int instream_start_jack(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *) {
|
||||||
soundio_panic("TODO");
|
soundio_panic("TODO start instream");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_begin_read_jack(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *,
|
static int instream_begin_read_jack(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *,
|
||||||
SoundIoChannelArea **out_areas, int *frame_count)
|
SoundIoChannelArea **out_areas, int *frame_count)
|
||||||
{
|
{
|
||||||
soundio_panic("TODO");
|
soundio_panic("TODO begin read");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_end_read_jack(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *) {
|
static int instream_end_read_jack(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *) {
|
||||||
soundio_panic("TODO");
|
soundio_panic("TODO end read");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int instream_pause_jack(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *, bool pause) {
|
static int instream_pause_jack(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *, bool pause) {
|
||||||
soundio_panic("TODO");
|
soundio_panic("TODO pause");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void split_str(const char *input_str, int input_str_len, char c,
|
static void split_str(const char *input_str, int input_str_len, char c,
|
||||||
|
@ -179,6 +253,7 @@ static SoundIoJackClient *find_or_create_client(SoundIoList<SoundIoJackClient> *
|
||||||
client->purpose = purpose;
|
client->purpose = purpose;
|
||||||
client->name = client_name;
|
client->name = client_name;
|
||||||
client->name_len = client_name_len;
|
client->name_len = client_name_len;
|
||||||
|
client->port_count = 0;
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +268,7 @@ static char *dupe_str(const char *str, int str_len) {
|
||||||
|
|
||||||
static int refresh_devices(SoundIoPrivate *si) {
|
static int refresh_devices(SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
SoundIo *soundio = &si->pub;
|
||||||
SoundIoJack *sij = (SoundIoJack *)si->backend_data;
|
SoundIoJack *sij = &si->backend_data.jack;
|
||||||
|
|
||||||
SoundIoDevicesInfo *devices_info = create<SoundIoDevicesInfo>();
|
SoundIoDevicesInfo *devices_info = create<SoundIoDevicesInfo>();
|
||||||
if (!devices_info)
|
if (!devices_info)
|
||||||
|
@ -208,13 +283,18 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundIoList<SoundIoJackClient> clients;
|
SoundIoList<SoundIoJackClient> clients;
|
||||||
int err;
|
|
||||||
|
|
||||||
const char **port_name_ptr = port_names;
|
const char **port_name_ptr = port_names;
|
||||||
while (*port_name_ptr) {
|
while (*port_name_ptr) {
|
||||||
const char *client_and_port_name = *port_name_ptr;
|
const char *client_and_port_name = *port_name_ptr;
|
||||||
jack_port_t *jport = jack_port_by_name(sij->client, client_and_port_name);
|
jack_port_t *jport = jack_port_by_name(sij->client, client_and_port_name);
|
||||||
int flags = jack_port_flags(jport);
|
int flags = jack_port_flags(jport);
|
||||||
|
|
||||||
|
const char *port_type = jack_port_type(jport);
|
||||||
|
if (strcmp(port_type, JACK_DEFAULT_AUDIO_TYPE) != 0) {
|
||||||
|
// we don't know how to support such a port
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
SoundIoDevicePurpose purpose = (flags & JackPortIsInput) ?
|
SoundIoDevicePurpose purpose = (flags & JackPortIsInput) ?
|
||||||
SoundIoDevicePurposeOutput : SoundIoDevicePurposeInput;
|
SoundIoDevicePurposeOutput : SoundIoDevicePurposeInput;
|
||||||
bool is_physical = flags & JackPortIsPhysical;
|
bool is_physical = flags & JackPortIsPhysical;
|
||||||
|
@ -236,12 +316,11 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
destroy(devices_info);
|
destroy(devices_info);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
if ((err = client->ports.add_one())) {
|
if (client->port_count >= SOUNDIO_MAX_CHANNELS) {
|
||||||
jack_free(port_names);
|
// we hit the channel limit, skip the leftovers
|
||||||
destroy(devices_info);
|
continue;
|
||||||
return SoundIoErrorNoMem;
|
|
||||||
}
|
}
|
||||||
SoundIoJackPort *port = &client->ports.last();
|
SoundIoJackPort *port = &client->ports[client->port_count++];
|
||||||
port->name = port_name;
|
port->name = port_name;
|
||||||
port->name_len = port_name_len;
|
port->name_len = port_name_len;
|
||||||
|
|
||||||
|
@ -251,7 +330,7 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
|
|
||||||
for (int i = 0; i < clients.length; i += 1) {
|
for (int i = 0; i < clients.length; i += 1) {
|
||||||
SoundIoJackClient *client = &clients.at(i);
|
SoundIoJackClient *client = &clients.at(i);
|
||||||
if (client->ports.length <= 0)
|
if (client->port_count <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SoundIoDevice *device = create<SoundIoDevice>();
|
SoundIoDevice *device = create<SoundIoDevice>();
|
||||||
|
@ -260,9 +339,9 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
destroy(devices_info);
|
destroy(devices_info);
|
||||||
return SoundIoErrorNoMem;
|
return SoundIoErrorNoMem;
|
||||||
}
|
}
|
||||||
int description_len = client->name_len + 3 + 2 * client->ports.length;
|
int description_len = client->name_len + 3 + 2 * client->port_count;
|
||||||
for (int port_index = 0; port_index < client->ports.length; port_index += 1) {
|
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
||||||
SoundIoJackPort *port = &client->ports.at(port_index);
|
SoundIoJackPort *port = &client->ports[port_index];
|
||||||
description_len += port->name_len;
|
description_len += port->name_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,21 +373,21 @@ static int refresh_devices(SoundIoPrivate *si) {
|
||||||
memcpy(device->description, client->name, client->name_len);
|
memcpy(device->description, client->name, client->name_len);
|
||||||
memcpy(&device->description[client->name_len], ": ", 2);
|
memcpy(&device->description[client->name_len], ": ", 2);
|
||||||
int index = client->name_len + 2;
|
int index = client->name_len + 2;
|
||||||
for (int port_index = 0; port_index < client->ports.length; port_index += 1) {
|
for (int port_index = 0; port_index < client->port_count; port_index += 1) {
|
||||||
SoundIoJackPort *port = &client->ports.at(port_index);
|
SoundIoJackPort *port = &client->ports[port_index];
|
||||||
memcpy(&device->description[index], port->name, port->name_len);
|
memcpy(&device->description[index], port->name, port->name_len);
|
||||||
index += port->name_len;
|
index += port->name_len;
|
||||||
if (port_index + 1 < client->ports.length) {
|
if (port_index + 1 < client->port_count) {
|
||||||
memcpy(&device->description[index], ", ", 2);
|
memcpy(&device->description[index], ", ", 2);
|
||||||
index += 2;
|
index += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct SoundIoChannelLayout *layout = soundio_channel_layout_get_default(client->ports.length);
|
const struct SoundIoChannelLayout *layout = soundio_channel_layout_get_default(client->port_count);
|
||||||
if (layout) {
|
if (layout) {
|
||||||
device->current_layout = *layout;
|
device->current_layout = *layout;
|
||||||
} else {
|
} else {
|
||||||
for (int port_index = 0; port_index < client->ports.length; port_index += 1)
|
for (int port_index = 0; port_index < client->port_count; port_index += 1)
|
||||||
device->current_layout.channels[port_index] = SoundIoChannelIdInvalid;
|
device->current_layout.channels[port_index] = SoundIoChannelIdInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,7 +434,7 @@ static int process_callback(jack_nframes_t nframes, void *arg) {
|
||||||
|
|
||||||
static int buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
static int buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
||||||
SoundIoJack *sij = (SoundIoJack *)si->backend_data;
|
SoundIoJack *sij = &si->backend_data.jack;
|
||||||
sij->buffer_size = nframes;
|
sij->buffer_size = nframes;
|
||||||
if (sij->initialized)
|
if (sij->initialized)
|
||||||
refresh_devices(si);
|
refresh_devices(si);
|
||||||
|
@ -364,7 +443,7 @@ static int buffer_size_callback(jack_nframes_t nframes, void *arg) {
|
||||||
|
|
||||||
static int sample_rate_callback(jack_nframes_t nframes, void *arg) {
|
static int sample_rate_callback(jack_nframes_t nframes, void *arg) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
||||||
SoundIoJack *sij = (SoundIoJack *)si->backend_data;
|
SoundIoJack *sij = &si->backend_data.jack;
|
||||||
sij->sample_rate = nframes;
|
sij->sample_rate = nframes;
|
||||||
if (sij->initialized)
|
if (sij->initialized)
|
||||||
refresh_devices(si);
|
refresh_devices(si);
|
||||||
|
@ -379,7 +458,7 @@ static int xrun_callback(void *arg) {
|
||||||
|
|
||||||
static void port_registration_callback(jack_port_id_t port_id, int reg, void *arg) {
|
static void port_registration_callback(jack_port_id_t port_id, int reg, void *arg) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
||||||
SoundIoJack *sij = (SoundIoJack *)si->backend_data;
|
SoundIoJack *sij = &si->backend_data.jack;
|
||||||
if (sij->initialized)
|
if (sij->initialized)
|
||||||
refresh_devices(si);
|
refresh_devices(si);
|
||||||
}
|
}
|
||||||
|
@ -388,7 +467,7 @@ static int port_rename_calllback(jack_port_id_t port_id,
|
||||||
const char *old_name, const char *new_name, void *arg)
|
const char *old_name, const char *new_name, void *arg)
|
||||||
{
|
{
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
SoundIoPrivate *si = (SoundIoPrivate *)arg;
|
||||||
SoundIoJack *sij = (SoundIoJack *)si->backend_data;
|
SoundIoJack *sij = &si->backend_data.jack;
|
||||||
if (sij->initialized)
|
if (sij->initialized)
|
||||||
refresh_devices(si);
|
refresh_devices(si);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -400,9 +479,7 @@ static void shutdown_callback(void *arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_jack(SoundIoPrivate *si) {
|
static void destroy_jack(SoundIoPrivate *si) {
|
||||||
SoundIoJack *sij = (SoundIoJack *)si->backend_data;
|
SoundIoJack *sij = &si->backend_data.jack;
|
||||||
if (!sij)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (sij->client)
|
if (sij->client)
|
||||||
jack_client_close(sij->client);
|
jack_client_close(sij->client);
|
||||||
|
@ -414,12 +491,10 @@ static void destroy_jack(SoundIoPrivate *si) {
|
||||||
soundio_os_mutex_destroy(sij->mutex);
|
soundio_os_mutex_destroy(sij->mutex);
|
||||||
|
|
||||||
soundio_destroy_devices_info(sij->ready_devices_info);
|
soundio_destroy_devices_info(sij->ready_devices_info);
|
||||||
|
|
||||||
destroy(sij);
|
|
||||||
si->backend_data = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int soundio_jack_init(struct SoundIoPrivate *si) {
|
int soundio_jack_init(struct SoundIoPrivate *si) {
|
||||||
|
SoundIoJack *sij = &si->backend_data.jack;
|
||||||
SoundIo *soundio = &si->pub;
|
SoundIo *soundio = &si->pub;
|
||||||
|
|
||||||
if (!global_msg_callback_flag.test_and_set()) {
|
if (!global_msg_callback_flag.test_and_set()) {
|
||||||
|
@ -430,14 +505,6 @@ int soundio_jack_init(struct SoundIoPrivate *si) {
|
||||||
global_msg_callback_flag.clear();
|
global_msg_callback_flag.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(!si->backend_data);
|
|
||||||
SoundIoJack *sij = create<SoundIoJack>();
|
|
||||||
if (!sij) {
|
|
||||||
destroy_jack(si);
|
|
||||||
return SoundIoErrorNoMem;
|
|
||||||
}
|
|
||||||
si->backend_data = sij;
|
|
||||||
|
|
||||||
sij->mutex = soundio_os_mutex_create();
|
sij->mutex = soundio_os_mutex_create();
|
||||||
if (!sij->mutex) {
|
if (!sij->mutex) {
|
||||||
destroy_jack(si);
|
destroy_jack(si);
|
||||||
|
|
19
src/jack.hpp
19
src/jack.hpp
|
@ -8,7 +8,26 @@
|
||||||
#ifndef SOUNDIO_JACK_HPP
|
#ifndef SOUNDIO_JACK_HPP
|
||||||
#define SOUNDIO_JACK_HPP
|
#define SOUNDIO_JACK_HPP
|
||||||
|
|
||||||
|
#include "os.hpp"
|
||||||
|
|
||||||
|
#include <jack/jack.h>
|
||||||
|
|
||||||
int soundio_jack_init(struct SoundIoPrivate *si);
|
int soundio_jack_init(struct SoundIoPrivate *si);
|
||||||
|
|
||||||
|
struct SoundIoDeviceJack {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SoundIoJack {
|
||||||
|
jack_client_t *client;
|
||||||
|
SoundIoOsMutex *mutex;
|
||||||
|
SoundIoOsCond *cond;
|
||||||
|
// this one is ready to be read with flush_events. protected by mutex
|
||||||
|
struct SoundIoDevicesInfo *ready_devices_info;
|
||||||
|
bool initialized;
|
||||||
|
int sample_rate;
|
||||||
|
int buffer_size;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,11 @@
|
||||||
|
|
||||||
#include "pulseaudio.hpp"
|
#include "pulseaudio.hpp"
|
||||||
#include "soundio.hpp"
|
#include "soundio.hpp"
|
||||||
#include "atomics.hpp"
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <pulse/pulseaudio.h>
|
|
||||||
|
|
||||||
struct SoundIoOutStreamPulseAudio {
|
struct SoundIoOutStreamPulseAudio {
|
||||||
pa_stream *stream;
|
pa_stream *stream;
|
||||||
|
@ -30,43 +28,17 @@ struct SoundIoInStreamPulseAudio {
|
||||||
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
SoundIoChannelArea areas[SOUNDIO_MAX_CHANNELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundIoPulseAudio {
|
|
||||||
bool connection_refused;
|
|
||||||
|
|
||||||
pa_context *pulse_context;
|
|
||||||
atomic_bool device_scan_queued;
|
|
||||||
|
|
||||||
// the one that we're working on building
|
|
||||||
struct SoundIoDevicesInfo *current_devices_info;
|
|
||||||
char * default_sink_name;
|
|
||||||
char * default_source_name;
|
|
||||||
|
|
||||||
// this one is ready to be read with flush_events. protected by mutex
|
|
||||||
struct SoundIoDevicesInfo *ready_devices_info;
|
|
||||||
|
|
||||||
bool have_sink_list;
|
|
||||||
bool have_source_list;
|
|
||||||
bool have_default_sink;
|
|
||||||
|
|
||||||
atomic_bool ready_flag;
|
|
||||||
atomic_bool have_devices_flag;
|
|
||||||
|
|
||||||
pa_threaded_mainloop *main_loop;
|
|
||||||
pa_proplist *props;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
|
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
sipa->device_scan_queued = true;
|
sipa->device_scan_queued = true;
|
||||||
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void subscribe_to_events(SoundIoPrivate *si) {
|
static void subscribe_to_events(SoundIoPrivate *si) {
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
pa_subscription_mask_t events = (pa_subscription_mask_t)(
|
pa_subscription_mask_t events = (pa_subscription_mask_t)(
|
||||||
PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE|PA_SUBSCRIPTION_MASK_SERVER);
|
PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE|PA_SUBSCRIPTION_MASK_SERVER);
|
||||||
pa_operation *subscribe_op = pa_context_subscribe(sipa->pulse_context,
|
pa_operation *subscribe_op = pa_context_subscribe(sipa->pulse_context,
|
||||||
|
@ -78,7 +50,7 @@ static void subscribe_to_events(SoundIoPrivate *si) {
|
||||||
|
|
||||||
static void context_state_callback(pa_context *context, void *userdata) {
|
static void context_state_callback(pa_context *context, void *userdata) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
|
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
switch (pa_context_get_state(context)) {
|
switch (pa_context_get_state(context)) {
|
||||||
case PA_CONTEXT_UNCONNECTED: // The context hasn't been connected yet.
|
case PA_CONTEXT_UNCONNECTED: // The context hasn't been connected yet.
|
||||||
|
@ -112,9 +84,7 @@ static void context_state_callback(pa_context *context, void *userdata) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_pa(SoundIoPrivate *si) {
|
static void destroy_pa(SoundIoPrivate *si) {
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
if (!sipa)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (sipa->main_loop)
|
if (sipa->main_loop)
|
||||||
pa_threaded_mainloop_stop(sipa->main_loop);
|
pa_threaded_mainloop_stop(sipa->main_loop);
|
||||||
|
@ -133,9 +103,6 @@ static void destroy_pa(SoundIoPrivate *si) {
|
||||||
|
|
||||||
free(sipa->default_sink_name);
|
free(sipa->default_sink_name);
|
||||||
free(sipa->default_source_name);
|
free(sipa->default_source_name);
|
||||||
|
|
||||||
destroy(sipa);
|
|
||||||
si->backend_data = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static SoundIoFormat from_pulseaudio_format(pa_sample_spec sample_spec) {
|
static SoundIoFormat from_pulseaudio_format(pa_sample_spec sample_spec) {
|
||||||
|
@ -232,7 +199,7 @@ static int set_all_device_formats(SoundIoDevice *device) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int perform_operation(SoundIoPrivate *si, pa_operation *op) {
|
static int perform_operation(SoundIoPrivate *si, pa_operation *op) {
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
switch (pa_operation_get_state(op)) {
|
switch (pa_operation_get_state(op)) {
|
||||||
case PA_OPERATION_RUNNING:
|
case PA_OPERATION_RUNNING:
|
||||||
|
@ -250,7 +217,7 @@ static int perform_operation(SoundIoPrivate *si, pa_operation *op) {
|
||||||
|
|
||||||
static void finish_device_query(SoundIoPrivate *si) {
|
static void finish_device_query(SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
SoundIo *soundio = &si->pub;
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
if (!sipa->have_sink_list ||
|
if (!sipa->have_sink_list ||
|
||||||
!sipa->have_source_list ||
|
!sipa->have_source_list ||
|
||||||
|
@ -298,7 +265,7 @@ static void finish_device_query(SoundIoPrivate *si) {
|
||||||
static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *info, int eol, void *userdata) {
|
static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *info, int eol, void *userdata) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
|
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
|
||||||
SoundIo *soundio = &si->pub;
|
SoundIo *soundio = &si->pub;
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
int err;
|
int err;
|
||||||
if (eol) {
|
if (eol) {
|
||||||
sipa->have_sink_list = true;
|
sipa->have_sink_list = true;
|
||||||
|
@ -348,7 +315,7 @@ static void sink_info_callback(pa_context *pulse_context, const pa_sink_info *in
|
||||||
static void source_info_callback(pa_context *pulse_context, const pa_source_info *info, int eol, void *userdata) {
|
static void source_info_callback(pa_context *pulse_context, const pa_source_info *info, int eol, void *userdata) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
|
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
|
||||||
SoundIo *soundio = &si->pub;
|
SoundIo *soundio = &si->pub;
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
int err;
|
int err;
|
||||||
if (eol) {
|
if (eol) {
|
||||||
sipa->have_source_list = true;
|
sipa->have_source_list = true;
|
||||||
|
@ -399,7 +366,7 @@ static void source_info_callback(pa_context *pulse_context, const pa_source_info
|
||||||
static void server_info_callback(pa_context *pulse_context, const pa_server_info *info, void *userdata) {
|
static void server_info_callback(pa_context *pulse_context, const pa_server_info *info, void *userdata) {
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
|
SoundIoPrivate *si = (SoundIoPrivate *)userdata;
|
||||||
assert(si);
|
assert(si);
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
free(sipa->default_sink_name);
|
free(sipa->default_sink_name);
|
||||||
free(sipa->default_source_name);
|
free(sipa->default_source_name);
|
||||||
|
@ -416,7 +383,7 @@ static void server_info_callback(pa_context *pulse_context, const pa_server_info
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scan_devices(SoundIoPrivate *si) {
|
static void scan_devices(SoundIoPrivate *si) {
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
sipa->have_sink_list = false;
|
sipa->have_sink_list = false;
|
||||||
sipa->have_default_sink = false;
|
sipa->have_default_sink = false;
|
||||||
|
@ -449,7 +416,7 @@ static void scan_devices(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void block_until_have_devices(SoundIoPrivate *si) {
|
static void block_until_have_devices(SoundIoPrivate *si) {
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
if (sipa->have_devices_flag)
|
if (sipa->have_devices_flag)
|
||||||
return;
|
return;
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
@ -460,7 +427,7 @@ static void block_until_have_devices(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void block_until_ready(SoundIoPrivate *si) {
|
static void block_until_ready(SoundIoPrivate *si) {
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
if (sipa->ready_flag)
|
if (sipa->ready_flag)
|
||||||
return;
|
return;
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
@ -474,7 +441,7 @@ static void flush_events(SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
SoundIo *soundio = &si->pub;
|
||||||
block_until_ready(si);
|
block_until_ready(si);
|
||||||
|
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
if (sipa->device_scan_queued) {
|
if (sipa->device_scan_queued) {
|
||||||
sipa->device_scan_queued = false;
|
sipa->device_scan_queued = false;
|
||||||
|
@ -504,13 +471,13 @@ static void flush_events(SoundIoPrivate *si) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wait_events(SoundIoPrivate *si) {
|
static void wait_events(SoundIoPrivate *si) {
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
flush_events(si);
|
flush_events(si);
|
||||||
pa_threaded_mainloop_wait(sipa->main_loop);
|
pa_threaded_mainloop_wait(sipa->main_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wakeup(SoundIoPrivate *si) {
|
static void wakeup(SoundIoPrivate *si) {
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
pa_threaded_mainloop_signal(sipa->main_loop, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,7 +569,7 @@ static void playback_stream_state_callback(pa_stream *stream, void *userdata) {
|
||||||
SoundIoOutStream *outstream = &os->pub;
|
SoundIoOutStream *outstream = &os->pub;
|
||||||
SoundIo *soundio = outstream->device->soundio;
|
SoundIo *soundio = outstream->device->soundio;
|
||||||
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
SoundIoPrivate *si = (SoundIoPrivate *)soundio;
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
|
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
|
||||||
switch (pa_stream_get_state(stream)) {
|
switch (pa_stream_get_state(stream)) {
|
||||||
case PA_STREAM_UNCONNECTED:
|
case PA_STREAM_UNCONNECTED:
|
||||||
|
@ -635,7 +602,7 @@ static void outstream_destroy_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os
|
||||||
if (!ospa)
|
if (!ospa)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
pa_stream *stream = ospa->stream;
|
pa_stream *stream = ospa->stream;
|
||||||
if (stream) {
|
if (stream) {
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
@ -666,7 +633,7 @@ static int outstream_open_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||||
}
|
}
|
||||||
os->backend_data = ospa;
|
os->backend_data = ospa;
|
||||||
|
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
ospa->stream_ready = false;
|
ospa->stream_ready = false;
|
||||||
|
|
||||||
assert(sipa->pulse_context);
|
assert(sipa->pulse_context);
|
||||||
|
@ -718,7 +685,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 = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
|
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
@ -786,7 +753,7 @@ static int outstream_clear_buffer_pa(SoundIoPrivate *si,
|
||||||
SoundIoOutStreamPrivate *os)
|
SoundIoOutStreamPrivate *os)
|
||||||
{
|
{
|
||||||
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
|
SoundIoOutStreamPulseAudio *ospa = (SoundIoOutStreamPulseAudio *)os->backend_data;
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
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);
|
||||||
pa_operation *op = pa_stream_flush(stream, NULL, NULL);
|
pa_operation *op = pa_stream_flush(stream, NULL, NULL);
|
||||||
|
@ -799,7 +766,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 = (SoundIoOutStreamPulseAudio *)os->backend_data;
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
|
@ -821,7 +788,7 @@ static void recording_stream_state_callback(pa_stream *stream, void *userdata) {
|
||||||
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;
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->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:
|
||||||
|
@ -852,7 +819,7 @@ static void instream_destroy_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *inst
|
||||||
if (!ispa)
|
if (!ispa)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
pa_stream *stream = ispa->stream;
|
pa_stream *stream = ispa->stream;
|
||||||
if (stream) {
|
if (stream) {
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
@ -878,7 +845,7 @@ static int instream_open_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||||
}
|
}
|
||||||
is->backend_data = ispa;
|
is->backend_data = ispa;
|
||||||
|
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
ispa->stream_ready = false;
|
ispa->stream_ready = false;
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
@ -923,7 +890,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 = (SoundIoInStreamPulseAudio *)is->backend_data;
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
pa_stream_flags_t flags = (instream->period_duration > 0.0) ? PA_STREAM_ADJUST_LATENCY : PA_STREAM_NOFLAGS;
|
pa_stream_flags_t flags = (instream->period_duration > 0.0) ? PA_STREAM_ADJUST_LATENCY : PA_STREAM_NOFLAGS;
|
||||||
|
@ -991,7 +958,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 = (SoundIoInStreamPulseAudio *)is->backend_data;
|
||||||
SoundIoPulseAudio *sipa = (SoundIoPulseAudio *)si->backend_data;
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(sipa->main_loop);
|
pa_threaded_mainloop_lock(sipa->main_loop);
|
||||||
|
|
||||||
|
@ -1009,14 +976,7 @@ static int instream_pause_pa(SoundIoPrivate *si, SoundIoInStreamPrivate *is, boo
|
||||||
|
|
||||||
int soundio_pulseaudio_init(SoundIoPrivate *si) {
|
int soundio_pulseaudio_init(SoundIoPrivate *si) {
|
||||||
SoundIo *soundio = &si->pub;
|
SoundIo *soundio = &si->pub;
|
||||||
|
SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;
|
||||||
assert(!si->backend_data);
|
|
||||||
SoundIoPulseAudio *sipa = create<SoundIoPulseAudio>();
|
|
||||||
if (!sipa) {
|
|
||||||
destroy_pa(si);
|
|
||||||
return SoundIoErrorNoMem;
|
|
||||||
}
|
|
||||||
si->backend_data = sipa;
|
|
||||||
|
|
||||||
sipa->connection_refused = false;
|
sipa->connection_refused = false;
|
||||||
sipa->device_scan_queued = false;
|
sipa->device_scan_queued = false;
|
||||||
|
|
|
@ -8,6 +8,39 @@
|
||||||
#ifndef SOUNDIO_PULSEAUDIO_HPP
|
#ifndef SOUNDIO_PULSEAUDIO_HPP
|
||||||
#define SOUNDIO_PULSEAUDIO_HPP
|
#define SOUNDIO_PULSEAUDIO_HPP
|
||||||
|
|
||||||
|
#include "atomics.hpp"
|
||||||
|
|
||||||
|
#include <pulse/pulseaudio.h>
|
||||||
|
|
||||||
int soundio_pulseaudio_init(struct SoundIoPrivate *si);
|
int soundio_pulseaudio_init(struct SoundIoPrivate *si);
|
||||||
|
|
||||||
|
struct SoundIoDevicePulseAudio {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SoundIoPulseAudio {
|
||||||
|
bool connection_refused;
|
||||||
|
|
||||||
|
pa_context *pulse_context;
|
||||||
|
atomic_bool device_scan_queued;
|
||||||
|
|
||||||
|
// the one that we're working on building
|
||||||
|
struct SoundIoDevicesInfo *current_devices_info;
|
||||||
|
char *default_sink_name;
|
||||||
|
char *default_source_name;
|
||||||
|
|
||||||
|
// this one is ready to be read with flush_events. protected by mutex
|
||||||
|
struct SoundIoDevicesInfo *ready_devices_info;
|
||||||
|
|
||||||
|
bool have_sink_list;
|
||||||
|
bool have_source_list;
|
||||||
|
bool have_default_sink;
|
||||||
|
|
||||||
|
atomic_bool ready_flag;
|
||||||
|
atomic_bool have_devices_flag;
|
||||||
|
|
||||||
|
pa_threaded_mainloop *main_loop;
|
||||||
|
pa_proplist *props;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,22 +7,9 @@
|
||||||
|
|
||||||
#include "soundio.hpp"
|
#include "soundio.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
#include "dummy.hpp"
|
|
||||||
#include "os.hpp"
|
#include "os.hpp"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#ifdef SOUNDIO_HAVE_JACK
|
|
||||||
#include "jack.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
|
||||||
#include "pulseaudio.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SOUNDIO_HAVE_ALSA
|
|
||||||
#include "alsa.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
@ -71,6 +58,7 @@ const char *soundio_strerror(int error) {
|
||||||
case SoundIoErrorStreaming: return "unrecoverable streaming failure";
|
case SoundIoErrorStreaming: return "unrecoverable streaming failure";
|
||||||
case SoundIoErrorIncompatibleDevice: return "incompatible device";
|
case SoundIoErrorIncompatibleDevice: return "incompatible device";
|
||||||
case SoundIoErrorNoSuchClient: return "no such client";
|
case SoundIoErrorNoSuchClient: return "no such client";
|
||||||
|
case SoundIoErrorIncompatibleBackend: return "incompatible backend";
|
||||||
}
|
}
|
||||||
soundio_panic("invalid error enum value: %d", error);
|
soundio_panic("invalid error enum value: %d", error);
|
||||||
}
|
}
|
||||||
|
@ -198,6 +186,8 @@ 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);
|
||||||
|
@ -211,7 +201,6 @@ void soundio_disconnect(struct SoundIo *soundio) {
|
||||||
|
|
||||||
if (si->destroy)
|
if (si->destroy)
|
||||||
si->destroy(si);
|
si->destroy(si);
|
||||||
assert(!si->backend_data);
|
|
||||||
|
|
||||||
soundio->current_backend = SoundIoBackendNone;
|
soundio->current_backend = SoundIoBackendNone;
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ enum SoundIoError {
|
||||||
SoundIoErrorStreaming,
|
SoundIoErrorStreaming,
|
||||||
SoundIoErrorIncompatibleDevice,
|
SoundIoErrorIncompatibleDevice,
|
||||||
SoundIoErrorNoSuchClient,
|
SoundIoErrorNoSuchClient,
|
||||||
|
SoundIoErrorIncompatibleBackend,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SoundIoChannelId {
|
enum SoundIoChannelId {
|
||||||
|
@ -210,6 +211,7 @@ struct SoundIo {
|
||||||
// Optional: Application name.
|
// Optional: Application name.
|
||||||
// PulseAudio uses this for "application name".
|
// PulseAudio uses this for "application name".
|
||||||
// JACK uses this for `client_name`.
|
// JACK uses this for `client_name`.
|
||||||
|
// Must not contain a colon (":").
|
||||||
const char *app_name;
|
const char *app_name;
|
||||||
|
|
||||||
// Optional: JACK info and error callbacks.
|
// Optional: JACK info and error callbacks.
|
||||||
|
@ -371,8 +373,14 @@ struct SoundIoOutStream {
|
||||||
// PulseAudio uses this for the stream name.
|
// PulseAudio uses this for the stream name.
|
||||||
// JACK uses this for the client name of the client that connects when you
|
// JACK uses this for the client name of the client that connects when you
|
||||||
// open the stream.
|
// open the stream.
|
||||||
|
// Must not contain a colon (":").
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
|
// Optional: Hint that this output stream is nonterminal. This is used by
|
||||||
|
// JACK and it means that the output stream data originates from an input
|
||||||
|
// stream. Defaults to `false`.
|
||||||
|
bool non_terminal_hint;
|
||||||
|
|
||||||
|
|
||||||
// computed automatically when you call soundio_outstream_open
|
// computed automatically when you call soundio_outstream_open
|
||||||
int bytes_per_frame;
|
int bytes_per_frame;
|
||||||
|
@ -425,6 +433,7 @@ struct SoundIoInStream {
|
||||||
// PulseAudio uses this for the stream name.
|
// PulseAudio uses this for the stream name.
|
||||||
// JACK uses this for the client name of the client that connects when you
|
// JACK uses this for the client name of the client that connects when you
|
||||||
// open the stream.
|
// open the stream.
|
||||||
|
// Must not contain a colon (":").
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
// computed automatically when you call soundio_instream_open
|
// computed automatically when you call soundio_instream_open
|
||||||
|
|
|
@ -11,6 +11,46 @@
|
||||||
#include "soundio.h"
|
#include "soundio.h"
|
||||||
#include "list.hpp"
|
#include "list.hpp"
|
||||||
|
|
||||||
|
#ifdef SOUNDIO_HAVE_JACK
|
||||||
|
#include "jack.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||||
|
#include "pulseaudio.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SOUNDIO_HAVE_ALSA
|
||||||
|
#include "alsa.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "dummy.hpp"
|
||||||
|
|
||||||
|
union SoundIoBackendData {
|
||||||
|
#ifdef SOUNDIO_HAVE_JACK
|
||||||
|
SoundIoJack jack;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||||
|
SoundIoPulseAudio pulseaudio;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_ALSA
|
||||||
|
SoundIoAlsa alsa;
|
||||||
|
#endif
|
||||||
|
SoundIoDummy dummy;
|
||||||
|
};
|
||||||
|
|
||||||
|
union SoundIoDeviceBackendData {
|
||||||
|
#ifdef SOUNDIO_HAVE_JACK
|
||||||
|
SoundIoDeviceJack jack;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_PULSEAUDIO
|
||||||
|
SoundIoDevicePulseAudio pulseaudio;
|
||||||
|
#endif
|
||||||
|
#ifdef SOUNDIO_HAVE_ALSA
|
||||||
|
SoundIoDeviceAlsa alsa;
|
||||||
|
#endif
|
||||||
|
SoundIoDeviceDummy dummy;
|
||||||
|
};
|
||||||
|
|
||||||
struct SoundIoDevicesInfo {
|
struct SoundIoDevicesInfo {
|
||||||
SoundIoList<SoundIoDevice *> input_devices;
|
SoundIoList<SoundIoDevice *> input_devices;
|
||||||
SoundIoList<SoundIoDevice *> output_devices;
|
SoundIoList<SoundIoDevice *> output_devices;
|
||||||
|
@ -35,7 +75,7 @@ struct SoundIoPrivate {
|
||||||
// Safe to read from a single thread without a mutex.
|
// Safe to read from a single thread without a mutex.
|
||||||
struct SoundIoDevicesInfo *safe_devices_info;
|
struct SoundIoDevicesInfo *safe_devices_info;
|
||||||
|
|
||||||
void *backend_data;
|
SoundIoBackendData backend_data;
|
||||||
void (*destroy)(struct SoundIoPrivate *);
|
void (*destroy)(struct SoundIoPrivate *);
|
||||||
void (*flush_events)(struct SoundIoPrivate *);
|
void (*flush_events)(struct SoundIoPrivate *);
|
||||||
void (*wait_events)(struct SoundIoPrivate *);
|
void (*wait_events)(struct SoundIoPrivate *);
|
||||||
|
@ -60,6 +100,11 @@ struct SoundIoPrivate {
|
||||||
int (*instream_pause)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *, bool pause);
|
int (*instream_pause)(struct SoundIoPrivate *, struct SoundIoInStreamPrivate *, bool pause);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SoundIoDevicePrivate {
|
||||||
|
SoundIoDevice pub;
|
||||||
|
SoundIoDeviceBackendData backend_data;
|
||||||
|
};
|
||||||
|
|
||||||
void soundio_destroy_devices_info(struct SoundIoDevicesInfo *devices_info);
|
void soundio_destroy_devices_info(struct SoundIoDevicesInfo *devices_info);
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue