mirror of
https://github.com/Ryujinx/libsoundio.git
synced 2024-12-22 22:35:28 +00:00
rt prio warning behavior is overridable
This commit is contained in:
parent
195ea59209
commit
c96405a091
|
@ -278,13 +278,13 @@ Then look at `html/index.html` in a browser.
|
|||
block_until_have_devices
|
||||
0. Integrate into libgroove and test with Groove Basin
|
||||
0. clear buffer maybe could take an argument to say how many frames to not clear
|
||||
0. create a test for clear buffer; ensure pause/play semantics work
|
||||
0. Verify that JACK xrun callback context is the same as process callback.
|
||||
If not, might need to hav xrun callback set a flag and have process callback
|
||||
call the underflow callback.
|
||||
0. Create a test for pausing and resuming input and output streams.
|
||||
- Should pause/resume be callable from outside the callbacks?
|
||||
- Ensure double pausing / double resuming works fine.
|
||||
- test clearing the buffer
|
||||
0. Create a test for the latency / synchronization API.
|
||||
- Input is an audio file and some events indexed at particular frame - when
|
||||
listening the events should line up exactly with a beat or visual
|
||||
|
@ -297,17 +297,13 @@ Then look at `html/index.html` in a browser.
|
|||
call lock and then unlock when done.
|
||||
0. add len arguments to APIs that have char *
|
||||
- replace strdup with `soundio_str_dupe`
|
||||
0. Support PulseAudio proplist properties for main context and streams
|
||||
0. Expose JACK options in `jack_client_open`
|
||||
0. mlock memory which is accessed in the real time path
|
||||
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
|
||||
changes are related to them, and how to recover from them.
|
||||
0. Consider testing on FreeBSD
|
||||
0. In ALSA do we need to wake up the poll when destroying the in or out stream?
|
||||
0. Detect PulseAudio server going offline and emit `on_backend_disconnect`.
|
||||
0. Add [sndio](http://www.sndio.org/) backend to support OpenBSD.
|
||||
0. Custom allocator support
|
||||
- default allocator mlock memory
|
||||
0. Support for stream icon.
|
||||
- PulseAudio: XDG icon name
|
||||
- WASAPI: path to .exe, .dll, or .ico
|
||||
|
|
|
@ -314,12 +314,23 @@ struct SoundIo {
|
|||
/// variable to wake up. Called when ::soundio_wait_events would be woken up.
|
||||
void (*on_events_signal)(struct SoundIo *);
|
||||
|
||||
/// Read-only. After calling ::soundio_connect or ::soundio_connect_backend,
|
||||
/// this field tells which backend is currently connected.
|
||||
enum SoundIoBackend current_backend;
|
||||
|
||||
/// Optional: Application name.
|
||||
/// PulseAudio uses this for "application name".
|
||||
/// JACK uses this for `client_name`.
|
||||
/// Must not contain a colon (":").
|
||||
const char *app_name;
|
||||
|
||||
/// Optional: Real time priority warning.
|
||||
/// This callback is fired when making thread real-time priority failed. By
|
||||
/// default, it will print to stderr only the first time it is called
|
||||
/// a message instructing the user how to configure their system to allow
|
||||
/// real-time priority threads.
|
||||
void (*emit_rtprio_warning)(void);
|
||||
|
||||
/// Optional: JACK info callback.
|
||||
/// By default, libsoundio sets this to an empty function in order to
|
||||
/// silence stdio messages from JACK. You may override the behavior by
|
||||
|
@ -330,10 +341,6 @@ struct SoundIo {
|
|||
/// Optional: JACK error callback.
|
||||
/// See SoundIo::jack_info_callback
|
||||
void (*jack_error_callback)(const char *msg);
|
||||
|
||||
/// Read-only. After calling ::soundio_connect or ::soundio_connect_backend,
|
||||
/// this field tells which backend is currently connected.
|
||||
enum SoundIoBackend current_backend;
|
||||
};
|
||||
|
||||
/// The size of this struct is not part of the API or ABI.
|
||||
|
|
|
@ -1267,12 +1267,13 @@ static int outstream_open_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
|||
|
||||
static int outstream_start_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) {
|
||||
SoundIoOutStreamAlsa *osa = &os->backend_data.alsa;
|
||||
SoundIo *soundio = &si->pub;
|
||||
|
||||
assert(!osa->thread);
|
||||
|
||||
int err;
|
||||
osa->thread_exit_flag.test_and_set();
|
||||
if ((err = soundio_os_thread_create(outstream_thread_run, os, true, &osa->thread)))
|
||||
if ((err = soundio_os_thread_create(outstream_thread_run, os, soundio->emit_rtprio_warning, &osa->thread)))
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
|
@ -1538,12 +1539,13 @@ static int instream_open_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
|||
|
||||
static int instream_start_alsa(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
||||
SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
|
||||
SoundIo *soundio = &si->pub;
|
||||
|
||||
assert(!isa->thread);
|
||||
|
||||
isa->thread_exit_flag.test_and_set();
|
||||
int err;
|
||||
if ((err = soundio_os_thread_create(instream_thread_run, is, true, &isa->thread))) {
|
||||
if ((err = soundio_os_thread_create(instream_thread_run, is, soundio->emit_rtprio_warning, &isa->thread))) {
|
||||
instream_destroy_alsa(si, is);
|
||||
return err;
|
||||
}
|
||||
|
@ -1706,7 +1708,7 @@ int soundio_alsa_init(SoundIoPrivate *si) {
|
|||
|
||||
wakeup_device_poll(sia);
|
||||
|
||||
if ((err = soundio_os_thread_create(device_thread_run, si, false, &sia->thread))) {
|
||||
if ((err = soundio_os_thread_create(device_thread_run, si, nullptr, &sia->thread))) {
|
||||
destroy_alsa(si);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -1360,7 +1360,7 @@ int soundio_coreaudio_init(SoundIoPrivate *si) {
|
|||
return SoundIoErrorSystemResources;
|
||||
}
|
||||
|
||||
if ((err = soundio_os_thread_create(device_thread_run, si, false, &sica->thread))) {
|
||||
if ((err = soundio_os_thread_create(device_thread_run, si, nullptr, &sica->thread))) {
|
||||
destroy_ca(si);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -175,6 +175,7 @@ static int outstream_open_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os)
|
|||
|
||||
static int outstream_pause_dummy(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, bool pause) {
|
||||
SoundIoOutStreamDummy *osd = &os->backend_data.dummy;
|
||||
SoundIo *soundio = &si->pub;
|
||||
if (pause) {
|
||||
if (osd->thread) {
|
||||
osd->abort_flag.clear();
|
||||
|
@ -186,7 +187,9 @@ static int outstream_pause_dummy(struct SoundIoPrivate *si, struct SoundIoOutStr
|
|||
if (!osd->thread) {
|
||||
osd->abort_flag.test_and_set();
|
||||
int err;
|
||||
if ((err = soundio_os_thread_create(playback_thread_run, os, true, &osd->thread))) {
|
||||
if ((err = soundio_os_thread_create(playback_thread_run, os,
|
||||
soundio->emit_rtprio_warning, &osd->thread)))
|
||||
{
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
@ -281,6 +284,7 @@ static int instream_open_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is) {
|
|||
|
||||
static int instream_pause_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is, bool pause) {
|
||||
SoundIoInStreamDummy *isd = &is->backend_data.dummy;
|
||||
SoundIo *soundio = &si->pub;
|
||||
if (pause) {
|
||||
if (isd->thread) {
|
||||
isd->abort_flag.clear();
|
||||
|
@ -292,7 +296,9 @@ static int instream_pause_dummy(SoundIoPrivate *si, SoundIoInStreamPrivate *is,
|
|||
if (!isd->thread) {
|
||||
isd->abort_flag.test_and_set();
|
||||
int err;
|
||||
if ((err = soundio_os_thread_create(capture_thread_run, is, true, &isd->thread))) {
|
||||
if ((err = soundio_os_thread_create(capture_thread_run, is,
|
||||
soundio->emit_rtprio_warning, &isd->thread)))
|
||||
{
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
|
17
src/os.cpp
17
src/os.cpp
|
@ -15,7 +15,6 @@
|
|||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
@ -180,18 +179,10 @@ static void *run_pthread(void *userdata) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static atomic_flag rtprio_seen = ATOMIC_FLAG_INIT;
|
||||
static void emit_rtprio_warning(void) {
|
||||
if (!rtprio_seen.test_and_set()) {
|
||||
fprintf(stderr, "warning: unable to set high priority thread: Operation not permitted\n");
|
||||
fprintf(stderr, "See https://github.com/andrewrk/genesis/wiki/"
|
||||
"warning:-unable-to-set-high-priority-thread:-Operation-not-permitted\n");
|
||||
}
|
||||
}
|
||||
|
||||
int soundio_os_thread_create(
|
||||
void (*run)(void *arg), void *arg,
|
||||
bool high_priority, struct SoundIoOsThread ** out_thread)
|
||||
void (*emit_rtprio_warning)(void),
|
||||
struct SoundIoOsThread ** out_thread)
|
||||
{
|
||||
*out_thread = NULL;
|
||||
|
||||
|
@ -210,7 +201,7 @@ int soundio_os_thread_create(
|
|||
soundio_os_thread_destroy(thread);
|
||||
return SoundIoErrorSystemResources;
|
||||
}
|
||||
if (high_priority) {
|
||||
if (emit_rtprio_warning) {
|
||||
if (!SetThreadPriority(thread->handle, THREAD_PRIORITY_TIME_CRITICAL)) {
|
||||
emit_rtprio_warning();
|
||||
}
|
||||
|
@ -223,7 +214,7 @@ int soundio_os_thread_create(
|
|||
}
|
||||
thread->attr_init = true;
|
||||
|
||||
if (high_priority) {
|
||||
if (emit_rtprio_warning) {
|
||||
int max_priority = sched_get_priority_max(SCHED_FIFO);
|
||||
if (max_priority == -1) {
|
||||
soundio_os_thread_destroy(thread);
|
||||
|
|
3
src/os.h
3
src/os.h
|
@ -21,7 +21,8 @@ double soundio_os_get_time(void);
|
|||
struct SoundIoOsThread;
|
||||
int soundio_os_thread_create(
|
||||
void (*run)(void *arg), void *arg,
|
||||
bool high_priority, struct SoundIoOsThread ** out_thread);
|
||||
void (*emit_rtprio_warning)(void),
|
||||
struct SoundIoOsThread ** out_thread);
|
||||
|
||||
void soundio_os_thread_destroy(struct SoundIoOsThread *thread);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static const SoundIoBackend available_backends[] = {
|
||||
#ifdef SOUNDIO_HAVE_JACK
|
||||
|
@ -168,6 +169,15 @@ static void default_backend_disconnect_cb(struct SoundIo *, int err) {
|
|||
soundio_panic("libsoundio: backend disconnected: %s", soundio_strerror(err));
|
||||
}
|
||||
|
||||
static atomic_flag rtprio_seen = ATOMIC_FLAG_INIT;
|
||||
static void default_emit_rtprio_warning(void) {
|
||||
if (!rtprio_seen.test_and_set()) {
|
||||
fprintf(stderr, "warning: unable to set high priority thread: Operation not permitted\n");
|
||||
fprintf(stderr, "See "
|
||||
"https://github.com/andrewrk/genesis/wiki/warning:-unable-to-set-high-priority-thread:-Operation-not-permitted\n");
|
||||
}
|
||||
}
|
||||
|
||||
struct SoundIo *soundio_create(void) {
|
||||
int err;
|
||||
if ((err = soundio_os_init()))
|
||||
|
@ -180,6 +190,7 @@ struct SoundIo *soundio_create(void) {
|
|||
soundio->on_backend_disconnect = default_backend_disconnect_cb;
|
||||
soundio->on_events_signal = do_nothing_cb;
|
||||
soundio->app_name = "SoundIo";
|
||||
soundio->emit_rtprio_warning = default_emit_rtprio_warning;
|
||||
soundio->jack_info_callback = default_msg_callback;
|
||||
soundio->jack_error_callback = default_msg_callback;
|
||||
return soundio;
|
||||
|
|
|
@ -1333,6 +1333,7 @@ static int outstream_open_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStr
|
|||
SoundIoOutStreamWasapi *osw = &os->backend_data.wasapi;
|
||||
SoundIoOutStream *outstream = &os->pub;
|
||||
SoundIoDevice *device = outstream->device;
|
||||
SoundIo *soundio = &si->pub;
|
||||
|
||||
// All the COM functions are supposed to be called from the same thread. libsoundio API does not
|
||||
// restrict the calling thread context in this way. Furthermore, the user might have called
|
||||
|
@ -1368,7 +1369,9 @@ static int outstream_open_wasapi(struct SoundIoPrivate *si, struct SoundIoOutStr
|
|||
|
||||
osw->thread_exit_flag.test_and_set();
|
||||
int err;
|
||||
if ((err = soundio_os_thread_create(outstream_thread_run, os, true, &osw->thread))) {
|
||||
if ((err = soundio_os_thread_create(outstream_thread_run, os,
|
||||
soundio->emit_rtprio_warning, &osw->thread)))
|
||||
{
|
||||
outstream_destroy_wasapi(si, os);
|
||||
return err;
|
||||
}
|
||||
|
@ -1726,6 +1729,7 @@ static int instream_open_wasapi(struct SoundIoPrivate *si, struct SoundIoInStrea
|
|||
SoundIoInStreamWasapi *isw = &is->backend_data.wasapi;
|
||||
SoundIoInStream *instream = &is->pub;
|
||||
SoundIoDevice *device = instream->device;
|
||||
SoundIo *soundio = &si->pub;
|
||||
|
||||
// All the COM functions are supposed to be called from the same thread. libsoundio API does not
|
||||
// restrict the calling thread context in this way. Furthermore, the user might have called
|
||||
|
@ -1761,7 +1765,9 @@ static int instream_open_wasapi(struct SoundIoPrivate *si, struct SoundIoInStrea
|
|||
|
||||
isw->thread_exit_flag.test_and_set();
|
||||
int err;
|
||||
if ((err = soundio_os_thread_create(instream_thread_run, is, true, &isw->thread))) {
|
||||
if ((err = soundio_os_thread_create(instream_thread_run, is,
|
||||
soundio->emit_rtprio_warning, &isw->thread)))
|
||||
{
|
||||
instream_destroy_wasapi(si, is);
|
||||
return err;
|
||||
}
|
||||
|
@ -1982,7 +1988,7 @@ int soundio_wasapi_init(SoundIoPrivate *si) {
|
|||
siw->device_events.lpVtbl = &soundio_MMNotificationClient;
|
||||
siw->device_events_refs = 1;
|
||||
|
||||
if ((err = soundio_os_thread_create(device_thread_run, si, false, &siw->thread))) {
|
||||
if ((err = soundio_os_thread_create(device_thread_run, si, nullptr, &siw->thread))) {
|
||||
destroy_wasapi(si);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -145,10 +145,10 @@ static void test_ring_buffer_threaded(void) {
|
|||
rb_done = false;
|
||||
|
||||
SoundIoOsThread *reader_thread;
|
||||
ok_or_panic(soundio_os_thread_create(reader_thread_run, nullptr, false, &reader_thread));
|
||||
ok_or_panic(soundio_os_thread_create(reader_thread_run, nullptr, nullptr, &reader_thread));
|
||||
|
||||
SoundIoOsThread *writer_thread;
|
||||
ok_or_panic(soundio_os_thread_create(writer_thread_run, nullptr, false, &writer_thread));
|
||||
ok_or_panic(soundio_os_thread_create(writer_thread_run, nullptr, nullptr, &writer_thread));
|
||||
|
||||
while (rb_read_it < 100000 || rb_write_it < 100000) {}
|
||||
rb_done = true;
|
||||
|
|
Loading…
Reference in a new issue