early-access version 2835
This commit is contained in:
147
externals/SDL/src/audio/pulseaudio/SDL_pulseaudio.c
vendored
147
externals/SDL/src/audio/pulseaudio/SDL_pulseaudio.c
vendored
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -107,8 +107,6 @@ static int (*PULSEAUDIO_pa_stream_connect_record) (pa_stream *, const char *,
|
||||
static pa_stream_state_t (*PULSEAUDIO_pa_stream_get_state) (const pa_stream *);
|
||||
static size_t (*PULSEAUDIO_pa_stream_writable_size) (const pa_stream *);
|
||||
static size_t (*PULSEAUDIO_pa_stream_readable_size) (const pa_stream *);
|
||||
static int (*PULSEAUDIO_pa_stream_begin_write) (pa_stream *, void **, size_t*);
|
||||
static int (*PULSEAUDIO_pa_stream_cancel_write) (pa_stream *);
|
||||
static int (*PULSEAUDIO_pa_stream_write) (pa_stream *, const void *, size_t,
|
||||
pa_free_cb_t, int64_t, pa_seek_mode_t);
|
||||
static pa_operation * (*PULSEAUDIO_pa_stream_drain) (pa_stream *,
|
||||
@@ -119,6 +117,7 @@ static pa_operation * (*PULSEAUDIO_pa_stream_flush) (pa_stream *,
|
||||
pa_stream_success_cb_t, void *);
|
||||
static int (*PULSEAUDIO_pa_stream_disconnect) (pa_stream *);
|
||||
static void (*PULSEAUDIO_pa_stream_unref) (pa_stream *);
|
||||
static void (*PULSEAUDIO_pa_stream_set_write_callback)(pa_stream *, pa_stream_request_cb_t, void *);
|
||||
|
||||
static int load_pulseaudio_syms(void);
|
||||
|
||||
@@ -222,8 +221,6 @@ load_pulseaudio_syms(void)
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_writable_size);
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_readable_size);
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_write);
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_begin_write);
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_cancel_write);
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_drain);
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_disconnect);
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_peek);
|
||||
@@ -232,6 +229,7 @@ load_pulseaudio_syms(void)
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_unref);
|
||||
SDL_PULSEAUDIO_SYM(pa_channel_map_init_auto);
|
||||
SDL_PULSEAUDIO_SYM(pa_strerror);
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_set_write_callback);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -359,51 +357,56 @@ ConnectToPulseServer(pa_mainloop **_mainloop, pa_context **_context)
|
||||
static void
|
||||
PULSEAUDIO_WaitDevice(_THIS)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = this->hidden;
|
||||
/* this is a no-op; we wait in PULSEAUDIO_PlayDevice now. */
|
||||
}
|
||||
|
||||
while (SDL_AtomicGet(&this->enabled)) {
|
||||
static void WriteCallback(pa_stream *p, size_t nbytes, void *userdata)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = (struct SDL_PrivateAudioData *) userdata;
|
||||
/*printf("PULSEAUDIO WRITE CALLBACK! nbytes=%u\n", (unsigned int) nbytes);*/
|
||||
h->bytes_requested += nbytes;
|
||||
}
|
||||
|
||||
static void
|
||||
PULSEAUDIO_PlayDevice(_THIS)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = this->hidden;
|
||||
int available = h->mixlen;
|
||||
int written = 0;
|
||||
int cpy;
|
||||
|
||||
/*printf("PULSEAUDIO PLAYDEVICE START! mixlen=%d\n", available);*/
|
||||
|
||||
while (SDL_AtomicGet(&this->enabled) && (available > 0)) {
|
||||
cpy = SDL_min(h->bytes_requested, available);
|
||||
if (cpy) {
|
||||
if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf + written, cpy, NULL, 0LL, PA_SEEK_RELATIVE) < 0) {
|
||||
SDL_OpenedAudioDeviceDisconnected(this);
|
||||
return;
|
||||
}
|
||||
/*printf("PULSEAUDIO FEED! nbytes=%u\n", (unsigned int) cpy);*/
|
||||
h->bytes_requested -= cpy;
|
||||
written += cpy;
|
||||
available -= cpy;
|
||||
}
|
||||
|
||||
/* let WriteCallback fire if necessary. */
|
||||
/*printf("PULSEAUDIO ITERATE!\n");*/
|
||||
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
|
||||
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
|
||||
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
|
||||
SDL_OpenedAudioDeviceDisconnected(this);
|
||||
return;
|
||||
}
|
||||
if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= (h->mixlen/8)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
PULSEAUDIO_PlayDevice(_THIS)
|
||||
{
|
||||
/* Write the audio data */
|
||||
struct SDL_PrivateAudioData *h = this->hidden;
|
||||
if (SDL_AtomicGet(&this->enabled)) {
|
||||
if (PULSEAUDIO_pa_stream_write(h->stream, h->pabuf, h->mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0) {
|
||||
SDL_OpenedAudioDeviceDisconnected(this);
|
||||
}
|
||||
}
|
||||
/*printf("PULSEAUDIO PLAYDEVICE END! written=%d\n", written);*/
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
PULSEAUDIO_GetDeviceBuf(_THIS)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = this->hidden;
|
||||
size_t nbytes = h->mixlen;
|
||||
int ret;
|
||||
|
||||
ret = PULSEAUDIO_pa_stream_begin_write(h->stream, &h->pabuf, &nbytes);
|
||||
|
||||
if (ret != 0) {
|
||||
/* fall back it intermediate buffer */
|
||||
h->pabuf = h->mixbuf;
|
||||
} else if (nbytes < h->mixlen) {
|
||||
PULSEAUDIO_pa_stream_cancel_write(h->stream);
|
||||
h->pabuf = h->mixbuf;
|
||||
}
|
||||
|
||||
return (Uint8 *)h->pabuf;
|
||||
return this->hidden->mixbuf;
|
||||
}
|
||||
|
||||
|
||||
@@ -522,7 +525,7 @@ SourceDeviceNameCallback(pa_context *c, const pa_source_info *i, int is_last, vo
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
FindDeviceName(struct SDL_PrivateAudioData *h, const int iscapture, void *handle)
|
||||
FindDeviceName(struct SDL_PrivateAudioData *h, const SDL_bool iscapture, void *handle)
|
||||
{
|
||||
const uint32_t idx = ((uint32_t) ((size_t) handle)) - 1;
|
||||
|
||||
@@ -544,16 +547,17 @@ FindDeviceName(struct SDL_PrivateAudioData *h, const int iscapture, void *handle
|
||||
}
|
||||
|
||||
static int
|
||||
PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
PULSEAUDIO_OpenDevice(_THIS, const char *devname)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = NULL;
|
||||
Uint16 test_format = 0;
|
||||
SDL_AudioFormat test_format;
|
||||
pa_sample_spec paspec;
|
||||
pa_buffer_attr paattr;
|
||||
pa_channel_map pacmap;
|
||||
pa_stream_flags_t flags = 0;
|
||||
const char *name = NULL;
|
||||
int state = 0;
|
||||
SDL_bool iscapture = this->iscapture;
|
||||
int state = 0, format = PA_SAMPLE_INVALID;
|
||||
int rc = 0;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
@@ -564,53 +568,45 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
}
|
||||
SDL_zerop(this->hidden);
|
||||
|
||||
paspec.format = PA_SAMPLE_INVALID;
|
||||
|
||||
/* Try for a closest match on audio format */
|
||||
for (test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
(paspec.format == PA_SAMPLE_INVALID) && test_format;) {
|
||||
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
|
||||
#endif
|
||||
switch (test_format) {
|
||||
case AUDIO_U8:
|
||||
paspec.format = PA_SAMPLE_U8;
|
||||
format = PA_SAMPLE_U8;
|
||||
break;
|
||||
case AUDIO_S16LSB:
|
||||
paspec.format = PA_SAMPLE_S16LE;
|
||||
format = PA_SAMPLE_S16LE;
|
||||
break;
|
||||
case AUDIO_S16MSB:
|
||||
paspec.format = PA_SAMPLE_S16BE;
|
||||
format = PA_SAMPLE_S16BE;
|
||||
break;
|
||||
case AUDIO_S32LSB:
|
||||
paspec.format = PA_SAMPLE_S32LE;
|
||||
format = PA_SAMPLE_S32LE;
|
||||
break;
|
||||
case AUDIO_S32MSB:
|
||||
paspec.format = PA_SAMPLE_S32BE;
|
||||
format = PA_SAMPLE_S32BE;
|
||||
break;
|
||||
case AUDIO_F32LSB:
|
||||
paspec.format = PA_SAMPLE_FLOAT32LE;
|
||||
format = PA_SAMPLE_FLOAT32LE;
|
||||
break;
|
||||
case AUDIO_F32MSB:
|
||||
paspec.format = PA_SAMPLE_FLOAT32BE;
|
||||
format = PA_SAMPLE_FLOAT32BE;
|
||||
break;
|
||||
default:
|
||||
paspec.format = PA_SAMPLE_INVALID;
|
||||
break;
|
||||
}
|
||||
if (paspec.format == PA_SAMPLE_INVALID) {
|
||||
test_format = SDL_NextAudioFormat();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (paspec.format == PA_SAMPLE_INVALID) {
|
||||
return SDL_SetError("Couldn't find any hardware audio formats");
|
||||
if (!test_format) {
|
||||
return SDL_SetError("%s: Unsupported audio format", "pulseaudio");
|
||||
}
|
||||
this->spec.format = test_format;
|
||||
paspec.format = format;
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
#ifdef PA_STREAM_ADJUST_LATENCY
|
||||
this->spec.samples /= 2; /* Mix in smaller chunck to avoid underruns */
|
||||
#endif
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Allocate mixing buffer */
|
||||
@@ -627,28 +623,18 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
paspec.rate = this->spec.freq;
|
||||
|
||||
/* Reduced prebuffering compared to the defaults. */
|
||||
#ifdef PA_STREAM_ADJUST_LATENCY
|
||||
paattr.fragsize = this->spec.size;
|
||||
/* 2x original requested bufsize */
|
||||
paattr.tlength = h->mixlen * 4;
|
||||
paattr.tlength = h->mixlen;
|
||||
paattr.prebuf = -1;
|
||||
paattr.maxlength = -1;
|
||||
/* -1 can lead to pa_stream_writable_size() >= mixlen never being true */
|
||||
paattr.minreq = h->mixlen;
|
||||
flags = PA_STREAM_ADJUST_LATENCY;
|
||||
#else
|
||||
paattr.fragsize = this->spec.size;
|
||||
paattr.tlength = h->mixlen*2;
|
||||
paattr.prebuf = h->mixlen*2;
|
||||
paattr.maxlength = h->mixlen*2;
|
||||
paattr.minreq = h->mixlen;
|
||||
#endif
|
||||
paattr.minreq = -1;
|
||||
flags |= PA_STREAM_ADJUST_LATENCY;
|
||||
|
||||
if (ConnectToPulseServer(&h->mainloop, &h->context) < 0) {
|
||||
return SDL_SetError("Could not connect to PulseAudio server");
|
||||
}
|
||||
|
||||
if (!FindDeviceName(h, iscapture, handle)) {
|
||||
if (!FindDeviceName(h, iscapture, this->handle)) {
|
||||
return SDL_SetError("Requested PulseAudio sink/source missing?");
|
||||
}
|
||||
|
||||
@@ -679,6 +665,7 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
if (iscapture) {
|
||||
rc = PULSEAUDIO_pa_stream_connect_record(h->stream, h->device_name, &paattr, flags);
|
||||
} else {
|
||||
PULSEAUDIO_pa_stream_set_write_callback(h->stream, WriteCallback, h);
|
||||
rc = PULSEAUDIO_pa_stream_connect_playback(h->stream, h->device_name, &paattr, flags, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -832,16 +819,16 @@ PULSEAUDIO_Deinitialize(void)
|
||||
UnloadPulseAudioLibrary();
|
||||
}
|
||||
|
||||
static int
|
||||
static SDL_bool
|
||||
PULSEAUDIO_Init(SDL_AudioDriverImpl * impl)
|
||||
{
|
||||
if (LoadPulseAudioLibrary() < 0) {
|
||||
return 0;
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (ConnectToPulseServer(&hotplug_mainloop, &hotplug_context) < 0) {
|
||||
UnloadPulseAudioLibrary();
|
||||
return 0;
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
include_monitors = SDL_GetHintBoolean(SDL_HINT_AUDIO_INCLUDE_MONITORS, SDL_FALSE);
|
||||
@@ -859,11 +846,11 @@ PULSEAUDIO_Init(SDL_AudioDriverImpl * impl)
|
||||
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
|
||||
return 1; /* this audio target is available. */
|
||||
return SDL_TRUE; /* this audio target is available. */
|
||||
}
|
||||
|
||||
AudioBootStrap PULSEAUDIO_bootstrap = {
|
||||
"pulseaudio", "PulseAudio", PULSEAUDIO_Init, 0
|
||||
"pulseaudio", "PulseAudio", PULSEAUDIO_Init, SDL_FALSE
|
||||
};
|
||||
|
||||
#endif /* SDL_AUDIO_DRIVER_PULSEAUDIO */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -43,11 +43,7 @@ struct SDL_PrivateAudioData
|
||||
Uint8 *mixbuf;
|
||||
int mixlen;
|
||||
|
||||
/* Pointer to the actual buffer in use in the current
|
||||
GetDeviceBuf() -> PlayDevice() iteration.
|
||||
Can be either the pointer returned by pa_stream_begin_write()
|
||||
or mixbuf */
|
||||
void *pabuf;
|
||||
int bytes_requested; /* bytes of data the hardware wants _now_. */
|
||||
|
||||
const Uint8 *capturebuf;
|
||||
int capturelen;
|
||||
|
||||
Reference in New Issue
Block a user