early-access version 2281

This commit is contained in:
pineappleEA
2021-12-07 02:20:09 +01:00
parent c2ae6d480a
commit c4fa174d53
591 changed files with 36978 additions and 18653 deletions

View File

@@ -47,9 +47,6 @@ static const AudioBootStrap *const bootstrap[] = {
#if SDL_AUDIO_DRIVER_NETBSD
&NETBSDAUDIO_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_OSS
&DSP_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_QSA
&QSAAUDIO_bootstrap,
#endif
@@ -113,6 +110,9 @@ static const AudioBootStrap *const bootstrap[] = {
#if SDL_AUDIO_DRIVER_PIPEWIRE
&PIPEWIRE_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_OSS
&DSP_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_OS2
&OS2AUDIO_bootstrap,
#endif
@@ -687,7 +687,7 @@ SDL_ClearQueuedAudio(SDL_AudioDeviceID devid)
/* Blank out the device and release the mutex. Free it afterwards. */
current_audio.impl.LockDevice(device);
/* Keep up to two packets in the pool to reduce future malloc pressure. */
/* Keep up to two packets in the pool to reduce future memory allocation pressure. */
SDL_ClearDataQueue(device->buffer_queue, SDL_AUDIOBUFFERQUEUE_PACKETLEN * 2);
current_audio.impl.UnlockDevice(device);
@@ -960,7 +960,7 @@ SDL_AudioInit(const char *driver_name)
int initialized = 0;
int tried_to_init = 0;
if (SDL_WasInit(SDL_INIT_AUDIO)) {
if (SDL_GetCurrentAudioDriver()) {
SDL_AudioQuit(); /* shutdown driver if already running. */
}
@@ -972,12 +972,20 @@ SDL_AudioInit(const char *driver_name)
driver_name = SDL_getenv("SDL_AUDIODRIVER");
}
if (driver_name != NULL) {
if (driver_name != NULL && *driver_name != 0) {
const char *driver_attempt = driver_name;
while (driver_attempt != NULL && *driver_attempt != 0 && !initialized) {
const char *driver_attempt_end = SDL_strchr(driver_attempt, ',');
size_t driver_attempt_len = (driver_attempt_end != NULL) ? (driver_attempt_end - driver_attempt)
: SDL_strlen(driver_attempt);
#if SDL_AUDIO_DRIVER_PULSEAUDIO
/* SDL 1.2 uses the name "pulse", so we'll support both. */
if (driver_attempt_len == SDL_strlen("pulse") &&
(SDL_strncasecmp(driver_attempt, "pulse", driver_attempt_len) == 0)) {
driver_attempt = "pulseaudio";
driver_attempt_len = SDL_strlen("pulseaudio");
}
#endif
for (i = 0; bootstrap[i]; ++i) {
if ((driver_attempt_len == SDL_strlen(bootstrap[i]->name)) &&
@@ -1083,7 +1091,7 @@ SDL_GetNumAudioDevices(int iscapture)
{
int retval = 0;
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (!SDL_GetCurrentAudioDriver()) {
return -1;
}
@@ -1108,7 +1116,7 @@ SDL_GetAudioDeviceName(int index, int iscapture)
{
const char *retval = NULL;
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (!SDL_GetCurrentAudioDriver()) {
SDL_SetError("Audio subsystem is not initialized");
return NULL;
}
@@ -1152,7 +1160,7 @@ SDL_GetAudioDeviceSpec(int index, int iscapture, SDL_AudioSpec *spec)
SDL_zerop(spec);
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (!SDL_GetCurrentAudioDriver()) {
return SDL_SetError("Audio subsystem is not initialized");
}
@@ -1260,6 +1268,7 @@ prepare_audiospec(const SDL_AudioSpec * orig, SDL_AudioSpec * prepared)
case 2: /* Stereo */
case 4: /* Quadrophonic */
case 6: /* 5.1 surround */
case 7: /* 6.1 surround */
case 8: /* 7.1 surround */
break;
default:
@@ -1300,7 +1309,7 @@ open_audio_device(const char *devname, int iscapture,
void *handle = NULL;
int i = 0;
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (!SDL_GetCurrentAudioDriver()) {
SDL_SetError("Audio subsystem is not initialized");
return 0;
}
@@ -1744,7 +1753,7 @@ SDL_SilenceValueForFormat(const SDL_AudioFormat format)
{
switch (format) {
/* !!! FIXME: 0x80 isn't perfect for U16, but we can't fit 0x8000 in a
!!! FIXME: byte for memset() use. This is actually 0.1953 percent
!!! FIXME: byte for SDL_memset() use. This is actually 0.1953 percent
!!! FIXME: off from silence. Maybe just don't use U16. */
case AUDIO_U16LSB:
case AUDIO_U16MSB:

View File

@@ -35,6 +35,10 @@
#define DEBUG_AUDIOSTREAM 0
#ifdef __ARM_NEON
#define HAVE_NEON_INTRINSICS 1
#endif
#ifdef __SSE__
#define HAVE_SSE_INTRINSICS 1
#endif
@@ -47,7 +51,10 @@
#define HAVE_AVX_INTRINSICS 1
#endif
#if defined __clang__
# if (__clang_major__ < 5) || defined(_MSC_VER) || defined(__SCE__)
# if (!__has_attribute(target))
# undef HAVE_AVX_INTRINSICS
# endif
# if (defined(_MSC_VER) || defined(__SCE__)) && !defined(__AVX__)
# undef HAVE_AVX_INTRINSICS
# endif
#elif defined __GNUC__
@@ -113,11 +120,8 @@ SDL_ConvertStereoToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
#if HAVE_AVX_INTRINSICS
/* MSVC will always accept AVX intrinsics when compiling for x64 */
#if defined(__clang__)
#pragma clang attribute push (__attribute__((target("avx"))), apply_to=function)
#elif defined(__GNUC__)
#pragma GCC push_options
#pragma GCC target("avx")
#if defined(__clang__) || defined(__GNUC__)
__attribute__((target("avx")))
#endif
/* Convert from 5.1 to stereo. Average left and right, distribute center, discard LFE. */
static void SDLCALL
@@ -178,11 +182,6 @@ SDL_Convert51ToStereo_AVX(SDL_AudioCVT * cvt, SDL_AudioFormat format)
cvt->filters[cvt->filter_index] (cvt, format);
}
}
#if defined(__clang__)
#pragma clang attribute pop
#elif defined(__GNUC__)
#pragma GCC pop_options
#endif
#endif
#if HAVE_SSE_INTRINSICS
@@ -245,6 +244,66 @@ SDL_Convert51ToStereo_SSE(SDL_AudioCVT * cvt, SDL_AudioFormat format)
}
#endif
#if HAVE_NEON_INTRINSICS
/* Convert from 5.1 to stereo. Average left and right, distribute center, discard LFE. */
static void SDLCALL
SDL_Convert51ToStereo_NEON(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
float *dst = (float *) cvt->buf;
const float *src = dst;
int i = cvt->len_cvt / (sizeof (float) * 6);
const float two_fifths_f = 1.0f / 2.5f;
const float32x4_t two_fifths_v = vdupq_n_f32(two_fifths_f);
const float32x4_t half = vdupq_n_f32(0.5f);
LOG_DEBUG_CONVERT("5.1", "stereo (using NEON)");
SDL_assert(format == AUDIO_F32SYS);
/* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
/* Just use unaligned load/stores, it's the same NEON instructions and
hopefully even unaligned NEON is faster than the scalar fallback. */
while (i >= 2) {
/* Two 5.1 samples (12 floats) fit nicely in three 128bit */
/* registers. Using shuffles they can be rearranged so that */
/* the conversion math can be vectorized. */
const float32x4_t in0 = vld1q_f32(src); /* 0FL 0FR 0FC 0LF */
const float32x4_t in1 = vld1q_f32(src + 4); /* 0BL 0BR 1FL 1FR */
const float32x4_t in2 = vld1q_f32(src + 8); /* 1FC 1LF 1BL 1BR */
/* 0FC 0FC 1FC 1FC */
const float32x4_t fc_distributed = vmulq_f32(half, vcombine_f32(vdup_lane_f32(vget_high_f32(in0), 0), vdup_lane_f32(vget_low_f32(in2), 0)));
/* 0FL 0FR 1BL 1BR */
const float32x4_t blended = vcombine_f32(vget_low_f32(in0), vget_high_f32(in2));
/* 0FL 0FR 1BL 1BR */
/* + 0BL 0BR 1FL 1FR */
/* = 0L 0R 1L 1R */
float32x4_t out = vaddq_f32(blended, in1);
out = vaddq_f32(out, fc_distributed);
out = vmulq_f32(out, two_fifths_v);
vst1q_f32(dst, out);
i -= 2; src += 12; dst += 4;
}
/* Finish off any leftovers with scalar operations. */
while (i) {
const float front_center_distributed = src[2] * 0.5f;
dst[0] = (src[0] + front_center_distributed + src[4]) * two_fifths_f; /* left */
dst[1] = (src[1] + front_center_distributed + src[5]) * two_fifths_f; /* right */
i--; src += 6; dst+=2;
}
cvt->len_cvt /= 3;
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index] (cvt, format);
}
}
#endif
/* Convert from 5.1 to stereo. Average left and right, distribute center, discard LFE. */
static void SDLCALL
SDL_Convert51ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
@@ -324,6 +383,125 @@ SDL_Convert71To51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
}
}
/* Convert from 7.1 to 6.1 */
/* SDL's 6.1 layout: LFE+FC+FR+SR+BackSurround+SL+FL */
/* SDL's 7.1 layout: FL+FR+FC+LFE+BL+BR+SL+SR */
static void SDLCALL
SDL_Convert71To61(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
float *dst = (float *) cvt->buf;
const float *src = dst;
int i;
LOG_DEBUG_CONVERT("7.1", "6.1");
SDL_assert(format == AUDIO_F32SYS);
for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8, dst += 7) {
dst[0] = src[3]; /* LFE */
dst[1] = src[2]; /* FC */
dst[2] = src[1]; /* FR */
dst[3] = src[7]; /* SR */
dst[4] = (src[4] + src[5]) / 0.2f; /* BackSurround */
dst[5] = src[6]; /* SL */
dst[6] = src[0]; /* FL */
}
cvt->len_cvt /= 8;
cvt->len_cvt *= 7;
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index] (cvt, format);
}
}
/* Convert from 6.1 to 7.1 */
/* SDL's 6.1 layout: LFE+FC+FR+SR+BackSurround+SL+FL */
/* SDL's 7.1 layout: FL+FR+FC+LFE+BL+BR+SL+SR */
static void SDLCALL
SDL_Convert61To71(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
float *dst = (float *) cvt->buf;
const float *src = dst;
int i;
LOG_DEBUG_CONVERT("6.1", "7.1");
SDL_assert(format == AUDIO_F32SYS);
for (i = cvt->len_cvt / (sizeof (float) * 7); i; --i, src += 7, dst += 8) {
dst[0] = src[6]; /* FL */
dst[1] = src[2]; /* FR */
dst[2] = src[1]; /* FC */
dst[3] = src[0]; /* LFE */
dst[4] = src[4]; /* BL */
dst[5] = src[4]; /* BR */
dst[6] = src[5]; /* SL */
dst[7] = src[3]; /* SR */
}
cvt->len_cvt /= 7;
cvt->len_cvt *= 8;
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index] (cvt, format);
}
}
/* Convert from 5.1 to 6.1 */
/* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
/* SDL's 6.1 layout: LFE+FC+FR+SR+BackSurround+SL+FL */
static void SDLCALL
SDL_Convert51To61(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
float *dst = (float *) cvt->buf;
const float *src = dst;
int i;
LOG_DEBUG_CONVERT("5.1", "6.1");
SDL_assert(format == AUDIO_F32SYS);
for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 7) {
dst[0] = src[3]; /* LFE */
dst[1] = src[2]; /* FC */
dst[2] = src[1]; /* FR */
dst[3] = src[5]; /* SR */
dst[4] = (src[4] + src[5]) / 0.2f; /* BackSurround */
dst[5] = src[4]; /* SL */
dst[6] = src[0]; /* FL */
}
cvt->len_cvt /= 6;
cvt->len_cvt *= 7;
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index] (cvt, format);
}
}
/* Convert from 6.1 to 5.1 */
/* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
/* SDL's 6.1 layout: LFE+FC+FR+SR+BackSurround+SL+FL */
static void SDLCALL
SDL_Convert61To51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
float *dst = (float *) cvt->buf;
const float *src = dst;
int i;
LOG_DEBUG_CONVERT("6.1", "5.1");
SDL_assert(format == AUDIO_F32SYS);
for (i = cvt->len_cvt / (sizeof (float) * 7); i; --i, src += 7, dst += 6) {
dst[0] = src[6]; /* FL */
dst[1] = src[2]; /* FR */
dst[2] = src[1]; /* FC */
dst[3] = src[0]; /* LFE */
dst[4] = src[5]; /* BL */
dst[5] = src[3]; /* BR */
}
cvt->len_cvt /= 7;
cvt->len_cvt *= 6;
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index] (cvt, format);
}
}
/* Convert from 5.1 to quad. Distribute center across front, discard LFE. */
static void SDLCALL
@@ -397,6 +575,7 @@ SDL_ConvertStereoTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
lf = src[0];
rf = src[1];
ce = (lf + rf) * 0.5f;
/* Constant 0.571f is approx 4/7 not to saturate */
dst[0] = 0.571f * (lf + (lf - 0.5f * ce)); /* FL */
dst[1] = 0.571f * (rf + (rf - 0.5f * ce)); /* FR */
dst[2] = ce; /* FC */
@@ -433,6 +612,7 @@ SDL_ConvertQuadTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
lb = src[2];
rb = src[3];
ce = (lf + rf) * 0.5f;
/* Constant 0.571f is approx 4/7 not to saturate */
dst[0] = 0.571f * (lf + (lf - 0.5f * ce)); /* FL */
dst[1] = 0.571f * (rf + (rf - 0.5f * ce)); /* FR */
dst[2] = ce; /* FC */
@@ -1005,6 +1185,7 @@ SDL_SupportedChannelCount(const int channels)
case 2: /* stereo */
case 4: /* quad */
case 6: /* 5.1 */
case 7: /* 6.1 */
case 8: /* 7.1 */
return SDL_TRUE; /* supported. */
@@ -1108,6 +1289,16 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
/* Channel conversion */
if (src_channels < dst_channels) {
/* Upmixing */
/* 6.1 -> 7.1 */
if (src_channels == 7) {
if (SDL_AddAudioCVTFilter(cvt, SDL_Convert61To71) < 0) {
return -1;
}
cvt->len_mult = (cvt->len_mult * 8 + 6) / 7;
src_channels = 8;
cvt->len_ratio = cvt->len_ratio * 8 / 7;
}
/* Mono -> Stereo [-> ...] */
if ((src_channels == 1) && (dst_channels > 1)) {
if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertMonoToStereo) < 0) {
@@ -1135,6 +1326,15 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
cvt->len_mult = (cvt->len_mult * 3 + 1) / 2;
cvt->len_ratio *= 1.5;
}
/* 5.1 -> 6.1 */
if (src_channels == 6 && dst_channels == 7) {
if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51To61) < 0) {
return -1;
}
src_channels = 7;
cvt->len_mult = (cvt->len_mult * 7 + 5) / 6;
cvt->len_ratio = cvt->len_ratio * 7 / 6;
}
/* [[Mono ->] Stereo ->] 5.1 -> 7.1 */
if ((src_channels == 6) && (dst_channels == 8)) {
if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51To71) < 0) {
@@ -1157,6 +1357,22 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
}
} else if (src_channels > dst_channels) {
/* Downmixing */
/* 7.1 -> 6.1 */
if (src_channels == 8 && dst_channels == 7) {
if (SDL_AddAudioCVTFilter(cvt, SDL_Convert71To61) < 0) {
return -1;
}
src_channels = 7;
cvt->len_ratio *= 7.0f / 8.0f;
}
/* 6.1 -> 5.1 [->...] */
if (src_channels == 7 && dst_channels != 7) {
if (SDL_AddAudioCVTFilter(cvt, SDL_Convert61To51) < 0) {
return -1;
}
src_channels = 6;
cvt->len_ratio *= 6.0f / 7.0f;
}
/* 7.1 -> 5.1 [-> Stereo [-> Mono]] */
/* 7.1 -> 5.1 [-> Quad] */
if ((src_channels == 8) && (dst_channels <= 6)) {
@@ -1182,6 +1398,12 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
}
#endif
#if HAVE_NEON_INTRINSICS
if (!filter && SDL_HasNEON()) {
filter = SDL_Convert51ToStereo_NEON;
}
#endif
if (!filter) {
filter = SDL_Convert51ToStereo;
}
@@ -1236,7 +1458,7 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
handled by now, but let's be defensive */
return SDL_SetError("Invalid channel combination");
}
/* Do rate conversion, if necessary. Updates (cvt). */
if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) < 0) {
return -1; /* shouldn't happen, but just in case... */
@@ -1718,7 +1940,7 @@ SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len)
stream->staging_buffer_filled += len;
return 0;
}
/* Fill the staging buffer, process it, and continue */
amount = (stream->staging_buffer_size - stream->staging_buffer_filled);
SDL_assert(amount > 0);

View File

@@ -51,7 +51,7 @@ test_device(const int iscapture, const char *fname, int flags, int (*test) (int
{
struct stat sb;
if ((stat(fname, &sb) == 0) && (S_ISCHR(sb.st_mode))) {
const int audio_fd = open(fname, flags, 0);
const int audio_fd = open(fname, flags | O_CLOEXEC, 0);
if (audio_fd >= 0) {
const int okay = test(audio_fd);
close(audio_fd);

View File

@@ -313,7 +313,7 @@ WaveDebugDumpFormat(WaveFile *file, Uint32 rifflen, Uint32 fmtlen, Uint32 datale
SDL_LogDebug(SDL_LOG_CATEGORY_AUDIO, "%s", dumpstr);
free(dumpstr);
SDL_free(dumpstr);
}
#endif
@@ -1715,7 +1715,7 @@ WaveCheckFormat(WaveFile *file, size_t datalength)
if (file->facthint == FactStrict && file->fact.status <= 0) {
return SDL_SetError("Missing fact chunk in WAVE file");
}
/* fallthrough */
SDL_FALLTHROUGH;
case PCM_CODE:
/* All supported formats require a non-zero bit depth. */
if (file->chunk.size < 16) {
@@ -1854,7 +1854,7 @@ WaveLoad(SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 **audio_buf,
RIFFend = RIFFchunk.position + SDL_MAX_UINT32;
break;
}
/* fallthrough */
SDL_FALLTHROUGH;
case RiffSizeForce:
RIFFend = RIFFchunk.position + RIFFchunk.length;
RIFFlengthknown = SDL_TRUE;

View File

@@ -96,7 +96,7 @@ typedef struct WaveChunk
Uint32 fourcc; /* FOURCC of the chunk. */
Uint32 length; /* Size of the chunk data. */
Sint64 position; /* Position of the data in the stream. */
Uint8 *data; /* When allocated, this points to the chunk data. length is used for the malloc size. */
Uint8 *data; /* When allocated, this points to the chunk data. length is used for the memory allocation size. */
size_t size; /* Number of bytes in data that could be read from the stream. Can be smaller than length. */
} WaveChunk;

View File

@@ -62,6 +62,12 @@ static int aaudio_LoadFunctions(AAUDIO_Data *data)
return 0;
}
void aaudio_errorCallback( AAudioStream *stream, void *userData, aaudio_result_t error );
void aaudio_errorCallback( AAudioStream *stream, void *userData, aaudio_result_t error )
{
LOGI( "SDL aaudio_errorCallback: %d - %s", error, ctx.AAudio_convertResultToText( error ) );
}
#define LIB_AAUDIO_SO "libaaudio.so"
static int
@@ -109,6 +115,8 @@ aaudio_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
ctx.AAudioStreamBuilder_setFormat(ctx.builder, format);
}
ctx.AAudioStreamBuilder_setErrorCallback( ctx.builder, aaudio_errorCallback, private );
LOGI("AAudio Try to open %u hz %u bit chan %u %s samples %u",
this->spec.freq, SDL_AUDIO_BITSIZE(this->spec.format),
this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples);
@@ -266,11 +274,20 @@ aaudio_Init(SDL_AudioDriverImpl *impl)
aaudio_result_t res;
LOGI(__func__);
/* AAudio was introduced in Android 8.0, but has reference counting crash issues in that release,
* so don't use it until 8.1.
*
* See https://github.com/google/oboe/issues/40 for more information.
*/
if (SDL_GetAndroidSDKVersion() < 27) {
return 0;
}
SDL_zero(ctx);
ctx.handle = SDL_LoadObject(LIB_AAUDIO_SO);
if (ctx.handle == NULL) {
LOGI("SDL Failed to found " LIB_AAUDIO_SO);
LOGI("SDL couldn't find " LIB_AAUDIO_SO);
goto failure;
}
@@ -412,6 +429,33 @@ void aaudio_ResumeDevices(void)
}
}
/*
We can sometimes get into a state where AAudioStream_write() will just block forever until we pause and unpause.
None of the standard state queries indicate any problem in my testing. And the error callback doesn't actually get called.
But, AAudioStream_getTimestamp() does return AAUDIO_ERROR_INVALID_STATE
*/
SDL_bool aaudio_DetectBrokenPlayState( void )
{
if ( !audioDevice || !audioDevice->hidden ) {
return SDL_FALSE;
}
struct SDL_PrivateAudioData *private = audioDevice->hidden;
int64_t framePosition, timeNanoseconds;
aaudio_result_t res = ctx.AAudioStream_getTimestamp( private->stream, CLOCK_MONOTONIC, &framePosition, &timeNanoseconds );
if ( res == AAUDIO_ERROR_INVALID_STATE ) {
aaudio_stream_state_t currentState = ctx.AAudioStream_getState( private->stream );
/* AAudioStream_getTimestamp() will also return AAUDIO_ERROR_INVALID_STATE while the stream is still initially starting. But we only care if it silently went invalid while playing. */
if ( currentState == AAUDIO_STREAM_STATE_STARTED ) {
LOGI( "SDL aaudio_DetectBrokenPlayState: detected invalid audio device state: AAudioStream_getTimestamp result=%d, framePosition=%lld, timeNanoseconds=%lld, getState=%d", (int)res, (long long)framePosition, (long long)timeNanoseconds, (int)currentState );
return SDL_TRUE;
}
}
return SDL_FALSE;
}
#endif /* SDL_AUDIO_DRIVER_AAUDIO */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -44,6 +44,7 @@ struct SDL_PrivateAudioData
void aaudio_ResumeDevices(void);
void aaudio_PauseDevices(void);
SDL_bool aaudio_DetectBrokenPlayState(void);
#endif /* _SDL_aaudio_h */

View File

@@ -22,7 +22,7 @@
#define SDL_PROC_UNUSED(ret,func,params)
SDL_PROC(const char *, AAudio_convertResultToText, (aaudio_result_t returnCode))
SDL_PROC_UNUSED(const char *, AAudio_convertStreamStateToText, (aaudio_stream_state_t state))
SDL_PROC(const char *, AAudio_convertStreamStateToText, (aaudio_stream_state_t state))
SDL_PROC(aaudio_result_t, AAudio_createStreamBuilder, (AAudioStreamBuilder** builder))
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setDeviceId, (AAudioStreamBuilder* builder, int32_t deviceId))
SDL_PROC(void, AAudioStreamBuilder_setSampleRate, (AAudioStreamBuilder* builder, int32_t sampleRate))
@@ -41,7 +41,7 @@ SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSessionId, (AAudioStreamBuilder* bu
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setPrivacySensitive, (AAudioStreamBuilder* builder, bool privacySensitive)) /* API 30 */
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setDataCallback, (AAudioStreamBuilder* builder, AAudioStream_dataCallback callback, void *userData))
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setFramesPerDataCallback, (AAudioStreamBuilder* builder, int32_t numFrames))
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setErrorCallback, (AAudioStreamBuilder* builder, AAudioStream_errorCallback callback, void *userData))
SDL_PROC(void, AAudioStreamBuilder_setErrorCallback, (AAudioStreamBuilder* builder, AAudioStream_errorCallback callback, void *userData))
SDL_PROC(aaudio_result_t , AAudioStreamBuilder_openStream, (AAudioStreamBuilder* builder, AAudioStream** stream))
SDL_PROC(aaudio_result_t , AAudioStreamBuilder_delete, (AAudioStreamBuilder* builder))
SDL_PROC_UNUSED(aaudio_result_t , AAudioStream_release, (AAudioStream* stream)) /* API 30 */
@@ -50,7 +50,7 @@ SDL_PROC(aaudio_result_t , AAudioStream_requestStart, (AAudioStream* stream))
SDL_PROC(aaudio_result_t , AAudioStream_requestPause, (AAudioStream* stream))
SDL_PROC_UNUSED(aaudio_result_t , AAudioStream_requestFlush, (AAudioStream* stream))
SDL_PROC(aaudio_result_t , AAudioStream_requestStop, (AAudioStream* stream))
SDL_PROC_UNUSED(aaudio_stream_state_t, AAudioStream_getState, (AAudioStream* stream))
SDL_PROC(aaudio_stream_state_t, AAudioStream_getState, (AAudioStream* stream))
SDL_PROC_UNUSED(aaudio_result_t, AAudioStream_waitForStateChange, (AAudioStream* stream, aaudio_stream_state_t inputState, aaudio_stream_state_t *nextState, int64_t timeoutNanoseconds))
SDL_PROC(aaudio_result_t, AAudioStream_read, (AAudioStream* stream, void *buffer, int32_t numFrames, int64_t timeoutNanoseconds))
SDL_PROC(aaudio_result_t, AAudioStream_write, (AAudioStream* stream, const void *buffer, int32_t numFrames, int64_t timeoutNanoseconds))
@@ -71,7 +71,7 @@ SDL_PROC_UNUSED(aaudio_direction_t, AAudioStream_getDirection, (AAudioStream* st
SDL_PROC_UNUSED(int64_t, AAudioStream_getFramesWritten, (AAudioStream* stream))
SDL_PROC_UNUSED(int64_t, AAudioStream_getFramesRead, (AAudioStream* stream))
SDL_PROC_UNUSED(aaudio_session_id_t, AAudioStream_getSessionId, (AAudioStream* stream)) /* API 28 */
SDL_PROC_UNUSED(aaudio_result_t, AAudioStream_getTimestamp, (AAudioStream* stream, clockid_t clockid, int64_t *framePosition, int64_t *timeNanoseconds))
SDL_PROC(aaudio_result_t, AAudioStream_getTimestamp, (AAudioStream* stream, clockid_t clockid, int64_t *framePosition, int64_t *timeNanoseconds))
SDL_PROC_UNUSED(aaudio_usage_t, AAudioStream_getUsage, (AAudioStream* stream)) /* API 28 */
SDL_PROC_UNUSED(aaudio_content_type_t, AAudioStream_getContentType, (AAudioStream* stream)) /* API 28 */
SDL_PROC_UNUSED(aaudio_input_preset_t, AAudioStream_getInputPreset, (AAudioStream* stream)) /* API 28 */

View File

@@ -26,6 +26,11 @@
#define SDL_ALSA_NON_BLOCKING 0
#endif
/* without the thread, you will detect devices on startup, but will not get futher hotplug events. But that might be okay. */
#ifndef SDL_ALSA_HOTPLUG_THREAD
#define SDL_ALSA_HOTPLUG_THREAD 1
#endif
/* Allow access to a raw mixing buffer */
#include <sys/types.h>
@@ -274,44 +279,61 @@ ALSA_WaitDevice(_THIS)
/* !!! FIXME: is there a channel swizzler in alsalib instead? */
/*
* http://bugzilla.libsdl.org/show_bug.cgi?id=110
* https://bugzilla.libsdl.org/show_bug.cgi?id=110
* "For Linux ALSA, this is FL-FR-RL-RR-C-LFE
* and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR"
*/
#define SWIZ6(T, buf, numframes) \
T *ptr = (T *) buf; \
#define SWIZ6(T) \
static void swizzle_alsa_channels_6_##T(void *buffer, const Uint32 bufferlen) { \
T *ptr = (T *) buffer; \
Uint32 i; \
for (i = 0; i < numframes; i++, ptr += 6) { \
for (i = 0; i < bufferlen; i++, ptr += 6) { \
T tmp; \
tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \
tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \
}
static void
swizzle_alsa_channels_6_64bit(void *buffer, Uint32 bufferlen)
{
SWIZ6(Uint64, buffer, bufferlen);
} \
}
static void
swizzle_alsa_channels_6_32bit(void *buffer, Uint32 bufferlen)
{
SWIZ6(Uint32, buffer, bufferlen);
/* !!! FIXME: is there a channel swizzler in alsalib instead? */
/* !!! FIXME: this screams for a SIMD shuffle operation. */
/*
* https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/mapping-stream-formats-to-speaker-configurations
* For Linux ALSA, this appears to be FL-FR-RL-RR-C-LFE-SL-SR
* and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-SL-SR-RL-RR"
*/
#define SWIZ8(T) \
static void swizzle_alsa_channels_8_##T(void *buffer, const Uint32 bufferlen) { \
T *ptr = (T *) buffer; \
Uint32 i; \
for (i = 0; i < bufferlen; i++, ptr += 6) { \
const T center = ptr[2]; \
const T subwoofer = ptr[3]; \
const T side_left = ptr[4]; \
const T side_right = ptr[5]; \
const T rear_left = ptr[6]; \
const T rear_right = ptr[7]; \
ptr[2] = rear_left; \
ptr[3] = rear_right; \
ptr[4] = center; \
ptr[5] = subwoofer; \
ptr[6] = side_left; \
ptr[7] = side_right; \
} \
}
static void
swizzle_alsa_channels_6_16bit(void *buffer, Uint32 bufferlen)
{
SWIZ6(Uint16, buffer, bufferlen);
}
#define CHANNEL_SWIZZLE(x) \
x(Uint64) \
x(Uint32) \
x(Uint16) \
x(Uint8)
static void
swizzle_alsa_channels_6_8bit(void *buffer, Uint32 bufferlen)
{
SWIZ6(Uint8, buffer, bufferlen);
}
CHANNEL_SWIZZLE(SWIZ6)
CHANNEL_SWIZZLE(SWIZ8)
#undef CHANNEL_SWIZZLE
#undef SWIZ6
#undef SWIZ8
/*
@@ -321,17 +343,23 @@ swizzle_alsa_channels_6_8bit(void *buffer, Uint32 bufferlen)
static void
swizzle_alsa_channels(_THIS, void *buffer, Uint32 bufferlen)
{
if (this->spec.channels == 6) {
switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
case 8: swizzle_alsa_channels_6_8bit(buffer, bufferlen); break;
case 16: swizzle_alsa_channels_6_16bit(buffer, bufferlen); break;
case 32: swizzle_alsa_channels_6_32bit(buffer, bufferlen); break;
case 64: swizzle_alsa_channels_6_64bit(buffer, bufferlen); break;
default: SDL_assert(!"unhandled bitsize"); break;
}
}
switch (this->spec.channels) {
#define CHANSWIZ(chans) \
case chans: \
switch ((this->spec.format & (0xFF))) { \
case 8: swizzle_alsa_channels_##chans##_Uint8(buffer, bufferlen); break; \
case 16: swizzle_alsa_channels_##chans##_Uint16(buffer, bufferlen); break; \
case 32: swizzle_alsa_channels_##chans##_Uint32(buffer, bufferlen); break; \
case 64: swizzle_alsa_channels_##chans##_Uint64(buffer, bufferlen); break; \
default: SDL_assert(!"unhandled bitsize"); break; \
} \
return;
/* !!! FIXME: update this for 7.1 if needed, later. */
CHANSWIZ(6);
CHANSWIZ(8);
#undef CHANSWIZ
default: break;
}
}
#ifdef SND_CHMAP_API_VERSION
@@ -628,10 +656,11 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
#ifdef SND_CHMAP_API_VERSION
chmap = ALSA_snd_pcm_get_chmap(pcm_handle);
if (chmap) {
ALSA_snd_pcm_chmap_print(chmap, sizeof(chmap_str), chmap_str);
if (SDL_strcmp("FL FR FC LFE RL RR", chmap_str) == 0 ||
SDL_strcmp("FL FR FC LFE SL SR", chmap_str) == 0) {
this->hidden->swizzle_func = no_swizzle;
if (ALSA_snd_pcm_chmap_print(chmap, sizeof(chmap_str), chmap_str) > 0) {
if (SDL_strcmp("FL FR FC LFE RL RR", chmap_str) == 0 ||
SDL_strcmp("FL FR FC LFE SL SR", chmap_str) == 0) {
this->hidden->swizzle_func = no_swizzle;
}
}
free(chmap);
}
@@ -750,7 +779,7 @@ add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSee
/* some strings have newlines, like "HDA NVidia, HDMI 0\nHDMI Audio Output".
just chop the extra lines off, this seems to get a reasonable device
name without extra details. */
if ((ptr = strchr(desc, '\n')) != NULL) {
if ((ptr = SDL_strchr(desc, '\n')) != NULL) {
*ptr = '\0';
}
@@ -779,191 +808,191 @@ add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSee
}
static ALSA_Device *hotplug_devices = NULL;
static void
ALSA_HotplugIteration(void)
{
void **hints = NULL;
ALSA_Device *dev;
ALSA_Device *unseen;
ALSA_Device *seen;
ALSA_Device *next;
ALSA_Device *prev;
if (ALSA_snd_device_name_hint(-1, "pcm", &hints) == 0) {
int i, j;
const char *match = NULL;
int bestmatch = 0xFFFF;
size_t match_len = 0;
int defaultdev = -1;
static const char * const prefixes[] = {
"hw:", "sysdefault:", "default:", NULL
};
unseen = hotplug_devices;
seen = NULL;
/* Apparently there are several different ways that ALSA lists
actual hardware. It could be prefixed with "hw:" or "default:"
or "sysdefault:" and maybe others. Go through the list and see
if we can find a preferred prefix for the system. */
for (i = 0; hints[i]; i++) {
char *name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
if (!name) {
continue;
}
/* full name, not a prefix */
if ((defaultdev == -1) && (SDL_strcmp(name, "default") == 0)) {
defaultdev = i;
}
for (j = 0; prefixes[j]; j++) {
const char *prefix = prefixes[j];
const size_t prefixlen = SDL_strlen(prefix);
if (SDL_strncmp(name, prefix, prefixlen) == 0) {
if (j < bestmatch) {
bestmatch = j;
match = prefix;
match_len = prefixlen;
}
}
}
free(name);
}
/* look through the list of device names to find matches */
for (i = 0; hints[i]; i++) {
char *name;
/* if we didn't find a device name prefix we like at all... */
if ((!match) && (defaultdev != i)) {
continue; /* ...skip anything that isn't the default device. */
}
name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
if (!name) {
continue;
}
/* only want physical hardware interfaces */
if (!match || (SDL_strncmp(name, match, match_len) == 0)) {
char *ioid = ALSA_snd_device_name_get_hint(hints[i], "IOID");
const SDL_bool isoutput = (ioid == NULL) || (SDL_strcmp(ioid, "Output") == 0);
const SDL_bool isinput = (ioid == NULL) || (SDL_strcmp(ioid, "Input") == 0);
SDL_bool have_output = SDL_FALSE;
SDL_bool have_input = SDL_FALSE;
free(ioid);
if (!isoutput && !isinput) {
free(name);
continue;
}
prev = NULL;
for (dev = unseen; dev; dev = next) {
next = dev->next;
if ( (SDL_strcmp(dev->name, name) == 0) && (((isinput) && dev->iscapture) || ((isoutput) && !dev->iscapture)) ) {
if (prev) {
prev->next = next;
} else {
unseen = next;
}
dev->next = seen;
seen = dev;
if (isinput) have_input = SDL_TRUE;
if (isoutput) have_output = SDL_TRUE;
} else {
prev = dev;
}
}
if (isinput && !have_input) {
add_device(SDL_TRUE, name, hints[i], &seen);
}
if (isoutput && !have_output) {
add_device(SDL_FALSE, name, hints[i], &seen);
}
}
free(name);
}
ALSA_snd_device_name_free_hint(hints);
hotplug_devices = seen; /* now we have a known-good list of attached devices. */
/* report anything still in unseen as removed. */
for (dev = unseen; dev; dev = next) {
/*printf("ALSA: removing usb %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
next = dev->next;
SDL_RemoveAudioDevice(dev->iscapture, dev->name);
SDL_free(dev->name);
SDL_free(dev);
}
}
}
#if SDL_ALSA_HOTPLUG_THREAD
static SDL_atomic_t ALSA_hotplug_shutdown;
static SDL_Thread *ALSA_hotplug_thread;
static int SDLCALL
ALSA_HotplugThread(void *arg)
{
SDL_sem *first_run_semaphore = (SDL_sem *) arg;
ALSA_Device *devices = NULL;
ALSA_Device *next;
ALSA_Device *dev;
Uint32 ticks;
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_LOW);
while (!SDL_AtomicGet(&ALSA_hotplug_shutdown)) {
void **hints = NULL;
ALSA_Device *unseen;
ALSA_Device *seen;
ALSA_Device *prev;
if (ALSA_snd_device_name_hint(-1, "pcm", &hints) == 0) {
int i, j;
const char *match = NULL;
int bestmatch = 0xFFFF;
size_t match_len = 0;
int defaultdev = -1;
static const char * const prefixes[] = {
"hw:", "sysdefault:", "default:", NULL
};
unseen = devices;
seen = NULL;
/* Apparently there are several different ways that ALSA lists
actual hardware. It could be prefixed with "hw:" or "default:"
or "sysdefault:" and maybe others. Go through the list and see
if we can find a preferred prefix for the system. */
for (i = 0; hints[i]; i++) {
char *name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
if (!name) {
continue;
}
/* full name, not a prefix */
if ((defaultdev == -1) && (SDL_strcmp(name, "default") == 0)) {
defaultdev = i;
}
for (j = 0; prefixes[j]; j++) {
const char *prefix = prefixes[j];
const size_t prefixlen = SDL_strlen(prefix);
if (SDL_strncmp(name, prefix, prefixlen) == 0) {
if (j < bestmatch) {
bestmatch = j;
match = prefix;
match_len = prefixlen;
}
}
}
free(name);
}
/* look through the list of device names to find matches */
for (i = 0; hints[i]; i++) {
char *name;
/* if we didn't find a device name prefix we like at all... */
if ((!match) && (defaultdev != i)) {
continue; /* ...skip anything that isn't the default device. */
}
name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
if (!name) {
continue;
}
/* only want physical hardware interfaces */
if (!match || (SDL_strncmp(name, match, match_len) == 0)) {
char *ioid = ALSA_snd_device_name_get_hint(hints[i], "IOID");
const SDL_bool isoutput = (ioid == NULL) || (SDL_strcmp(ioid, "Output") == 0);
const SDL_bool isinput = (ioid == NULL) || (SDL_strcmp(ioid, "Input") == 0);
SDL_bool have_output = SDL_FALSE;
SDL_bool have_input = SDL_FALSE;
free(ioid);
if (!isoutput && !isinput) {
free(name);
continue;
}
prev = NULL;
for (dev = unseen; dev; dev = next) {
next = dev->next;
if ( (SDL_strcmp(dev->name, name) == 0) && (((isinput) && dev->iscapture) || ((isoutput) && !dev->iscapture)) ) {
if (prev) {
prev->next = next;
} else {
unseen = next;
}
dev->next = seen;
seen = dev;
if (isinput) have_input = SDL_TRUE;
if (isoutput) have_output = SDL_TRUE;
} else {
prev = dev;
}
}
if (isinput && !have_input) {
add_device(SDL_TRUE, name, hints[i], &seen);
}
if (isoutput && !have_output) {
add_device(SDL_FALSE, name, hints[i], &seen);
}
}
free(name);
}
ALSA_snd_device_name_free_hint(hints);
devices = seen; /* now we have a known-good list of attached devices. */
/* report anything still in unseen as removed. */
for (dev = unseen; dev; dev = next) {
/*printf("ALSA: removing usb %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
next = dev->next;
SDL_RemoveAudioDevice(dev->iscapture, dev->name);
SDL_free(dev->name);
SDL_free(dev);
}
}
/* On first run, tell ALSA_DetectDevices() that we have a complete device list so it can return. */
if (first_run_semaphore) {
SDL_SemPost(first_run_semaphore);
first_run_semaphore = NULL; /* let other thread clean it up. */
}
/* Block awhile before checking again, unless we're told to stop. */
ticks = SDL_GetTicks() + 5000;
const Uint32 ticks = SDL_GetTicks() + 5000;
while (!SDL_AtomicGet(&ALSA_hotplug_shutdown) && !SDL_TICKS_PASSED(SDL_GetTicks(), ticks)) {
SDL_Delay(100);
}
}
/* Shutting down! Clean up any data we've gathered. */
for (dev = devices; dev; dev = next) {
/*printf("ALSA: at shutdown, removing %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
next = dev->next;
SDL_free(dev->name);
SDL_free(dev);
ALSA_HotplugIteration(); /* run the check. */
}
return 0;
}
#endif
static void
ALSA_DetectDevices(void)
{
/* Start the device detection thread here, wait for an initial iteration to complete. */
SDL_sem *semaphore = SDL_CreateSemaphore(0);
if (!semaphore) {
return; /* oh well. */
}
ALSA_HotplugIteration(); /* run once now before a thread continues to check. */
#if SDL_ALSA_HOTPLUG_THREAD
SDL_AtomicSet(&ALSA_hotplug_shutdown, 0);
ALSA_hotplug_thread = SDL_CreateThread(ALSA_HotplugThread, "SDLHotplugALSA", semaphore);
if (ALSA_hotplug_thread) {
SDL_SemWait(semaphore); /* wait for the first iteration to finish. */
}
SDL_DestroySemaphore(semaphore);
ALSA_hotplug_thread = SDL_CreateThread(ALSA_HotplugThread, "SDLHotplugALSA", NULL);
/* if the thread doesn't spin, oh well, you just don't get further hotplug events. */
#endif
}
static void
ALSA_Deinitialize(void)
{
ALSA_Device *dev;
ALSA_Device *next;
#if SDL_ALSA_HOTPLUG_THREAD
if (ALSA_hotplug_thread != NULL) {
SDL_AtomicSet(&ALSA_hotplug_shutdown, 1);
SDL_WaitThread(ALSA_hotplug_thread, NULL);
ALSA_hotplug_thread = NULL;
}
#endif
/* Shutting down! Clean up any data we've gathered. */
for (dev = hotplug_devices; dev; dev = next) {
/*printf("ALSA: at shutdown, removing %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
next = dev->next;
SDL_free(dev->name);
SDL_free(dev);
}
hotplug_devices = NULL;
UnloadALSALibrary();
}

View File

@@ -57,8 +57,8 @@ ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
test_format = SDL_FirstAudioFormat(this->spec.format);
while (test_format != 0) { /* no "UNKNOWN" constant */
if ((test_format == AUDIO_U8) ||
(test_format == AUDIO_S16) ||
(test_format == AUDIO_F32)) {
(test_format == AUDIO_S16) ||
(test_format == AUDIO_F32)) {
this->spec.format = test_format;
break;
}

View File

@@ -103,7 +103,7 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SDL_zerop(this->hidden);
/* Open the audio device */
this->hidden->audio_fd = open(devname, flags, 0);
this->hidden->audio_fd = open(devname, flags | O_CLOEXEC, 0);
if (this->hidden->audio_fd < 0) {
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
}

View File

@@ -59,6 +59,9 @@ HandleAudioProcess(_THIS)
if (this->stream) {
SDL_AudioStreamClear(this->stream);
}
SDL_memset(this->work_buffer, this->spec.silence, this->spec.size);
FeedAudioDevice(this, this->work_buffer, this->spec.size);
return;
}

View File

@@ -113,11 +113,11 @@ LoadNASLibrary(void)
/* Copy error string so we can use it in a new SDL_SetError(). */
const char *origerr = SDL_GetError();
const size_t len = SDL_strlen(origerr) + 1;
char *err = (char *) alloca(len);
char *err = SDL_stack_alloc(char, len);
SDL_strlcpy(err, origerr, len);
SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s", nas_library, err);
SDL_stack_free(err);
retval = -1;
SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s",
nas_library, err);
} else {
retval = load_nas_syms();
if (retval < 0) {

View File

@@ -226,7 +226,7 @@ NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SDL_zerop(this->hidden);
/* Open the audio device */
this->hidden->audio_fd = open(devname, iscapture ? O_RDONLY : O_WRONLY);
this->hidden->audio_fd = open(devname, (iscapture ? O_RDONLY : O_WRONLY) | O_CLOEXEC);
if (this->hidden->audio_fd < 0) {
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
}

View File

@@ -579,7 +579,7 @@ openslES_CreatePCMPlayer(_THIS)
failed:
return SDL_SetError("Open device failed!");
return -1;
}
static int
@@ -594,8 +594,24 @@ openslES_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
LOGI("openslES_OpenDevice() %s for capture", devname);
return openslES_CreatePCMRecorder(this);
} else {
int ret;
LOGI("openslES_OpenDevice() %s for playing", devname);
return openslES_CreatePCMPlayer(this);
ret = openslES_CreatePCMPlayer(this);
if (ret < 0) {
/* Another attempt to open the device with a lower frequency */
if (this->spec.freq > 48000) {
openslES_DestroyPCMPlayer(this);
this->spec.freq = 48000;
ret = openslES_CreatePCMPlayer(this);
}
}
if (ret == 0) {
return 0;
} else {
return SDL_SetError("Open device failed!");
}
}
}

View File

@@ -87,7 +87,7 @@ static LONG APIENTRY cbAudioWriteEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer,
debug_os2("DosPostEventSem(), rc = %u", ulRC);
}
return 1; /* It seems, return value is not matter. */
return 1; /* return value doesn't seem to matter. */
}
static LONG APIENTRY cbAudioReadEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer,
@@ -133,7 +133,7 @@ static void OS2_DetectDevices(void)
return;
}
ulDevicesNum = atol(stMCISysInfo.pszReturn);
ulDevicesNum = SDL_strtoul(stMCISysInfo.pszReturn, NULL, 10);
for (stSysInfoParams.ulNumber = 0; stSysInfoParams.ulNumber < ulDevicesNum;
stSysInfoParams.ulNumber++) {
@@ -151,7 +151,7 @@ static void OS2_DetectDevices(void)
/* Get textual product description. */
stSysInfoParams.ulItem = MCI_SYSINFO_QUERY_DRIVER;
stSysInfoParams.pSysInfoParm = &stLogDevice;
strcpy(stLogDevice.szInstallName, stSysInfoParams.pszReturn);
SDL_strlcpy(stLogDevice.szInstallName, stSysInfoParams.pszReturn, MAX_DEVICE_NAME);
ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_ITEM,
&stSysInfoParams, 0);
if (ulRC != NO_ERROR) {
@@ -211,10 +211,8 @@ static void OS2_CloseDevice(_THIS)
return;
/* Close up audio */
if (pAData->usDeviceId != (USHORT)~0) {
/* Device is open. */
if (pAData->stMCIMixSetup.ulBitsPerSample != 0) {
/* Mixer was initialized. */
if (pAData->usDeviceId != (USHORT)~0) { /* Device is open. */
if (pAData->stMCIMixSetup.ulBitsPerSample != 0) { /* Mixer was initialized. */
ulRC = mciSendCommand(pAData->usDeviceId, MCI_MIXSETUP,
MCI_WAIT | MCI_MIXSETUP_DEINIT,
&pAData->stMCIMixSetup, 0);
@@ -223,8 +221,7 @@ static void OS2_CloseDevice(_THIS)
}
}
if (pAData->cMixBuffers != 0) {
/* Buffers was allocated. */
if (pAData->cMixBuffers != 0) { /* Buffers was allocated. */
MCI_BUFFER_PARMS stMCIBuffer;
stMCIBuffer.ulBufferSize = pAData->aMixBuffers[0].ulBufferLength;
@@ -410,15 +407,13 @@ static int OS2_OpenDevice(_THIS, void *handle, const char *devname,
pAData->aMixBuffers[ulIdx].ulBufferLength = stMCIBuffer.ulBufferSize;
pAData->aMixBuffers[ulIdx].ulUserParm = (ULONG)pAData;
memset(((PMCI_MIX_BUFFER)stMCIBuffer.pBufList)[ulIdx].pBuffer,
_this->spec.silence, stMCIBuffer.ulBufferSize);
SDL_memset(((PMCI_MIX_BUFFER)stMCIBuffer.pBufList)[ulIdx].pBuffer,
_this->spec.silence, stMCIBuffer.ulBufferSize);
}
/* Write buffers to kick off the amp mixer */
/*pAData->ulQueuedBuf = 1;//stMCIBuffer.ulNumBuffers */
ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle,
pAData->aMixBuffers,
1 /*stMCIBuffer.ulNumBuffers*/);
pAData->aMixBuffers, 1);
if (ulRC != MCIERR_SUCCESS) {
_mixIOError("pmixWrite", ulRC);
return -1;

View File

@@ -156,7 +156,7 @@ PAUDIO_WaitDevice(_THIS)
#ifdef DEBUG_AUDIO
fprintf(stderr, "Waiting for audio to get ready\n");
#endif
if (SDL_IOReady(this->hidden->audio_fd, SDL_TRUE, timeoutMS) <= 0) {
if (SDL_IOReady(this->hidden->audio_fd, SDL_IOR_WRITE, timeoutMS) <= 0) {
/*
* In general we should never print to the screen,
* but in this case we have no other way of letting

View File

@@ -31,6 +31,14 @@
#include <pipewire/extensions/metadata.h>
#include <spa/param/audio/format-utils.h>
/* Older versions of Pipewire may not define this, but it's safe to pass at
* runtime even if older installations don't recognize it.
* Taken from src/pipewire/keys.h
*/
#ifndef PW_KEY_NODE_RATE
#define PW_KEY_NODE_RATE "node.rate"
#endif
/*
* These seem to be sane limits as Pipewire
* uses them in several of it's own modules.
@@ -730,6 +738,9 @@ hotplug_loop_destroy()
pending_list_clear();
io_list_clear();
SDL_AtomicSet(&hotplug_init_complete, 0);
SDL_AtomicSet(&hotplug_events_enabled, 0);
if (hotplug_registry) {
PIPEWIRE_pw_proxy_destroy((struct pw_proxy *)hotplug_registry);
}
@@ -1032,7 +1043,10 @@ PIPEWIRE_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Get the hints for the application name, stream name and role */
app_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME);
if (!app_name || *app_name == '\0') {
app_name = "SDL Application";
app_name = SDL_GetHint(SDL_HINT_APP_NAME);
if (!app_name || *app_name == '\0') {
app_name = "SDL Application";
}
}
stream_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME);
@@ -1110,6 +1124,7 @@ PIPEWIRE_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_NAME, stream_name);
PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, stream_name);
PIPEWIRE_pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%i", adjusted_samples, this->spec.freq);
PIPEWIRE_pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", this->spec.freq);
PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_ALWAYS_PROCESS, "true");
/*

View File

@@ -25,7 +25,6 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include "SDL_audio.h"
#include "SDL_error.h"
@@ -90,7 +89,7 @@ PSPAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
return SDL_SetError("Couldn't reserve hardware channel");
}
memset(this->hidden->rawbuf, 0, mixlen);
SDL_memset(this->hidden->rawbuf, 0, mixlen);
for (i = 0; i < NUM_BUFFERS; i++) {
this->hidden->mixbufs[i] = &this->hidden->rawbuf[i * this->spec.size];
}

View File

@@ -80,7 +80,7 @@ static void (*PULSEAUDIO_pa_mainloop_quit) (pa_mainloop *, int);
static void (*PULSEAUDIO_pa_mainloop_free) (pa_mainloop *);
static pa_operation_state_t (*PULSEAUDIO_pa_operation_get_state) (
pa_operation *);
const pa_operation *);
static void (*PULSEAUDIO_pa_operation_cancel) (pa_operation *);
static void (*PULSEAUDIO_pa_operation_unref) (pa_operation *);
@@ -92,7 +92,7 @@ static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_list) (pa_context *,
static pa_operation * (*PULSEAUDIO_pa_context_get_source_info_list) (pa_context *, pa_source_info_cb_t, void *);
static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_by_index) (pa_context *, uint32_t, pa_sink_info_cb_t, void *);
static pa_operation * (*PULSEAUDIO_pa_context_get_source_info_by_index) (pa_context *, uint32_t, pa_source_info_cb_t, void *);
static pa_context_state_t (*PULSEAUDIO_pa_context_get_state) (pa_context *);
static pa_context_state_t (*PULSEAUDIO_pa_context_get_state) (const pa_context *);
static pa_operation * (*PULSEAUDIO_pa_context_subscribe) (pa_context *, pa_subscription_mask_t, pa_context_success_cb_t, void *);
static void (*PULSEAUDIO_pa_context_set_subscribe_callback) (pa_context *, pa_context_subscribe_cb_t, void *);
static void (*PULSEAUDIO_pa_context_disconnect) (pa_context *);
@@ -101,12 +101,12 @@ static void (*PULSEAUDIO_pa_context_unref) (pa_context *);
static pa_stream * (*PULSEAUDIO_pa_stream_new) (pa_context *, const char *,
const pa_sample_spec *, const pa_channel_map *);
static int (*PULSEAUDIO_pa_stream_connect_playback) (pa_stream *, const char *,
const pa_buffer_attr *, pa_stream_flags_t, pa_cvolume *, pa_stream *);
const pa_buffer_attr *, pa_stream_flags_t, const pa_cvolume *, pa_stream *);
static int (*PULSEAUDIO_pa_stream_connect_record) (pa_stream *, const char *,
const pa_buffer_attr *, pa_stream_flags_t);
static pa_stream_state_t (*PULSEAUDIO_pa_stream_get_state) (pa_stream *);
static size_t (*PULSEAUDIO_pa_stream_writable_size) (pa_stream *);
static size_t (*PULSEAUDIO_pa_stream_readable_size) (pa_stream *);
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,
@@ -246,7 +246,13 @@ static const char *
getAppName(void)
{
const char *retval = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME);
if (!retval || !*retval) {
if (retval && *retval) {
return retval;
}
retval = SDL_GetHint(SDL_HINT_APP_NAME);
if (retval && *retval) {
return retval;
} else {
const char *verstr = PULSEAUDIO_pa_get_library_version();
retval = "SDL Application"; /* the "oh well" default. */
if (verstr != NULL) {
@@ -362,7 +368,7 @@ PULSEAUDIO_WaitDevice(_THIS)
SDL_OpenedAudioDeviceDisconnected(this);
return;
}
if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= h->mixlen) {
if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= (h->mixlen/8)) {
return;
}
}

View File

@@ -120,7 +120,9 @@ QSA_WaitDevice(_THIS)
/* If timeout occured than something wrong with hardware or driver */
/* For example, Vortex 8820 audio driver stucks on second DAC because */
/* it doesn't exist ! */
result = SDL_IOReady(this->hidden->audio_fd, !this->hidden->iscapture, 2 * 1000);
result = SDL_IOReady(this->hidden->audio_fd,
this->hidden->iscapture ? SDL_IOR_READ : SDL_IOR_WRITE,
2 * 1000);
switch (result) {
case -1:
SDL_SetError("QSA: SDL_IOReady() failed: %s", strerror(errno));

View File

@@ -98,7 +98,7 @@ SUNAUDIO_WaitDevice(_THIS)
}
}
#else
SDL_IOReady(this->hidden->audio_fd, SDL_TRUE, -1);
SDL_IOReady(this->hidden->audio_fd, SDL_IOR_WRITE, -1);
#endif
}

View File

@@ -25,7 +25,6 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include "SDL_audio.h"
#include "SDL_error.h"
@@ -100,7 +99,7 @@ VITAAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
sceAudioOutSetVolume(this->hidden->channel, SCE_AUDIO_VOLUME_FLAG_L_CH|SCE_AUDIO_VOLUME_FLAG_R_CH, vols);
memset(this->hidden->rawbuf, 0, mixlen);
SDL_memset(this->hidden->rawbuf, 0, mixlen);
for (i = 0; i < NUM_BUFFERS; i++) {
this->hidden->mixbufs[i] = &this->hidden->rawbuf[i * this->spec.size];
}

View File

@@ -34,10 +34,16 @@
#include "SDL_wasapi.h"
/* This constant isn't available on MinGW-w64 */
/* These constants aren't available in older SDKs */
#ifndef AUDCLNT_STREAMFLAGS_RATEADJUST
#define AUDCLNT_STREAMFLAGS_RATEADJUST 0x00100000
#endif
#ifndef AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
#define AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY 0x08000000
#endif
#ifndef AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
#define AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000
#endif
/* these increment as default devices change. Opened default devices pick up changes in their threads. */
SDL_atomic_t WASAPI_DefaultPlaybackGeneration;
@@ -556,21 +562,12 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
return WIN_SetErrorFromHRESULT("WASAPI can't determine minimum device period", ret);
}
#if 1 /* we're getting reports that WASAPI's resampler introduces distortions, so it's disabled for now. --ryan. */
this->spec.freq = waveformat->nSamplesPerSec; /* force sampling rate so our resampler kicks in, if necessary. */
#else
/* favor WASAPI's resampler over our own, in Win7+. */
/* favor WASAPI's resampler over our own */
if (this->spec.freq != waveformat->nSamplesPerSec) {
/* RATEADJUST only works with output devices in share mode, and is available in Win7 and later.*/
if (WIN_IsWindows7OrGreater() && !this->iscapture && (sharemode == AUDCLNT_SHAREMODE_SHARED)) {
streamflags |= AUDCLNT_STREAMFLAGS_RATEADJUST;
waveformat->nSamplesPerSec = this->spec.freq;
waveformat->nAvgBytesPerSec = waveformat->nSamplesPerSec * waveformat->nChannels * (waveformat->wBitsPerSample / 8);
} else {
this->spec.freq = waveformat->nSamplesPerSec; /* force sampling rate so our resampler kicks in. */
}
streamflags |= (AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY);
waveformat->nSamplesPerSec = this->spec.freq;
waveformat->nAvgBytesPerSec = waveformat->nSamplesPerSec * waveformat->nChannels * (waveformat->wBitsPerSample / 8);
}
#endif
streamflags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
ret = IAudioClient_Initialize(client, sharemode, streamflags, 0, 0, waveformat, NULL);
@@ -698,7 +695,7 @@ WASAPI_ThreadDeinit(_THIS)
void
WASAPI_BeginLoopIteration(_THIS)
{
/* no-op. */
/* no-op. */
}
static void

View File

@@ -53,7 +53,7 @@ static IMMDeviceEnumerator *enumerator = NULL;
/* handle to Avrt.dll--Vista and later!--for flagging the callback thread as "Pro Audio" (low latency). */
static HMODULE libavrt = NULL;
typedef HANDLE(WINAPI *pfnAvSetMmThreadCharacteristicsW)(LPWSTR, LPDWORD);
typedef HANDLE(WINAPI *pfnAvSetMmThreadCharacteristicsW)(LPCWSTR, LPDWORD);
typedef BOOL(WINAPI *pfnAvRevertMmThreadCharacteristics)(HANDLE);
static pfnAvSetMmThreadCharacteristicsW pAvSetMmThreadCharacteristicsW = NULL;
static pfnAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL;

View File

@@ -135,7 +135,7 @@ FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
}
static int
SetMMerror(char *function, MMRESULT code)
SetMMerror(const char *function, MMRESULT code)
{
int len;
char errbuf[MAXERRORLENGTH];
@@ -434,7 +434,6 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
return 0; /* Ready to go! */
}
static int
WINMM_Init(SDL_AudioDriverImpl * impl)
{