Merge commit '852f2a6343518919e5ca8d3c1bbcab9f493e3cd8'

This commit is contained in:
2024-01-17 17:02:59 +01:00
1244 changed files with 50102 additions and 28146 deletions

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -38,7 +38,8 @@
#include "SDL_assert_c.h"
#include "SDL_log_c.h"
#include "audio/SDL_audio_c.h"
#include "SDL_properties_c.h"
#include "audio/SDL_sysaudio.h"
#include "video/SDL_video_c.h"
#include "events/SDL_events_c.h"
#include "haptic/SDL_haptic_c.h"
@ -47,9 +48,7 @@
#include "sensor/SDL_sensor_c.h"
/* Initialization/Cleanup routines */
#ifndef SDL_TIMERS_DISABLED
#include "timer/SDL_timer_c.h"
#endif
#ifdef SDL_VIDEO_DRIVER_WINDOWS
extern int SDL_HelperWindowCreate(void);
extern int SDL_HelperWindowDestroy(void);
@ -136,7 +135,7 @@ static SDL_bool SDL_ShouldInitSubsystem(Uint32 subsystem)
{
const int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
SDL_assert((subsystem_index < 0) || (SDL_SubsystemRefCount[subsystem_index] < 255));
return ((subsystem_index >= 0) && (SDL_SubsystemRefCount[subsystem_index] == 0)) ? SDL_TRUE : SDL_FALSE;
return ((subsystem_index >= 0) && (SDL_SubsystemRefCount[subsystem_index] == 0));
}
/* Private helper to check if a system needs to be quit. */
@ -150,7 +149,23 @@ static SDL_bool SDL_ShouldQuitSubsystem(Uint32 subsystem)
/* If we're in SDL_Quit, we shut down every subsystem, even if refcount
* isn't zero.
*/
return (((subsystem_index >= 0) && (SDL_SubsystemRefCount[subsystem_index] == 1)) || SDL_bInMainQuit) ? SDL_TRUE : SDL_FALSE;
return (((subsystem_index >= 0) && (SDL_SubsystemRefCount[subsystem_index] == 1)) || SDL_bInMainQuit);
}
/* Private helper to either increment's existing ref counter,
* or fully init a new subsystem. */
static SDL_bool SDL_InitOrIncrementSubsystem(Uint32 subsystem)
{
int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
SDL_assert((subsystem_index < 0) || (SDL_SubsystemRefCount[subsystem_index] < 255));
if (subsystem_index < 0) {
return SDL_FALSE;
}
if (SDL_SubsystemRefCount[subsystem_index] > 0) {
++SDL_SubsystemRefCount[subsystem_index];
return SDL_TRUE;
}
return SDL_InitSubSystem(subsystem) == 0;
}
void SDL_SetMainReady(void)
@ -167,6 +182,8 @@ int SDL_InitSubSystem(Uint32 flags)
}
SDL_InitLog();
SDL_InitProperties();
SDL_GetGlobalProperties();
/* Clear the error message */
SDL_ClearError();
@ -175,16 +192,6 @@ int SDL_InitSubSystem(Uint32 flags)
SDL_DBus_Init();
#endif
if (flags & SDL_INIT_GAMEPAD) {
/* game controller implies joystick */
flags |= SDL_INIT_JOYSTICK;
}
if (flags & (SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO)) {
/* video or joystick or audio implies events */
flags |= SDL_INIT_EVENTS;
}
#ifdef SDL_VIDEO_DRIVER_WINDOWS
if (flags & (SDL_INIT_HAPTIC | SDL_INIT_JOYSTICK)) {
if (SDL_HelperWindowCreate() < 0) {
@ -193,9 +200,7 @@ int SDL_InitSubSystem(Uint32 flags)
}
#endif
#ifndef SDL_TIMERS_DISABLED
SDL_InitTicks();
#endif
/* Initialize the event subsystem */
if (flags & SDL_INIT_EVENTS) {
@ -218,7 +223,6 @@ int SDL_InitSubSystem(Uint32 flags)
/* Initialize the timer subsystem */
if (flags & SDL_INIT_TIMER) {
#if !defined(SDL_TIMERS_DISABLED) && !defined(SDL_TIMER_DUMMY)
if (SDL_ShouldInitSubsystem(SDL_INIT_TIMER)) {
SDL_IncrementSubsystemRefCount(SDL_INIT_TIMER);
if (SDL_InitTimers() < 0) {
@ -229,16 +233,17 @@ int SDL_InitSubSystem(Uint32 flags)
SDL_IncrementSubsystemRefCount(SDL_INIT_TIMER);
}
flags_initialized |= SDL_INIT_TIMER;
#else
SDL_SetError("SDL not built with timer support");
goto quit_and_error;
#endif
}
/* Initialize the video subsystem */
if (flags & SDL_INIT_VIDEO) {
#ifndef SDL_VIDEO_DISABLED
if (SDL_ShouldInitSubsystem(SDL_INIT_VIDEO)) {
/* video implies events */
if (!SDL_InitOrIncrementSubsystem(SDL_INIT_EVENTS)) {
goto quit_and_error;
}
SDL_IncrementSubsystemRefCount(SDL_INIT_VIDEO);
if (SDL_VideoInit(NULL) < 0) {
SDL_DecrementSubsystemRefCount(SDL_INIT_VIDEO);
@ -258,6 +263,11 @@ int SDL_InitSubSystem(Uint32 flags)
if (flags & SDL_INIT_AUDIO) {
#ifndef SDL_AUDIO_DISABLED
if (SDL_ShouldInitSubsystem(SDL_INIT_AUDIO)) {
/* audio implies events */
if (!SDL_InitOrIncrementSubsystem(SDL_INIT_EVENTS)) {
goto quit_and_error;
}
SDL_IncrementSubsystemRefCount(SDL_INIT_AUDIO);
if (SDL_InitAudio(NULL) < 0) {
SDL_DecrementSubsystemRefCount(SDL_INIT_AUDIO);
@ -277,6 +287,11 @@ int SDL_InitSubSystem(Uint32 flags)
if (flags & SDL_INIT_JOYSTICK) {
#ifndef SDL_JOYSTICK_DISABLED
if (SDL_ShouldInitSubsystem(SDL_INIT_JOYSTICK)) {
/* joystick implies events */
if (!SDL_InitOrIncrementSubsystem(SDL_INIT_EVENTS)) {
goto quit_and_error;
}
SDL_IncrementSubsystemRefCount(SDL_INIT_JOYSTICK);
if (SDL_InitJoysticks() < 0) {
SDL_DecrementSubsystemRefCount(SDL_INIT_JOYSTICK);
@ -295,6 +310,11 @@ int SDL_InitSubSystem(Uint32 flags)
if (flags & SDL_INIT_GAMEPAD) {
#ifndef SDL_JOYSTICK_DISABLED
if (SDL_ShouldInitSubsystem(SDL_INIT_GAMEPAD)) {
/* game controller implies joystick */
if (!SDL_InitOrIncrementSubsystem(SDL_INIT_JOYSTICK)) {
goto quit_and_error;
}
SDL_IncrementSubsystemRefCount(SDL_INIT_GAMEPAD);
if (SDL_InitGamepads() < 0) {
SDL_DecrementSubsystemRefCount(SDL_INIT_GAMEPAD);
@ -376,21 +396,19 @@ void SDL_QuitSubSystem(Uint32 flags)
#ifndef SDL_JOYSTICK_DISABLED
if (flags & SDL_INIT_GAMEPAD) {
/* game controller implies joystick */
flags |= SDL_INIT_JOYSTICK;
if (SDL_ShouldQuitSubsystem(SDL_INIT_GAMEPAD)) {
SDL_QuitGamepads();
/* game controller implies joystick */
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
}
SDL_DecrementSubsystemRefCount(SDL_INIT_GAMEPAD);
}
if (flags & SDL_INIT_JOYSTICK) {
/* joystick implies events */
flags |= SDL_INIT_EVENTS;
if (SDL_ShouldQuitSubsystem(SDL_INIT_JOYSTICK)) {
SDL_QuitJoysticks();
/* joystick implies events */
SDL_QuitSubSystem(SDL_INIT_EVENTS);
}
SDL_DecrementSubsystemRefCount(SDL_INIT_JOYSTICK);
}
@ -407,11 +425,10 @@ void SDL_QuitSubSystem(Uint32 flags)
#ifndef SDL_AUDIO_DISABLED
if (flags & SDL_INIT_AUDIO) {
/* audio implies events */
flags |= SDL_INIT_EVENTS;
if (SDL_ShouldQuitSubsystem(SDL_INIT_AUDIO)) {
SDL_QuitAudio();
/* audio implies events */
SDL_QuitSubSystem(SDL_INIT_EVENTS);
}
SDL_DecrementSubsystemRefCount(SDL_INIT_AUDIO);
}
@ -419,24 +436,21 @@ void SDL_QuitSubSystem(Uint32 flags)
#ifndef SDL_VIDEO_DISABLED
if (flags & SDL_INIT_VIDEO) {
/* video implies events */
flags |= SDL_INIT_EVENTS;
if (SDL_ShouldQuitSubsystem(SDL_INIT_VIDEO)) {
SDL_VideoQuit();
/* video implies events */
SDL_QuitSubSystem(SDL_INIT_EVENTS);
}
SDL_DecrementSubsystemRefCount(SDL_INIT_VIDEO);
}
#endif
#if !defined(SDL_TIMERS_DISABLED) && !defined(SDL_TIMER_DUMMY)
if (flags & SDL_INIT_TIMER) {
if (SDL_ShouldQuitSubsystem(SDL_INIT_TIMER)) {
SDL_QuitTimers();
}
SDL_DecrementSubsystemRefCount(SDL_INIT_TIMER);
}
#endif
#ifndef SDL_EVENTS_DISABLED
if (flags & SDL_INIT_EVENTS) {
@ -488,17 +502,16 @@ void SDL_Quit(void)
#endif
SDL_QuitSubSystem(SDL_INIT_EVERYTHING);
#ifndef SDL_TIMERS_DISABLED
SDL_QuitTicks();
#endif
SDL_ClearHints();
SDL_AssertionsQuit();
#ifdef SDL_USE_LIBDBUS
SDL_DBus_Quit();
#endif
SDL_ClearHints();
SDL_AssertionsQuit();
SDL_QuitProperties();
SDL_QuitLog();
/* Now that every subsystem has been quit, we reset the subsystem refcount
@ -511,13 +524,27 @@ void SDL_Quit(void)
SDL_bInMainQuit = SDL_FALSE;
}
/* Assume we can wrap SDL_AtomicInt values and cast to Uint32 */
SDL_COMPILE_TIME_ASSERT(sizeof_object_id, sizeof(int) == sizeof(Uint32));
Uint32 SDL_GetNextObjectID(void)
{
static SDL_AtomicInt last_id;
Uint32 id = (Uint32)SDL_AtomicIncRef(&last_id) + 1;
if (id == 0) {
id = (Uint32)SDL_AtomicIncRef(&last_id) + 1;
}
return id;
}
/* Get the library version number */
int SDL_GetVersion(SDL_version *ver)
{
static SDL_bool check_hint = SDL_TRUE;
static SDL_bool legacy_version = SDL_FALSE;
if (ver == NULL) {
if (!ver) {
return SDL_InvalidParamError("ver");
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -106,11 +106,11 @@ static void SDL_GenerateAssertionReport(void)
const SDL_AssertData *item = triggered_assertions;
/* only do this if the app hasn't assigned an assertion handler. */
if ((item != NULL) && (assertion_handler != SDL_PromptAssertion)) {
if ((item) && (assertion_handler != SDL_PromptAssertion)) {
debug_print("\n\nSDL assertion report.\n");
debug_print("All SDL assertions between last init/quit:\n\n");
while (item != NULL) {
while (item) {
debug_print(
"'%s'\n"
" * %s (%s:%d)\n"
@ -198,7 +198,7 @@ static SDL_AssertState SDLCALL SDL_PromptAssertion(const SDL_AssertData *data, v
/* let env. variable override, so unit tests won't block in a GUI. */
envr = SDL_getenv("SDL_ASSERT");
if (envr != NULL) {
if (envr) {
if (message != stack_buf) {
SDL_free(message);
}
@ -334,9 +334,9 @@ SDL_AssertState SDL_ReportAssertion(SDL_AssertData *data, const char *func, cons
#ifndef SDL_THREADS_DISABLED
static SDL_SpinLock spinlock = 0;
SDL_AtomicLock(&spinlock);
if (assertion_mutex == NULL) { /* never called SDL_Init()? */
if (!assertion_mutex) { /* never called SDL_Init()? */
assertion_mutex = SDL_CreateMutex();
if (assertion_mutex == NULL) {
if (!assertion_mutex) {
SDL_AtomicUnlock(&spinlock);
return SDL_ASSERTION_IGNORE; /* oh well, I guess. */
}
@ -401,7 +401,7 @@ void SDL_AssertionsQuit(void)
#if SDL_ASSERT_LEVEL > 0
SDL_GenerateAssertionReport();
#ifndef SDL_THREADS_DISABLED
if (assertion_mutex != NULL) {
if (assertion_mutex) {
SDL_DestroyMutex(assertion_mutex);
assertion_mutex = NULL;
}
@ -429,7 +429,7 @@ void SDL_ResetAssertionReport(void)
{
SDL_AssertData *next = NULL;
SDL_AssertData *item;
for (item = triggered_assertions; item != NULL; item = next) {
for (item = triggered_assertions; item; item = next) {
next = (SDL_AssertData *)item->next;
item->always_ignore = SDL_FALSE;
item->trigger_count = 0;
@ -446,7 +446,7 @@ SDL_AssertionHandler SDL_GetDefaultAssertionHandler(void)
SDL_AssertionHandler SDL_GetAssertionHandler(void **userdata)
{
if (userdata != NULL) {
if (userdata) {
*userdata = assertion_userdata;
}
return assertion_handler;

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -27,12 +27,12 @@
int SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
{
/* Ignore call if invalid format pointer was passed */
if (fmt != NULL) {
if (fmt) {
va_list ap;
int result;
SDL_error *error = SDL_GetErrBuf();
SDL_error *error = SDL_GetErrBuf(SDL_TRUE);
error->error = 1; /* mark error as valid */
error->error = SDL_ErrorCodeGeneric;
va_start(ap, fmt);
result = SDL_vsnprintf(error->str, error->len, fmt, ap);
@ -62,13 +62,29 @@ int SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
/* Available for backwards compatibility */
const char *SDL_GetError(void)
{
const SDL_error *error = SDL_GetErrBuf();
return error->error ? error->str : "";
const SDL_error *error = SDL_GetErrBuf(SDL_FALSE);
if (!error) {
return "";
}
switch (error->error) {
case SDL_ErrorCodeGeneric:
return error->str;
case SDL_ErrorCodeOutOfMemory:
return "Out of memory";
default:
return "";
}
}
void SDL_ClearError(void)
{
SDL_GetErrBuf()->error = 0;
SDL_error *error = SDL_GetErrBuf(SDL_FALSE);
if (error) {
error->error = SDL_ErrorCodeNone;
}
}
/* Very common errors go here */
@ -76,7 +92,8 @@ int SDL_Error(SDL_errorcode code)
{
switch (code) {
case SDL_ENOMEM:
return SDL_SetError("Out of memory");
SDL_GetErrBuf(SDL_TRUE)->error = SDL_ErrorCodeOutOfMemory;
return -1;
case SDL_EFREAD:
return SDL_SetError("Error reading from datastream");
case SDL_EFWRITE:
@ -89,16 +106,3 @@ int SDL_Error(SDL_errorcode code)
return SDL_SetError("Unknown SDL error");
}
}
char *SDL_GetErrorMsg(char *errstr, int maxlen)
{
const SDL_error *error = SDL_GetErrBuf();
if (error->error) {
SDL_strlcpy(errstr, error->str, maxlen);
} else {
*errstr = '\0';
}
return errstr;
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -27,9 +27,16 @@
#ifndef SDL_error_c_h_
#define SDL_error_c_h_
typedef enum
{
SDL_ErrorCodeNone,
SDL_ErrorCodeGeneric,
SDL_ErrorCodeOutOfMemory,
} SDL_ErrorCode;
typedef struct SDL_error
{
int error; /* This is a numeric value corresponding to the current error */
SDL_ErrorCode error;
char *str;
size_t len;
SDL_realloc_func realloc_func;
@ -37,6 +44,6 @@ typedef struct SDL_error
} SDL_error;
/* Defined in SDL_thread.c */
extern SDL_error *SDL_GetErrBuf(void);
extern SDL_error *SDL_GetErrBuf(SDL_bool create);
#endif /* SDL_error_c_h_ */

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -26,7 +26,7 @@ int SDL_GUIDToString(SDL_GUID guid, char *pszGUID, int cbGUID)
static const char k_rgchHexToASCII[] = "0123456789abcdef";
int i;
if (pszGUID == NULL) {
if (!pszGUID) {
return SDL_InvalidParamError("pszGUID");
}
if (cbGUID <= 0) {

273
external/sdl/SDL/src/SDL_hashtable.c vendored Normal file
View File

@ -0,0 +1,273 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_hashtable.h"
typedef struct SDL_HashItem
{
const void *key;
const void *value;
struct SDL_HashItem *next;
} SDL_HashItem;
struct SDL_HashTable
{
SDL_HashItem **table;
Uint32 table_len;
SDL_bool stackable;
void *data;
SDL_HashTable_HashFn hash;
SDL_HashTable_KeyMatchFn keymatch;
SDL_HashTable_NukeFn nuke;
};
SDL_HashTable *SDL_CreateHashTable(void *data, const Uint32 num_buckets, const SDL_HashTable_HashFn hashfn,
const SDL_HashTable_KeyMatchFn keymatchfn,
const SDL_HashTable_NukeFn nukefn,
const SDL_bool stackable)
{
SDL_HashTable *table;
// num_buckets must be a power of two so we get a solid block of bits to mask hash values against.
if ((num_buckets == 0) || ((num_buckets & (num_buckets - 1)) != 0)) {
SDL_SetError("num_buckets must be a power of two");
return NULL;
}
table = (SDL_HashTable *) SDL_calloc(1, sizeof (SDL_HashTable));
if (!table) {
return NULL;
}
table->table = (SDL_HashItem **) SDL_calloc(num_buckets, sizeof (SDL_HashItem *));
if (!table->table) {
SDL_free(table);
return NULL;
}
table->table_len = num_buckets;
table->stackable = stackable;
table->data = data;
table->hash = hashfn;
table->keymatch = keymatchfn;
table->nuke = nukefn;
return table;
}
static SDL_INLINE Uint32 calc_hash(const SDL_HashTable *table, const void *key)
{
return table->hash(key, table->data) & (table->table_len - 1);
}
SDL_bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value)
{
SDL_HashItem *item;
const Uint32 hash = calc_hash(table, key);
if ( (!table->stackable) && (SDL_FindInHashTable(table, key, NULL)) ) {
return SDL_FALSE;
}
// !!! FIXME: grow and rehash table if it gets too saturated.
item = (SDL_HashItem *) SDL_malloc(sizeof (SDL_HashItem));
if (!item) {
return SDL_FALSE;
}
item->key = key;
item->value = value;
item->next = table->table[hash];
table->table[hash] = item;
return SDL_TRUE;
}
SDL_bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void **_value)
{
const Uint32 hash = calc_hash(table, key);
void *data = table->data;
SDL_HashItem *i;
for (i = table->table[hash]; i; i = i->next) {
if (table->keymatch(key, i->key, data)) {
if (_value) {
*_value = i->value;
}
return SDL_TRUE;
}
}
return SDL_FALSE;
}
SDL_bool SDL_RemoveFromHashTable(SDL_HashTable *table, const void *key)
{
const Uint32 hash = calc_hash(table, key);
SDL_HashItem *item = NULL;
SDL_HashItem *prev = NULL;
void *data = table->data;
for (item = table->table[hash]; item; item = item->next) {
if (table->keymatch(key, item->key, data)) {
if (prev) {
prev->next = item->next;
} else {
table->table[hash] = item->next;
}
table->nuke(item->key, item->value, data);
SDL_free(item);
return SDL_TRUE;
}
prev = item;
}
return SDL_FALSE;
}
SDL_bool SDL_IterateHashTableKey(const SDL_HashTable *table, const void *key, const void **_value, void **iter)
{
SDL_HashItem *item = *iter ? ((SDL_HashItem *) *iter)->next : table->table[calc_hash(table, key)];
while (item) {
if (table->keymatch(key, item->key, table->data)) {
*_value = item->value;
*iter = item;
return SDL_TRUE;
}
item = item->next;
}
// no more matches.
*_value = NULL;
*iter = NULL;
return SDL_FALSE;
}
SDL_bool SDL_IterateHashTable(const SDL_HashTable *table, const void **_key, const void **_value, void **iter)
{
SDL_HashItem *item = (SDL_HashItem *) *iter;
Uint32 idx = 0;
if (item) {
const SDL_HashItem *orig = item;
item = item->next;
if (!item) {
idx = calc_hash(table, orig->key) + 1; // !!! FIXME: we probably shouldn't rehash each time.
}
}
while (!item && (idx < table->table_len)) {
item = table->table[idx++]; // skip empty buckets...
}
if (!item) { // no more matches?
*_key = NULL;
*iter = NULL;
return SDL_FALSE;
}
*_key = item->key;
*_value = item->value;
*iter = item;
return SDL_TRUE;
}
SDL_bool SDL_HashTableEmpty(SDL_HashTable *table)
{
if (table) {
Uint32 i;
for (i = 0; i < table->table_len; i++) {
SDL_HashItem *item = table->table[i];
if (item) {
return SDL_FALSE;
}
}
}
return SDL_TRUE;
}
void SDL_DestroyHashTable(SDL_HashTable *table)
{
if (table) {
void *data = table->data;
Uint32 i;
for (i = 0; i < table->table_len; i++) {
SDL_HashItem *item = table->table[i];
while (item) {
SDL_HashItem *next = item->next;
table->nuke(item->key, item->value, data);
SDL_free(item);
item = next;
}
}
SDL_free(table->table);
SDL_free(table);
}
}
// this is djb's xor hashing function.
static SDL_INLINE Uint32 hash_string_djbxor(const char *str, size_t len)
{
Uint32 hash = 5381;
while (len--) {
hash = ((hash << 5) + hash) ^ *(str++);
}
return hash;
}
Uint32 SDL_HashString(const void *key, void *data)
{
const char *str = (const char *)key;
return hash_string_djbxor(str, SDL_strlen(str));
}
SDL_bool SDL_KeyMatchString(const void *a, const void *b, void *data)
{
if (a == b) {
return SDL_TRUE; // same pointer, must match.
} else if (!a || !b) {
return SDL_FALSE; // one pointer is NULL (and first test shows they aren't the same pointer), must not match.
}
return (SDL_strcmp((const char *)a, (const char *)b) == 0); // Check against actual string contents.
}
// We assume we can fit the ID in the key directly
SDL_COMPILE_TIME_ASSERT(SDL_HashID_KeySize, sizeof(Uint32) <= sizeof(const void *));
Uint32 SDL_HashID(const void *key, void *unused)
{
return (Uint32)(uintptr_t)key;
}
SDL_bool SDL_KeyMatchID(const void *a, const void *b, void *unused)
{
if (a == b) {
return SDL_TRUE;
}
return SDL_FALSE;
}

57
external/sdl/SDL/src/SDL_hashtable.h vendored Normal file
View File

@ -0,0 +1,57 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_hashtable_h_
#define SDL_hashtable_h_
/* this is not (currently) a public API. But maybe it should be! */
struct SDL_HashTable;
typedef struct SDL_HashTable SDL_HashTable;
typedef Uint32 (*SDL_HashTable_HashFn)(const void *key, void *data);
typedef SDL_bool (*SDL_HashTable_KeyMatchFn)(const void *a, const void *b, void *data);
typedef void (*SDL_HashTable_NukeFn)(const void *key, const void *value, void *data);
SDL_HashTable *SDL_CreateHashTable(void *data,
const Uint32 num_buckets,
const SDL_HashTable_HashFn hashfn,
const SDL_HashTable_KeyMatchFn keymatchfn,
const SDL_HashTable_NukeFn nukefn,
const SDL_bool stackable);
void SDL_DestroyHashTable(SDL_HashTable *table);
SDL_bool SDL_InsertIntoHashTable(SDL_HashTable *table, const void *key, const void *value);
SDL_bool SDL_RemoveFromHashTable(SDL_HashTable *table, const void *key);
SDL_bool SDL_FindInHashTable(const SDL_HashTable *table, const void *key, const void **_value);
SDL_bool SDL_HashTableEmpty(SDL_HashTable *table);
// iterate all values for a specific key. This only makes sense if the hash is stackable. If not-stackable, just use SDL_FindInHashTable().
SDL_bool SDL_IterateHashTableKey(const SDL_HashTable *table, const void *key, const void **_value, void **iter);
// iterate all key/value pairs in a hash (stackable hashes can have duplicate keys with multiple values).
SDL_bool SDL_IterateHashTable(const SDL_HashTable *table, const void **_key, const void **_value, void **iter);
Uint32 SDL_HashString(const void *key, void *unused);
SDL_bool SDL_KeyMatchString(const void *a, const void *b, void *unused);
Uint32 SDL_HashID(const void *key, void *unused);
SDL_bool SDL_KeyMatchID(const void *a, const void *b, void *unused);
#endif /* SDL_hashtable_h_ */

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -49,7 +49,7 @@ SDL_bool SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPr
SDL_Hint *hint;
SDL_HintWatch *entry;
if (name == NULL) {
if (!name) {
return SDL_FALSE;
}
@ -64,7 +64,7 @@ SDL_bool SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPr
return SDL_FALSE;
}
if (hint->value != value &&
(value == NULL || !hint->value || SDL_strcmp(hint->value, value) != 0)) {
(!value || !hint->value || SDL_strcmp(hint->value, value) != 0)) {
char *old_value = hint->value;
hint->value = value ? SDL_strdup(value) : NULL;
@ -85,7 +85,7 @@ SDL_bool SDL_SetHintWithPriority(const char *name, const char *value, SDL_HintPr
/* Couldn't find the hint, add a new one */
hint = (SDL_Hint *)SDL_malloc(sizeof(*hint));
if (hint == NULL) {
if (!hint) {
return SDL_FALSE;
}
hint->name = SDL_strdup(name);
@ -103,16 +103,16 @@ SDL_bool SDL_ResetHint(const char *name)
SDL_Hint *hint;
SDL_HintWatch *entry;
if (name == NULL) {
if (!name) {
return SDL_FALSE;
}
env = SDL_getenv(name);
for (hint = SDL_hints; hint; hint = hint->next) {
if (SDL_strcmp(name, hint->name) == 0) {
if ((env == NULL && hint->value != NULL) ||
(env != NULL && hint->value == NULL) ||
(env != NULL && SDL_strcmp(env, hint->value) != 0)) {
if ((!env && hint->value) ||
(env && !hint->value) ||
(env && SDL_strcmp(env, hint->value) != 0)) {
for (entry = hint->callbacks; entry;) {
/* Save the next entry in case this one is deleted */
SDL_HintWatch *next = entry->next;
@ -137,9 +137,9 @@ void SDL_ResetHints(void)
for (hint = SDL_hints; hint; hint = hint->next) {
env = SDL_getenv(hint->name);
if ((env == NULL && hint->value != NULL) ||
(env != NULL && hint->value == NULL) ||
(env != NULL && SDL_strcmp(env, hint->value) != 0)) {
if ((!env && hint->value) ||
(env && !hint->value) ||
(env && SDL_strcmp(env, hint->value) != 0)) {
for (entry = hint->callbacks; entry;) {
/* Save the next entry in case this one is deleted */
SDL_HintWatch *next = entry->next;
@ -166,7 +166,7 @@ const char *SDL_GetHint(const char *name)
env = SDL_getenv(name);
for (hint = SDL_hints; hint; hint = hint->next) {
if (SDL_strcmp(name, hint->name) == 0) {
if (env == NULL || hint->priority == SDL_HINT_OVERRIDE) {
if (!env || hint->priority == SDL_HINT_OVERRIDE) {
return hint->value;
}
break;
@ -177,7 +177,7 @@ const char *SDL_GetHint(const char *name)
int SDL_GetStringInteger(const char *value, int default_value)
{
if (value == NULL || !*value) {
if (!value || !*value) {
return default_value;
}
if (*value == '0' || SDL_strcasecmp(value, "false") == 0) {
@ -194,7 +194,7 @@ int SDL_GetStringInteger(const char *value, int default_value)
SDL_bool SDL_GetStringBoolean(const char *value, SDL_bool default_value)
{
if (value == NULL || !*value) {
if (!value || !*value) {
return default_value;
}
if (*value == '0' || SDL_strcasecmp(value, "false") == 0) {
@ -215,7 +215,7 @@ int SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userd
SDL_HintWatch *entry;
const char *value;
if (name == NULL || !*name) {
if (!name || !*name) {
return SDL_InvalidParamError("name");
}
if (!callback) {
@ -225,8 +225,8 @@ int SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userd
SDL_DelHintCallback(name, callback, userdata);
entry = (SDL_HintWatch *)SDL_malloc(sizeof(*entry));
if (entry == NULL) {
return SDL_OutOfMemory();
if (!entry) {
return -1;
}
entry->callback = callback;
entry->userdata = userdata;
@ -236,18 +236,18 @@ int SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userd
break;
}
}
if (hint == NULL) {
if (!hint) {
/* Need to add a hint entry for this watcher */
hint = (SDL_Hint *)SDL_malloc(sizeof(*hint));
if (hint == NULL) {
if (!hint) {
SDL_free(entry);
return SDL_OutOfMemory();
return -1;
}
hint->name = SDL_strdup(name);
if (!hint->name) {
SDL_free(entry);
SDL_free(hint);
return SDL_OutOfMemory();
return -1;
}
hint->value = NULL;
hint->priority = SDL_HINT_DEFAULT;

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -40,6 +40,17 @@
#define SDL_VARIABLE_LENGTH_ARRAY
#endif
#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) || defined(__clang__)
#define HAVE_GCC_DIAGNOSTIC_PRAGMA 1
#endif
#ifdef _MSC_VER /* We use constant comparison for generated code */
#pragma warning(disable : 6326)
#endif
#ifdef _MSC_VER /* SDL_MAX_SMALL_ALLOC_STACKSIZE is smaller than _ALLOCA_S_THRESHOLD and should be generally safe */
#pragma warning(disable : 6255)
#endif
#define SDL_MAX_SMALL_ALLOC_STACKSIZE 128
#define SDL_small_alloc(type, count, pisstack) ((*(pisstack) = ((sizeof(type) * (count)) < SDL_MAX_SMALL_ALLOC_STACKSIZE)), (*(pisstack) ? SDL_stack_alloc(type, count) : (type *)SDL_malloc(sizeof(type) * (count))))
#define SDL_small_free(ptr, isstack) \
@ -197,9 +208,10 @@
extern "C" {
#endif
extern DECLSPEC Uint32 SDLCALL SDL_GetNextObjectID(void);
extern DECLSPEC int SDLCALL SDL_WaitSemaphoreTimeoutNS(SDL_Semaphore *sem, Sint64 timeoutNS);
extern DECLSPEC int SDLCALL SDL_WaitConditionTimeoutNS(SDL_Condition *cond, SDL_Mutex *mutex, Sint64 timeoutNS);
extern DECLSPEC int SDLCALL SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS);
extern DECLSPEC SDL_bool SDLCALL SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -27,8 +27,8 @@ int SDL_ListAdd(SDL_ListNode **head, void *ent)
{
SDL_ListNode *node = SDL_malloc(sizeof(*node));
if (node == NULL) {
return SDL_OutOfMemory();
if (!node) {
return -1;
}
node->entry = ent;
@ -43,7 +43,7 @@ void SDL_ListPop(SDL_ListNode **head, void **ent)
SDL_ListNode **ptr = head;
/* Invalid or empty */
if (head == NULL || *head == NULL) {
if (!head || !*head) {
return;
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -65,7 +65,7 @@ static SDL_LogOutputFunction SDL_log_function = SDL_LogOutput;
static void *SDL_log_userdata = NULL;
static SDL_Mutex *log_function_mutex = NULL;
#ifdef __GNUC__
#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif
@ -80,7 +80,7 @@ static const char *SDL_priority_prefixes[SDL_NUM_LOG_PRIORITIES] = {
"CRITICAL"
};
#ifdef __GNUC__
#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
#pragma GCC diagnostic pop
#endif
@ -112,7 +112,7 @@ static int SDL_android_priority[SDL_NUM_LOG_PRIORITIES] = {
void SDL_InitLog(void)
{
if (log_function_mutex == NULL) {
if (!log_function_mutex) {
/* if this fails we'll try to continue without it. */
log_function_mutex = SDL_CreateMutex();
}
@ -282,7 +282,7 @@ static const char *GetCategoryPrefix(int category)
}
#endif /* __ANDROID__ */
void SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list ap)
void SDL_LogMessageV(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap)
{
char *message = NULL;
char stack_buf[SDL_MAX_LOG_MESSAGE_STACK];
@ -305,7 +305,7 @@ void SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va
return;
}
if (log_function_mutex == NULL) {
if (!log_function_mutex) {
/* this mutex creation can race if you log from two threads at startup. You should have called SDL_Init first! */
log_function_mutex = SDL_CreateMutex();
}
@ -323,7 +323,7 @@ void SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va
if (len >= sizeof(stack_buf) && SDL_size_add_overflow(len, 1, &len_plus_term) == 0) {
/* Allocate exactly what we need, including the zero-terminator */
message = (char *)SDL_malloc(len_plus_term);
if (message == NULL) {
if (!message) {
return;
}
va_copy(aq, ap);
@ -459,7 +459,7 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority
{
FILE *pFile;
pFile = fopen("SDL_Log.txt", "a");
if (pFile != NULL) {
if (pFile) {
(void)fprintf(pFile, "%s: %s\n", SDL_priority_prefixes[priority], message);
(void)fclose(pFile);
}
@ -468,7 +468,7 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority
{
FILE *pFile;
pFile = fopen("ux0:/data/SDL_Log.txt", "a");
if (pFile != NULL) {
if (pFile) {
(void)fprintf(pFile, "%s: %s\n", SDL_priority_prefixes[priority], message);
(void)fclose(pFile);
}
@ -477,7 +477,7 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority
{
FILE *pFile;
pFile = fopen("sdmc:/3ds/SDL_Log.txt", "a");
if (pFile != NULL) {
if (pFile) {
(void)fprintf(pFile, "%s: %s\n", SDL_priority_prefixes[priority], message);
(void)fclose(pFile);
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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

722
external/sdl/SDL/src/SDL_properties.c vendored Normal file
View File

@ -0,0 +1,722 @@
/*
Simple DiretMedia Layer
Copyright (C) 1997-2024 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_hashtable.h"
#include "SDL_hints_c.h"
#include "SDL_properties_c.h"
typedef struct
{
SDL_PropertyType type;
union {
void *pointer_value;
char *string_value;
Sint64 number_value;
float float_value;
SDL_bool boolean_value;
} value;
char *string_storage;
void (SDLCALL *cleanup)(void *userdata, void *value);
void *userdata;
} SDL_Property;
typedef struct
{
SDL_HashTable *props;
SDL_Mutex *lock;
} SDL_Properties;
static SDL_HashTable *SDL_properties;
static SDL_Mutex *SDL_properties_lock;
static SDL_PropertiesID SDL_last_properties_id;
static SDL_PropertiesID SDL_global_properties;
static void SDL_FreePropertyWithCleanup(const void *key, const void *value, void *data, SDL_bool cleanup)
{
SDL_Property *property = (SDL_Property *)value;
if (property) {
switch (property->type) {
case SDL_PROPERTY_TYPE_POINTER:
if (property->cleanup && cleanup) {
property->cleanup(property->userdata, property->value.pointer_value);
}
break;
case SDL_PROPERTY_TYPE_STRING:
SDL_free(property->value.string_value);
break;
default:
break;
}
if (property->string_storage) {
SDL_free(property->string_storage);
}
}
SDL_free((void *)key);
SDL_free((void *)value);
}
static void SDL_FreeProperty(const void *key, const void *value, void *data)
{
SDL_FreePropertyWithCleanup(key, value, data, SDL_TRUE);
}
static void SDL_FreeProperties(const void *key, const void *value, void *data)
{
SDL_Properties *properties = (SDL_Properties *)value;
if (properties) {
if (properties->props) {
SDL_DestroyHashTable(properties->props);
properties->props = NULL;
}
if (properties->lock) {
SDL_DestroyMutex(properties->lock);
properties->lock = NULL;
}
SDL_free(properties);
}
}
int SDL_InitProperties(void)
{
if (!SDL_properties_lock) {
SDL_properties_lock = SDL_CreateMutex();
if (!SDL_properties_lock) {
return -1;
}
}
if (!SDL_properties) {
SDL_properties = SDL_CreateHashTable(NULL, 16, SDL_HashID, SDL_KeyMatchID, SDL_FreeProperties, SDL_FALSE);
if (!SDL_properties) {
return -1;
}
}
return 0;
}
void SDL_QuitProperties(void)
{
if (SDL_global_properties) {
SDL_DestroyProperties(SDL_global_properties);
SDL_global_properties = 0;
}
if (SDL_properties) {
SDL_DestroyHashTable(SDL_properties);
SDL_properties = NULL;
}
if (SDL_properties_lock) {
SDL_DestroyMutex(SDL_properties_lock);
SDL_properties_lock = NULL;
}
}
SDL_PropertiesID SDL_GetGlobalProperties(void)
{
if (!SDL_global_properties) {
SDL_global_properties = SDL_CreateProperties();
}
return SDL_global_properties;
}
SDL_PropertiesID SDL_CreateProperties(void)
{
SDL_PropertiesID props = 0;
SDL_Properties *properties = NULL;
SDL_bool inserted = SDL_FALSE;
if (!SDL_properties && SDL_InitProperties() < 0) {
return 0;
}
properties = SDL_calloc(1, sizeof(*properties));
if (!properties) {
goto error;
}
properties->props = SDL_CreateHashTable(NULL, 4, SDL_HashString, SDL_KeyMatchString, SDL_FreeProperty, SDL_FALSE);
if (!properties->props) {
goto error;
}
properties->lock = SDL_CreateMutex();
if (!properties->lock) {
goto error;
}
if (SDL_InitProperties() < 0) {
goto error;
}
SDL_LockMutex(SDL_properties_lock);
++SDL_last_properties_id;
if (SDL_last_properties_id == 0) {
++SDL_last_properties_id;
}
props = SDL_last_properties_id;
if (SDL_InsertIntoHashTable(SDL_properties, (const void *)(uintptr_t)props, properties)) {
inserted = SDL_TRUE;
}
SDL_UnlockMutex(SDL_properties_lock);
if (inserted) {
/* All done! */
return props;
}
error:
SDL_FreeProperties(NULL, properties, NULL);
return 0;
}
int SDL_LockProperties(SDL_PropertiesID props)
{
SDL_Properties *properties = NULL;
if (!props) {
return SDL_InvalidParamError("props");
}
SDL_LockMutex(SDL_properties_lock);
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties);
SDL_UnlockMutex(SDL_properties_lock);
if (!properties) {
return SDL_InvalidParamError("props");
}
SDL_LockMutex(properties->lock);
return 0;
}
void SDL_UnlockProperties(SDL_PropertiesID props)
{
SDL_Properties *properties = NULL;
if (!props) {
return;
}
SDL_LockMutex(SDL_properties_lock);
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties);
SDL_UnlockMutex(SDL_properties_lock);
if (!properties) {
return;
}
SDL_UnlockMutex(properties->lock);
}
static int SDL_PrivateSetProperty(SDL_PropertiesID props, const char *name, SDL_Property *property)
{
SDL_Properties *properties = NULL;
int result = 0;
if (!props) {
SDL_FreePropertyWithCleanup(NULL, property, NULL, SDL_FALSE);
return SDL_InvalidParamError("props");
}
if (!name || !*name) {
SDL_FreePropertyWithCleanup(NULL, property, NULL, SDL_FALSE);
return SDL_InvalidParamError("name");
}
SDL_LockMutex(SDL_properties_lock);
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties);
SDL_UnlockMutex(SDL_properties_lock);
if (!properties) {
SDL_FreePropertyWithCleanup(NULL, property, NULL, SDL_FALSE);
return SDL_InvalidParamError("props");
}
SDL_LockMutex(properties->lock);
{
SDL_RemoveFromHashTable(properties->props, name);
if (property) {
char *key = SDL_strdup(name);
if (!SDL_InsertIntoHashTable(properties->props, key, property)) {
SDL_FreePropertyWithCleanup(key, property, NULL, SDL_FALSE);
result = -1;
}
}
}
SDL_UnlockMutex(properties->lock);
return result;
}
int SDL_SetPropertyWithCleanup(SDL_PropertiesID props, const char *name, void *value, void (SDLCALL *cleanup)(void *userdata, void *value), void *userdata)
{
SDL_Property *property;
if (!value) {
return SDL_ClearProperty(props, name);
}
property = (SDL_Property *)SDL_calloc(1, sizeof(*property));
if (!property) {
return -1;
}
property->type = SDL_PROPERTY_TYPE_POINTER;
property->value.pointer_value = value;
property->cleanup = cleanup;
property->userdata = userdata;
return SDL_PrivateSetProperty(props, name, property);
}
int SDL_SetProperty(SDL_PropertiesID props, const char *name, void *value)
{
SDL_Property *property;
if (!value) {
return SDL_ClearProperty(props, name);
}
property = (SDL_Property *)SDL_calloc(1, sizeof(*property));
if (!property) {
return -1;
}
property->type = SDL_PROPERTY_TYPE_POINTER;
property->value.pointer_value = value;
return SDL_PrivateSetProperty(props, name, property);
}
int SDL_SetStringProperty(SDL_PropertiesID props, const char *name, const char *value)
{
SDL_Property *property;
if (!value) {
return SDL_ClearProperty(props, name);
}
property = (SDL_Property *)SDL_calloc(1, sizeof(*property));
if (!property) {
return -1;
}
property->type = SDL_PROPERTY_TYPE_STRING;
property->value.string_value = SDL_strdup(value);
if (!property->value.string_value) {
SDL_free(property);
return -1;
}
return SDL_PrivateSetProperty(props, name, property);
}
int SDL_SetNumberProperty(SDL_PropertiesID props, const char *name, Sint64 value)
{
SDL_Property *property = (SDL_Property *)SDL_calloc(1, sizeof(*property));
if (!property) {
return -1;
}
property->type = SDL_PROPERTY_TYPE_NUMBER;
property->value.number_value = value;
return SDL_PrivateSetProperty(props, name, property);
}
int SDL_SetFloatProperty(SDL_PropertiesID props, const char *name, float value)
{
SDL_Property *property = (SDL_Property *)SDL_calloc(1, sizeof(*property));
if (!property) {
return -1;
}
property->type = SDL_PROPERTY_TYPE_FLOAT;
property->value.float_value = value;
return SDL_PrivateSetProperty(props, name, property);
}
int SDL_SetBooleanProperty(SDL_PropertiesID props, const char *name, SDL_bool value)
{
SDL_Property *property = (SDL_Property *)SDL_calloc(1, sizeof(*property));
if (!property) {
return -1;
}
property->type = SDL_PROPERTY_TYPE_BOOLEAN;
property->value.boolean_value = value ? SDL_TRUE : SDL_FALSE;
return SDL_PrivateSetProperty(props, name, property);
}
SDL_PropertyType SDL_GetPropertyType(SDL_PropertiesID props, const char *name)
{
SDL_Properties *properties = NULL;
SDL_PropertyType type = SDL_PROPERTY_TYPE_INVALID;
if (!props) {
SDL_InvalidParamError("props");
return SDL_PROPERTY_TYPE_INVALID;
}
if (!name || !*name) {
SDL_InvalidParamError("name");
return SDL_PROPERTY_TYPE_INVALID;
}
SDL_LockMutex(SDL_properties_lock);
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties);
SDL_UnlockMutex(SDL_properties_lock);
if (!properties) {
SDL_InvalidParamError("props");
return SDL_PROPERTY_TYPE_INVALID;
}
SDL_LockMutex(properties->lock);
{
SDL_Property *property = NULL;
if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) {
type = property->type;
} else {
SDL_SetError("Couldn't find property named %s", name);
}
}
SDL_UnlockMutex(properties->lock);
return type;
}
void *SDL_GetProperty(SDL_PropertiesID props, const char *name, void *default_value)
{
SDL_Properties *properties = NULL;
void *value = default_value;
if (!props) {
SDL_InvalidParamError("props");
return value;
}
if (!name || !*name) {
SDL_InvalidParamError("name");
return value;
}
SDL_LockMutex(SDL_properties_lock);
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties);
SDL_UnlockMutex(SDL_properties_lock);
if (!properties) {
SDL_InvalidParamError("props");
return value;
}
/* Note that taking the lock here only guarantees that we won't read the
* hashtable while it's being modified. The value itself can easily be
* freed from another thread after it is returned here.
*/
SDL_LockMutex(properties->lock);
{
SDL_Property *property = NULL;
if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) {
if (property->type == SDL_PROPERTY_TYPE_POINTER) {
value = property->value.pointer_value;
} else {
SDL_SetError("Property %s isn't a pointer value", name);
}
} else {
SDL_SetError("Couldn't find property named %s", name);
}
}
SDL_UnlockMutex(properties->lock);
return value;
}
const char *SDL_GetStringProperty(SDL_PropertiesID props, const char *name, const char *default_value)
{
SDL_Properties *properties = NULL;
const char *value = default_value;
if (!props) {
SDL_InvalidParamError("props");
return value;
}
if (!name || !*name) {
SDL_InvalidParamError("name");
return value;
}
SDL_LockMutex(SDL_properties_lock);
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties);
SDL_UnlockMutex(SDL_properties_lock);
if (!properties) {
SDL_InvalidParamError("props");
return value;
}
/* Note that taking the lock here only guarantees that we won't read the
* hashtable while it's being modified. The value itself can easily be
* freed from another thread after it is returned here.
*
* FIXME: Should we SDL_strdup() the return value to avoid this?
*/
SDL_LockMutex(properties->lock);
{
SDL_Property *property = NULL;
if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) {
switch (property->type) {
case SDL_PROPERTY_TYPE_STRING:
value = property->value.string_value;
break;
case SDL_PROPERTY_TYPE_NUMBER:
if (property->string_storage) {
value = property->string_storage;
} else {
SDL_asprintf(&property->string_storage, "%" SDL_PRIs64 "", property->value.number_value);
if (property->string_storage) {
value = property->string_storage;
}
}
break;
case SDL_PROPERTY_TYPE_FLOAT:
if (property->string_storage) {
value = property->string_storage;
} else {
SDL_asprintf(&property->string_storage, "%f", property->value.float_value);
if (property->string_storage) {
value = property->string_storage;
}
}
break;
case SDL_PROPERTY_TYPE_BOOLEAN:
value = property->value.boolean_value ? "true" : "false";
break;
default:
SDL_SetError("Property %s isn't a string value", name);
break;
}
} else {
SDL_SetError("Couldn't find property named %s", name);
}
}
SDL_UnlockMutex(properties->lock);
return value;
}
Sint64 SDL_GetNumberProperty(SDL_PropertiesID props, const char *name, Sint64 default_value)
{
SDL_Properties *properties = NULL;
Sint64 value = default_value;
if (!props) {
SDL_InvalidParamError("props");
return value;
}
if (!name || !*name) {
SDL_InvalidParamError("name");
return value;
}
SDL_LockMutex(SDL_properties_lock);
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties);
SDL_UnlockMutex(SDL_properties_lock);
if (!properties) {
SDL_InvalidParamError("props");
return value;
}
SDL_LockMutex(properties->lock);
{
SDL_Property *property = NULL;
if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) {
switch (property->type) {
case SDL_PROPERTY_TYPE_STRING:
value = SDL_strtoll(property->value.string_value, NULL, 0);
break;
case SDL_PROPERTY_TYPE_NUMBER:
value = property->value.number_value;
break;
case SDL_PROPERTY_TYPE_FLOAT:
value = (Sint64)SDL_round((double)property->value.float_value);
break;
case SDL_PROPERTY_TYPE_BOOLEAN:
value = property->value.boolean_value;
break;
default:
SDL_SetError("Property %s isn't a number value", name);
break;
}
} else {
SDL_SetError("Couldn't find property named %s", name);
}
}
SDL_UnlockMutex(properties->lock);
return value;
}
float SDL_GetFloatProperty(SDL_PropertiesID props, const char *name, float default_value)
{
SDL_Properties *properties = NULL;
float value = default_value;
if (!props) {
SDL_InvalidParamError("props");
return value;
}
if (!name || !*name) {
SDL_InvalidParamError("name");
return value;
}
SDL_LockMutex(SDL_properties_lock);
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties);
SDL_UnlockMutex(SDL_properties_lock);
if (!properties) {
SDL_InvalidParamError("props");
return value;
}
SDL_LockMutex(properties->lock);
{
SDL_Property *property = NULL;
if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) {
switch (property->type) {
case SDL_PROPERTY_TYPE_STRING:
value = (float)SDL_atof(property->value.string_value);
break;
case SDL_PROPERTY_TYPE_NUMBER:
value = (float)property->value.number_value;
break;
case SDL_PROPERTY_TYPE_FLOAT:
value = property->value.float_value;
break;
case SDL_PROPERTY_TYPE_BOOLEAN:
value = (float)property->value.boolean_value;
break;
default:
SDL_SetError("Property %s isn't a float value", name);
break;
}
} else {
SDL_SetError("Couldn't find property named %s", name);
}
}
SDL_UnlockMutex(properties->lock);
return value;
}
SDL_bool SDL_GetBooleanProperty(SDL_PropertiesID props, const char *name, SDL_bool default_value)
{
SDL_Properties *properties = NULL;
SDL_bool value = default_value;
if (!props) {
SDL_InvalidParamError("props");
return value;
}
if (!name || !*name) {
SDL_InvalidParamError("name");
return value;
}
SDL_LockMutex(SDL_properties_lock);
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties);
SDL_UnlockMutex(SDL_properties_lock);
if (!properties) {
SDL_InvalidParamError("props");
return value;
}
SDL_LockMutex(properties->lock);
{
SDL_Property *property = NULL;
if (SDL_FindInHashTable(properties->props, name, (const void **)&property)) {
switch (property->type) {
case SDL_PROPERTY_TYPE_STRING:
value = SDL_GetStringBoolean(property->value.string_value, default_value);
break;
case SDL_PROPERTY_TYPE_NUMBER:
value = (property->value.number_value != 0);
break;
case SDL_PROPERTY_TYPE_FLOAT:
value = (property->value.float_value != 0.0f);
break;
case SDL_PROPERTY_TYPE_BOOLEAN:
value = property->value.boolean_value;
break;
default:
SDL_SetError("Property %s isn't a boolean value", name);
break;
}
} else {
SDL_SetError("Couldn't find property named %s", name);
}
}
SDL_UnlockMutex(properties->lock);
return value;
}
int SDL_ClearProperty(SDL_PropertiesID props, const char *name)
{
return SDL_PrivateSetProperty(props, name, NULL);
}
int SDL_EnumerateProperties(SDL_PropertiesID props, SDL_EnumeratePropertiesCallback callback, void *userdata)
{
SDL_Properties *properties = NULL;
if (!props) {
return SDL_InvalidParamError("props");
}
if (!callback) {
return SDL_InvalidParamError("callback");
}
SDL_LockMutex(SDL_properties_lock);
SDL_FindInHashTable(SDL_properties, (const void *)(uintptr_t)props, (const void **)&properties);
SDL_UnlockMutex(SDL_properties_lock);
if (!properties) {
return SDL_InvalidParamError("props");
}
SDL_LockMutex(properties->lock);
{
void *iter;
const void *key, *value;
iter = NULL;
while (SDL_IterateHashTable(properties->props, &key, &value, &iter)) {
callback(userdata, props, (const char *)key);
}
}
SDL_UnlockMutex(properties->lock);
return 0;
}
void SDL_DestroyProperties(SDL_PropertiesID props)
{
if (!props) {
return;
}
SDL_LockMutex(SDL_properties_lock);
SDL_RemoveFromHashTable(SDL_properties, (const void *)(uintptr_t)props);
SDL_UnlockMutex(SDL_properties_lock);
}

23
external/sdl/SDL/src/SDL_properties_c.h vendored Normal file
View File

@ -0,0 +1,23 @@
/*
Simple DiretMedia Layer
Copyright (C) 1997-2024 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
extern int SDL_InitProperties(void);
extern void SDL_QuitProperties(void);

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -128,13 +128,13 @@ SDL_bool SDL_AtomicCAS(SDL_AtomicInt *a, int oldval, int newval)
SDL_COMPILE_TIME_ASSERT(atomic_cas, sizeof(long) == sizeof(a->value));
return _InterlockedCompareExchange((long *)&a->value, (long)newval, (long)oldval) == (long)oldval;
#elif defined(HAVE_WATCOM_ATOMICS)
return (SDL_bool)_SDL_cmpxchg_watcom(&a->value, newval, oldval);
return _SDL_cmpxchg_watcom(&a->value, newval, oldval);
#elif defined(HAVE_GCC_ATOMICS)
return (SDL_bool)__sync_bool_compare_and_swap(&a->value, oldval, newval);
return __sync_bool_compare_and_swap(&a->value, oldval, newval);
#elif defined(__MACOS__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
return (SDL_bool)OSAtomicCompareAndSwap32Barrier(oldval, newval, &a->value);
return OSAtomicCompareAndSwap32Barrier(oldval, newval, &a->value);
#elif defined(__SOLARIS__)
return (SDL_bool)((int)atomic_cas_uint((volatile uint_t *)&a->value, (uint_t)oldval, (uint_t)newval) == oldval);
return ((int)atomic_cas_uint((volatile uint_t *)&a->value, (uint_t)oldval, (uint_t)newval) == oldval);
#elif defined(EMULATE_CAS)
SDL_bool retval = SDL_FALSE;
@ -156,15 +156,15 @@ SDL_bool SDL_AtomicCASPtr(void **a, void *oldval, void *newval)
#ifdef HAVE_MSC_ATOMICS
return _InterlockedCompareExchangePointer(a, newval, oldval) == oldval;
#elif defined(HAVE_WATCOM_ATOMICS)
return (SDL_bool)_SDL_cmpxchg_watcom((int *)a, (long)newval, (long)oldval);
return _SDL_cmpxchg_watcom((int *)a, (long)newval, (long)oldval);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_bool_compare_and_swap(a, oldval, newval);
#elif defined(__MACOS__) && defined(__LP64__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
return (SDL_bool)OSAtomicCompareAndSwap64Barrier((int64_t)oldval, (int64_t)newval, (int64_t *)a);
return OSAtomicCompareAndSwap64Barrier((int64_t)oldval, (int64_t)newval, (int64_t *)a);
#elif defined(__MACOS__) && !defined(__LP64__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
return (SDL_bool)OSAtomicCompareAndSwap32Barrier((int32_t)oldval, (int32_t)newval, (int32_t *)a);
return OSAtomicCompareAndSwap32Barrier((int32_t)oldval, (int32_t)newval, (int32_t *)a);
#elif defined(__SOLARIS__)
return (SDL_bool)(atomic_cas_ptr(a, oldval, newval) == oldval);
return (atomic_cas_ptr(a, oldval, newval) == oldval);
#elif defined(EMULATE_CAS)
SDL_bool retval = SDL_FALSE;

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -63,7 +63,7 @@ SDL_bool SDL_AtomicTryLock(SDL_SpinLock *lock)
/* Terrible terrible damage */
static SDL_Mutex *_spinlock_mutex;
if (_spinlock_mutex == NULL) {
if (!_spinlock_mutex) {
/* Race condition on first lock... */
_spinlock_mutex = SDL_CreateMutex();
}
@ -139,11 +139,11 @@ SDL_bool SDL_AtomicTryLock(SDL_SpinLock *lock)
#elif defined(__SOLARIS__) && defined(_LP64)
/* Used for Solaris with non-gcc compilers. */
return (SDL_bool)((int)atomic_cas_64((volatile uint64_t *)lock, 0, 1) == 0);
return ((int)atomic_cas_64((volatile uint64_t *)lock, 0, 1) == 0);
#elif defined(__SOLARIS__) && !defined(_LP64)
/* Used for Solaris with non-gcc compilers. */
return (SDL_bool)((int)atomic_cas_32((volatile uint32_t *)lock, 0, 1) == 0);
return ((int)atomic_cas_32((volatile uint32_t *)lock, 0, 1) == 0);
#elif defined(PS2)
uint32_t oldintr;
SDL_bool res = SDL_FALSE;

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -22,8 +22,6 @@
#ifndef SDL_audio_c_h_
#define SDL_audio_c_h_
/* !!! FIXME: remove this header and have things just include SDL_sysaudio.h directly. */
#include "SDL_sysaudio.h"
extern void SDL_UpdateAudio(void);
#endif /* SDL_audio_c_h_ */

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -19,7 +19,7 @@
3. This notice may not be removed or altered from any source distribution.
*/
/* DO NOT EDIT, THIS FILE WAS GENERATED BY build-scripts/gen_audio_channel_conversion.c */
// DO NOT EDIT, THIS FILE WAS GENERATED BY build-scripts/gen_audio_channel_conversion.c
typedef void (*SDL_AudioChannelConverter)(float *dst, const float *src, int num_frames);
@ -30,7 +30,7 @@ static void SDL_ConvertMonoToStereo(float *dst, const float *src, int num_frames
LOG_DEBUG_AUDIO_CONVERT("mono", "stereo");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1);
dst += (num_frames-1) * 2;
for (i = num_frames; i; i--, src--, dst -= 2) {
@ -47,7 +47,7 @@ static void SDL_ConvertMonoTo21(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("mono", "2.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1);
dst += (num_frames-1) * 3;
for (i = num_frames; i; i--, src--, dst -= 3) {
@ -65,7 +65,7 @@ static void SDL_ConvertMonoToQuad(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("mono", "quad");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1);
dst += (num_frames-1) * 4;
for (i = num_frames; i; i--, src--, dst -= 4) {
@ -84,7 +84,7 @@ static void SDL_ConvertMonoTo41(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("mono", "4.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1);
dst += (num_frames-1) * 5;
for (i = num_frames; i; i--, src--, dst -= 5) {
@ -104,7 +104,7 @@ static void SDL_ConvertMonoTo51(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("mono", "5.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1);
dst += (num_frames-1) * 6;
for (i = num_frames; i; i--, src--, dst -= 6) {
@ -125,7 +125,7 @@ static void SDL_ConvertMonoTo61(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("mono", "6.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1);
dst += (num_frames-1) * 7;
for (i = num_frames; i; i--, src--, dst -= 7) {
@ -147,7 +147,7 @@ static void SDL_ConvertMonoTo71(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("mono", "7.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1);
dst += (num_frames-1) * 8;
for (i = num_frames; i; i--, src--, dst -= 8) {
@ -182,7 +182,7 @@ static void SDL_ConvertStereoTo21(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("stereo", "2.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 2;
dst += (num_frames-1) * 3;
for (i = num_frames; i; i--, src -= 2, dst -= 3) {
@ -199,7 +199,7 @@ static void SDL_ConvertStereoToQuad(float *dst, const float *src, int num_frames
LOG_DEBUG_AUDIO_CONVERT("stereo", "quad");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 2;
dst += (num_frames-1) * 4;
for (i = num_frames; i; i--, src -= 2, dst -= 4) {
@ -217,7 +217,7 @@ static void SDL_ConvertStereoTo41(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("stereo", "4.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 2;
dst += (num_frames-1) * 5;
for (i = num_frames; i; i--, src -= 2, dst -= 5) {
@ -236,7 +236,7 @@ static void SDL_ConvertStereoTo51(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("stereo", "5.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 2;
dst += (num_frames-1) * 6;
for (i = num_frames; i; i--, src -= 2, dst -= 6) {
@ -256,7 +256,7 @@ static void SDL_ConvertStereoTo61(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("stereo", "6.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 2;
dst += (num_frames-1) * 7;
for (i = num_frames; i; i--, src -= 2, dst -= 7) {
@ -277,7 +277,7 @@ static void SDL_ConvertStereoTo71(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("stereo", "7.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 2;
dst += (num_frames-1) * 8;
for (i = num_frames; i; i--, src -= 2, dst -= 8) {
@ -325,7 +325,7 @@ static void SDL_Convert21ToQuad(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("2.1", "quad");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 3;
dst += (num_frames-1) * 4;
for (i = num_frames; i; i--, src -= 3, dst -= 4) {
@ -344,7 +344,7 @@ static void SDL_Convert21To41(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("2.1", "4.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 3;
dst += (num_frames-1) * 5;
for (i = num_frames; i; i--, src -= 3, dst -= 5) {
@ -363,7 +363,7 @@ static void SDL_Convert21To51(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("2.1", "5.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 3;
dst += (num_frames-1) * 6;
for (i = num_frames; i; i--, src -= 3, dst -= 6) {
@ -383,7 +383,7 @@ static void SDL_Convert21To61(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("2.1", "6.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 3;
dst += (num_frames-1) * 7;
for (i = num_frames; i; i--, src -= 3, dst -= 7) {
@ -404,7 +404,7 @@ static void SDL_Convert21To71(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("2.1", "7.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 3;
dst += (num_frames-1) * 8;
for (i = num_frames; i; i--, src -= 3, dst -= 8) {
@ -469,7 +469,7 @@ static void SDL_ConvertQuadTo41(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("quad", "4.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 4;
dst += (num_frames-1) * 5;
for (i = num_frames; i; i--, src -= 4, dst -= 5) {
@ -488,7 +488,7 @@ static void SDL_ConvertQuadTo51(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("quad", "5.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 4;
dst += (num_frames-1) * 6;
for (i = num_frames; i; i--, src -= 4, dst -= 6) {
@ -508,7 +508,7 @@ static void SDL_ConvertQuadTo61(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("quad", "6.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 4;
dst += (num_frames-1) * 7;
for (i = num_frames; i; i--, src -= 4, dst -= 7) {
@ -531,7 +531,7 @@ static void SDL_ConvertQuadTo71(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("quad", "7.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 4;
dst += (num_frames-1) * 8;
for (i = num_frames; i; i--, src -= 4, dst -= 8) {
@ -613,7 +613,7 @@ static void SDL_Convert41To51(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("4.1", "5.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 5;
dst += (num_frames-1) * 6;
for (i = num_frames; i; i--, src -= 5, dst -= 6) {
@ -633,7 +633,7 @@ static void SDL_Convert41To61(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("4.1", "6.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 5;
dst += (num_frames-1) * 7;
for (i = num_frames; i; i--, src -= 5, dst -= 7) {
@ -656,7 +656,7 @@ static void SDL_Convert41To71(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("4.1", "7.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 5;
dst += (num_frames-1) * 8;
for (i = num_frames; i; i--, src -= 5, dst -= 8) {
@ -758,7 +758,7 @@ static void SDL_Convert51To61(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("5.1", "6.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 6;
dst += (num_frames-1) * 7;
for (i = num_frames; i; i--, src -= 6, dst -= 7) {
@ -781,7 +781,7 @@ static void SDL_Convert51To71(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("5.1", "7.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 6;
dst += (num_frames-1) * 8;
for (i = num_frames; i; i--, src -= 6, dst -= 8) {
@ -911,7 +911,7 @@ static void SDL_Convert61To71(float *dst, const float *src, int num_frames)
LOG_DEBUG_AUDIO_CONVERT("6.1", "7.1");
/* convert backwards, since output is growing in-place. */
// convert backwards, since output is growing in-place.
src += (num_frames-1) * 7;
dst += (num_frames-1) * 8;
for (i = num_frames; i; i--, src -= 7, dst -= 8) {

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -19,7 +19,7 @@
3. This notice may not be removed or altered from any source distribution.
*/
/* DO NOT EDIT, THIS FILE WAS GENERATED BY build-scripts/gen_audio_resampler_filter.c */
// DO NOT EDIT, THIS FILE WAS GENERATED BY build-scripts/gen_audio_resampler_filter.c
#define RESAMPLER_ZERO_CROSSINGS 5
#define RESAMPLER_BITS_PER_SAMPLE 16

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -20,7 +20,7 @@
*/
#include "SDL_internal.h"
#include "SDL_audio_c.h"
#include "SDL_sysaudio.h"
#include "SDL_audioqueue.h"
#include "SDL_audioresample.h"
@ -207,7 +207,7 @@ static SDL_bool SDL_IsSupportedAudioFormat(const SDL_AudioFormat fmt)
static SDL_bool SDL_IsSupportedChannelCount(const int channels)
{
return ((channels >= 1) && (channels <= 8)) ? SDL_TRUE : SDL_FALSE;
return ((channels >= 1) && (channels <= 8));
}
@ -278,7 +278,7 @@ void ConvertAudio(int num_frames, const void *src, SDL_AudioFormat src_format, i
}
}
if (scratch == NULL) {
if (!scratch) {
scratch = dst;
}
@ -389,7 +389,7 @@ static int UpdateAudioStreamInputSpec(SDL_AudioStream *stream, const SDL_AudioSp
if (stream->history_buffer_allocation < history_buffer_allocation) {
history_buffer = (Uint8 *) SDL_aligned_alloc(SDL_SIMDGetAlignment(), history_buffer_allocation);
if (!history_buffer) {
return SDL_OutOfMemory();
return -1;
}
SDL_aligned_free(stream->history_buffer);
stream->history_buffer = history_buffer;
@ -404,27 +404,24 @@ static int UpdateAudioStreamInputSpec(SDL_AudioStream *stream, const SDL_AudioSp
SDL_AudioStream *SDL_CreateAudioStream(const SDL_AudioSpec *src_spec, const SDL_AudioSpec *dst_spec)
{
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
SDL_SetError("Audio subsystem is not initialized");
return NULL;
}
SDL_ChooseAudioConverters();
SDL_SetupAudioResampler();
SDL_AudioStream *retval = (SDL_AudioStream *)SDL_calloc(1, sizeof(SDL_AudioStream));
if (retval == NULL) {
SDL_OutOfMemory();
if (!retval) {
return NULL;
}
retval->freq_ratio = 1.0f;
retval->queue = SDL_CreateAudioQueue(4096);
if (retval->queue == NULL) {
if (!retval->queue) {
SDL_free(retval);
return NULL;
}
retval->lock = SDL_CreateMutex();
if (retval->lock == NULL) {
if (!retval->lock) {
SDL_free(retval->queue);
SDL_free(retval);
return NULL;
@ -440,6 +437,18 @@ SDL_AudioStream *SDL_CreateAudioStream(const SDL_AudioSpec *src_spec, const SDL_
return retval;
}
SDL_PropertiesID SDL_GetAudioStreamProperties(SDL_AudioStream *stream)
{
if (!stream) {
SDL_InvalidParamError("stream");
return 0;
}
if (stream->props == 0) {
stream->props = SDL_CreateProperties();
}
return stream->props;
}
int SDL_SetAudioStreamGetCallback(SDL_AudioStream *stream, SDL_AudioStreamCallback callback, void *userdata)
{
if (!stream) {
@ -466,12 +475,20 @@ int SDL_SetAudioStreamPutCallback(SDL_AudioStream *stream, SDL_AudioStreamCallba
int SDL_LockAudioStream(SDL_AudioStream *stream)
{
return stream ? SDL_LockMutex(stream->lock) : SDL_InvalidParamError("stream");
if (!stream) {
return SDL_InvalidParamError("stream");
}
SDL_LockMutex(stream->lock);
return 0;
}
int SDL_UnlockAudioStream(SDL_AudioStream *stream)
{
return stream ? SDL_UnlockMutex(stream->lock) : SDL_InvalidParamError("stream");
if (!stream) {
return SDL_InvalidParamError("stream");
}
SDL_UnlockMutex(stream->lock);
return 0;
}
int SDL_GetAudioStreamFormat(SDL_AudioStream *stream, SDL_AudioSpec *src_spec, SDL_AudioSpec *dst_spec)
@ -568,7 +585,7 @@ float SDL_GetAudioStreamFrequencyRatio(SDL_AudioStream *stream)
}
SDL_LockMutex(stream->lock);
float freq_ratio = stream->freq_ratio;
const float freq_ratio = stream->freq_ratio;
SDL_UnlockMutex(stream->lock);
return freq_ratio;
@ -581,8 +598,8 @@ int SDL_SetAudioStreamFrequencyRatio(SDL_AudioStream *stream, float freq_ratio)
}
// Picked mostly arbitrarily.
static const float min_freq_ratio = 0.01f;
static const float max_freq_ratio = 100.0f;
const float min_freq_ratio = 0.01f;
const float max_freq_ratio = 100.0f;
if (freq_ratio < min_freq_ratio) {
return SDL_SetError("Frequency ratio is too low");
@ -614,9 +631,9 @@ int SDL_PutAudioStreamData(SDL_AudioStream *stream, const void *buf, int len)
SDL_Log("AUDIOSTREAM: wants to put %d bytes", len);
#endif
if (stream == NULL) {
if (!stream) {
return SDL_InvalidParamError("stream");
} else if (buf == NULL) {
} else if (!buf) {
return SDL_InvalidParamError("buf");
} else if (len < 0) {
return SDL_InvalidParamError("len");
@ -651,7 +668,7 @@ int SDL_PutAudioStreamData(SDL_AudioStream *stream, const void *buf, int len)
size_t chunk_size = SDL_GetAudioQueueChunkSize(stream->queue);
track = SDL_CreateChunkedAudioTrack(&src_spec, buf, len, chunk_size);
if (track == NULL) {
if (!track) {
return -1;
}
@ -662,7 +679,7 @@ int SDL_PutAudioStreamData(SDL_AudioStream *stream, const void *buf, int len)
int retval = 0;
if (track != NULL) {
if (track) {
SDL_AddTrackToAudioQueue(stream->queue, track);
} else {
retval = SDL_WriteToAudioQueue(stream->queue, &stream->src_spec, buf, len);
@ -683,7 +700,7 @@ int SDL_PutAudioStreamData(SDL_AudioStream *stream, const void *buf, int len)
int SDL_FlushAudioStream(SDL_AudioStream *stream)
{
if (stream == NULL) {
if (!stream) {
return SDL_InvalidParamError("stream");
}
@ -703,8 +720,7 @@ static Uint8 *EnsureAudioStreamWorkBufferSize(SDL_AudioStream *stream, size_t ne
}
Uint8 *ptr = (Uint8 *) SDL_aligned_alloc(SDL_SIMDGetAlignment(), newlen);
if (ptr == NULL) {
SDL_OutOfMemory();
if (!ptr) {
return NULL; // previous work buffer is still valid!
}
@ -723,7 +739,7 @@ static void UpdateAudioStreamHistoryBuffer(SDL_AudioStream* stream,
Uint8 *history_buffer = stream->history_buffer;
int history_bytes = history_buffer_frames * SDL_AUDIO_FRAMESIZE(stream->input_spec);
if (left_padding != NULL) {
if (left_padding) {
// Fill in the left padding using the history buffer
SDL_assert(padding_bytes <= history_bytes);
SDL_memcpy(left_padding, history_buffer + history_bytes - padding_bytes, padding_bytes);
@ -817,7 +833,7 @@ static Sint64 GetAudioStreamHead(SDL_AudioStream* stream, SDL_AudioSpec* out_spe
{
void* iter = SDL_BeginAudioQueueIter(stream->queue);
if (iter == NULL) {
if (!iter) {
SDL_zerop(out_spec);
*out_flushed = SDL_FALSE;
return 0;
@ -1007,9 +1023,9 @@ int SDL_GetAudioStreamData(SDL_AudioStream *stream, void *voidbuf, int len)
SDL_Log("AUDIOSTREAM: want to get %d converted bytes", len);
#endif
if (stream == NULL) {
if (!stream) {
return SDL_InvalidParamError("stream");
} else if (buf == NULL) {
} else if (!buf) {
return SDL_InvalidParamError("buf");
} else if (len < 0) {
return SDL_InvalidParamError("len");
@ -1142,7 +1158,7 @@ int SDL_GetAudioStreamQueued(SDL_AudioStream *stream)
int SDL_ClearAudioStream(SDL_AudioStream *stream)
{
if (stream == NULL) {
if (!stream) {
return SDL_InvalidParamError("stream");
}
@ -1159,16 +1175,20 @@ int SDL_ClearAudioStream(SDL_AudioStream *stream)
void SDL_DestroyAudioStream(SDL_AudioStream *stream)
{
if (stream == NULL) {
if (!stream) {
return;
}
SDL_DestroyProperties(stream->props);
OnAudioStreamDestroy(stream);
const SDL_bool simplified = stream->simplified;
if (simplified) {
SDL_assert(stream->bound_device->simplified);
SDL_CloseAudioDevice(stream->bound_device->instance_id); // this will unbind the stream.
if (stream->bound_device) {
SDL_assert(stream->bound_device->simplified);
SDL_CloseAudioDevice(stream->bound_device->instance_id); // this will unbind the stream.
}
} else {
SDL_UnbindAudioStream(stream);
}
@ -1192,13 +1212,13 @@ int SDL_ConvertAudioSamples(const SDL_AudioSpec *src_spec, const Uint8 *src_data
*dst_len = 0;
}
if (src_data == NULL) {
if (!src_data) {
return SDL_InvalidParamError("src_data");
} else if (src_len < 0) {
return SDL_InvalidParamError("src_len");
} else if (dst_data == NULL) {
} else if (!dst_data) {
return SDL_InvalidParamError("dst_data");
} else if (dst_len == NULL) {
} else if (!dst_len) {
return SDL_InvalidParamError("dst_len");
}
@ -1207,14 +1227,12 @@ int SDL_ConvertAudioSamples(const SDL_AudioSpec *src_spec, const Uint8 *src_data
int dstlen = 0;
SDL_AudioStream *stream = SDL_CreateAudioStream(src_spec, dst_spec);
if (stream != NULL) {
if (stream) {
if ((SDL_PutAudioStreamData(stream, src_data, src_len) == 0) && (SDL_FlushAudioStream(stream) == 0)) {
dstlen = SDL_GetAudioStreamAvailable(stream);
if (dstlen >= 0) {
dst = (Uint8 *)SDL_malloc(dstlen);
if (!dst) {
SDL_OutOfMemory();
} else {
if (dst) {
retval = (SDL_GetAudioStreamData(stream, dst, dstlen) >= 0) ? 0 : -1;
}
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -20,14 +20,14 @@
*/
#include "SDL_internal.h"
/* Get the name of the audio device we use for output */
// Get the name of the audio device we use for output
#if defined(SDL_AUDIO_DRIVER_NETBSD) || defined(SDL_AUDIO_DRIVER_OSS)
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h> /* For close() */
#include <unistd.h> // For close()
#include "SDL_audiodev_c.h"
@ -80,22 +80,22 @@ static void SDL_EnumUnixAudioDevices_Internal(const SDL_bool iscapture, const SD
const char *audiodev;
char audiopath[1024];
if (test == NULL) {
if (!test) {
test = test_stub;
}
/* Figure out what our audio device is */
// Figure out what our audio device is
audiodev = SDL_getenv("SDL_PATH_DSP");
if (audiodev == NULL) {
if (!audiodev) {
audiodev = SDL_getenv("AUDIODEV");
}
if (audiodev == NULL) {
if (!audiodev) {
if (classic) {
audiodev = SDL_PATH_DEV_AUDIO;
} else {
struct stat sb;
/* Added support for /dev/sound/\* in Linux 2.4 */
// Added support for /dev/sound/\* in Linux 2.4
if (((stat("/dev/sound", &sb) == 0) && S_ISDIR(sb.st_mode)) && ((stat(SDL_PATH_DEV_DSP24, &sb) == 0) && S_ISCHR(sb.st_mode))) {
audiodev = SDL_PATH_DEV_DSP24;
} else {
@ -122,4 +122,4 @@ void SDL_EnumUnixAudioDevices(const SDL_bool classic, SDL_bool (*test)(int))
SDL_EnumUnixAudioDevices_Internal(SDL_FALSE, classic, test);
}
#endif /* Audio driver selection */
#endif // Audio device selection

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -25,8 +25,8 @@
#include "SDL_internal.h"
#include "SDL_sysaudio.h"
/* Open the audio device for playback, and don't block if busy */
/* #define USE_BLOCKING_WRITES */
// Open the audio device for playback, and don't block if busy
//#define USE_BLOCKING_WRITES
#ifdef USE_BLOCKING_WRITES
#define OPEN_FLAGS_OUTPUT O_WRONLY
@ -38,4 +38,4 @@
extern void SDL_EnumUnixAudioDevices(const SDL_bool classic, SDL_bool (*test)(int));
#endif /* SDL_audiodev_c_h_ */
#endif // SDL_audiodev_c_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -92,7 +92,7 @@ static SDL_AudioChunk *CreateAudioChunk(size_t chunk_size)
{
SDL_AudioChunk *chunk = (SDL_AudioChunk *)SDL_malloc(sizeof(*chunk) + chunk_size);
if (chunk == NULL) {
if (!chunk) {
return NULL;
}
@ -146,11 +146,11 @@ static int WriteToChunkedAudioTrack(void *ctx, const Uint8 *data, size_t len)
SDL_AudioChunk *chunk = track->tail;
// Handle the first chunk
if (chunk == NULL) {
if (!chunk) {
chunk = CreateAudioTrackChunk(track);
if (chunk == NULL) {
return SDL_OutOfMemory();
if (!chunk) {
return -1;
}
SDL_assert((track->head == NULL) && (track->tail == NULL) && (track->queued_bytes == 0));
@ -180,7 +180,7 @@ static int WriteToChunkedAudioTrack(void *ctx, const Uint8 *data, size_t len)
}
// Roll back the changes if we couldn't write all the data
if (chunk == NULL) {
if (!chunk) {
chunk = track->tail;
SDL_AudioChunk *next = chunk->next;
@ -189,7 +189,7 @@ static int WriteToChunkedAudioTrack(void *ctx, const Uint8 *data, size_t len)
DestroyAudioChunks(next);
return SDL_OutOfMemory();
return -1;
}
track->tail = chunk;
@ -255,8 +255,7 @@ static SDL_AudioTrack *CreateChunkedAudioTrack(const SDL_AudioSpec *spec, size_t
{
SDL_ChunkedAudioTrack *track = (SDL_ChunkedAudioTrack *)SDL_calloc(1, sizeof(*track));
if (track == NULL) {
SDL_OutOfMemory();
if (!track) {
return NULL;
}
@ -275,8 +274,7 @@ SDL_AudioQueue *SDL_CreateAudioQueue(size_t chunk_size)
{
SDL_AudioQueue *queue = (SDL_AudioQueue *)SDL_calloc(1, sizeof(*queue));
if (queue == NULL) {
SDL_OutOfMemory();
if (!queue) {
return NULL;
}
@ -338,7 +336,7 @@ void SDL_PopAudioQueueHead(SDL_AudioQueue *queue)
queue->head = track;
if (track == NULL) {
if (!track) {
queue->tail = NULL;
}
}
@ -352,7 +350,7 @@ SDL_AudioTrack *SDL_CreateChunkedAudioTrack(const SDL_AudioSpec *spec, const Uin
{
SDL_AudioTrack *track = CreateChunkedAudioTrack(spec, chunk_size);
if (track == NULL) {
if (!track) {
return NULL;
}
@ -390,15 +388,15 @@ int SDL_WriteToAudioQueue(SDL_AudioQueue *queue, const SDL_AudioSpec *spec, cons
SDL_AudioTrack *track = queue->tail;
if ((track != NULL) && !AUDIO_SPECS_EQUAL(track->spec, *spec)) {
if ((track) && !AUDIO_SPECS_EQUAL(track->spec, *spec)) {
SDL_FlushAudioTrack(track);
}
if ((track == NULL) || (track->write == NULL)) {
if ((!track) || (!track->write)) {
SDL_AudioTrack *new_track = CreateChunkedAudioTrack(spec, queue->chunk_size);
if (new_track == NULL) {
return SDL_OutOfMemory();
if (!new_track) {
return -1;
}
if (track) {
@ -462,7 +460,7 @@ int SDL_ReadFromAudioQueue(SDL_AudioQueue *queue, Uint8 *data, size_t len)
SDL_AudioTrack *track = queue->head;
for (;;) {
if (track == NULL) {
if (!track) {
return SDL_SetError("Reading past end of queue");
}
@ -478,7 +476,7 @@ int SDL_ReadFromAudioQueue(SDL_AudioQueue *queue, Uint8 *data, size_t len)
SDL_AudioTrack *next = track->next;
if (next == NULL) {
if (!next) {
return SDL_SetError("Reading past end of incomplete track");
}
@ -495,7 +493,7 @@ int SDL_PeekIntoAudioQueue(SDL_AudioQueue *queue, Uint8 *data, size_t len)
SDL_AudioTrack *track = queue->head;
for (;;) {
if (track == NULL) {
if (!track) {
return SDL_SetError("Peeking past end of queue");
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -23,13 +23,13 @@
#include "SDL_sysaudio.h"
#include "SDL_audioresample.h"
/* SDL's resampler uses a "bandlimited interpolation" algorithm:
https://ccrma.stanford.edu/~jos/resample/ */
// SDL's resampler uses a "bandlimited interpolation" algorithm:
// https://ccrma.stanford.edu/~jos/resample/
#include "SDL_audio_resampler_filter.h"
/* For a given srcpos, `srcpos + frame` are sampled, where `-RESAMPLER_ZERO_CROSSINGS < frame <= RESAMPLER_ZERO_CROSSINGS`.
* Note, when upsampling, it is also possible to start sampling from `srcpos = -1`. */
// For a given srcpos, `srcpos + frame` are sampled, where `-RESAMPLER_ZERO_CROSSINGS < frame <= RESAMPLER_ZERO_CROSSINGS`.
// Note, when upsampling, it is also possible to start sampling from `srcpos = -1`.
#define RESAMPLER_MAX_PADDING_FRAMES (RESAMPLER_ZERO_CROSSINGS + 1)
#define RESAMPLER_FILTER_INTERP_BITS (32 - RESAMPLER_BITS_PER_ZERO_CROSSING)

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -26,7 +26,7 @@
// Internal functions used by SDL_AudioStream for resampling audio.
// The resampler uses 32:32 fixed-point arithmetic to track its position.
Sint64 SDL_GetResampleRate(const int src_rate, const int dst_rate);
Sint64 SDL_GetResampleRate(int src_rate, int dst_rate);
int SDL_GetResamplerHistoryFrames(void);
int SDL_GetResamplerPaddingFrames(Sint64 resample_rate);

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -20,30 +20,33 @@
*/
#include "SDL_internal.h"
#include "SDL_audio_c.h"
#include "SDL_sysaudio.h"
// TODO: NEON is disabled until https://github.com/libsdl-org/SDL/issues/8352 can be fixed
#undef SDL_NEON_INTRINSICS
#ifndef SDL_CPUINFO_DISABLED
#if defined(__x86_64__) && defined(SDL_SSE2_INTRINSICS)
#define NEED_SCALAR_CONVERTER_FALLBACKS 0 /* x86_64 guarantees SSE2. */
#define NEED_SCALAR_CONVERTER_FALLBACKS 0 // x86_64 guarantees SSE2.
#elif defined(__MACOS__) && defined(SDL_SSE2_INTRINSICS)
#define NEED_SCALAR_CONVERTER_FALLBACKS 0 /* macOS/Intel guarantees SSE2. */
#define NEED_SCALAR_CONVERTER_FALLBACKS 0 // macOS/Intel guarantees SSE2.
#elif defined(__ARM_ARCH) && (__ARM_ARCH >= 8) && defined(SDL_NEON_INTRINSICS)
#define NEED_SCALAR_CONVERTER_FALLBACKS 0 /* ARMv8+ promise NEON. */
#define NEED_SCALAR_CONVERTER_FALLBACKS 0 // ARMv8+ promise NEON.
#elif defined(__APPLE__) && defined(__ARM_ARCH) && (__ARM_ARCH >= 7) && defined(SDL_NEON_INTRINSICS)
#define NEED_SCALAR_CONVERTER_FALLBACKS 0 /* All Apple ARMv7 chips promise NEON support. */
#define NEED_SCALAR_CONVERTER_FALLBACKS 0 // All Apple ARMv7 chips promise NEON support.
#endif
#endif
/* Set to zero if platform is guaranteed to use a SIMD codepath here. */
// Set to zero if platform is guaranteed to use a SIMD codepath here.
#if !defined(NEED_SCALAR_CONVERTER_FALLBACKS) || defined(SDL_CPUINFO_DISABLED)
#define NEED_SCALAR_CONVERTER_FALLBACKS 1
#endif
#define DIVBY2147483648 0.0000000004656612873077392578125f /* 0x1p-31f */
#define DIVBY2147483648 0.0000000004656612873077392578125f // 0x1p-31f
#if NEED_SCALAR_CONVERTER_FALLBACKS
/* This code requires that floats are in the IEEE-754 binary32 format */
// This code requires that floats are in the IEEE-754 binary32 format
SDL_COMPILE_TIME_ASSERT(float_bits, sizeof(float) == sizeof(Uint32));
union float_bits {
@ -107,7 +110,7 @@ static void SDL_Convert_S32_to_F32_Scalar(float *dst, const Sint32 *src, int num
}
}
/* Create a bit-mask based on the sign-bit. Should optimize to a single arithmetic-shift-right */
// Create a bit-mask based on the sign-bit. Should optimize to a single arithmetic-shift-right
#define SIGNMASK(x) (Uint32)(0u - ((Uint32)(x) >> 31))
static void SDL_Convert_F32_to_S8_Scalar(Sint8 *dst, const float *src, int num_samples)
@ -198,7 +201,7 @@ static void SDL_Convert_F32_to_S32_Scalar(Sint32 *dst, const float *src, int num
#undef SIGNMASK
#endif /* NEED_SCALAR_CONVERTER_FALLBACKS */
#endif // NEED_SCALAR_CONVERTER_FALLBACKS
#ifdef SDL_SSE2_INTRINSICS
static void SDL_TARGETING("sse2") SDL_Convert_S8_to_F32_SSE2(float *dst, const Sint8 *src, int num_samples)
@ -320,7 +323,7 @@ static void SDL_TARGETING("sse2") SDL_Convert_S32_to_F32_SSE2(float *dst, const
{
int i = num_samples;
/* dst[i] = f32(src[i]) / f32(0x80000000) */
// dst[i] = f32(src[i]) / f32(0x80000000)
const __m128 scaler = _mm_set1_ps(DIVBY2147483648);
LOG_DEBUG_AUDIO_CONVERT("S32", "F32 (using SSE2)");
@ -539,9 +542,9 @@ static void SDL_TARGETING("sse2") SDL_Convert_F32_to_S32_SSE2(Sint32 *dst, const
#endif
#ifdef SDL_NEON_INTRINSICS
#define DIVBY128 0.0078125f /* 0x1p-7f */
#define DIVBY32768 0.000030517578125f /* 0x1p-15f */
#define DIVBY8388607 0.00000011920930376163766f /* 0x1.000002p-23f */
#define DIVBY128 0.0078125f // 0x1p-7f
#define DIVBY32768 0.000030517578125f // 0x1p-15f
#define DIVBY8388607 0.00000011920930376163766f // 0x1.000002p-23f
static void SDL_Convert_S8_to_F32_NEON(float *dst, const Sint8 *src, int num_samples)
{
@ -552,25 +555,25 @@ static void SDL_Convert_S8_to_F32_NEON(float *dst, const Sint8 *src, int num_sam
src += num_samples - 1;
dst += num_samples - 1;
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
// Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src)
for (i = num_samples; i && (((size_t)(dst - 15)) & 15); --i, --src, --dst) {
*dst = ((float)*src) * DIVBY128;
}
src -= 15;
dst -= 15; /* adjust to read NEON blocks from the start. */
dst -= 15; // adjust to read NEON blocks from the start.
SDL_assert(!i || !(((size_t)dst) & 15));
/* Make sure src is aligned too. */
// Make sure src is aligned too.
if (!(((size_t)src) & 15)) {
/* Aligned! Do NEON blocks as long as we have 16 bytes available. */
// Aligned! Do NEON blocks as long as we have 16 bytes available.
const int8_t *mmsrc = (const int8_t *)src;
const float32x4_t divby128 = vdupq_n_f32(DIVBY128);
while (i >= 16) { /* 16 * 8-bit */
const int8x16_t bytes = vld1q_s8(mmsrc); /* get 16 sint8 into a NEON register. */
const int16x8_t int16hi = vmovl_s8(vget_high_s8(bytes)); /* convert top 8 bytes to 8 int16 */
const int16x8_t int16lo = vmovl_s8(vget_low_s8(bytes)); /* convert bottom 8 bytes to 8 int16 */
/* split int16 to two int32, then convert to float, then multiply to normalize, store. */
while (i >= 16) { // 16 * 8-bit
const int8x16_t bytes = vld1q_s8(mmsrc); // get 16 sint8 into a NEON register.
const int16x8_t int16hi = vmovl_s8(vget_high_s8(bytes)); // convert top 8 bytes to 8 int16
const int16x8_t int16lo = vmovl_s8(vget_low_s8(bytes)); // convert bottom 8 bytes to 8 int16
// split int16 to two int32, then convert to float, then multiply to normalize, store.
vst1q_f32(dst, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(int16lo))), divby128));
vst1q_f32(dst + 4, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(int16lo))), divby128));
vst1q_f32(dst + 8, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(int16hi))), divby128));
@ -584,9 +587,9 @@ static void SDL_Convert_S8_to_F32_NEON(float *dst, const Sint8 *src, int num_sam
}
src += 15;
dst += 15; /* adjust for any scalar finishing. */
dst += 15; // adjust for any scalar finishing.
/* Finish off any leftovers with scalar operations. */
// Finish off any leftovers with scalar operations.
while (i) {
*dst = ((float)*src) * DIVBY128;
i--;
@ -604,26 +607,26 @@ static void SDL_Convert_U8_to_F32_NEON(float *dst, const Uint8 *src, int num_sam
src += num_samples - 1;
dst += num_samples - 1;
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
// Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src)
for (i = num_samples; i && (((size_t)(dst - 15)) & 15); --i, --src, --dst) {
*dst = (((float)*src) * DIVBY128) - 1.0f;
}
src -= 15;
dst -= 15; /* adjust to read NEON blocks from the start. */
dst -= 15; // adjust to read NEON blocks from the start.
SDL_assert(!i || !(((size_t)dst) & 15));
/* Make sure src is aligned too. */
// Make sure src is aligned too.
if (!(((size_t)src) & 15)) {
/* Aligned! Do NEON blocks as long as we have 16 bytes available. */
// Aligned! Do NEON blocks as long as we have 16 bytes available.
const uint8_t *mmsrc = (const uint8_t *)src;
const float32x4_t divby128 = vdupq_n_f32(DIVBY128);
const float32x4_t negone = vdupq_n_f32(-1.0f);
while (i >= 16) { /* 16 * 8-bit */
const uint8x16_t bytes = vld1q_u8(mmsrc); /* get 16 uint8 into a NEON register. */
const uint16x8_t uint16hi = vmovl_u8(vget_high_u8(bytes)); /* convert top 8 bytes to 8 uint16 */
const uint16x8_t uint16lo = vmovl_u8(vget_low_u8(bytes)); /* convert bottom 8 bytes to 8 uint16 */
/* split uint16 to two uint32, then convert to float, then multiply to normalize, subtract to adjust for sign, store. */
while (i >= 16) { // 16 * 8-bit
const uint8x16_t bytes = vld1q_u8(mmsrc); // get 16 uint8 into a NEON register.
const uint16x8_t uint16hi = vmovl_u8(vget_high_u8(bytes)); // convert top 8 bytes to 8 uint16
const uint16x8_t uint16lo = vmovl_u8(vget_low_u8(bytes)); // convert bottom 8 bytes to 8 uint16
// split uint16 to two uint32, then convert to float, then multiply to normalize, subtract to adjust for sign, store.
vst1q_f32(dst, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16lo))), divby128));
vst1q_f32(dst + 4, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16lo))), divby128));
vst1q_f32(dst + 8, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16hi))), divby128));
@ -637,9 +640,9 @@ static void SDL_Convert_U8_to_F32_NEON(float *dst, const Uint8 *src, int num_sam
}
src += 15;
dst += 15; /* adjust for any scalar finishing. */
dst += 15; // adjust for any scalar finishing.
/* Finish off any leftovers with scalar operations. */
// Finish off any leftovers with scalar operations.
while (i) {
*dst = (((float)*src) * DIVBY128) - 1.0f;
i--;
@ -657,22 +660,22 @@ static void SDL_Convert_S16_to_F32_NEON(float *dst, const Sint16 *src, int num_s
src += num_samples - 1;
dst += num_samples - 1;
/* Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src) */
// Get dst aligned to 16 bytes (since buffer is growing, we don't have to worry about overreading from src)
for (i = num_samples; i && (((size_t)(dst - 7)) & 15); --i, --src, --dst) {
*dst = ((float)*src) * DIVBY32768;
}
src -= 7;
dst -= 7; /* adjust to read NEON blocks from the start. */
dst -= 7; // adjust to read NEON blocks from the start.
SDL_assert(!i || !(((size_t)dst) & 15));
/* Make sure src is aligned too. */
// Make sure src is aligned too.
if (!(((size_t)src) & 15)) {
/* Aligned! Do NEON blocks as long as we have 16 bytes available. */
// Aligned! Do NEON blocks as long as we have 16 bytes available.
const float32x4_t divby32768 = vdupq_n_f32(DIVBY32768);
while (i >= 8) { /* 8 * 16-bit */
const int16x8_t ints = vld1q_s16((int16_t const *)src); /* get 8 sint16 into a NEON register. */
/* split int16 to two int32, then convert to float, then multiply to normalize, store. */
while (i >= 8) { // 8 * 16-bit
const int16x8_t ints = vld1q_s16((int16_t const *)src); // get 8 sint16 into a NEON register.
// split int16 to two int32, then convert to float, then multiply to normalize, store.
vst1q_f32(dst, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(ints))), divby32768));
vst1q_f32(dst + 4, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(ints))), divby32768));
i -= 8;
@ -682,9 +685,9 @@ static void SDL_Convert_S16_to_F32_NEON(float *dst, const Sint16 *src, int num_s
}
src += 7;
dst += 7; /* adjust for any scalar finishing. */
dst += 7; // adjust for any scalar finishing.
/* Finish off any leftovers with scalar operations. */
// Finish off any leftovers with scalar operations.
while (i) {
*dst = ((float)*src) * DIVBY32768;
i--;
@ -699,20 +702,20 @@ static void SDL_Convert_S32_to_F32_NEON(float *dst, const Sint32 *src, int num_s
LOG_DEBUG_AUDIO_CONVERT("S32", "F32 (using NEON)");
/* Get dst aligned to 16 bytes */
// Get dst aligned to 16 bytes
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
*dst = ((float)(*src >> 8)) * DIVBY8388607;
}
SDL_assert(!i || !(((size_t)dst) & 15));
/* Make sure src is aligned too. */
// Make sure src is aligned too.
if (!(((size_t)src) & 15)) {
/* Aligned! Do NEON blocks as long as we have 16 bytes available. */
// Aligned! Do NEON blocks as long as we have 16 bytes available.
const float32x4_t divby8388607 = vdupq_n_f32(DIVBY8388607);
const int32_t *mmsrc = (const int32_t *)src;
while (i >= 4) { /* 4 * sint32 */
/* shift out lowest bits so int fits in a float32. Small precision loss, but much faster. */
while (i >= 4) { // 4 * sint32
// shift out lowest bits so int fits in a float32. Small precision loss, but much faster.
vst1q_f32(dst, vmulq_f32(vcvtq_f32_s32(vshrq_n_s32(vld1q_s32(mmsrc), 8)), divby8388607));
i -= 4;
mmsrc += 4;
@ -721,7 +724,7 @@ static void SDL_Convert_S32_to_F32_NEON(float *dst, const Sint32 *src, int num_s
src = (const Sint32 *)mmsrc;
}
/* Finish off any leftovers with scalar operations. */
// Finish off any leftovers with scalar operations.
while (i) {
*dst = ((float)(*src >> 8)) * DIVBY8388607;
i--;
@ -736,7 +739,7 @@ static void SDL_Convert_F32_to_S8_NEON(Sint8 *dst, const float *src, int num_sam
LOG_DEBUG_AUDIO_CONVERT("F32", "S8 (using NEON)");
/* Get dst aligned to 16 bytes */
// Get dst aligned to 16 bytes
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
const float sample = *src;
if (sample >= 1.0f) {
@ -750,21 +753,21 @@ static void SDL_Convert_F32_to_S8_NEON(Sint8 *dst, const float *src, int num_sam
SDL_assert(!i || !(((size_t)dst) & 15));
/* Make sure src is aligned too. */
// Make sure src is aligned too.
if (!(((size_t)src) & 15)) {
/* Aligned! Do NEON blocks as long as we have 16 bytes available. */
// Aligned! Do NEON blocks as long as we have 16 bytes available.
const float32x4_t one = vdupq_n_f32(1.0f);
const float32x4_t negone = vdupq_n_f32(-1.0f);
const float32x4_t mulby127 = vdupq_n_f32(127.0f);
int8_t *mmdst = (int8_t *)dst;
while (i >= 16) { /* 16 * float32 */
const int32x4_t ints1 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src)), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
const int32x4_t ints2 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src + 4)), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
const int32x4_t ints3 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src + 8)), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
const int32x4_t ints4 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src + 12)), one), mulby127)); /* load 4 floats, clamp, convert to sint32 */
const int8x8_t i8lo = vmovn_s16(vcombine_s16(vmovn_s32(ints1), vmovn_s32(ints2))); /* narrow to sint16, combine, narrow to sint8 */
const int8x8_t i8hi = vmovn_s16(vcombine_s16(vmovn_s32(ints3), vmovn_s32(ints4))); /* narrow to sint16, combine, narrow to sint8 */
vst1q_s8(mmdst, vcombine_s8(i8lo, i8hi)); /* combine to int8x16_t, store out */
while (i >= 16) { // 16 * float32
const int32x4_t ints1 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src)), one), mulby127)); // load 4 floats, clamp, convert to sint32
const int32x4_t ints2 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src + 4)), one), mulby127)); // load 4 floats, clamp, convert to sint32
const int32x4_t ints3 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src + 8)), one), mulby127)); // load 4 floats, clamp, convert to sint32
const int32x4_t ints4 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src + 12)), one), mulby127)); // load 4 floats, clamp, convert to sint32
const int8x8_t i8lo = vmovn_s16(vcombine_s16(vmovn_s32(ints1), vmovn_s32(ints2))); // narrow to sint16, combine, narrow to sint8
const int8x8_t i8hi = vmovn_s16(vcombine_s16(vmovn_s32(ints3), vmovn_s32(ints4))); // narrow to sint16, combine, narrow to sint8
vst1q_s8(mmdst, vcombine_s8(i8lo, i8hi)); // combine to int8x16_t, store out
i -= 16;
src += 16;
mmdst += 16;
@ -772,7 +775,7 @@ static void SDL_Convert_F32_to_S8_NEON(Sint8 *dst, const float *src, int num_sam
dst = (Sint8 *)mmdst;
}
/* Finish off any leftovers with scalar operations. */
// Finish off any leftovers with scalar operations.
while (i) {
const float sample = *src;
if (sample >= 1.0f) {
@ -794,7 +797,7 @@ static void SDL_Convert_F32_to_U8_NEON(Uint8 *dst, const float *src, int num_sam
LOG_DEBUG_AUDIO_CONVERT("F32", "U8 (using NEON)");
/* Get dst aligned to 16 bytes */
// Get dst aligned to 16 bytes
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
const float sample = *src;
if (sample >= 1.0f) {
@ -808,21 +811,21 @@ static void SDL_Convert_F32_to_U8_NEON(Uint8 *dst, const float *src, int num_sam
SDL_assert(!i || !(((size_t)dst) & 15));
/* Make sure src is aligned too. */
// Make sure src is aligned too.
if (!(((size_t)src) & 15)) {
/* Aligned! Do NEON blocks as long as we have 16 bytes available. */
// Aligned! Do NEON blocks as long as we have 16 bytes available.
const float32x4_t one = vdupq_n_f32(1.0f);
const float32x4_t negone = vdupq_n_f32(-1.0f);
const float32x4_t mulby127 = vdupq_n_f32(127.0f);
uint8_t *mmdst = (uint8_t *)dst;
while (i >= 16) { /* 16 * float32 */
const uint32x4_t uints1 = vcvtq_u32_f32(vmulq_f32(vaddq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src)), one), one), mulby127)); /* load 4 floats, clamp, convert to uint32 */
const uint32x4_t uints2 = vcvtq_u32_f32(vmulq_f32(vaddq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src + 4)), one), one), mulby127)); /* load 4 floats, clamp, convert to uint32 */
const uint32x4_t uints3 = vcvtq_u32_f32(vmulq_f32(vaddq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src + 8)), one), one), mulby127)); /* load 4 floats, clamp, convert to uint32 */
const uint32x4_t uints4 = vcvtq_u32_f32(vmulq_f32(vaddq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src + 12)), one), one), mulby127)); /* load 4 floats, clamp, convert to uint32 */
const uint8x8_t ui8lo = vmovn_u16(vcombine_u16(vmovn_u32(uints1), vmovn_u32(uints2))); /* narrow to uint16, combine, narrow to uint8 */
const uint8x8_t ui8hi = vmovn_u16(vcombine_u16(vmovn_u32(uints3), vmovn_u32(uints4))); /* narrow to uint16, combine, narrow to uint8 */
vst1q_u8(mmdst, vcombine_u8(ui8lo, ui8hi)); /* combine to uint8x16_t, store out */
while (i >= 16) { // 16 * float32
const uint32x4_t uints1 = vcvtq_u32_f32(vmulq_f32(vaddq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src)), one), one), mulby127)); // load 4 floats, clamp, convert to uint32
const uint32x4_t uints2 = vcvtq_u32_f32(vmulq_f32(vaddq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src + 4)), one), one), mulby127)); // load 4 floats, clamp, convert to uint32
const uint32x4_t uints3 = vcvtq_u32_f32(vmulq_f32(vaddq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src + 8)), one), one), mulby127)); // load 4 floats, clamp, convert to uint32
const uint32x4_t uints4 = vcvtq_u32_f32(vmulq_f32(vaddq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src + 12)), one), one), mulby127)); // load 4 floats, clamp, convert to uint32
const uint8x8_t ui8lo = vmovn_u16(vcombine_u16(vmovn_u32(uints1), vmovn_u32(uints2))); // narrow to uint16, combine, narrow to uint8
const uint8x8_t ui8hi = vmovn_u16(vcombine_u16(vmovn_u32(uints3), vmovn_u32(uints4))); // narrow to uint16, combine, narrow to uint8
vst1q_u8(mmdst, vcombine_u8(ui8lo, ui8hi)); // combine to uint8x16_t, store out
i -= 16;
src += 16;
mmdst += 16;
@ -831,7 +834,7 @@ static void SDL_Convert_F32_to_U8_NEON(Uint8 *dst, const float *src, int num_sam
dst = (Uint8 *)mmdst;
}
/* Finish off any leftovers with scalar operations. */
// Finish off any leftovers with scalar operations.
while (i) {
const float sample = *src;
if (sample >= 1.0f) {
@ -853,7 +856,7 @@ static void SDL_Convert_F32_to_S16_NEON(Sint16 *dst, const float *src, int num_s
LOG_DEBUG_AUDIO_CONVERT("F32", "S16 (using NEON)");
/* Get dst aligned to 16 bytes */
// Get dst aligned to 16 bytes
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
const float sample = *src;
if (sample >= 1.0f) {
@ -867,17 +870,17 @@ static void SDL_Convert_F32_to_S16_NEON(Sint16 *dst, const float *src, int num_s
SDL_assert(!i || !(((size_t)dst) & 15));
/* Make sure src is aligned too. */
// Make sure src is aligned too.
if (!(((size_t)src) & 15)) {
/* Aligned! Do NEON blocks as long as we have 16 bytes available. */
// Aligned! Do NEON blocks as long as we have 16 bytes available.
const float32x4_t one = vdupq_n_f32(1.0f);
const float32x4_t negone = vdupq_n_f32(-1.0f);
const float32x4_t mulby32767 = vdupq_n_f32(32767.0f);
int16_t *mmdst = (int16_t *)dst;
while (i >= 8) { /* 8 * float32 */
const int32x4_t ints1 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src)), one), mulby32767)); /* load 4 floats, clamp, convert to sint32 */
const int32x4_t ints2 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src + 4)), one), mulby32767)); /* load 4 floats, clamp, convert to sint32 */
vst1q_s16(mmdst, vcombine_s16(vmovn_s32(ints1), vmovn_s32(ints2))); /* narrow to sint16, combine, store out. */
while (i >= 8) { // 8 * float32
const int32x4_t ints1 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src)), one), mulby32767)); // load 4 floats, clamp, convert to sint32
const int32x4_t ints2 = vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src + 4)), one), mulby32767)); // load 4 floats, clamp, convert to sint32
vst1q_s16(mmdst, vcombine_s16(vmovn_s32(ints1), vmovn_s32(ints2))); // narrow to sint16, combine, store out.
i -= 8;
src += 8;
mmdst += 8;
@ -885,7 +888,7 @@ static void SDL_Convert_F32_to_S16_NEON(Sint16 *dst, const float *src, int num_s
dst = (Sint16 *)mmdst;
}
/* Finish off any leftovers with scalar operations. */
// Finish off any leftovers with scalar operations.
while (i) {
const float sample = *src;
if (sample >= 1.0f) {
@ -907,7 +910,7 @@ static void SDL_Convert_F32_to_S32_NEON(Sint32 *dst, const float *src, int num_s
LOG_DEBUG_AUDIO_CONVERT("F32", "S32 (using NEON)");
/* Get dst aligned to 16 bytes */
// Get dst aligned to 16 bytes
for (i = num_samples; i && (((size_t)dst) & 15); --i, ++src, ++dst) {
const float sample = *src;
if (sample >= 1.0f) {
@ -923,12 +926,12 @@ static void SDL_Convert_F32_to_S32_NEON(Sint32 *dst, const float *src, int num_s
SDL_assert(!i || !(((size_t)src) & 15));
{
/* Aligned! Do NEON blocks as long as we have 16 bytes available. */
// Aligned! Do NEON blocks as long as we have 16 bytes available.
const float32x4_t one = vdupq_n_f32(1.0f);
const float32x4_t negone = vdupq_n_f32(-1.0f);
const float32x4_t mulby8388607 = vdupq_n_f32(8388607.0f);
int32_t *mmdst = (int32_t *)dst;
while (i >= 4) { /* 4 * float32 */
while (i >= 4) { // 4 * float32
vst1q_s32(mmdst, vshlq_n_s32(vcvtq_s32_f32(vmulq_f32(vminq_f32(vmaxq_f32(negone, vld1q_f32(src)), one), mulby8388607)), 8));
i -= 4;
src += 4;
@ -937,7 +940,7 @@ static void SDL_Convert_F32_to_S32_NEON(Sint32 *dst, const float *src, int num_s
dst = (Sint32 *)mmdst;
}
/* Finish off any leftovers with scalar operations. */
// Finish off any leftovers with scalar operations.
while (i) {
const float sample = *src;
if (sample >= 1.0f) {
@ -954,7 +957,7 @@ static void SDL_Convert_F32_to_S32_NEON(Sint32 *dst, const float *src, int num_s
}
#endif
/* Function pointers set to a CPU-specific implementation. */
// Function pointers set to a CPU-specific implementation.
void (*SDL_Convert_S8_to_F32)(float *dst, const Sint8 *src, int num_samples) = NULL;
void (*SDL_Convert_U8_to_F32)(float *dst, const Uint8 *src, int num_samples) = NULL;
void (*SDL_Convert_S16_to_F32)(float *dst, const Sint16 *src, int num_samples) = NULL;

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -20,7 +20,7 @@
*/
#include "SDL_internal.h"
/* This provides the default mixing callback for the SDL audio routines */
// This provides the default mixing callback for the SDL audio routines
#include "SDL_sysaudio.h"
@ -77,12 +77,12 @@ static const Uint8 mix8[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
/* The volume ranges from 0 - 128 */
// The volume ranges from 0 - 128
#define ADJUST_VOLUME(type, s, v) ((s) = (type)(((s) * (v)) / SDL_MIX_MAXVOLUME))
#define ADJUST_VOLUME_U8(s, v) ((s) = (Uint8)(((((s) - 128) * (v)) / SDL_MIX_MAXVOLUME) + 128))
/* !!! FIXME: this needs some SIMD magic. */
// !!! FIXME: this needs some SIMD magic.
int SDL_MixAudioFormat(Uint8 *dst, const Uint8 *src, SDL_AudioFormat format,
Uint32 len, int volume)
@ -237,7 +237,7 @@ int SDL_MixAudioFormat(Uint8 *dst, const Uint8 *src, SDL_AudioFormat format,
float *dst32 = (float *)dst;
float src1, src2;
double dst_sample;
/* !!! FIXME: are these right? */
// !!! FIXME: are these right?
const double max_audioval = 3.402823466e+38F;
const double min_audioval = -3.402823466e+38F;
@ -265,7 +265,7 @@ int SDL_MixAudioFormat(Uint8 *dst, const Uint8 *src, SDL_AudioFormat format,
float *dst32 = (float *)dst;
float src1, src2;
double dst_sample;
/* !!! FIXME: are these right? */
// !!! FIXME: are these right?
const double max_audioval = 3.402823466e+38F;
const double min_audioval = -3.402823466e+38F;
@ -285,7 +285,7 @@ int SDL_MixAudioFormat(Uint8 *dst, const Uint8 *src, SDL_AudioFormat format,
}
} break;
default: /* If this happens... FIXME! */
default: // If this happens... FIXME!
return SDL_SetError("SDL_MixAudioFormat(): unknown audio format");
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -24,6 +24,8 @@
#ifndef SDL_sysaudio_h_
#define SDL_sysaudio_h_
#include "../SDL_hashtable.h"
#define DEBUG_AUDIOSTREAM 0
#define DEBUG_AUDIO_CONVERT 0
@ -104,6 +106,9 @@ extern void SDL_UpdatedAudioDeviceFormat(SDL_AudioDevice *device);
// Backends can call this to get a standardized name for a thread to power a specific audio device.
extern char *SDL_GetAudioThreadName(SDL_AudioDevice *device, char *buf, size_t buflen);
// Backends can call these to change a device's refcount.
extern void RefPhysicalAudioDevice(SDL_AudioDevice *device);
extern void UnrefPhysicalAudioDevice(SDL_AudioDevice *device);
// These functions are the heart of the audio threads. Backends can call them directly if they aren't using the SDL-provided thread.
extern void SDL_OutputAudioThreadSetup(SDL_AudioDevice *device);
@ -128,38 +133,48 @@ typedef struct SDL_AudioDriverImpl
int (*OpenDevice)(SDL_AudioDevice *device);
void (*ThreadInit)(SDL_AudioDevice *device); // Called by audio thread at start
void (*ThreadDeinit)(SDL_AudioDevice *device); // Called by audio thread at end
void (*WaitDevice)(SDL_AudioDevice *device);
int (*WaitDevice)(SDL_AudioDevice *device);
int (*PlayDevice)(SDL_AudioDevice *device, const Uint8 *buffer, int buflen); // buffer and buflen are always from GetDeviceBuf, passed here for convenience.
Uint8 *(*GetDeviceBuf)(SDL_AudioDevice *device, int *buffer_size);
void (*WaitCaptureDevice)(SDL_AudioDevice *device);
int (*WaitCaptureDevice)(SDL_AudioDevice *device);
int (*CaptureFromDevice)(SDL_AudioDevice *device, void *buffer, int buflen);
void (*FlushCapture)(SDL_AudioDevice *device);
void (*CloseDevice)(SDL_AudioDevice *device);
void (*FreeDeviceHandle)(SDL_AudioDevice *device); // SDL is done with this device; free the handle from SDL_AddAudioDevice()
void (*DeinitializeStart)(void); // SDL calls this, then starts destroying objects, then calls Deinitialize. This is a good place to stop hotplug detection.
void (*Deinitialize)(void);
// Some flags to push duplicate code into the core and reduce #ifdefs.
SDL_bool ProvidesOwnCallbackThread; // !!! FIXME: rename this, it's not a callback thread anymore.
SDL_bool HasCaptureSupport;
SDL_bool OnlyHasDefaultOutputDevice;
SDL_bool OnlyHasDefaultCaptureDevice;
SDL_bool AllowsArbitraryDeviceNames;
SDL_bool OnlyHasDefaultCaptureDevice; // !!! FIXME: is there ever a time where you'd have a default output and not a default capture (or vice versa)?
} SDL_AudioDriverImpl;
typedef struct SDL_PendingAudioDeviceEvent
{
Uint32 type;
SDL_AudioDeviceID devid;
struct SDL_PendingAudioDeviceEvent *next;
} SDL_PendingAudioDeviceEvent;
typedef struct SDL_AudioDriver
{
const char *name; // The name of this audio driver
const char *desc; // The description of this audio driver
SDL_AudioDriverImpl impl; // the backend's interface
SDL_RWLock *device_list_lock; // A mutex for device detection
SDL_AudioDevice *output_devices; // the list of currently-available audio output devices.
SDL_AudioDevice *capture_devices; // the list of currently-available audio capture devices.
SDL_RWLock *device_hash_lock; // A rwlock that protects `device_hash`
SDL_HashTable *device_hash; // the collection of currently-available audio devices (capture, playback, logical and physical!)
SDL_AudioStream *existing_streams; // a list of all existing SDL_AudioStreams.
SDL_AudioDeviceID default_output_device_id;
SDL_AudioDeviceID default_capture_device_id;
SDL_PendingAudioDeviceEvent pending_events;
SDL_PendingAudioDeviceEvent *pending_events_tail;
// !!! FIXME: most (all?) of these don't have to be atomic.
SDL_AtomicInt output_device_count;
SDL_AtomicInt capture_device_count;
SDL_AtomicInt last_device_instance_id; // increments on each device add to provide unique instance IDs
SDL_AtomicInt shutting_down; // non-zero during SDL_Quit, so we known not to accept any last-minute device hotplugs.
} SDL_AudioDriver;
@ -169,6 +184,8 @@ struct SDL_AudioStream
{
SDL_Mutex* lock;
SDL_PropertiesID props;
SDL_AudioStreamCallback get_callback;
void *get_callback_userdata;
SDL_AudioStreamCallback put_callback;
@ -240,6 +257,20 @@ struct SDL_AudioDevice
// A mutex for locking access to this struct
SDL_Mutex *lock;
// A condition variable to protect device close, where we can't hold the device lock forever.
SDL_Condition *close_cond;
// Reference count of the device; logical devices, device threads, etc, add to this.
SDL_AtomicInt refcount;
// These are, initially, set from current_audio, but we might swap them out with Zombie versions on disconnect/failure.
int (*WaitDevice)(SDL_AudioDevice *device);
int (*PlayDevice)(SDL_AudioDevice *device, const Uint8 *buffer, int buflen);
Uint8 *(*GetDeviceBuf)(SDL_AudioDevice *device, int *buffer_size);
int (*WaitCaptureDevice)(SDL_AudioDevice *device);
int (*CaptureFromDevice)(SDL_AudioDevice *device, void *buffer, int buflen);
void (*FlushCapture)(SDL_AudioDevice *device);
// human-readable name of the device. ("SoundBlaster Pro 16")
char *name;
@ -265,15 +296,9 @@ struct SDL_AudioDevice
// non-zero if we are signaling the audio thread to end.
SDL_AtomicInt shutdown;
// non-zero if we want the device to be destroyed (so audio thread knows to do it on termination).
SDL_AtomicInt condemned;
// non-zero if this was a disconnected default device and we're waiting for its replacement.
// non-zero if this was a disconnected device and we're waiting for it to be decommissioned.
SDL_AtomicInt zombie;
// non-zero if this has a thread running (which might be `thread` or something provided by the backend!)
SDL_AtomicInt thread_alive;
// SDL_TRUE if this is a capture device instead of an output device
SDL_bool iscapture;
@ -299,10 +324,6 @@ struct SDL_AudioDevice
// All logical devices associated with this physical device.
SDL_LogicalAudioDevice *logical_devices;
// double-linked list of all physical devices.
struct SDL_AudioDevice *prev;
struct SDL_AudioDevice *next;
};
typedef struct AudioBootStrap
@ -329,7 +350,7 @@ extern AudioBootStrap COREAUDIO_bootstrap;
extern AudioBootStrap DISKAUDIO_bootstrap;
extern AudioBootStrap DUMMYAUDIO_bootstrap;
extern AudioBootStrap AAUDIO_bootstrap;
extern AudioBootStrap openslES_bootstrap; // !!! FIXME: capitalize this to match the others
extern AudioBootStrap OPENSLES_bootstrap;
extern AudioBootStrap ANDROIDAUDIO_bootstrap;
extern AudioBootStrap PS2AUDIO_bootstrap;
extern AudioBootStrap PSPAUDIO_bootstrap;

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -34,7 +34,7 @@
/* Microsoft WAVE file loading routines */
#include "SDL_wave.h"
#include "SDL_audio_c.h"
#include "SDL_sysaudio.h"
/* Reads the value stored at the location of the f1 pointer, multiplies it
* with the second argument and then stores the result to f1.
@ -262,7 +262,7 @@ static void WaveDebugDumpFormat(WaveFile *file, Uint32 rifflen, Uint32 fmtlen, U
int res;
dumpstr = SDL_malloc(bufsize);
if (dumpstr == NULL) {
if (!dumpstr) {
return;
}
dumpstr[0] = 0;
@ -439,8 +439,8 @@ static int MS_ADPCM_Init(WaveFile *file, size_t datalength)
coeffdata = (MS_ADPCM_CoeffData *)SDL_malloc(sizeof(MS_ADPCM_CoeffData) + coeffcount * 4);
file->decoderdata = coeffdata; /* Freed in cleanup. */
if (coeffdata == NULL) {
return SDL_OutOfMemory();
if (!coeffdata) {
return -1;
}
coeffdata->coeff = &coeffdata->aligndummy;
coeffdata->coeffcount = (Uint16)coeffcount;
@ -674,7 +674,7 @@ static int MS_ADPCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
/* The output size in bytes. May get modified if data is truncated. */
outputsize = (size_t)state.framestotal;
if (SafeMult(&outputsize, state.framesize)) {
return SDL_OutOfMemory();
return SDL_SetError("WAVE file too big");
} else if (outputsize > SDL_MAX_UINT32 || state.framestotal > SIZE_MAX) {
return SDL_SetError("WAVE file too big");
}
@ -682,8 +682,8 @@ static int MS_ADPCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
state.output.pos = 0;
state.output.size = outputsize / sizeof(Sint16);
state.output.data = (Sint16 *)SDL_calloc(1, outputsize);
if (state.output.data == NULL) {
return SDL_OutOfMemory();
if (!state.output.data) {
return -1;
}
state.cstate = cstate;
@ -985,7 +985,7 @@ static int IMA_ADPCM_DecodeBlockData(ADPCM_DecoderState *state)
const size_t remainingbytes = blockleft % subblockframesize;
blockframesleft = guaranteedframes;
if (remainingbytes > subblockframesize - 4) {
blockframesleft += (remainingbytes % 4) * 2;
blockframesleft += (Sint64)(remainingbytes % 4) * 2;
}
/* Signal the truncation. */
retval = -1;
@ -1065,7 +1065,7 @@ static int IMA_ADPCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len
/* The output size in bytes. May get modified if data is truncated. */
outputsize = (size_t)state.framestotal;
if (SafeMult(&outputsize, state.framesize)) {
return SDL_OutOfMemory();
return SDL_SetError("WAVE file too big");
} else if (outputsize > SDL_MAX_UINT32 || state.framestotal > SIZE_MAX) {
return SDL_SetError("WAVE file too big");
}
@ -1073,14 +1073,14 @@ static int IMA_ADPCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len
state.output.pos = 0;
state.output.size = outputsize / sizeof(Sint16);
state.output.data = (Sint16 *)SDL_malloc(outputsize);
if (state.output.data == NULL) {
return SDL_OutOfMemory();
if (!state.output.data) {
return -1;
}
cstate = (Sint8 *)SDL_calloc(state.channels, sizeof(Sint8));
if (cstate == NULL) {
if (!cstate) {
SDL_free(state.output.data);
return SDL_OutOfMemory();
return -1;
}
state.cstate = cstate;
@ -1221,20 +1221,20 @@ static int LAW_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
sample_count = (size_t)file->sampleframes;
if (SafeMult(&sample_count, format->channels)) {
return SDL_OutOfMemory();
return SDL_SetError("WAVE file too big");
}
expanded_len = sample_count;
if (SafeMult(&expanded_len, sizeof(Sint16))) {
return SDL_OutOfMemory();
return SDL_SetError("WAVE file too big");
} else if (expanded_len > SDL_MAX_UINT32 || file->sampleframes > SIZE_MAX) {
return SDL_SetError("WAVE file too big");
}
/* 1 to avoid allocating zero bytes, to keep static analysis happy. */
src = (Uint8 *)SDL_realloc(chunk->data, expanded_len ? expanded_len : 1);
if (src == NULL) {
return SDL_OutOfMemory();
if (!src) {
return -1;
}
chunk->data = NULL;
chunk->size = 0;
@ -1352,20 +1352,20 @@ static int PCM_ConvertSint24ToSint32(WaveFile *file, Uint8 **audio_buf, Uint32 *
sample_count = (size_t)file->sampleframes;
if (SafeMult(&sample_count, format->channels)) {
return SDL_OutOfMemory();
return SDL_SetError("WAVE file too big");
}
expanded_len = sample_count;
if (SafeMult(&expanded_len, sizeof(Sint32))) {
return SDL_OutOfMemory();
return SDL_SetError("WAVE file too big");
} else if (expanded_len > SDL_MAX_UINT32 || file->sampleframes > SIZE_MAX) {
return SDL_SetError("WAVE file too big");
}
/* 1 to avoid allocating zero bytes, to keep static analysis happy. */
ptr = (Uint8 *)SDL_realloc(chunk->data, expanded_len ? expanded_len : 1);
if (ptr == NULL) {
return SDL_OutOfMemory();
if (!ptr) {
return -1;
}
/* This pointer is now invalid. */
@ -1421,7 +1421,7 @@ static int PCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
outputsize = (size_t)file->sampleframes;
if (SafeMult(&outputsize, format->blockalign)) {
return SDL_OutOfMemory();
return SDL_SetError("WAVE file too big");
} else if (outputsize > SDL_MAX_UINT32 || file->sampleframes > SIZE_MAX) {
return SDL_SetError("WAVE file too big");
}
@ -1440,7 +1440,7 @@ static WaveRiffSizeHint WaveGetRiffSizeHint(void)
{
const char *hint = SDL_GetHint(SDL_HINT_WAVE_RIFF_CHUNK_SIZE);
if (hint != NULL) {
if (hint) {
if (SDL_strcmp(hint, "force") == 0) {
return RiffSizeForce;
} else if (SDL_strcmp(hint, "ignore") == 0) {
@ -1459,7 +1459,7 @@ static WaveTruncationHint WaveGetTruncationHint(void)
{
const char *hint = SDL_GetHint(SDL_HINT_WAVE_TRUNCATION);
if (hint != NULL) {
if (hint) {
if (SDL_strcmp(hint, "verystrict") == 0) {
return TruncVeryStrict;
} else if (SDL_strcmp(hint, "strict") == 0) {
@ -1478,7 +1478,7 @@ static WaveFactChunkHint WaveGetFactChunkHint(void)
{
const char *hint = SDL_GetHint(SDL_HINT_WAVE_FACT_CHUNK);
if (hint != NULL) {
if (hint) {
if (SDL_strcmp(hint, "truncate") == 0) {
return FactTruncate;
} else if (SDL_strcmp(hint, "strict") == 0) {
@ -1495,7 +1495,7 @@ static WaveFactChunkHint WaveGetFactChunkHint(void)
static void WaveFreeChunkData(WaveChunk *chunk)
{
if (chunk->data != NULL) {
if (chunk->data) {
SDL_free(chunk->data);
chunk->data = NULL;
}
@ -1544,8 +1544,8 @@ static int WaveReadPartialChunkData(SDL_RWops *src, WaveChunk *chunk, size_t len
if (length > 0) {
chunk->data = (Uint8 *)SDL_malloc(length);
if (chunk->data == NULL) {
return SDL_OutOfMemory();
if (!chunk->data) {
return -1;
}
if (SDL_RWseek(src, chunk->position, SDL_RW_SEEK_SET) != chunk->position) {
@ -1610,8 +1610,8 @@ static int WaveReadFormat(WaveFile *file)
return SDL_SetError("Data of WAVE fmt chunk too big");
}
fmtsrc = SDL_RWFromConstMem(chunk->data, (int)chunk->size);
if (fmtsrc == NULL) {
return SDL_OutOfMemory();
if (!fmtsrc) {
return -1;
}
if (!SDL_ReadU16LE(fmtsrc, &format->formattag) ||
@ -1788,7 +1788,7 @@ static int WaveLoad(SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 *
SDL_zero(datachunk);
envchunkcountlimit = SDL_getenv("SDL_WAVE_CHUNK_LIMIT");
if (envchunkcountlimit != NULL) {
if (envchunkcountlimit) {
unsigned int count;
if (SDL_sscanf(envchunkcountlimit, "%u", &count) == 1) {
chunkcountlimit = count <= SDL_MAX_UINT32 ? count : SDL_MAX_UINT32;
@ -2081,15 +2081,15 @@ int SDL_LoadWAV_RW(SDL_RWops *src, SDL_bool freesrc, SDL_AudioSpec *spec, Uint8
WaveFile file;
/* Make sure we are passed a valid data source */
if (src == NULL) {
if (!src) {
goto done; /* Error may come from RWops. */
} else if (spec == NULL) {
} else if (!spec) {
SDL_InvalidParamError("spec");
goto done;
} else if (audio_buf == NULL) {
} else if (!audio_buf) {
SDL_InvalidParamError("audio_buf");
goto done;
} else if (audio_len == NULL) {
} else if (!audio_len) {
SDL_InvalidParamError("audio_len");
goto done;
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -23,7 +23,6 @@
#ifdef SDL_AUDIO_DRIVER_AAUDIO
#include "../SDL_sysaudio.h"
#include "../SDL_audio_c.h"
#include "SDL_aaudio.h"
#include "../../core/android/SDL_android.h"
@ -37,10 +36,14 @@
struct SDL_PrivateAudioData
{
AAudioStream *stream;
Uint8 *mixbuf; // Raw mixing buffer
int num_buffers;
Uint8 *mixbuf; // Raw mixing buffer
size_t mixbuf_bytes; // num_buffers * device->buffer_size
size_t callback_bytes;
size_t processed_bytes;
SDL_Semaphore *semaphore;
SDL_AtomicInt error_callback_triggered;
int resume; // Resume device if it was paused automatically
SDL_bool resume; // Resume device if it was paused automatically
};
// Debug
@ -79,54 +82,168 @@ static void AAUDIO_errorCallback(AAudioStream *stream, void *userData, aaudio_re
LOGI("SDL AAUDIO_errorCallback: %d - %s", error, ctx.AAudio_convertResultToText(error));
// You MUST NOT close the audio stream from this callback, so we cannot call SDL_AudioDeviceDisconnected here.
// Just flag the device so we can kill it in WaitDevice/PlayDevice instead.
// Just flag the device so we can kill it in PlayDevice instead.
SDL_AudioDevice *device = (SDL_AudioDevice *) userData;
SDL_AtomicSet(&device->hidden->error_callback_triggered, 1);
SDL_AtomicSet(&device->hidden->error_callback_triggered, (int) error); // AAUDIO_OK is zero, so !triggered means no error.
SDL_PostSemaphore(device->hidden->semaphore); // in case we're blocking in WaitDevice.
}
// due to the way the aaudio data callback works, PlayDevice is a no-op. The callback collects audio while SDL camps in WaitDevice and
// fires a semaphore that will unblock WaitDevice and start a new iteration, so when the callback runs again, WaitDevice is ready
// to hand it more data.
static aaudio_data_callback_result_t AAUDIO_dataCallback(AAudioStream *stream, void *userData, void *audioData, int32_t numFrames)
{
SDL_AudioDevice *device = (SDL_AudioDevice *) userData;
SDL_assert(numFrames == device->sample_frames);
struct SDL_PrivateAudioData *hidden = device->hidden;
size_t framesize = SDL_AUDIO_FRAMESIZE(device->spec);
size_t callback_bytes = numFrames * framesize;
size_t old_buffer_index = hidden->callback_bytes / device->buffer_size;
if (device->iscapture) {
SDL_memcpy(device->hidden->mixbuf, audioData, device->buffer_size);
const Uint8 *input = (const Uint8 *)audioData;
size_t available_bytes = hidden->mixbuf_bytes - (hidden->callback_bytes - hidden->processed_bytes);
size_t size = SDL_min(available_bytes, callback_bytes);
size_t offset = hidden->callback_bytes % hidden->mixbuf_bytes;
size_t end = (offset + size) % hidden->mixbuf_bytes;
SDL_assert(size <= hidden->mixbuf_bytes);
//LOGI("Recorded %zu frames, %zu available, %zu max (%zu written, %zu read)\n", callback_bytes / framesize, available_bytes / framesize, hidden->mixbuf_bytes / framesize, hidden->callback_bytes / framesize, hidden->processed_bytes / framesize);
if (offset <= end) {
SDL_memcpy(&hidden->mixbuf[offset], input, size);
} else {
size_t partial = (hidden->mixbuf_bytes - offset);
SDL_memcpy(&hidden->mixbuf[offset], &input[0], partial);
SDL_memcpy(&hidden->mixbuf[0], &input[partial], end);
}
SDL_MemoryBarrierRelease();
hidden->callback_bytes += size;
if (size < callback_bytes) {
LOGI("Audio recording overflow, dropped %zu frames\n", (callback_bytes - size) / framesize);
}
} else {
SDL_memcpy(audioData, device->hidden->mixbuf, device->buffer_size);
Uint8 *output = (Uint8 *)audioData;
size_t available_bytes = (hidden->processed_bytes - hidden->callback_bytes);
size_t size = SDL_min(available_bytes, callback_bytes);
size_t offset = hidden->callback_bytes % hidden->mixbuf_bytes;
size_t end = (offset + size) % hidden->mixbuf_bytes;
SDL_assert(size <= hidden->mixbuf_bytes);
//LOGI("Playing %zu frames, %zu available, %zu max (%zu written, %zu read)\n", callback_bytes / framesize, available_bytes / framesize, hidden->mixbuf_bytes / framesize, hidden->processed_bytes / framesize, hidden->callback_bytes / framesize);
SDL_MemoryBarrierAcquire();
if (offset <= end) {
SDL_memcpy(output, &hidden->mixbuf[offset], size);
} else {
size_t partial = (hidden->mixbuf_bytes - offset);
SDL_memcpy(&output[0], &hidden->mixbuf[offset], partial);
SDL_memcpy(&output[partial], &hidden->mixbuf[0], end);
}
hidden->callback_bytes += size;
if (size < callback_bytes) {
LOGI("Audio playback underflow, missed %zu frames\n", (callback_bytes - size) / framesize);
SDL_memset(&output[size], device->silence_value, (callback_bytes - size));
}
}
SDL_PostSemaphore(device->hidden->semaphore);
size_t new_buffer_index = hidden->callback_bytes / device->buffer_size;
while (old_buffer_index < new_buffer_index) {
// Trigger audio processing
SDL_PostSemaphore(hidden->semaphore);
++old_buffer_index;
}
return AAUDIO_CALLBACK_RESULT_CONTINUE;
}
static Uint8 *AAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *bufsize)
{
return device->hidden->mixbuf;
struct SDL_PrivateAudioData *hidden = device->hidden;
size_t offset = (hidden->processed_bytes % hidden->mixbuf_bytes);
return &hidden->mixbuf[offset];
}
static void AAUDIO_WaitDevice(SDL_AudioDevice *device)
static int AAUDIO_WaitDevice(SDL_AudioDevice *device)
{
SDL_WaitSemaphore(device->hidden->semaphore);
return 0;
}
static int AAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
static int BuildAAudioStream(SDL_AudioDevice *device);
static int RecoverAAudioDevice(SDL_AudioDevice *device)
{
// AAUDIO_dataCallback picks up our work and unblocks AAUDIO_WaitDevice. But make sure we didn't fail here.
if (SDL_AtomicGet(&device->hidden->error_callback_triggered)) {
SDL_AtomicSet(&device->hidden->error_callback_triggered, 0);
return -1;
struct SDL_PrivateAudioData *hidden = device->hidden;
// attempt to build a new stream, in case there's a new default device.
ctx.AAudioStream_requestStop(hidden->stream);
ctx.AAudioStream_close(hidden->stream);
hidden->stream = NULL;
SDL_aligned_free(hidden->mixbuf);
hidden->mixbuf = NULL;
SDL_DestroySemaphore(hidden->semaphore);
hidden->semaphore = NULL;
const int prev_sample_frames = device->sample_frames;
SDL_AudioSpec prevspec;
SDL_copyp(&prevspec, &device->spec);
if (BuildAAudioStream(device) < 0) {
return -1; // oh well, we tried.
}
// we don't know the new device spec until we open the new device, so we saved off the old one and force it back
// so SDL_AudioDeviceFormatChanged can set up all the important state if necessary and then set it back to the new spec.
const int new_sample_frames = device->sample_frames;
SDL_AudioSpec newspec;
SDL_copyp(&newspec, &device->spec);
device->sample_frames = prev_sample_frames;
SDL_copyp(&device->spec, &prevspec);
if (SDL_AudioDeviceFormatChangedAlreadyLocked(device, &newspec, new_sample_frames) < 0) {
return -1; // ugh
}
return 0;
}
static int AAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
{
struct SDL_PrivateAudioData *hidden = device->hidden;
// AAUDIO_dataCallback picks up our work and unblocks AAUDIO_WaitDevice. But make sure we didn't fail here.
const aaudio_result_t err = (aaudio_result_t) SDL_AtomicGet(&hidden->error_callback_triggered);
if (err) {
SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "aaudio: Audio device triggered error %d (%s)", (int) err, ctx.AAudio_convertResultToText(err));
if (RecoverAAudioDevice(device) < 0) {
return -1; // oh well, we went down hard.
}
} else {
SDL_MemoryBarrierRelease();
hidden->processed_bytes += buflen;
}
return 0;
}
// no need for a FlushCapture implementation, just don't read mixbuf until the next iteration.
static int AAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
{
const int cpy = SDL_min(buflen, device->buffer_size);
SDL_memcpy(buffer, device->hidden->mixbuf, cpy);
return cpy;
struct SDL_PrivateAudioData *hidden = device->hidden;
// AAUDIO_dataCallback picks up our work and unblocks AAUDIO_WaitDevice. But make sure we didn't fail here.
if (SDL_AtomicGet(&hidden->error_callback_triggered)) {
SDL_AtomicSet(&hidden->error_callback_triggered, 0);
return -1;
}
SDL_assert(buflen == device->buffer_size); // If this isn't true, we need to change semaphore trigger logic and account for wrapping copies here
size_t offset = (hidden->processed_bytes % hidden->mixbuf_bytes);
SDL_MemoryBarrierAcquire();
SDL_memcpy(buffer, &hidden->mixbuf[offset], buflen);
hidden->processed_bytes += buflen;
return buflen;
}
static void AAUDIO_CloseDevice(SDL_AudioDevice *device)
@ -146,34 +263,18 @@ static void AAUDIO_CloseDevice(SDL_AudioDevice *device)
SDL_DestroySemaphore(hidden->semaphore);
}
SDL_free(hidden->mixbuf);
SDL_aligned_free(hidden->mixbuf);
SDL_free(hidden);
device->hidden = NULL;
}
}
static int AAUDIO_OpenDevice(SDL_AudioDevice *device)
static int BuildAAudioStream(SDL_AudioDevice *device)
{
struct SDL_PrivateAudioData *hidden;
struct SDL_PrivateAudioData *hidden = device->hidden;
const SDL_bool iscapture = device->iscapture;
aaudio_result_t res;
SDL_assert(device->handle != NULL); // AAUDIO_UNSPECIFIED is zero, so legit devices should all be non-zero.
LOGI(__func__);
if (iscapture) {
if (!Android_JNI_RequestPermission("android.permission.RECORD_AUDIO")) {
LOGI("This app doesn't have RECORD_AUDIO permission");
return SDL_SetError("This app doesn't have RECORD_AUDIO permission");
}
}
hidden = device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
if (hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_AtomicSet(&hidden->error_callback_triggered, 0);
AAudioStreamBuilder *builder = NULL;
@ -181,23 +282,19 @@ static int AAUDIO_OpenDevice(SDL_AudioDevice *device)
if (res != AAUDIO_OK) {
LOGI("SDL Failed AAudio_createStreamBuilder %d", res);
return SDL_SetError("SDL Failed AAudio_createStreamBuilder %d", res);
} else if (builder == NULL) {
} else if (!builder) {
LOGI("SDL Failed AAudio_createStreamBuilder - builder NULL");
return SDL_SetError("SDL Failed AAudio_createStreamBuilder - builder NULL");
}
// !!! FIXME: call AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY); ?
ctx.AAudioStreamBuilder_setSampleRate(builder, device->spec.freq);
ctx.AAudioStreamBuilder_setChannelCount(builder, device->spec.channels);
#if ALLOW_MULTIPLE_ANDROID_AUDIO_DEVICES
const int aaudio_device_id = (int) ((size_t) device->handle);
LOGI("Opening device id %d", aaudio_device_id);
ctx.AAudioStreamBuilder_setDeviceId(builder, aaudio_device_id);
#endif
const aaudio_direction_t direction = (iscapture ? AAUDIO_DIRECTION_INPUT : AAUDIO_DIRECTION_OUTPUT);
ctx.AAudioStreamBuilder_setDirection(builder, direction);
aaudio_format_t format;
#ifdef SET_AUDIO_FORMAT
if ((device->spec.format == SDL_AUDIO_S32) && (SDL_GetAndroidSDKVersion() >= 31)) {
format = AAUDIO_FORMAT_PCM_I32;
} else if (device->spec.format == SDL_AUDIO_F32) {
@ -205,41 +302,38 @@ static int AAUDIO_OpenDevice(SDL_AudioDevice *device)
} else {
format = AAUDIO_FORMAT_PCM_I16; // sint16 is a safe bet for everything else.
}
ctx.AAudioStreamBuilder_setFormat(builder, format);
ctx.AAudioStreamBuilder_setSampleRate(builder, device->spec.freq);
ctx.AAudioStreamBuilder_setChannelCount(builder, device->spec.channels);
#endif
const aaudio_direction_t direction = (iscapture ? AAUDIO_DIRECTION_INPUT : AAUDIO_DIRECTION_OUTPUT);
ctx.AAudioStreamBuilder_setDirection(builder, direction);
ctx.AAudioStreamBuilder_setErrorCallback(builder, AAUDIO_errorCallback, device);
ctx.AAudioStreamBuilder_setDataCallback(builder, AAUDIO_dataCallback, device);
ctx.AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
// Some devices have flat sounding audio when low latency mode is enabled, but this is a better experience for most people
if (SDL_GetHintBoolean("SDL_ANDROID_LOW_LATENCY_AUDIO", SDL_TRUE)) {
ctx.AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
}
LOGI("AAudio Try to open %u hz %u bit chan %u %s samples %u",
device->spec.freq, SDL_AUDIO_BITSIZE(device->spec.format),
device->spec.channels, SDL_AUDIO_ISBIGENDIAN(device->spec.format) ? "BE" : "LE", device->sample_frames);
res = ctx.AAudioStreamBuilder_openStream(builder, &hidden->stream);
if (res != AAUDIO_OK) {
LOGI("SDL Failed AAudioStreamBuilder_openStream %d", res);
ctx.AAudioStreamBuilder_delete(builder);
return SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
}
device->sample_frames = (int) ctx.AAudioStream_getFramesPerDataCallback(hidden->stream);
if (device->sample_frames == AAUDIO_UNSPECIFIED) {
// if this happens, figure out a reasonable sample frame count, tear down this stream and force it in a new stream.
device->sample_frames = (int) (ctx.AAudioStream_getBufferCapacityInFrames(hidden->stream) / 4);
LOGI("AAUDIO: Got a stream with unspecified sample frames per data callback! Retrying with %d frames...", device->sample_frames);
ctx.AAudioStream_close(hidden->stream);
ctx.AAudioStreamBuilder_setFramesPerDataCallback(builder, device->sample_frames);
res = ctx.AAudioStreamBuilder_openStream(builder, &hidden->stream);
if (res != AAUDIO_OK) { // oh well, we tried.
LOGI("SDL Failed AAudioStreamBuilder_openStream %d", res);
ctx.AAudioStreamBuilder_delete(builder);
return SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
}
}
ctx.AAudioStreamBuilder_delete(builder);
device->sample_frames = (int)ctx.AAudioStream_getFramesPerDataCallback(hidden->stream);
if (device->sample_frames == AAUDIO_UNSPECIFIED) {
// We'll get variable frames in the callback, make sure we have at least half a buffer available
device->sample_frames = (int)ctx.AAudioStream_getBufferCapacityInFrames(hidden->stream) / 2;
}
device->spec.freq = ctx.AAudioStream_getSampleRate(hidden->stream);
device->spec.channels = ctx.AAudioStream_getChannelCount(hidden->stream);
@ -254,25 +348,28 @@ static int AAUDIO_OpenDevice(SDL_AudioDevice *device)
return SDL_SetError("Got unexpected audio format %d from AAudioStream_getFormat", (int) format);
}
LOGI("AAudio Actually opened %u hz %u bit chan %u %s samples %u",
device->spec.freq, SDL_AUDIO_BITSIZE(device->spec.format),
device->spec.channels, SDL_AUDIO_ISBIGENDIAN(device->spec.format) ? "BE" : "LE", device->sample_frames);
SDL_UpdatedAudioDeviceFormat(device);
// Allocate mixing buffer
hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
if (hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
// Allocate a double buffered mixing buffer
hidden->num_buffers = 2;
hidden->mixbuf_bytes = (hidden->num_buffers * device->buffer_size);
hidden->mixbuf = (Uint8 *)SDL_aligned_alloc(SDL_SIMDGetAlignment(), hidden->mixbuf_bytes);
if (!hidden->mixbuf) {
return -1;
}
SDL_memset(hidden->mixbuf, device->silence_value, device->buffer_size);
hidden->processed_bytes = 0;
hidden->callback_bytes = 0;
hidden->semaphore = SDL_CreateSemaphore(0);
hidden->semaphore = SDL_CreateSemaphore(iscapture ? 0 : hidden->num_buffers);
if (!hidden->semaphore) {
LOGI("SDL Failed SDL_CreateSemaphore %s iscapture:%d", SDL_GetError(), iscapture);
return -1;
}
LOGI("AAudio Actually opened %u hz %u bit chan %u %s samples %u, buffers %d",
device->spec.freq, SDL_AUDIO_BITSIZE(device->spec.format),
device->spec.channels, SDL_AUDIO_ISBIGENDIAN(device->spec.format) ? "BE" : "LE", device->sample_frames, hidden->num_buffers);
res = ctx.AAudioStream_requestStart(hidden->stream);
if (res != AAUDIO_OK) {
LOGI("SDL Failed AAudioStream_requestStart %d iscapture:%d", res, iscapture);
@ -280,13 +377,37 @@ static int AAUDIO_OpenDevice(SDL_AudioDevice *device)
}
LOGI("SDL AAudioStream_requestStart OK");
return 0;
}
static int AAUDIO_OpenDevice(SDL_AudioDevice *device)
{
#if ALLOW_MULTIPLE_ANDROID_AUDIO_DEVICES
SDL_assert(device->handle); // AAUDIO_UNSPECIFIED is zero, so legit devices should all be non-zero.
#endif
LOGI(__func__);
if (device->iscapture) {
if (!Android_JNI_RequestPermission("android.permission.RECORD_AUDIO")) {
LOGI("This app doesn't have RECORD_AUDIO permission");
return SDL_SetError("This app doesn't have RECORD_AUDIO permission");
}
}
device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
if (!device->hidden) {
return -1;
}
return BuildAAudioStream(device);
}
static SDL_bool PauseOneDevice(SDL_AudioDevice *device, void *userdata)
{
struct SDL_PrivateAudioData *hidden = (struct SDL_PrivateAudioData *)device->hidden;
if (hidden != NULL) {
if (hidden) {
if (hidden->stream) {
aaudio_result_t res;
@ -312,7 +433,7 @@ static SDL_bool PauseOneDevice(SDL_AudioDevice *device, void *userdata)
// Pause (block) all non already paused audio devices by taking their mixer lock
void AAUDIO_PauseDevices(void)
{
if (ctx.handle != NULL) { // AAUDIO driver is used?
if (ctx.handle) { // AAUDIO driver is used?
(void) SDL_FindPhysicalAudioDeviceByCallback(PauseOneDevice, NULL);
}
}
@ -321,7 +442,7 @@ void AAUDIO_PauseDevices(void)
static SDL_bool ResumeOneDevice(SDL_AudioDevice *device, void *userdata)
{
struct SDL_PrivateAudioData *hidden = device->hidden;
if (hidden != NULL) {
if (hidden) {
if (hidden->resume) {
hidden->resume = SDL_FALSE;
SDL_UnlockMutex(device->lock);
@ -340,42 +461,11 @@ static SDL_bool ResumeOneDevice(SDL_AudioDevice *device, void *userdata)
void AAUDIO_ResumeDevices(void)
{
if (ctx.handle != NULL) { // AAUDIO driver is used?
if (ctx.handle) { // AAUDIO driver is used?
(void) SDL_FindPhysicalAudioDeviceByCallback(ResumeOneDevice, NULL);
}
}
// !!! FIXME: do we need this now that we use the callback?
/*
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
*/
static SDL_bool DetectBrokenPlayStatePerDevice(SDL_AudioDevice *device, void *userdata)
{
SDL_assert(device != NULL);
if (!device->iscapture && device->hidden != NULL) {
struct SDL_PrivateAudioData *hidden = device->hidden;
int64_t framePosition, timeNanoseconds;
aaudio_result_t res = ctx.AAudioStream_getTimestamp(hidden->stream, CLOCK_MONOTONIC, &framePosition, &timeNanoseconds);
if (res == AAUDIO_ERROR_INVALID_STATE) {
aaudio_stream_state_t currentState = ctx.AAudioStream_getState(hidden->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; // this guy.
}
}
}
return SDL_FALSE; // enumerate more devices.
}
SDL_bool AAUDIO_DetectBrokenPlayState(void)
{
return (ctx.handle && SDL_FindPhysicalAudioDeviceByCallback(DetectBrokenPlayStatePerDevice, NULL) != NULL) ? SDL_TRUE : SDL_FALSE;
}
static void AAUDIO_Deinitialize(void)
{
Android_StopAudioHotplug();
@ -405,7 +495,7 @@ static SDL_bool AAUDIO_Init(SDL_AudioDriverImpl *impl)
SDL_zero(ctx);
ctx.handle = SDL_LoadObject(LIB_AAUDIO_SO);
if (ctx.handle == NULL) {
if (!ctx.handle) {
LOGI("SDL couldn't find " LIB_AAUDIO_SO);
return SDL_FALSE;
}
@ -417,7 +507,6 @@ static SDL_bool AAUDIO_Init(SDL_AudioDriverImpl *impl)
}
impl->ThreadInit = Android_AudioThreadInit;
impl->DetectDevices = Android_StartAudioHotplug;
impl->Deinitialize = AAUDIO_Deinitialize;
impl->OpenDevice = AAUDIO_OpenDevice;
impl->CloseDevice = AAUDIO_CloseDevice;
@ -429,6 +518,13 @@ static SDL_bool AAUDIO_Init(SDL_AudioDriverImpl *impl)
impl->HasCaptureSupport = SDL_TRUE;
#if ALLOW_MULTIPLE_ANDROID_AUDIO_DEVICES
impl->DetectDevices = Android_StartAudioHotplug;
#else
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
#endif
LOGI("SDL AAUDIO_Init OK");
return SDL_TRUE;
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -27,14 +27,12 @@
void AAUDIO_ResumeDevices(void);
void AAUDIO_PauseDevices(void);
SDL_bool AAUDIO_DetectBrokenPlayState(void);
#else
#define AAUDIO_ResumeDevices()
#define AAUDIO_PauseDevices()
#define AAUDIO_DetectBrokenPlayState() (SDL_FALSE)
#endif
#endif /* SDL_aaudio_h_ */
#endif // SDL_aaudio_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright , (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright , (C) 1997-2024 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
@ -33,18 +33,18 @@ SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSharingMode, (AAudioStreamBuilder *
SDL_PROC(void, AAudioStreamBuilder_setDirection, (AAudioStreamBuilder * builder, aaudio_direction_t direction))
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder * builder, int32_t numFrames))
SDL_PROC(void, AAudioStreamBuilder_setPerformanceMode, (AAudioStreamBuilder * builder, aaudio_performance_mode_t mode))
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setUsage, (AAudioStreamBuilder * builder, aaudio_usage_t usage)) /* API 28 */
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setContentType, (AAudioStreamBuilder * builder, aaudio_content_type_t contentType)) /* API 28 */
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setInputPreset, (AAudioStreamBuilder * builder, aaudio_input_preset_t inputPreset)) /* API 28 */
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setAllowedCapturePolicy, (AAudioStreamBuilder * builder, aaudio_allowed_capture_policy_t capturePolicy)) /* API 29 */
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSessionId, (AAudioStreamBuilder * builder, aaudio_session_id_t sessionId)) /* API 28 */
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setPrivacySensitive, (AAudioStreamBuilder * builder, bool privacySensitive)) /* API 30 */
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setUsage, (AAudioStreamBuilder * builder, aaudio_usage_t usage)) // API 28
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setContentType, (AAudioStreamBuilder * builder, aaudio_content_type_t contentType)) // API 28
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setInputPreset, (AAudioStreamBuilder * builder, aaudio_input_preset_t inputPreset)) // API 28
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setAllowedCapturePolicy, (AAudioStreamBuilder * builder, aaudio_allowed_capture_policy_t capturePolicy)) // API 29
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSessionId, (AAudioStreamBuilder * builder, aaudio_session_id_t sessionId)) // API 28
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setPrivacySensitive, (AAudioStreamBuilder * builder, bool privacySensitive)) // API 30
SDL_PROC(void, AAudioStreamBuilder_setDataCallback, (AAudioStreamBuilder * builder, AAudioStream_dataCallback callback, void *userData))
SDL_PROC(void, AAudioStreamBuilder_setFramesPerDataCallback, (AAudioStreamBuilder * builder, int32_t numFrames))
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 */
SDL_PROC_UNUSED(aaudio_result_t, AAudioStream_release, (AAudioStream * stream)) // API 30
SDL_PROC(aaudio_result_t, AAudioStream_close, (AAudioStream * stream))
SDL_PROC(aaudio_result_t, AAudioStream_requestStart, (AAudioStream * stream))
SDL_PROC(aaudio_result_t, AAudioStream_requestPause, (AAudioStream * stream))
@ -70,13 +70,13 @@ SDL_PROC_UNUSED(aaudio_performance_mode_t, AAudioStream_getPerformanceMode, (AAu
SDL_PROC_UNUSED(aaudio_direction_t, AAudioStream_getDirection, (AAudioStream * stream))
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_session_id_t, AAudioStream_getSessionId, (AAudioStream * stream)) // API 28
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 */
SDL_PROC_UNUSED(aaudio_allowed_capture_policy_t, AAudioStream_getAllowedCapturePolicy, (AAudioStream * stream)) /* API 29 */
SDL_PROC_UNUSED(bool, AAudioStream_isPrivacySensitive, (AAudioStream * stream)) /* API 30 */
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
SDL_PROC_UNUSED(aaudio_allowed_capture_policy_t, AAudioStream_getAllowedCapturePolicy, (AAudioStream * stream)) // API 29
SDL_PROC_UNUSED(bool, AAudioStream_isPrivacySensitive, (AAudioStream * stream)) // API 30
#undef SDL_PROC
#undef SDL_PROC_UNUSED

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -20,26 +20,24 @@
*/
#include "SDL_internal.h"
// !!! FIXME: Clean out the fprintf and printf calls, replace with SDL_Log
#ifdef SDL_AUDIO_DRIVER_ALSA
#ifndef SDL_ALSA_NON_BLOCKING
#define SDL_ALSA_NON_BLOCKING 0
#endif
/* without the thread, you will detect devices on startup, but will not get further hotplug events. But that might be okay. */
// without the thread, you will detect devices on startup, but will not get further 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 */
// Allow access to a raw mixing buffer
#include <sys/types.h>
#include <signal.h> /* For kill() */
#include <signal.h> // For kill()
#include <string.h>
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_alsa_audio.h"
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
@ -98,15 +96,15 @@ static void *alsa_handle = NULL;
static int load_alsa_sym(const char *fn, void **addr)
{
*addr = SDL_LoadFunction(alsa_handle, fn);
if (*addr == NULL) {
/* Don't call SDL_SetError(): SDL_LoadFunction already did. */
if (!*addr) {
// Don't call SDL_SetError(): SDL_LoadFunction already did.
return 0;
}
return 1;
}
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
// cast funcs to char* first, to please GCC's strict aliasing rules.
#define SDL_ALSA_SYM(x) \
if (!load_alsa_sym(#x, (void **)(char *)&ALSA_##x)) \
return -1
@ -167,7 +165,7 @@ static int load_alsa_syms(void)
static void UnloadALSALibrary(void)
{
if (alsa_handle != NULL) {
if (alsa_handle) {
SDL_UnloadObject(alsa_handle);
alsa_handle = NULL;
}
@ -176,11 +174,11 @@ static void UnloadALSALibrary(void)
static int LoadALSALibrary(void)
{
int retval = 0;
if (alsa_handle == NULL) {
if (!alsa_handle) {
alsa_handle = SDL_LoadObject(alsa_library);
if (alsa_handle == NULL) {
if (!alsa_handle) {
retval = -1;
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
// Don't call SDL_SetError(): SDL_LoadObject already did.
} else {
retval = load_alsa_syms();
if (retval < 0) {
@ -203,15 +201,35 @@ static int LoadALSALibrary(void)
return 0;
}
#endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */
#endif // SDL_AUDIO_DRIVER_ALSA_DYNAMIC
typedef struct ALSA_Device
{
char *name;
SDL_bool iscapture;
struct ALSA_Device *next;
} ALSA_Device;
static const ALSA_Device default_output_handle = {
"default",
SDL_FALSE,
NULL
};
static const ALSA_Device default_capture_handle = {
"default",
SDL_TRUE,
NULL
};
static const char *get_audio_device(void *handle, const int channels)
{
SDL_assert(handle != NULL); // SDL2 used NULL to mean "default" but that's not true in SDL3.
if (SDL_strcmp((const char *) handle, "default") == 0) {
const char *device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */
if (device != NULL) {
ALSA_Device *dev = (ALSA_Device *)handle;
if (SDL_strcmp(dev->name, "default") == 0) {
const char *device = SDL_getenv("AUDIODEV"); // Is there a standard variable name?
if (device) {
return device;
} else if (channels == 6) {
return "plug:surround51";
@ -221,15 +239,14 @@ static const char *get_audio_device(void *handle, const int channels)
return "default";
}
return (const char *)handle;
return dev->name;
}
/* !!! FIXME: is there a channel swizzler in alsalib instead? */
/*
* 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"
*/
// !!! FIXME: is there a channel swizzler in alsalib instead?
// 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) \
static void swizzle_alsa_channels_6_##T(void *buffer, const Uint32 bufferlen) \
{ \
@ -246,13 +263,13 @@ static const char *get_audio_device(void *handle, const int channels)
} \
}
/* !!! 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"
*/
// !!! 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) \
{ \
@ -287,10 +304,8 @@ CHANNEL_SWIZZLE(SWIZ8)
#undef SWIZ6
#undef SWIZ8
/*
* Called right before feeding device->hidden->mixbuf to the hardware. Swizzle
* channels from Windows/Mac order to the format alsalib will want.
*/
// Called right before feeding device->hidden->mixbuf to the hardware. Swizzle
// channels from Windows/Mac order to the format alsalib will want.
static void swizzle_alsa_channels(SDL_AudioDevice *device, void *buffer, Uint32 bufferlen)
{
switch (device->spec.channels) {
@ -324,70 +339,66 @@ static void swizzle_alsa_channels(SDL_AudioDevice *device, void *buffer, Uint32
}
#ifdef SND_CHMAP_API_VERSION
/* Some devices have the right channel map, no swizzling necessary */
// Some devices have the right channel map, no swizzling necessary
static void no_swizzle(SDL_AudioDevice *device, void *buffer, Uint32 bufferlen)
{
}
#endif /* SND_CHMAP_API_VERSION */
#endif // SND_CHMAP_API_VERSION
/* This function waits until it is possible to write a full sound buffer */
static void ALSA_WaitDevice(SDL_AudioDevice *device)
// This function waits until it is possible to write a full sound buffer
static int ALSA_WaitDevice(SDL_AudioDevice *device)
{
const snd_pcm_sframes_t needed = (snd_pcm_sframes_t)device->sample_frames;
const int fulldelay = (int) ((((Uint64) device->sample_frames) * 1000) / device->spec.freq);
const int delay = SDL_max(fulldelay, 10);
while (!SDL_AtomicGet(&device->shutdown)) {
const snd_pcm_sframes_t rc = ALSA_snd_pcm_avail(device->hidden->pcm_handle);
if ((rc < 0) && (rc != -EAGAIN)) {
/* Hmm, not much we can do - abort */
fprintf(stderr, "ALSA snd_pcm_avail failed (unrecoverable): %s\n",
ALSA_snd_strerror(rc));
SDL_AudioDeviceDisconnected(device);
return;
} else if (rc < needed) {
const Uint32 delay = ((needed - (SDL_max(rc, 0))) * 1000) / device->spec.freq;
SDL_Delay(SDL_max(delay, 10));
} else {
break; /* ready to go! */
const int rc = ALSA_snd_pcm_wait(device->hidden->pcm_handle, delay);
if (rc < 0 && (rc != -EAGAIN)) {
const int status = ALSA_snd_pcm_recover(device->hidden->pcm_handle, rc, 0);
if (status < 0) {
// Hmm, not much we can do - abort
SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "ALSA: snd_pcm_wait failed (unrecoverable): %s", ALSA_snd_strerror(rc));
return -1;
}
continue;
}
if (rc > 0) {
break; // ready to go!
}
// Timed out! Make sure we aren't shutting down and then wait again.
}
return 0;
}
static int ALSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
{
SDL_assert(buffer == device->hidden->mixbuf);
Uint8 *sample_buf = device->hidden->mixbuf;
Uint8 *sample_buf = (Uint8 *) buffer; // !!! FIXME: deal with this without casting away constness
const int frame_size = SDL_AUDIO_FRAMESIZE(device->spec);
snd_pcm_uframes_t frames_left = (snd_pcm_uframes_t) (buflen / frame_size);
device->hidden->swizzle_func(device, sample_buf, frames_left);
while ((frames_left > 0) && !SDL_AtomicGet(&device->shutdown)) {
int status = ALSA_snd_pcm_writei(device->hidden->pcm_handle,
sample_buf, frames_left);
if (status < 0) {
if (status == -EAGAIN) {
/* Apparently snd_pcm_recover() doesn't handle this case -
does it assume snd_pcm_wait() above? */
SDL_Delay(1);
continue;
}
status = ALSA_snd_pcm_recover(device->hidden->pcm_handle, status, 0);
const int rc = ALSA_snd_pcm_writei(device->hidden->pcm_handle, sample_buf, frames_left);
//SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "ALSA PLAYDEVICE: WROTE %d of %d bytes", (rc >= 0) ? ((int) (rc * frame_size)) : rc, (int) (frames_left * frame_size));
SDL_assert(rc != 0); // assuming this can't happen if we used snd_pcm_wait and queried for available space.
if (rc < 0) {
SDL_assert(rc != -EAGAIN); // assuming this can't happen if we used snd_pcm_wait and queried for available space. snd_pcm_recover won't handle it!
const int status = ALSA_snd_pcm_recover(device->hidden->pcm_handle, rc, 0);
if (status < 0) {
/* Hmm, not much we can do - abort */
SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
"ALSA write failed (unrecoverable): %s",
ALSA_snd_strerror(status));
// Hmm, not much we can do - abort
SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "ALSA write failed (unrecoverable): %s", ALSA_snd_strerror(rc));
return -1;
}
continue;
} else if (status == 0) {
/* No frames were written (no available space in pcm device).
Allow other threads to catch up. */
SDL_Delay((frames_left / 2 * 1000) / device->spec.freq);
}
sample_buf += status * frame_size;
frames_left -= status;
sample_buf += rc * frame_size;
frames_left -= rc;
}
return 0;
@ -395,45 +406,54 @@ static int ALSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buf
static Uint8 *ALSA_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
{
snd_pcm_sframes_t rc = ALSA_snd_pcm_avail(device->hidden->pcm_handle);
if (rc <= 0) {
// Wait a bit and try again, maybe the hardware isn't quite ready yet?
SDL_Delay(1);
rc = ALSA_snd_pcm_avail(device->hidden->pcm_handle);
if (rc <= 0) {
// We'll catch it next time
*buffer_size = 0;
return NULL;
}
}
const int requested_frames = SDL_min(device->sample_frames, rc);
const int requested_bytes = requested_frames * SDL_AUDIO_FRAMESIZE(device->spec);
SDL_assert(requested_bytes <= *buffer_size);
//SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "ALSA GETDEVICEBUF: NEED %d BYTES", requested_bytes);
*buffer_size = requested_bytes;
return device->hidden->mixbuf;
}
static int ALSA_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
{
Uint8 *sample_buf = (Uint8 *)buffer;
const int frame_size = SDL_AUDIO_FRAMESIZE(device->spec);
const int total_frames = buflen / frame_size;
snd_pcm_uframes_t frames_left = total_frames;
SDL_assert((buflen % frame_size) == 0);
while ((frames_left > 0) && !SDL_AtomicGet(&device->shutdown)) {
int status = ALSA_snd_pcm_readi(device->hidden->pcm_handle,
sample_buf, frames_left);
const snd_pcm_sframes_t total_available = ALSA_snd_pcm_avail(device->hidden->pcm_handle);
const int total_frames = SDL_min(buflen / frame_size, total_available);
if (status == -EAGAIN) {
break; // Can this even happen? Go back to WaitCaptureDevice, where the device lock isn't held.
} else if (status < 0) {
/*printf("ALSA: capture error %d\n", status);*/
status = ALSA_snd_pcm_recover(device->hidden->pcm_handle, status, 0);
if (status < 0) {
/* Hmm, not much we can do - abort */
SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
"ALSA read failed (unrecoverable): %s\n",
ALSA_snd_strerror(status));
return -1;
}
break; // Go back to WaitCaptureDevice, where the device lock isn't held.
const int rc = ALSA_snd_pcm_readi(device->hidden->pcm_handle, buffer, total_frames);
SDL_assert(rc != -EAGAIN); // assuming this can't happen if we used snd_pcm_wait and queried for available space. snd_pcm_recover won't handle it!
if (rc < 0) {
const int status = ALSA_snd_pcm_recover(device->hidden->pcm_handle, rc, 0);
if (status < 0) {
// Hmm, not much we can do - abort
SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "ALSA read failed (unrecoverable): %s", ALSA_snd_strerror(rc));
return -1;
}
/*printf("ALSA: captured %d bytes\n", status * frame_size);*/
sample_buf += status * frame_size;
frames_left -= status;
return 0; // go back to WaitDevice and try again.
} else if (rc > 0) {
device->hidden->swizzle_func(device, buffer, total_frames - rc);
}
device->hidden->swizzle_func(device, buffer, total_frames - frames_left);
//SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "ALSA: captured %d bytes", rc * frame_size);
return (total_frames - frames_left) * frame_size;
return rc * frame_size;
}
static void ALSA_FlushCapture(SDL_AudioDevice *device)
@ -445,9 +465,7 @@ static void ALSA_CloseDevice(SDL_AudioDevice *device)
{
if (device->hidden) {
if (device->hidden->pcm_handle) {
/* Wait for the submitted audio to drain
ALSA_snd_pcm_drop() can hang, so don't use that.
*/
// Wait for the submitted audio to drain. ALSA_snd_pcm_drop() can hang, so don't use that.
SDL_Delay(((device->sample_frames * 1000) / device->spec.freq) * 2);
ALSA_snd_pcm_close(device->hidden->pcm_handle);
}
@ -463,11 +481,11 @@ static int ALSA_set_buffer_size(SDL_AudioDevice *device, snd_pcm_hw_params_t *pa
snd_pcm_uframes_t persize;
unsigned int periods;
/* Copy the hardware parameters for this setup */
// Copy the hardware parameters for this setup
snd_pcm_hw_params_alloca(&hwparams);
ALSA_snd_pcm_hw_params_copy(hwparams, params);
/* Attempt to match the period size to the requested buffer size */
// Attempt to match the period size to the requested buffer size
persize = device->sample_frames;
status = ALSA_snd_pcm_hw_params_set_period_size_near(
device->hidden->pcm_handle, hwparams, &persize, NULL);
@ -475,7 +493,7 @@ static int ALSA_set_buffer_size(SDL_AudioDevice *device, snd_pcm_hw_params_t *pa
return -1;
}
/* Need to at least double buffer */
// Need to at least double buffer
periods = 2;
status = ALSA_snd_pcm_hw_params_set_periods_min(
device->hidden->pcm_handle, hwparams, &periods, NULL);
@ -489,7 +507,7 @@ static int ALSA_set_buffer_size(SDL_AudioDevice *device, snd_pcm_hw_params_t *pa
return -1;
}
/* "set" the hardware with the desired parameters */
// "set" the hardware with the desired parameters
status = ALSA_snd_pcm_hw_params(device->hidden->pcm_handle, hwparams);
if (status < 0) {
return -1;
@ -497,14 +515,14 @@ static int ALSA_set_buffer_size(SDL_AudioDevice *device, snd_pcm_hw_params_t *pa
device->sample_frames = persize;
/* This is useful for debugging */
// This is useful for debugging
if (SDL_getenv("SDL_AUDIO_ALSA_DEBUG")) {
snd_pcm_uframes_t bufsize;
ALSA_snd_pcm_hw_params_get_buffer_size(hwparams, &bufsize);
SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
"ALSA: period size = %ld, periods = %u, buffer size = %lu\n",
"ALSA: period size = %ld, periods = %u, buffer size = %lu",
persize, periods, bufsize);
}
@ -516,14 +534,14 @@ static int ALSA_OpenDevice(SDL_AudioDevice *device)
const SDL_bool iscapture = device->iscapture;
int status = 0;
/* Initialize all variables that we clean on shutdown */
// Initialize all variables that we clean on shutdown
device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
if (!device->hidden) {
return -1;
}
/* Open the audio device */
/* Name of device should depend on # channels in spec */
// Open the audio device
// Name of device should depend on # channels in spec
snd_pcm_t *pcm_handle = NULL;
status = ALSA_snd_pcm_open(&pcm_handle,
get_audio_device(device->handle, device->spec.channels),
@ -536,7 +554,7 @@ static int ALSA_OpenDevice(SDL_AudioDevice *device)
device->hidden->pcm_handle = pcm_handle;
/* Figure out what the hardware is capable of */
// Figure out what the hardware is capable of
snd_pcm_hw_params_t *hwparams = NULL;
snd_pcm_hw_params_alloca(&hwparams);
status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams);
@ -544,14 +562,14 @@ static int ALSA_OpenDevice(SDL_AudioDevice *device)
return SDL_SetError("ALSA: Couldn't get hardware config: %s", ALSA_snd_strerror(status));
}
/* SDL only uses interleaved sample output */
// SDL only uses interleaved sample output
status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
SND_PCM_ACCESS_RW_INTERLEAVED);
if (status < 0) {
return SDL_SetError("ALSA: Couldn't set interleaved access: %s", ALSA_snd_strerror(status));
}
/* Try for a closest match on audio format */
// Try for a closest match on audio format
snd_pcm_format_t format = 0;
const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(device->spec.format);
SDL_AudioFormat test_format;
@ -593,9 +611,8 @@ static int ALSA_OpenDevice(SDL_AudioDevice *device)
}
device->spec.format = test_format;
/* Validate number of channels and determine if swizzling is necessary
* Assume original swizzling, until proven otherwise.
*/
// Validate number of channels and determine if swizzling is necessary.
// Assume original swizzling, until proven otherwise.
device->hidden->swizzle_func = swizzle_alsa_channels;
#ifdef SND_CHMAP_API_VERSION
snd_pcm_chmap_t *chmap = ALSA_snd_pcm_get_chmap(pcm_handle);
@ -607,11 +624,11 @@ static int ALSA_OpenDevice(SDL_AudioDevice *device)
device->hidden->swizzle_func = no_swizzle;
}
}
free(chmap); /* This should NOT be SDL_free() */
free(chmap); // This should NOT be SDL_free()
}
#endif /* SND_CHMAP_API_VERSION */
#endif // SND_CHMAP_API_VERSION
/* Set the number of channels */
// Set the number of channels
status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
device->spec.channels);
unsigned int channels = device->spec.channels;
@ -623,7 +640,7 @@ static int ALSA_OpenDevice(SDL_AudioDevice *device)
device->spec.channels = channels;
}
/* Set the audio rate */
// Set the audio rate
unsigned int rate = device->spec.freq;
status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
&rate, NULL);
@ -632,13 +649,13 @@ static int ALSA_OpenDevice(SDL_AudioDevice *device)
}
device->spec.freq = rate;
/* Set the buffer size, in samples */
// Set the buffer size, in samples
status = ALSA_set_buffer_size(device, hwparams);
if (status < 0) {
return SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status));
}
/* Set the software parameters */
// Set the software parameters
snd_pcm_sw_params_t *swparams = NULL;
snd_pcm_sw_params_alloca(&swparams);
status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
@ -665,8 +682,8 @@ static int ALSA_OpenDevice(SDL_AudioDevice *device)
// Allocate mixing buffer
if (!iscapture) {
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
if (device->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
if (!device->hidden->mixbuf) {
return -1;
}
SDL_memset(device->hidden->mixbuf, device->silence_value, device->buffer_size);
}
@ -679,35 +696,26 @@ static int ALSA_OpenDevice(SDL_AudioDevice *device)
ALSA_snd_pcm_start(pcm_handle);
/* We're ready to rock and roll. :-) */
return 0;
return 0; // We're ready to rock and roll. :-)
}
typedef struct ALSA_Device
{
char *name;
SDL_bool iscapture;
struct ALSA_Device *next;
} ALSA_Device;
static void add_device(const SDL_bool iscapture, const char *name, void *hint, ALSA_Device **pSeen)
{
ALSA_Device *dev = SDL_malloc(sizeof(ALSA_Device));
char *desc;
char *handle = NULL;
char *ptr;
if (dev == NULL) {
if (!dev) {
return;
}
/* Not all alsa devices are enumerable via snd_device_name_get_hint
(i.e. bluetooth devices). Therefore if hint is passed in to this
function as NULL, assume name contains desc.
Make sure not to free the storage associated with desc in this case */
// Not all alsa devices are enumerable via snd_device_name_get_hint
// (i.e. bluetooth devices). Therefore if hint is passed in to this
// function as NULL, assume name contains desc.
// Make sure not to free the storage associated with desc in this case
if (hint) {
desc = ALSA_snd_device_name_get_hint(hint, "DESC");
if (desc == NULL) {
if (!desc) {
SDL_free(dev);
return;
}
@ -717,34 +725,34 @@ static void add_device(const SDL_bool iscapture, const char *name, void *hint, A
SDL_assert(name != NULL);
/* 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. */
// 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.
ptr = SDL_strchr(desc, '\n');
if (ptr != NULL) {
if (ptr) {
*ptr = '\0';
}
/*printf("ALSA: adding %s device '%s' (%s)\n", iscapture ? "capture" : "output", name, desc);*/
//SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "ALSA: adding %s device '%s' (%s)", iscapture ? "capture" : "output", name, desc);
handle = SDL_strdup(name);
if (handle == NULL) {
dev->name = SDL_strdup(name);
if (!dev->name) {
if (hint) {
free(desc); /* This should NOT be SDL_free() */
free(desc); // This should NOT be SDL_free()
}
SDL_free(dev->name);
SDL_free(dev);
return;
}
/* Note that spec is NULL, because we are required to open the device before
* acquiring the mix format, making this information inaccessible at
* enumeration time
*/
SDL_AddAudioDevice(iscapture, desc, NULL, handle);
// Note that spec is NULL, because we are required to open the device before
// acquiring the mix format, making this information inaccessible at
// enumeration time
SDL_AddAudioDevice(iscapture, desc, NULL, dev);
if (hint) {
free(desc); /* This should NOT be SDL_free() */
free(desc); // This should NOT be SDL_free()
}
dev->name = handle;
dev->iscapture = iscapture;
dev->next = *pSeen;
*pSeen = dev;
@ -770,13 +778,13 @@ static void ALSA_HotplugIteration(SDL_bool *has_default_output, SDL_bool *has_de
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. */
// 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 (int i = 0; hints[i]; i++) {
char *name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
if (name == NULL) {
if (!name) {
continue;
}
@ -797,31 +805,31 @@ static void ALSA_HotplugIteration(SDL_bool *has_default_output, SDL_bool *has_de
}
}
free(name); /* This should NOT be SDL_free() */
free(name); // This should NOT be SDL_free()
}
}
/* look through the list of device names to find matches */
// look through the list of device names to find matches
if (match || (has_default >= 0)) { // did we find a device name prefix we like at all...?
for (int i = 0; hints[i]; i++) {
char *name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
if (name == NULL) {
if (!name) {
continue;
}
// only want physical hardware interfaces
const SDL_bool is_default = (has_default == i) ? SDL_TRUE : SDL_FALSE;
if (is_default || (match != NULL && SDL_strncmp(name, match, match_len) == 0)) {
const SDL_bool is_default = (has_default == i);
if (is_default || (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);
const SDL_bool isoutput = (!ioid) || (SDL_strcmp(ioid, "Output") == 0);
const SDL_bool isinput = (!ioid) || (SDL_strcmp(ioid, "Input") == 0);
SDL_bool have_output = SDL_FALSE;
SDL_bool have_input = SDL_FALSE;
free(ioid);
free(ioid); // This should NOT be SDL_free()
if (!isoutput && !isinput) {
free(name);
free(name); // This should NOT be SDL_free()
continue;
}
@ -831,7 +839,7 @@ static void ALSA_HotplugIteration(SDL_bool *has_default_output, SDL_bool *has_de
} else if (has_default_capture && isinput) {
*has_default_capture = SDL_TRUE;
}
free(name);
free(name); // This should NOT be SDL_free()
continue;
}
@ -866,20 +874,20 @@ static void ALSA_HotplugIteration(SDL_bool *has_default_output, SDL_bool *has_de
}
}
free(name); /* This should NOT be SDL_free() */
free(name); // This should NOT be SDL_free()
}
}
ALSA_snd_device_name_free_hint(hints);
hotplug_devices = seen; /* now we have a known-good list of attached devices. */
hotplug_devices = seen; // now we have a known-good list of attached devices.
/* report anything still in unseen as removed. */
// report anything still in unseen as removed.
ALSA_Device *next = NULL;
for (ALSA_Device *dev = unseen; dev; dev = next) {
/*printf("ALSA: removing usb %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
//SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "ALSA: removing %s device '%s'", dev->iscapture ? "capture" : "output", dev->name);
next = dev->next;
SDL_AudioDeviceDisconnected(SDL_FindPhysicalAudioDeviceByHandle(dev->name));
SDL_AudioDeviceDisconnected(SDL_FindPhysicalAudioDeviceByHandle(dev));
SDL_free(dev->name);
SDL_free(dev);
}
@ -895,13 +903,13 @@ static int SDLCALL ALSA_HotplugThread(void *arg)
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_LOW);
while (!SDL_AtomicGet(&ALSA_hotplug_shutdown)) {
/* Block awhile before checking again, unless we're told to stop. */
// Block awhile before checking again, unless we're told to stop.
const Uint64 ticks = SDL_GetTicks() + 5000;
while (!SDL_AtomicGet(&ALSA_hotplug_shutdown) && SDL_GetTicks() < ticks) {
SDL_Delay(100);
}
ALSA_HotplugIteration(NULL, NULL); /* run the check. */
ALSA_HotplugIteration(NULL, NULL); // run the check.
}
return 0;
@ -913,43 +921,46 @@ static void ALSA_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice
// ALSA doesn't have a concept of a changeable default device, afaik, so we expose a generic default
// device here. It's the best we can do at this level.
SDL_bool has_default_output = SDL_FALSE, has_default_capture = SDL_FALSE;
ALSA_HotplugIteration(&has_default_output, &has_default_capture); // run once now before a thread continues to check. */
ALSA_HotplugIteration(&has_default_output, &has_default_capture); // run once now before a thread continues to check.
if (has_default_output) {
*default_output = SDL_AddAudioDevice(/*iscapture=*/SDL_FALSE, "ALSA default output device", NULL, SDL_strdup("default"));
*default_output = SDL_AddAudioDevice(/*iscapture=*/SDL_FALSE, "ALSA default output device", NULL, (void*)&default_output_handle);
}
if (has_default_capture) {
*default_capture = SDL_AddAudioDevice(/*iscapture=*/SDL_TRUE, "ALSA default capture device", NULL, SDL_strdup("default"));
*default_capture = SDL_AddAudioDevice(/*iscapture=*/SDL_TRUE, "ALSA default capture device", NULL, (void*)&default_capture_handle);
}
#if SDL_ALSA_HOTPLUG_THREAD
SDL_AtomicSet(&ALSA_hotplug_shutdown, 0);
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. */
// if the thread doesn't spin, oh well, you just don't get further hotplug events.
#endif
}
static void ALSA_Deinitialize(void)
static void ALSA_DeinitializeStart(void)
{
ALSA_Device *dev;
ALSA_Device *next;
#if SDL_ALSA_HOTPLUG_THREAD
if (ALSA_hotplug_thread != NULL) {
if (ALSA_hotplug_thread) {
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. */
// 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);*/
//SDL_LogInfo(SDL_LOG_CATEGORY_AUDIO, "ALSA: at shutdown, removing %s device '%s'", dev->iscapture ? "capture" : "output", dev->name);
next = dev->next;
SDL_free(dev->name);
SDL_free(dev);
}
hotplug_devices = NULL;
}
static void ALSA_Deinitialize(void)
{
UnloadALSALibrary();
}
@ -959,13 +970,13 @@ static SDL_bool ALSA_Init(SDL_AudioDriverImpl *impl)
return SDL_FALSE;
}
/* Set the function pointers */
impl->DetectDevices = ALSA_DetectDevices;
impl->OpenDevice = ALSA_OpenDevice;
impl->WaitDevice = ALSA_WaitDevice;
impl->GetDeviceBuf = ALSA_GetDeviceBuf;
impl->PlayDevice = ALSA_PlayDevice;
impl->CloseDevice = ALSA_CloseDevice;
impl->DeinitializeStart = ALSA_DeinitializeStart;
impl->Deinitialize = ALSA_Deinitialize;
impl->WaitCaptureDevice = ALSA_WaitDevice;
impl->CaptureFromDevice = ALSA_CaptureFromDevice;
@ -973,11 +984,11 @@ static SDL_bool ALSA_Init(SDL_AudioDriverImpl *impl)
impl->HasCaptureSupport = SDL_TRUE;
return SDL_TRUE; /* this audio target is available. */
return SDL_TRUE;
}
AudioBootStrap ALSA_bootstrap = {
"alsa", "ALSA PCM audio", ALSA_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_ALSA */
#endif // SDL_AUDIO_DRIVER_ALSA

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -29,14 +29,14 @@
struct SDL_PrivateAudioData
{
/* The audio device handle */
// The audio device handle
snd_pcm_t *pcm_handle;
/* Raw mixing buffer */
// Raw mixing buffer
Uint8 *mixbuf;
/* swizzle function */
// swizzle function
void (*swizzle_func)(SDL_AudioDevice *_this, void *buffer, Uint32 bufferlen);
};
#endif /* SDL_ALSA_audio_h_ */
#endif // SDL_ALSA_audio_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -25,7 +25,6 @@
// Output audio to Android (legacy interface)
#include "../SDL_sysaudio.h"
#include "../SDL_audio_c.h"
#include "SDL_androidaudio.h"
#include "../../core/android/SDL_android.h"
@ -43,8 +42,8 @@ static SDL_AudioDevice *captureDevice = NULL;
static int ANDROIDAUDIO_OpenDevice(SDL_AudioDevice *device)
{
device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
if (!device->hidden) {
return -1;
}
const SDL_bool iscapture = device->iscapture;
@ -132,13 +131,13 @@ void ANDROIDAUDIO_PauseDevices(void)
{
// TODO: Handle multiple devices?
struct SDL_PrivateAudioData *hidden;
if (audioDevice != NULL && audioDevice->hidden != NULL) {
if (audioDevice && audioDevice->hidden) {
hidden = (struct SDL_PrivateAudioData *)audioDevice->hidden;
SDL_LockMutex(audioDevice->lock);
hidden->resume = SDL_TRUE;
}
if (captureDevice != NULL && captureDevice->hidden != NULL) {
if (captureDevice && captureDevice->hidden) {
hidden = (struct SDL_PrivateAudioData *)captureDevice->hidden;
SDL_LockMutex(captureDevice->lock);
hidden->resume = SDL_TRUE;
@ -150,7 +149,7 @@ void ANDROIDAUDIO_ResumeDevices(void)
{
// TODO: Handle multiple devices?
struct SDL_PrivateAudioData *hidden;
if (audioDevice != NULL && audioDevice->hidden != NULL) {
if (audioDevice && audioDevice->hidden) {
hidden = (struct SDL_PrivateAudioData *)audioDevice->hidden;
if (hidden->resume) {
hidden->resume = SDL_FALSE;
@ -158,7 +157,7 @@ void ANDROIDAUDIO_ResumeDevices(void)
}
}
if (captureDevice != NULL && captureDevice->hidden != NULL) {
if (captureDevice && captureDevice->hidden) {
hidden = (struct SDL_PrivateAudioData *)captureDevice->hidden;
if (hidden->resume) {
hidden->resume = SDL_FALSE;
@ -172,7 +171,7 @@ static SDL_bool ANDROIDAUDIO_Init(SDL_AudioDriverImpl *impl)
// !!! FIXME: if on Android API < 24, DetectDevices and Deinitialize should be NULL and OnlyHasDefaultOutputDevice and OnlyHasDefaultCaptureDevice should be SDL_TRUE, since audio device enum and hotplug appears to require Android 7.0+.
impl->ThreadInit = Android_AudioThreadInit;
impl->DetectDevices = Android_StartAudioHotplug;
impl->Deinitialize = Android_StopAudioHotplug;
impl->DeinitializeStart = Android_StopAudioHotplug;
impl->OpenDevice = ANDROIDAUDIO_OpenDevice;
impl->PlayDevice = ANDROIDAUDIO_PlayDevice;
impl->GetDeviceBuf = ANDROIDAUDIO_GetDeviceBuf;

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -35,4 +35,4 @@ static void ANDROIDAUDIO_PauseDevices(void) {}
#endif
#endif /* SDL_androidaudio_h_ */
#endif // SDL_androidaudio_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -39,7 +39,7 @@
#include <AudioToolbox/AudioToolbox.h>
#include <AudioUnit/AudioUnit.h>
/* Things named "Master" were renamed to "Main" in macOS 12.0's SDK. */
// Things named "Master" were renamed to "Main" in macOS 12.0's SDK.
#ifdef MACOSX_COREAUDIO
#include <AvailabilityMacros.h>
#ifndef MAC_OS_VERSION_12_0
@ -65,4 +65,4 @@ struct SDL_PrivateAudioData
#endif
};
#endif /* SDL_coreaudio_h_ */
#endif // SDL_coreaudio_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -22,7 +22,6 @@
#ifdef SDL_AUDIO_DRIVER_COREAUDIO
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_coreaudio.h"
#include "../../thread/SDL_systhread.h"
@ -79,9 +78,9 @@ static OSStatus DeviceAliveNotification(AudioObjectID devid, UInt32 num_addr, co
SDL_bool dead = SDL_FALSE;
if (error == kAudioHardwareBadDeviceError) {
dead = SDL_TRUE; /* device was unplugged. */
dead = SDL_TRUE; // device was unplugged.
} else if ((error == kAudioHardwareNoError) && (!alive)) {
dead = SDL_TRUE; /* device died in some other way. */
dead = SDL_TRUE; // device died in some other way.
}
if (dead) {
@ -186,7 +185,7 @@ static void RefreshPhysicalDevices(void)
CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr), kCFStringEncodingUTF8);
char *name = (char *)SDL_malloc(len + 1);
SDL_bool usable = ((name != NULL) && (CFStringGetCString(cfstr, name, len + 1, kCFStringEncodingUTF8))) ? SDL_TRUE : SDL_FALSE;
SDL_bool usable = ((name != NULL) && (CFStringGetCString(cfstr, name, len + 1, kCFStringEncodingUTF8)));
CFRelease(cfstr);
@ -232,7 +231,7 @@ static OSStatus DeviceListChangedNotification(AudioObjectID systemObj, UInt32 nu
static OSStatus DefaultAudioDeviceChangedNotification(AudioObjectID inObjectID, const AudioObjectPropertyAddress *addr)
{
AudioDeviceID devid;
Uint32 size = sizeof(devid);
UInt32 size = sizeof(devid);
if (AudioObjectGetPropertyData(inObjectID, addr, 0, NULL, &size, &devid) == noErr) {
SDL_DefaultAudioDeviceChanged(SDL_FindPhysicalAudioDeviceByHandle((void *)((size_t)devid)));
}
@ -263,7 +262,7 @@ static void COREAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioD
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, DeviceListChangedNotification, NULL);
/* Get the Device ID */
// Get the Device ID
UInt32 size;
AudioDeviceID devid;
@ -428,7 +427,7 @@ static SDL_bool UpdateAudioSession(SDL_AudioDevice *device, SDL_bool open, SDL_b
/* AVAudioSessionCategoryOptionAllowBluetooth isn't available in the SDK for
Apple TV but is still needed in order to output to Bluetooth devices.
*/
options |= 0x4; /* AVAudioSessionCategoryOptionAllowBluetooth; */
options |= 0x4; // AVAudioSessionCategoryOptionAllowBluetooth;
}
if (category == AVAudioSessionCategoryPlayAndRecord) {
options |= AVAudioSessionCategoryOptionAllowBluetoothA2DP |
@ -441,7 +440,7 @@ static SDL_bool UpdateAudioSession(SDL_AudioDevice *device, SDL_bool open, SDL_b
if ([session respondsToSelector:@selector(setCategory:mode:options:error:)]) {
if (![session.category isEqualToString:category] || session.categoryOptions != options) {
/* Stop the current session so we don't interrupt other application audio */
// Stop the current session so we don't interrupt other application audio
PauseAudioDevices();
[session setActive:NO error:nil];
session_active = SDL_FALSE;
@ -454,7 +453,7 @@ static SDL_bool UpdateAudioSession(SDL_AudioDevice *device, SDL_bool open, SDL_b
}
} else {
if (![session.category isEqualToString:category]) {
/* Stop the current session so we don't interrupt other application audio */
// Stop the current session so we don't interrupt other application audio
PauseAudioDevices();
[session setActive:NO error:nil];
session_active = SDL_FALSE;
@ -498,7 +497,7 @@ static SDL_bool UpdateAudioSession(SDL_AudioDevice *device, SDL_bool open, SDL_b
/* An interruption end notification is not guaranteed to be sent if
we were previously interrupted... resuming if needed when the app
becomes active seems to be the way to go. */
// Note: object: below needs to be nil, as otherwise it filters by the object, and session doesn't send foreground / active notifications. johna
// Note: object: below needs to be nil, as otherwise it filters by the object, and session doesn't send foreground / active notifications.
[center addObserver:listener
selector:@selector(applicationBecameActive:)
name:UIApplicationDidBecomeActiveNotification
@ -717,7 +716,7 @@ static int PrepareAudioQueue(SDL_AudioDevice *device)
SDL_UpdatedAudioDeviceFormat(device); // make sure this is correct.
/* Set the channel layout for the audio queue */
// Set the channel layout for the audio queue
AudioChannelLayout layout;
SDL_zero(layout);
switch (device->spec.channels) {
@ -740,7 +739,7 @@ static int PrepareAudioQueue(SDL_AudioDevice *device)
layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_5_1_A;
break;
case 7:
/* FIXME: Need to move channel[4] (BC) to channel[6] */
// FIXME: Need to move channel[4] (BC) to channel[6]
layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_6_1_A;
break;
case 8:
@ -763,14 +762,14 @@ static int PrepareAudioQueue(SDL_AudioDevice *device)
int numAudioBuffers = 2;
const double msecs = (device->sample_frames / ((double)device->spec.freq)) * 1000.0;
if (msecs < MINIMUM_AUDIO_BUFFER_TIME_MS) { /* use more buffers if we have a VERY small sample set. */
if (msecs < MINIMUM_AUDIO_BUFFER_TIME_MS) { // use more buffers if we have a VERY small sample set.
numAudioBuffers = ((int)SDL_ceil(MINIMUM_AUDIO_BUFFER_TIME_MS / msecs) * 2);
}
device->hidden->numAudioBuffers = numAudioBuffers;
device->hidden->audioBuffer = SDL_calloc(numAudioBuffers, sizeof(AudioQueueBufferRef));
if (device->hidden->audioBuffer == NULL) {
return SDL_OutOfMemory();
return -1;
}
#if DEBUG_COREAUDIO
@ -782,7 +781,7 @@ static int PrepareAudioQueue(SDL_AudioDevice *device)
CHECK_RESULT("AudioQueueAllocateBuffer");
SDL_memset(device->hidden->audioBuffer[i]->mAudioData, device->silence_value, device->hidden->audioBuffer[i]->mAudioDataBytesCapacity);
device->hidden->audioBuffer[i]->mAudioDataByteSize = device->hidden->audioBuffer[i]->mAudioDataBytesCapacity;
/* !!! FIXME: should we use AudioQueueEnqueueBufferWithParameters and specify all frames be "trimmed" so these are immediately ready to refill with SDL callback data? */
// !!! FIXME: should we use AudioQueueEnqueueBufferWithParameters and specify all frames be "trimmed" so these are immediately ready to refill with SDL callback data?
result = AudioQueueEnqueueBuffer(device->hidden->audioQueue, device->hidden->audioBuffer[i], 0, NULL);
CHECK_RESULT("AudioQueueEnqueueBuffer");
}
@ -831,10 +830,10 @@ static int AudioQueueThreadEntry(void *arg)
static int COREAUDIO_OpenDevice(SDL_AudioDevice *device)
{
/* Initialize all variables that we clean on shutdown */
// Initialize all variables that we clean on shutdown
device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
return -1;
}
#ifndef MACOSX_COREAUDIO
@ -842,7 +841,7 @@ static int COREAUDIO_OpenDevice(SDL_AudioDevice *device)
return -1;
}
/* Stop CoreAudio from doing expensive audio rate conversion */
// Stop CoreAudio from doing expensive audio rate conversion
@autoreleasepool {
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setPreferredSampleRate:device->spec.freq error:nil];
@ -856,12 +855,12 @@ static int COREAUDIO_OpenDevice(SDL_AudioDevice *device)
device->spec.channels = session.preferredOutputNumberOfChannels;
}
#else
/* Calling setPreferredOutputNumberOfChannels seems to break audio output on iOS */
#endif /* TARGET_OS_TV */
// Calling setPreferredOutputNumberOfChannels seems to break audio output on iOS
#endif // TARGET_OS_TV
}
#endif
/* Setup a AudioStreamBasicDescription with the requested format */
// Setup a AudioStreamBasicDescription with the requested format
AudioStreamBasicDescription *strdesc = &device->hidden->strdesc;
strdesc->mFormatID = kAudioFormatLinearPCM;
strdesc->mFormatFlags = kLinearPCMFormatFlagIsPacked;
@ -872,7 +871,7 @@ static int COREAUDIO_OpenDevice(SDL_AudioDevice *device)
const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(device->spec.format);
SDL_AudioFormat test_format;
while ((test_format = *(closefmts++)) != 0) {
/* CoreAudio handles most of SDL's formats natively. */
// CoreAudio handles most of SDL's formats natively.
switch (test_format) {
case SDL_AUDIO_U8:
case SDL_AUDIO_S8:
@ -890,7 +889,7 @@ static int COREAUDIO_OpenDevice(SDL_AudioDevice *device)
break;
}
if (!test_format) { /* shouldn't happen, but just in case... */
if (!test_format) { // shouldn't happen, but just in case...
return SDL_SetError("%s: Unsupported audio format", "coreaudio");
}
device->spec.format = test_format;
@ -914,10 +913,10 @@ static int COREAUDIO_OpenDevice(SDL_AudioDevice *device)
}
#endif
/* This has to init in a new thread so it can get its own CFRunLoop. :/ */
// This has to init in a new thread so it can get its own CFRunLoop. :/
device->hidden->ready_semaphore = SDL_CreateSemaphore(0);
if (!device->hidden->ready_semaphore) {
return -1; /* oh well. */
return -1; // oh well.
}
char threadname[64];
@ -940,7 +939,7 @@ static int COREAUDIO_OpenDevice(SDL_AudioDevice *device)
return (device->hidden->thread != NULL) ? 0 : -1;
}
static void COREAUDIO_Deinitialize(void)
static void COREAUDIO_DeinitializeStart(void)
{
#ifdef MACOSX_COREAUDIO
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &devlist_address, DeviceListChangedNotification, NULL);
@ -951,14 +950,13 @@ static void COREAUDIO_Deinitialize(void)
static SDL_bool COREAUDIO_Init(SDL_AudioDriverImpl *impl)
{
/* Set the function pointers */
impl->OpenDevice = COREAUDIO_OpenDevice;
impl->PlayDevice = COREAUDIO_PlayDevice;
impl->GetDeviceBuf = COREAUDIO_GetDeviceBuf;
impl->CaptureFromDevice = COREAUDIO_CaptureFromDevice;
impl->FlushCapture = COREAUDIO_FlushCapture;
impl->CloseDevice = COREAUDIO_CloseDevice;
impl->Deinitialize = COREAUDIO_Deinitialize;
impl->DeinitializeStart = COREAUDIO_DeinitializeStart;
#ifdef MACOSX_COREAUDIO
impl->DetectDevices = COREAUDIO_DetectDevices;
@ -971,11 +969,11 @@ static SDL_bool COREAUDIO_Init(SDL_AudioDriverImpl *impl)
impl->ProvidesOwnCallbackThread = SDL_TRUE;
impl->HasCaptureSupport = SDL_TRUE;
return SDL_TRUE; /* this audio target is available. */
return SDL_TRUE;
}
AudioBootStrap COREAUDIO_bootstrap = {
"coreaudio", "CoreAudio", COREAUDIO_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_COREAUDIO */
#endif // SDL_AUDIO_DRIVER_COREAUDIO

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -22,7 +22,7 @@
#ifdef SDL_AUDIO_DRIVER_DSOUND
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_directsound.h"
#include <mmreg.h>
#ifdef HAVE_MMDEVICEAPI_H
@ -62,7 +62,7 @@ static void DSOUND_Unload(void)
pDirectSoundCaptureEnumerateW = NULL;
pGetDeviceID = NULL;
if (DSoundDLL != NULL) {
if (DSoundDLL) {
SDL_UnloadObject(DSoundDLL);
DSoundDLL = NULL;
}
@ -75,7 +75,7 @@ static int DSOUND_Load(void)
DSOUND_Unload();
DSoundDLL = SDL_LoadObject("DSOUND.DLL");
if (DSoundDLL == NULL) {
if (!DSoundDLL) {
SDL_SetError("DirectSound: failed to load DSOUND.DLL");
} else {
// Now make sure we have DirectX 8 or better...
@ -176,7 +176,7 @@ static BOOL CALLBACK FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVO
FindAllDevsData *data = (FindAllDevsData *) userdata;
if (guid != NULL) { // skip default device
char *str = WIN_LookupAudioDeviceName(desc, guid);
if (str != NULL) {
if (str) {
LPGUID cpyguid = (LPGUID)SDL_malloc(sizeof(GUID));
if (cpyguid) {
SDL_copyp(cpyguid, guid);
@ -225,64 +225,39 @@ static void DSOUND_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevi
}
static void DSOUND_WaitDevice(SDL_AudioDevice *device)
static int DSOUND_WaitDevice(SDL_AudioDevice *device)
{
DWORD status = 0;
DWORD cursor = 0;
DWORD junk = 0;
HRESULT result = DS_OK;
/* Semi-busy wait, since we have no way of getting play notification
on a primary mixing buffer located in hardware (DirectX 5.0)
*/
result = IDirectSoundBuffer_GetCurrentPosition(device->hidden->mixbuf,
&junk, &cursor);
if (result != DS_OK) {
if (result == DSERR_BUFFERLOST) {
IDirectSoundBuffer_Restore(device->hidden->mixbuf);
}
#ifdef DEBUG_SOUND
SetDSerror("DirectSound GetCurrentPosition", result);
#endif
return;
}
while ((cursor / device->buffer_size) == device->hidden->lastchunk) {
if (SDL_AtomicGet(&device->shutdown)) {
return;
}
SDL_Delay(1);
while (!SDL_AtomicGet(&device->shutdown)) {
DWORD status = 0;
DWORD cursor = 0;
DWORD junk = 0;
HRESULT result = DS_OK;
// Try to restore a lost sound buffer
IDirectSoundBuffer_GetStatus(device->hidden->mixbuf, &status);
if (status & DSBSTATUS_BUFFERLOST) {
IDirectSoundBuffer_Restore(device->hidden->mixbuf);
IDirectSoundBuffer_GetStatus(device->hidden->mixbuf, &status);
if (status & DSBSTATUS_BUFFERLOST) {
break;
} else if (!(status & DSBSTATUS_PLAYING)) {
result = IDirectSoundBuffer_Play(device->hidden->mixbuf, 0, 0, DSBPLAY_LOOPING);
} else {
// Find out where we are playing
result = IDirectSoundBuffer_GetCurrentPosition(device->hidden->mixbuf, &junk, &cursor);
if ((result == DS_OK) && ((cursor / device->buffer_size) != device->hidden->lastchunk)) {
break; // ready for next chunk!
}
}
if (!(status & DSBSTATUS_PLAYING)) {
result = IDirectSoundBuffer_Play(device->hidden->mixbuf, 0, 0,
DSBPLAY_LOOPING);
if (result == DS_OK) {
continue;
}
#ifdef DEBUG_SOUND
SetDSerror("DirectSound Play", result);
#endif
return;
}
// Find out where we are playing
result = IDirectSoundBuffer_GetCurrentPosition(device->hidden->mixbuf,
&junk, &cursor);
if (result != DS_OK) {
SetDSerror("DirectSound GetCurrentPosition", result);
return;
if ((result != DS_OK) && (result != DSERR_BUFFERLOST)) {
return -1;
}
SDL_Delay(1); // not ready yet; sleep a bit.
}
return 0;
}
static int DSOUND_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
@ -354,19 +329,20 @@ static Uint8 *DSOUND_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
return device->hidden->locked_buf;
}
static void DSOUND_WaitCaptureDevice(SDL_AudioDevice *device)
static int DSOUND_WaitCaptureDevice(SDL_AudioDevice *device)
{
struct SDL_PrivateAudioData *h = device->hidden;
while (!SDL_AtomicGet(&device->shutdown)) {
DWORD junk, cursor;
if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) != DS_OK) {
SDL_AudioDeviceDisconnected(device);
return;
return -1;
} else if ((cursor / device->buffer_size) != h->lastchunk) {
return;
break;
}
SDL_Delay(1);
}
return 0;
}
static int DSOUND_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
@ -408,18 +384,18 @@ static void DSOUND_FlushCapture(SDL_AudioDevice *device)
static void DSOUND_CloseDevice(SDL_AudioDevice *device)
{
if (device->hidden) {
if (device->hidden->mixbuf != NULL) {
if (device->hidden->mixbuf) {
IDirectSoundBuffer_Stop(device->hidden->mixbuf);
IDirectSoundBuffer_Release(device->hidden->mixbuf);
}
if (device->hidden->sound != NULL) {
if (device->hidden->sound) {
IDirectSound_Release(device->hidden->sound);
}
if (device->hidden->capturebuf != NULL) {
if (device->hidden->capturebuf) {
IDirectSoundCaptureBuffer_Stop(device->hidden->capturebuf);
IDirectSoundCaptureBuffer_Release(device->hidden->capturebuf);
}
if (device->hidden->capture != NULL) {
if (device->hidden->capture) {
IDirectSoundCapture_Release(device->hidden->capture);
}
SDL_free(device->hidden);
@ -515,8 +491,8 @@ static int DSOUND_OpenDevice(SDL_AudioDevice *device)
{
// Initialize all variables that we clean on shutdown
device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
if (!device->hidden) {
return -1;
}
// Open the audio device
@ -647,15 +623,21 @@ static int DSOUND_OpenDevice(SDL_AudioDevice *device)
return 0; // good to go.
}
static void DSOUND_Deinitialize(void)
static void DSOUND_DeinitializeStart(void)
{
#ifdef HAVE_MMDEVICEAPI_H
if (SupportsIMMDevice) {
SDL_IMMDevice_Quit();
SupportsIMMDevice = SDL_FALSE;
}
#endif
}
static void DSOUND_Deinitialize(void)
{
DSOUND_Unload();
#ifdef HAVE_MMDEVICEAPI_H
SupportsIMMDevice = SDL_FALSE;
#endif
}
static SDL_bool DSOUND_Init(SDL_AudioDriverImpl *impl)
@ -665,7 +647,7 @@ static SDL_bool DSOUND_Init(SDL_AudioDriverImpl *impl)
}
#ifdef HAVE_MMDEVICEAPI_H
SupportsIMMDevice = !(SDL_IMMDevice_Init() < 0);
SupportsIMMDevice = !(SDL_IMMDevice_Init(NULL) < 0);
#endif
impl->DetectDevices = DSOUND_DetectDevices;
@ -678,6 +660,7 @@ static SDL_bool DSOUND_Init(SDL_AudioDriverImpl *impl)
impl->FlushCapture = DSOUND_FlushCapture;
impl->CloseDevice = DSOUND_CloseDevice;
impl->FreeDeviceHandle = DSOUND_FreeDeviceHandle;
impl->DeinitializeStart = DSOUND_DeinitializeStart;
impl->Deinitialize = DSOUND_Deinitialize;
impl->HasCaptureSupport = SDL_TRUE;

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -24,7 +24,7 @@
// Output raw audio data to a file.
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_diskaudio.h"
// !!! FIXME: these should be SDL hints, not environment variables.
@ -35,9 +35,10 @@
#define DISKDEFAULT_INFILE "sdlaudio-in.raw"
#define DISKENVR_IODELAY "SDL_DISKAUDIODELAY"
static void DISKAUDIO_WaitDevice(SDL_AudioDevice *device)
static int DISKAUDIO_WaitDevice(SDL_AudioDevice *device)
{
SDL_Delay(device->hidden->io_delay);
return 0;
}
static int DISKAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
@ -86,7 +87,7 @@ static void DISKAUDIO_FlushCapture(SDL_AudioDevice *device)
static void DISKAUDIO_CloseDevice(SDL_AudioDevice *device)
{
if (device->hidden) {
if (device->hidden->io != NULL) {
if (device->hidden->io) {
SDL_RWclose(device->hidden->io);
}
SDL_free(device->hidden->mixbuf);
@ -98,7 +99,7 @@ static void DISKAUDIO_CloseDevice(SDL_AudioDevice *device)
static const char *get_filename(const SDL_bool iscapture)
{
const char *devname = SDL_getenv(iscapture ? DISKENVR_INFILE : DISKENVR_OUTFILE);
if (devname == NULL) {
if (!devname) {
devname = iscapture ? DISKDEFAULT_INFILE : DISKDEFAULT_OUTFILE;
}
return devname;
@ -111,11 +112,11 @@ static int DISKAUDIO_OpenDevice(SDL_AudioDevice *device)
const char *envr = SDL_getenv(DISKENVR_IODELAY);
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
if (!device->hidden) {
return -1;
}
if (envr != NULL) {
if (envr) {
device->hidden->io_delay = SDL_atoi(envr);
} else {
device->hidden->io_delay = ((device->sample_frames * 1000) / device->spec.freq);
@ -123,15 +124,15 @@ static int DISKAUDIO_OpenDevice(SDL_AudioDevice *device)
// Open the "audio device"
device->hidden->io = SDL_RWFromFile(fname, iscapture ? "rb" : "wb");
if (device->hidden->io == NULL) {
if (!device->hidden->io) {
return -1;
}
// Allocate mixing buffer
if (!iscapture) {
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
if (device->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
if (!device->hidden->mixbuf) {
return -1;
}
SDL_memset(device->hidden->mixbuf, device->silence_value, device->buffer_size);
}
@ -160,7 +161,6 @@ static SDL_bool DISKAUDIO_Init(SDL_AudioDriverImpl *impl)
impl->CloseDevice = DISKAUDIO_CloseDevice;
impl->DetectDevices = DISKAUDIO_DetectDevices;
impl->AllowsArbitraryDeviceNames = SDL_TRUE;
impl->HasCaptureSupport = SDL_TRUE;
return SDL_TRUE;

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -27,10 +27,10 @@
struct SDL_PrivateAudioData
{
/* The file descriptor for the audio device */
// The file descriptor for the audio device
SDL_RWops *io;
Uint32 io_delay;
Uint8 *mixbuf;
};
#endif /* SDL_diskaudio_h_ */
#endif // SDL_diskaudio_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -24,8 +24,8 @@
#ifdef SDL_AUDIO_DRIVER_OSS
#include <stdio.h> /* For perror() */
#include <string.h> /* For strerror() */
#include <stdio.h> // For perror()
#include <string.h> // For strerror()
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
@ -36,7 +36,6 @@
#include <sys/soundcard.h>
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "../../SDL_utils_c.h"
#include "SDL_dspaudio.h"
@ -71,8 +70,8 @@ static int DSP_OpenDevice(SDL_AudioDevice *device)
// Initialize all variables that we clean on shutdown
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
if (!device->hidden) {
return -1;
}
// Open the audio device; we hardcode the device path in `device->name` for lack of better info, so use that.
@ -97,7 +96,7 @@ static int DSP_OpenDevice(SDL_AudioDevice *device)
return SDL_SetError("Couldn't get audio format list");
}
/* Try for a closest match on audio format */
// Try for a closest match on audio format
int format = 0;
SDL_AudioFormat test_format;
const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(device->spec.format);
@ -156,7 +155,7 @@ static int DSP_OpenDevice(SDL_AudioDevice *device)
}
device->spec.freq = value;
/* Calculate the final parameters for this audio specification */
// Calculate the final parameters for this audio specification
SDL_UpdatedAudioDeviceFormat(device);
/* Determine the power of two of the fragment size
@ -168,9 +167,9 @@ static int DSP_OpenDevice(SDL_AudioDevice *device)
while ((0x01U << frag_spec) < device->buffer_size) {
frag_spec++;
}
frag_spec |= 0x00020000; /* two fragments, for low latency */
frag_spec |= 0x00020000; // two fragments, for low latency
/* Set the audio buffering parameters */
// Set the audio buffering parameters
#ifdef DEBUG_AUDIO
fprintf(stderr, "Requesting %d fragments of size %d\n",
(frag_spec >> 16), 1 << (frag_spec & 0xFFFF));
@ -189,11 +188,11 @@ static int DSP_OpenDevice(SDL_AudioDevice *device)
}
#endif
/* Allocate mixing buffer */
// Allocate mixing buffer
if (!device->iscapture) {
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
if (device->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
if (!device->hidden->mixbuf) {
return -1;
}
SDL_memset(device->hidden->mixbuf, device->silence_value, device->buffer_size);
}
@ -201,7 +200,7 @@ static int DSP_OpenDevice(SDL_AudioDevice *device)
return 0; // We're ready to rock and roll. :-)
}
static void DSP_WaitDevice(SDL_AudioDevice *device)
static int DSP_WaitDevice(SDL_AudioDevice *device)
{
const unsigned long ioctlreq = device->iscapture ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE;
struct SDL_PrivateAudioData *h = device->hidden;
@ -215,14 +214,15 @@ static void DSP_WaitDevice(SDL_AudioDevice *device)
}
// Hmm, not much we can do - abort
fprintf(stderr, "dsp WaitDevice ioctl failed (unrecoverable): %s\n", strerror(errno));
SDL_AudioDeviceDisconnected(device);
return;
return -1;
} else if (info.bytes < device->buffer_size) {
SDL_Delay(10);
} else {
break; // ready to go!
}
}
return 0;
}
static int DSP_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
@ -268,8 +268,8 @@ static void DSP_FlushCapture(SDL_AudioDevice *device)
static SDL_bool InitTimeDevicesExist = SDL_FALSE;
static SDL_bool look_for_devices_test(int fd)
{
InitTimeDevicesExist = SDL_TRUE; /* note that _something_ exists. */
/* Don't add to the device list, we're just seeing if any devices exist. */
InitTimeDevicesExist = SDL_TRUE; // note that _something_ exists.
// Don't add to the device list, we're just seeing if any devices exist.
return SDL_FALSE;
}
@ -279,10 +279,9 @@ static SDL_bool DSP_Init(SDL_AudioDriverImpl *impl)
SDL_EnumUnixAudioDevices(SDL_FALSE, look_for_devices_test);
if (!InitTimeDevicesExist) {
SDL_SetError("dsp: No such audio device");
return SDL_FALSE; /* maybe try a different backend. */
return SDL_FALSE; // maybe try a different backend.
}
/* Set the function pointers */
impl->DetectDevices = DSP_DetectDevices;
impl->OpenDevice = DSP_OpenDevice;
impl->WaitDevice = DSP_WaitDevice;
@ -293,14 +292,13 @@ static SDL_bool DSP_Init(SDL_AudioDriverImpl *impl)
impl->CaptureFromDevice = DSP_CaptureFromDevice;
impl->FlushCapture = DSP_FlushCapture;
impl->AllowsArbitraryDeviceNames = SDL_TRUE;
impl->HasCaptureSupport = SDL_TRUE;
return SDL_TRUE; /* this audio target is available. */
return SDL_TRUE;
}
AudioBootStrap DSP_bootstrap = {
"dsp", "Open Sound System (/dev/dsp)", DSP_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_OSS */
#endif // SDL_AUDIO_DRIVER_OSS

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -27,11 +27,11 @@
struct SDL_PrivateAudioData
{
/* The file descriptor for the audio device */
// The file descriptor for the audio device
int audio_fd;
/* Raw mixing buffer */
// Raw mixing buffer
Uint8 *mixbuf;
};
#endif /* SDL_dspaudio_h_ */
#endif // SDL_dspaudio_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -22,15 +22,16 @@
// Output audio to nowhere...
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_dummyaudio.h"
// !!! FIXME: this should be an SDL hint, not an environment variable.
#define DUMMYENVR_IODELAY "SDL_DUMMYAUDIODELAY"
static void DUMMYAUDIO_WaitDevice(SDL_AudioDevice *device)
static int DUMMYAUDIO_WaitDevice(SDL_AudioDevice *device)
{
SDL_Delay(device->hidden->io_delay);
return 0;
}
static int DUMMYAUDIO_OpenDevice(SDL_AudioDevice *device)
@ -39,13 +40,13 @@ static int DUMMYAUDIO_OpenDevice(SDL_AudioDevice *device)
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
if (!device->hidden) {
return SDL_OutOfMemory();
return -1;
}
if (!device->iscapture) {
device->hidden->mixbuf = (Uint8 *) SDL_malloc(device->buffer_size);
if (!device->hidden->mixbuf) {
return SDL_OutOfMemory();
return -1;
}
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -22,7 +22,7 @@
#ifdef SDL_AUDIO_DRIVER_EMSCRIPTEN
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_emscriptenaudio.h"
#include <emscripten/emscripten.h>
@ -177,8 +177,8 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
// Initialize all variables that we clean on shutdown
device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
if (!device->hidden) {
return -1;
}
// limit to native freq
@ -188,8 +188,8 @@ static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *device)
if (!device->iscapture) {
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
if (device->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
if (!device->hidden->mixbuf) {
return -1;
}
SDL_memset(device->hidden->mixbuf, device->silence_value, device->buffer_size);
}
@ -321,7 +321,7 @@ static SDL_bool EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl *impl)
return true;
}
return false;
}) ? SDL_TRUE : SDL_FALSE;
});
if (!available) {
SDL_SetError("No audio context available");
@ -334,10 +334,10 @@ static SDL_bool EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl *impl)
return true;
}
return false;
}) ? SDL_TRUE : SDL_FALSE;
});
impl->HasCaptureSupport = capture_available ? SDL_TRUE : SDL_FALSE;
impl->OnlyHasDefaultCaptureDevice = capture_available ? SDL_TRUE : SDL_FALSE;
impl->HasCaptureSupport = capture_available;
impl->OnlyHasDefaultCaptureDevice = capture_available;
return available;
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -30,4 +30,4 @@ struct SDL_PrivateAudioData
Uint8 *mixbuf;
};
#endif /* SDL_emscriptenaudio_h_ */
#endif // SDL_emscriptenaudio_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -32,7 +32,6 @@
extern "C"
{
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_haikuaudio.h"

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -32,4 +32,4 @@ struct SDL_PrivateAudioData
int current_buffer_len;
};
#endif /* SDL_haikuaudio_h_ */
#endif // SDL_haikuaudio_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -22,7 +22,7 @@
#ifdef SDL_AUDIO_DRIVER_JACK
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_jackaudio.h"
#include "../../thread/SDL_systhread.h"
@ -43,6 +43,8 @@ static const char *(*JACK_jack_port_name)(const jack_port_t *);
static const char *(*JACK_jack_port_type)(const jack_port_t *);
static int (*JACK_jack_connect)(jack_client_t *, const char *, const char *);
static int (*JACK_jack_set_process_callback)(jack_client_t *, JackProcessCallback, void *);
static int (*JACK_jack_set_sample_rate_callback)(jack_client_t *, JackSampleRateCallback, void *);
static int (*JACK_jack_set_buffer_size_callback)(jack_client_t *, JackBufferSizeCallback, void *);
static int load_jack_syms(void);
@ -51,26 +53,26 @@ static int load_jack_syms(void);
static const char *jack_library = SDL_AUDIO_DRIVER_JACK_DYNAMIC;
static void *jack_handle = NULL;
/* !!! FIXME: this is copy/pasted in several places now */
// !!! FIXME: this is copy/pasted in several places now
static int load_jack_sym(const char *fn, void **addr)
{
*addr = SDL_LoadFunction(jack_handle, fn);
if (*addr == NULL) {
/* Don't call SDL_SetError(): SDL_LoadFunction already did. */
if (!*addr) {
// Don't call SDL_SetError(): SDL_LoadFunction already did.
return 0;
}
return 1;
}
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
// cast funcs to char* first, to please GCC's strict aliasing rules.
#define SDL_JACK_SYM(x) \
if (!load_jack_sym(#x, (void **)(char *)&JACK_##x)) \
return -1
static void UnloadJackLibrary(void)
{
if (jack_handle != NULL) {
if (jack_handle) {
SDL_UnloadObject(jack_handle);
jack_handle = NULL;
}
@ -79,11 +81,11 @@ static void UnloadJackLibrary(void)
static int LoadJackLibrary(void)
{
int retval = 0;
if (jack_handle == NULL) {
if (!jack_handle) {
jack_handle = SDL_LoadObject(jack_library);
if (jack_handle == NULL) {
if (!jack_handle) {
retval = -1;
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
// Don't call SDL_SetError(): SDL_LoadObject already did.
} else {
retval = load_jack_syms();
if (retval < 0) {
@ -108,7 +110,7 @@ static int LoadJackLibrary(void)
return 0;
}
#endif /* SDL_AUDIO_DRIVER_JACK_DYNAMIC */
#endif // SDL_AUDIO_DRIVER_JACK_DYNAMIC
static int load_jack_syms(void)
{
@ -129,18 +131,41 @@ static int load_jack_syms(void)
SDL_JACK_SYM(jack_port_type);
SDL_JACK_SYM(jack_connect);
SDL_JACK_SYM(jack_set_process_callback);
SDL_JACK_SYM(jack_set_sample_rate_callback);
SDL_JACK_SYM(jack_set_buffer_size_callback);
return 0;
}
static void jackShutdownCallback(void *arg) /* JACK went away; device is lost. */
static void jackShutdownCallback(void *arg) // JACK went away; device is lost.
{
SDL_AudioDeviceDisconnected((SDL_AudioDevice *)arg);
}
// !!! FIXME: implement and register these!
// typedef int(* JackSampleRateCallback)(jack_nframes_t nframes, void *arg)
// typedef int(* JackBufferSizeCallback)(jack_nframes_t nframes, void *arg)
static int jackSampleRateCallback(jack_nframes_t nframes, void *arg)
{
//SDL_Log("JACK Sample Rate Callback! %d", (int) nframes);
SDL_AudioDevice *device = (SDL_AudioDevice *) arg;
SDL_AudioSpec newspec;
SDL_copyp(&newspec, &device->spec);
newspec.freq = (int) nframes;
if (SDL_AudioDeviceFormatChanged(device, &newspec, device->sample_frames) < 0) {
SDL_AudioDeviceDisconnected(device);
}
return 0;
}
static int jackBufferSizeCallback(jack_nframes_t nframes, void *arg)
{
//SDL_Log("JACK Buffer Size Callback! %d", (int) nframes);
SDL_AudioDevice *device = (SDL_AudioDevice *) arg;
SDL_AudioSpec newspec;
SDL_copyp(&newspec, &device->spec);
if (SDL_AudioDeviceFormatChanged(device, &newspec, (int) nframes) < 0) {
SDL_AudioDeviceDisconnected(device);
}
return 0;
}
static int jackProcessPlaybackCallback(jack_nframes_t nframes, void *arg)
{
@ -269,34 +294,34 @@ static int JACK_OpenDevice(SDL_AudioDevice *device)
int ports = 0;
int i;
/* Initialize all variables that we clean on shutdown */
// Initialize all variables that we clean on shutdown
device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
if (!device->hidden) {
return -1;
}
client = JACK_jack_client_open(GetJackAppName(), JackNoStartServer, &status, NULL);
device->hidden->client = client;
if (client == NULL) {
if (!client) {
return SDL_SetError("Can't open JACK client");
}
devports = JACK_jack_get_ports(client, NULL, NULL, JackPortIsPhysical | sysportflags);
if (devports == NULL || !devports[0]) {
if (!devports || !devports[0]) {
return SDL_SetError("No physical JACK ports available");
}
while (devports[++ports]) {
/* spin to count devports */
// spin to count devports
}
/* Filter out non-audio ports */
// Filter out non-audio ports
audio_ports = SDL_calloc(ports, sizeof(*audio_ports));
for (i = 0; i < ports; i++) {
const jack_port_t *dport = JACK_jack_port_by_name(client, devports[i]);
const char *type = JACK_jack_port_type(dport);
const int len = SDL_strlen(type);
/* See if type ends with "audio" */
// See if type ends with "audio"
if (len >= 5 && !SDL_memcmp(type + len - 5, "audio", 5)) {
audio_ports[channels++] = i;
}
@ -306,9 +331,7 @@ static int JACK_OpenDevice(SDL_AudioDevice *device)
return SDL_SetError("No physical JACK ports available");
}
/* !!! FIXME: docs say about buffer size: "This size may change, clients that depend on it must register a bufsize_callback so they will be notified if it does." */
/* Jack pretty much demands what it wants. */
// Jack pretty much demands what it wants.
device->spec.format = SDL_AUDIO_F32;
device->spec.freq = JACK_jack_get_sample_rate(client);
device->spec.channels = channels;
@ -320,15 +343,15 @@ static int JACK_OpenDevice(SDL_AudioDevice *device)
device->hidden->iobuffer = (float *)SDL_calloc(1, device->buffer_size);
if (!device->hidden->iobuffer) {
SDL_free(audio_ports);
return SDL_OutOfMemory();
return -1;
}
}
/* Build SDL's ports, which we will connect to the device ports. */
// Build SDL's ports, which we will connect to the device ports.
device->hidden->sdlports = (jack_port_t **)SDL_calloc(channels, sizeof(jack_port_t *));
if (device->hidden->sdlports == NULL) {
if (!device->hidden->sdlports) {
SDL_free(audio_ports);
return SDL_OutOfMemory();
return -1;
}
for (i = 0; i < channels; i++) {
@ -341,7 +364,13 @@ static int JACK_OpenDevice(SDL_AudioDevice *device)
}
}
if (JACK_jack_set_process_callback(client, callback, device) != 0) {
if (JACK_jack_set_buffer_size_callback(client, jackBufferSizeCallback, device) != 0) {
SDL_free(audio_ports);
return SDL_SetError("JACK: Couldn't set buffer size callback");
} else if (JACK_jack_set_sample_rate_callback(client, jackSampleRateCallback, device) != 0) {
SDL_free(audio_ports);
return SDL_SetError("JACK: Couldn't set sample rate callback");
} else if (JACK_jack_set_process_callback(client, callback, device) != 0) {
SDL_free(audio_ports);
return SDL_SetError("JACK: Couldn't set process callback");
}
@ -353,7 +382,7 @@ static int JACK_OpenDevice(SDL_AudioDevice *device)
return SDL_SetError("Failed to activate JACK client");
}
/* once activated, we can connect all the ports. */
// once activated, we can connect all the ports.
for (i = 0; i < channels; i++) {
const char *sdlport = JACK_jack_port_name(device->hidden->sdlports[i]);
const char *srcport = iscapture ? devports[audio_ports[i]] : sdlport;
@ -364,11 +393,11 @@ static int JACK_OpenDevice(SDL_AudioDevice *device)
}
}
/* don't need these anymore. */
// don't need these anymore.
JACK_jack_free(devports);
SDL_free(audio_ports);
/* We're ready to rock and roll. :-) */
// We're ready to rock and roll. :-)
return 0;
}
@ -382,17 +411,16 @@ static SDL_bool JACK_Init(SDL_AudioDriverImpl *impl)
if (LoadJackLibrary() < 0) {
return SDL_FALSE;
} else {
/* Make sure a JACK server is running and available. */
// Make sure a JACK server is running and available.
jack_status_t status;
jack_client_t *client = JACK_jack_client_open("SDL", JackNoStartServer, &status, NULL);
if (client == NULL) {
if (!client) {
UnloadJackLibrary();
return SDL_FALSE;
}
JACK_jack_client_close(client);
}
/* Set the function pointers */
impl->OpenDevice = JACK_OpenDevice;
impl->GetDeviceBuf = JACK_GetDeviceBuf;
impl->PlayDevice = JACK_PlayDevice;
@ -405,11 +433,11 @@ static SDL_bool JACK_Init(SDL_AudioDriverImpl *impl)
impl->HasCaptureSupport = SDL_TRUE;
impl->ProvidesOwnCallbackThread = SDL_TRUE;
return SDL_TRUE; /* this audio target is available. */
return SDL_TRUE;
}
AudioBootStrap JACK_bootstrap = {
"jack", "JACK Audio Connection Kit", JACK_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_JACK */
#endif // SDL_AUDIO_DRIVER_JACK

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -32,4 +32,4 @@ struct SDL_PrivateAudioData
float *iobuffer;
};
#endif /* SDL_jackaudio_h_ */
#endif // SDL_jackaudio_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -32,6 +32,7 @@
static dspHookCookie dsp_hook;
static SDL_AudioDevice *audio_device;
// fully local functions related to the wavebufs / DSP, not the same as the `device->lock` SDL_Mutex!
static SDL_INLINE void contextLock(SDL_AudioDevice *device)
{
LightLock_Lock(&device->hidden->lock);
@ -82,8 +83,8 @@ static int N3DSAUDIO_OpenDevice(SDL_AudioDevice *device)
float mix[12];
device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
if (!device->hidden) {
return -1;
}
// Initialise the DSP service
@ -133,14 +134,14 @@ static int N3DSAUDIO_OpenDevice(SDL_AudioDevice *device)
}
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
if (device->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
if (!device->hidden->mixbuf) {
return -1;
}
SDL_memset(device->hidden->mixbuf, device->silence_value, device->buffer_size);
data_vaddr = (Uint8 *)linearAlloc(device->buffer_size * NUM_BUFFERS);
if (data_vaddr == NULL) {
if (!data_vaddr) {
return SDL_OutOfMemory();
}
@ -200,7 +201,7 @@ static int N3DSAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, in
return 0;
}
static void N3DSAUDIO_WaitDevice(SDL_AudioDevice *device)
static int N3DSAUDIO_WaitDevice(SDL_AudioDevice *device)
{
contextLock(device);
while (!device->hidden->isCancelled && !SDL_AtomicGet(&device->shutdown) &&
@ -208,6 +209,7 @@ static void N3DSAUDIO_WaitDevice(SDL_AudioDevice *device)
CondVar_Wait(&device->hidden->cv, &device->hidden->lock);
}
contextUnlock(device);
return 0;
}
static Uint8 *N3DSAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
@ -251,7 +253,7 @@ static void N3DSAUDIO_CloseDevice(SDL_AudioDevice *device)
static void N3DSAUDIO_ThreadInit(SDL_AudioDevice *device)
{
s32 current_priority;
s32 current_priority = 0x30;
svcGetThreadPriority(&current_priority, CUR_THREAD_HANDLE);
current_priority--;
// 0x18 is reserved for video, 0x30 is the default for main thread

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -24,11 +24,11 @@
#include <3ds.h>
#define NUM_BUFFERS 2 /* -- Don't lower this! */
#define NUM_BUFFERS 3 // -- Minimum 2!
struct SDL_PrivateAudioData
{
/* Speaker data */
// Speaker data
Uint8 *mixbuf;
Uint32 nextbuf;
ndspWaveBuf waveBuf[NUM_BUFFERS];
@ -37,4 +37,4 @@ struct SDL_PrivateAudioData
SDL_bool isCancelled;
};
#endif /* SDL_n3dsaudio_h */
#endif // SDL_n3dsaudio_h

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -34,7 +34,6 @@
#include <sys/audioio.h>
#include "../../core/unix/SDL_poll.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_netbsdaudio.h"
@ -115,7 +114,7 @@ static void NETBSDAUDIO_Status(SDL_AudioDevice *device)
#endif // DEBUG_AUDIO
}
static void NETBSDAUDIO_WaitDevice(SDL_AudioDevice *device)
static int NETBSDAUDIO_WaitDevice(SDL_AudioDevice *device)
{
const SDL_bool iscapture = device->iscapture;
while (!SDL_AtomicGet(&device->shutdown)) {
@ -127,8 +126,7 @@ static void NETBSDAUDIO_WaitDevice(SDL_AudioDevice *device)
}
// Hmm, not much we can do - abort
fprintf(stderr, "netbsdaudio WaitDevice ioctl failed (unrecoverable): %s\n", strerror(errno));
SDL_AudioDeviceDisconnected(device);
return;
return -1;
}
const size_t remain = (size_t)((iscapture ? info.record.seek : info.play.seek) * SDL_AUDIO_BYTESIZE(device->spec.format));
if (!iscapture && (remain >= device->buffer_size)) {
@ -136,9 +134,11 @@ static void NETBSDAUDIO_WaitDevice(SDL_AudioDevice *device)
} else if (iscapture && (remain < device->buffer_size)) {
SDL_Delay(10);
} else {
break; /* ready to go! */
break; // ready to go!
}
}
return 0;
}
static int NETBSDAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
@ -215,8 +215,8 @@ static int NETBSDAUDIO_OpenDevice(SDL_AudioDevice *device)
// Initialize all variables that we clean on shutdown
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
if (!device->hidden) {
return -1;
}
// Open the audio device; we hardcode the device path in `device->name` for lack of better info, so use that.
@ -293,8 +293,8 @@ static int NETBSDAUDIO_OpenDevice(SDL_AudioDevice *device)
// Allocate mixing buffer
device->hidden->mixlen = device->buffer_size;
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->hidden->mixlen);
if (device->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
if (!device->hidden->mixbuf) {
return -1;
}
SDL_memset(device->hidden->mixbuf, device->silence_value, device->buffer_size);
}
@ -317,7 +317,6 @@ static SDL_bool NETBSDAUDIO_Init(SDL_AudioDriverImpl *impl)
impl->FlushCapture = NETBSDAUDIO_FlushCapture;
impl->HasCaptureSupport = SDL_TRUE;
impl->AllowsArbitraryDeviceNames = SDL_TRUE;
return SDL_TRUE;
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -27,18 +27,18 @@
struct SDL_PrivateAudioData
{
/* The file descriptor for the audio device */
// The file descriptor for the audio device
int audio_fd;
/* Raw mixing buffer */
// Raw mixing buffer
Uint8 *mixbuf;
int mixlen;
/* Support for audio timing using a timer, in addition to SDL_IOReady() */
// Support for audio timing using a timer, in addition to SDL_IOReady()
float frame_ticks;
float next_frame;
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
#define FUDGE_TICKS 10 // The scheduler overhead ticks per frame
#endif /* SDL_netbsdaudio_h_ */
#endif // SDL_netbsdaudio_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -26,7 +26,6 @@
// https://googlesamples.github.io/android-audio-high-performance/guides/opensl_es.html
#include "../SDL_sysaudio.h"
#include "../SDL_audio_c.h"
#include "SDL_openslES.h"
#include "../../core/android/SDL_android.h"
@ -108,7 +107,7 @@ static const char *sldevaudioplayerstr = "SLES Audio Player";
#define SLES_DEV_AUDIO_RECORDER sldevaudiorecorderstr
#define SLES_DEV_AUDIO_PLAYER sldevaudioplayerstr
static void openslES_DetectDevices( int iscapture )
static void OPENSLES_DetectDevices( int iscapture )
{
LOGI( "openSLES_DetectDevices()" );
if ( iscapture )
@ -118,9 +117,9 @@ static void openslES_DetectDevices( int iscapture )
}
#endif
static void openslES_DestroyEngine(void)
static void OPENSLES_DestroyEngine(void)
{
LOGI("openslES_DestroyEngine()");
LOGI("OPENSLES_DestroyEngine()");
// destroy output mix object, and invalidate all associated interfaces
if (outputMixObject != NULL) {
@ -136,7 +135,7 @@ static void openslES_DestroyEngine(void)
}
}
static int openslES_CreateEngine(void)
static int OPENSLES_CreateEngine(void)
{
const SLInterfaceID ids[1] = { SL_IID_VOLUME };
const SLboolean req[1] = { SL_BOOLEAN_FALSE };
@ -185,7 +184,7 @@ static int openslES_CreateEngine(void)
return 1;
error:
openslES_DestroyEngine();
OPENSLES_DestroyEngine();
return 0;
}
@ -198,7 +197,7 @@ static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
SDL_PostSemaphore(audiodata->playsem);
}
static void openslES_DestroyPCMRecorder(SDL_AudioDevice *device)
static void OPENSLES_DestroyPCMRecorder(SDL_AudioDevice *device)
{
struct SDL_PrivateAudioData *audiodata = device->hidden;
SLresult result;
@ -229,7 +228,7 @@ static void openslES_DestroyPCMRecorder(SDL_AudioDevice *device)
}
}
static int openslES_CreatePCMRecorder(SDL_AudioDevice *device)
static int OPENSLES_CreatePCMRecorder(SDL_AudioDevice *device)
{
struct SDL_PrivateAudioData *audiodata = device->hidden;
SLDataFormat_PCM format_pcm;
@ -328,7 +327,7 @@ static int openslES_CreatePCMRecorder(SDL_AudioDevice *device)
// Create the sound buffers
audiodata->mixbuff = (Uint8 *)SDL_malloc(NUM_BUFFERS * device->buffer_size);
if (audiodata->mixbuff == NULL) {
if (!audiodata->mixbuff) {
LOGE("mixbuffer allocate - out of memory");
goto failed;
}
@ -375,7 +374,7 @@ static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
SDL_PostSemaphore(audiodata->playsem);
}
static void openslES_DestroyPCMPlayer(SDL_AudioDevice *device)
static void OPENSLES_DestroyPCMPlayer(SDL_AudioDevice *device)
{
struct SDL_PrivateAudioData *audiodata = device->hidden;
@ -406,7 +405,7 @@ static void openslES_DestroyPCMPlayer(SDL_AudioDevice *device)
}
}
static int openslES_CreatePCMPlayer(SDL_AudioDevice *device)
static int OPENSLES_CreatePCMPlayer(SDL_AudioDevice *device)
{
/* If we want to add floating point audio support (requires API level 21)
it can be done as described here:
@ -575,7 +574,7 @@ static int openslES_CreatePCMPlayer(SDL_AudioDevice *device)
// Create the sound buffers
audiodata->mixbuff = (Uint8 *)SDL_malloc(NUM_BUFFERS * device->buffer_size);
if (audiodata->mixbuff == NULL) {
if (!audiodata->mixbuff) {
LOGE("mixbuffer allocate - out of memory");
goto failed;
}
@ -597,26 +596,26 @@ failed:
return -1;
}
static int openslES_OpenDevice(SDL_AudioDevice *device)
static int OPENSLES_OpenDevice(SDL_AudioDevice *device)
{
device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
if (!device->hidden) {
return -1;
}
if (device->iscapture) {
LOGI("openslES_OpenDevice() for capture");
return openslES_CreatePCMRecorder(device);
LOGI("OPENSLES_OpenDevice() for capture");
return OPENSLES_CreatePCMRecorder(device);
} else {
int ret;
LOGI("openslES_OpenDevice() for playing");
ret = openslES_CreatePCMPlayer(device);
LOGI("OPENSLES_OpenDevice() for playing");
ret = OPENSLES_CreatePCMPlayer(device);
if (ret < 0) {
// Another attempt to open the device with a lower frequency
if (device->spec.freq > 48000) {
openslES_DestroyPCMPlayer(device);
OPENSLES_DestroyPCMPlayer(device);
device->spec.freq = 48000;
ret = openslES_CreatePCMPlayer(device);
ret = OPENSLES_CreatePCMPlayer(device);
}
}
@ -628,21 +627,21 @@ static int openslES_OpenDevice(SDL_AudioDevice *device)
return 0;
}
static void openslES_WaitDevice(SDL_AudioDevice *device)
static int OPENSLES_WaitDevice(SDL_AudioDevice *device)
{
struct SDL_PrivateAudioData *audiodata = device->hidden;
LOGV("openslES_WaitDevice()");
LOGV("OPENSLES_WaitDevice()");
// Wait for an audio chunk to finish
SDL_WaitSemaphore(audiodata->playsem);
return SDL_WaitSemaphore(audiodata->playsem);
}
static int openslES_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
static int OPENSLES_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
{
struct SDL_PrivateAudioData *audiodata = device->hidden;
LOGV("======openslES_PlayDevice()======");
LOGV("======OPENSLES_PlayDevice()======");
// Queue it up
const SLresult result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer, buflen);
@ -673,15 +672,15 @@ static int openslES_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int
//
// okay..
static Uint8 *openslES_GetDeviceBuf(SDL_AudioDevice *device, int *bufsize)
static Uint8 *OPENSLES_GetDeviceBuf(SDL_AudioDevice *device, int *bufsize)
{
struct SDL_PrivateAudioData *audiodata = device->hidden;
LOGV("openslES_GetDeviceBuf()");
LOGV("OPENSLES_GetDeviceBuf()");
return audiodata->pmixbuff[audiodata->next_buffer];
}
static int openslES_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
static int OPENSLES_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
{
struct SDL_PrivateAudioData *audiodata = device->hidden;
@ -704,16 +703,16 @@ static int openslES_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int
return device->buffer_size;
}
static void openslES_CloseDevice(SDL_AudioDevice *device)
static void OPENSLES_CloseDevice(SDL_AudioDevice *device)
{
// struct SDL_PrivateAudioData *audiodata = device->hidden;
if (device->hidden) {
if (device->iscapture) {
LOGI("openslES_CloseDevice() for capture");
openslES_DestroyPCMRecorder(device);
LOGI("OPENSLES_CloseDevice() for capture");
OPENSLES_DestroyPCMRecorder(device);
} else {
LOGI("openslES_CloseDevice() for playing");
openslES_DestroyPCMPlayer(device);
LOGI("OPENSLES_CloseDevice() for playing");
OPENSLES_DestroyPCMPlayer(device);
}
SDL_free(device->hidden);
@ -721,61 +720,61 @@ static void openslES_CloseDevice(SDL_AudioDevice *device)
}
}
static SDL_bool openslES_Init(SDL_AudioDriverImpl *impl)
static SDL_bool OPENSLES_Init(SDL_AudioDriverImpl *impl)
{
LOGI("openslES_Init() called");
LOGI("OPENSLES_Init() called");
if (!openslES_CreateEngine()) {
if (!OPENSLES_CreateEngine()) {
return SDL_FALSE;
}
LOGI("openslES_Init() - set pointers");
LOGI("OPENSLES_Init() - set pointers");
// Set the function pointers
// impl->DetectDevices = openslES_DetectDevices;
// impl->DetectDevices = OPENSLES_DetectDevices;
impl->ThreadInit = Android_AudioThreadInit;
impl->OpenDevice = openslES_OpenDevice;
impl->WaitDevice = openslES_WaitDevice;
impl->PlayDevice = openslES_PlayDevice;
impl->GetDeviceBuf = openslES_GetDeviceBuf;
impl->WaitCaptureDevice = openslES_WaitDevice;
impl->CaptureFromDevice = openslES_CaptureFromDevice;
impl->CloseDevice = openslES_CloseDevice;
impl->Deinitialize = openslES_DestroyEngine;
impl->OpenDevice = OPENSLES_OpenDevice;
impl->WaitDevice = OPENSLES_WaitDevice;
impl->PlayDevice = OPENSLES_PlayDevice;
impl->GetDeviceBuf = OPENSLES_GetDeviceBuf;
impl->WaitCaptureDevice = OPENSLES_WaitDevice;
impl->CaptureFromDevice = OPENSLES_CaptureFromDevice;
impl->CloseDevice = OPENSLES_CloseDevice;
impl->Deinitialize = OPENSLES_DestroyEngine;
// and the capabilities
impl->HasCaptureSupport = SDL_TRUE;
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
LOGI("openslES_Init() - success");
LOGI("OPENSLES_Init() - success");
// this audio target is available.
return SDL_TRUE;
}
AudioBootStrap openslES_bootstrap = {
"openslES", "opensl ES audio driver", openslES_Init, SDL_FALSE
AudioBootStrap OPENSLES_bootstrap = {
"openslES", "OpenSL ES audio driver", OPENSLES_Init, SDL_FALSE
};
void openslES_ResumeDevices(void)
void OPENSLES_ResumeDevices(void)
{
if (bqPlayerPlay != NULL) {
// set the player's state to 'playing'
SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
if (SL_RESULT_SUCCESS != result) {
LOGE("openslES_ResumeDevices failed: %d", result);
LOGE("OPENSLES_ResumeDevices failed: %d", result);
}
}
}
void openslES_PauseDevices(void)
void OPENSLES_PauseDevices(void)
{
if (bqPlayerPlay != NULL) {
// set the player's state to 'paused'
SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED);
if (SL_RESULT_SUCCESS != result) {
LOGE("openslES_PauseDevices failed: %d", result);
LOGE("OPENSLES_PauseDevices failed: %d", result);
}
}
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -25,14 +25,14 @@
#ifdef SDL_AUDIO_DRIVER_OPENSLES
void openslES_ResumeDevices(void);
void openslES_PauseDevices(void);
void OPENSLES_ResumeDevices(void);
void OPENSLES_PauseDevices(void);
#else
static void openslES_ResumeDevices(void) {}
static void openslES_PauseDevices(void) {}
static void OPENSLES_ResumeDevices(void) {}
static void OPENSLES_PauseDevices(void) {}
#endif
#endif /* SDL_openslesaudio_h_ */
#endif // SDL_openslesaudio_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -63,7 +63,7 @@
* This seems to be a sane lower limit as Pipewire
* uses it in several of it's own modules.
*/
#define PW_MIN_SAMPLES 32 /* About 0.67ms at 48kHz */
#define PW_MIN_SAMPLES 32 // About 0.67ms at 48kHz
#define PW_BASE_CLOCK_RATE 48000
#define PW_POD_BUFFER_LENGTH 1024
@ -82,7 +82,7 @@ enum PW_READY_FLAGS
static SDL_bool pipewire_initialized = SDL_FALSE;
/* Pipewire entry points */
// Pipewire entry points
static const char *(*PIPEWIRE_pw_get_library_version)(void);
static void (*PIPEWIRE_pw_init)(int *, char ***);
static void (*PIPEWIRE_pw_deinit)(void);
@ -126,8 +126,8 @@ static void *pipewire_handle = NULL;
static int pipewire_dlsym(const char *fn, void **addr)
{
*addr = SDL_LoadFunction(pipewire_handle, fn);
if (*addr == NULL) {
/* Don't call SDL_SetError(): SDL_LoadFunction already did. */
if (!*addr) {
// Don't call SDL_SetError(): SDL_LoadFunction already did.
return 0;
}
@ -142,7 +142,7 @@ static int pipewire_dlsym(const char *fn, void **addr)
static int load_pipewire_library(void)
{
pipewire_handle = SDL_LoadObject(pipewire_library);
return pipewire_handle != NULL ? 0 : -1;
return pipewire_handle ? 0 : -1;
}
static void unload_pipewire_library(void)
@ -163,10 +163,11 @@ static int load_pipewire_library(void)
}
static void unload_pipewire_library(void)
{ /* Nothing to do */
{
// Nothing to do
}
#endif /* SDL_AUDIO_DRIVER_PIPEWIRE_DYNAMIC */
#endif // SDL_AUDIO_DRIVER_PIPEWIRE_DYNAMIC
static int load_pipewire_syms(void)
{
@ -220,7 +221,7 @@ static int init_pipewire_library(void)
return -1;
}
/* SDL can build against 0.3.20, but requires 0.3.24 */
// SDL can build against 0.3.20, but requires 0.3.24
if (pipewire_version_at_least(0, 3, 24)) {
PIPEWIRE_pw_init(NULL, NULL);
return 0;
@ -237,7 +238,7 @@ static void deinit_pipewire_library(void)
unload_pipewire_library();
}
/* A generic Pipewire node object used for enumeration. */
// A generic Pipewire node object used for enumeration.
struct node_object
{
struct spa_list link;
@ -260,7 +261,7 @@ struct node_object
struct spa_hook core_listener;
};
/* A sink/source node used for stream I/O. */
// A sink/source node used for stream I/O.
struct io_node
{
struct spa_list link;
@ -269,13 +270,13 @@ struct io_node
SDL_bool is_capture;
SDL_AudioSpec spec;
const char *name; /* Friendly name */
const char *path; /* OS identifier (i.e. ALSA endpoint) */
const char *name; // Friendly name
const char *path; // OS identifier (i.e. ALSA endpoint)
char buf[]; /* Buffer to hold the name and path strings. */
char buf[]; // Buffer to hold the name and path strings.
};
/* The global hotplug thread and associated objects. */
// The global hotplug thread and associated objects.
static struct pw_thread_loop *hotplug_loop;
static struct pw_core *hotplug_core;
static struct pw_context *hotplug_context;
@ -291,13 +292,13 @@ static SDL_bool hotplug_events_enabled;
static char *pipewire_default_sink_id = NULL;
static char *pipewire_default_source_id = NULL;
/* The active node list */
// The active node list
static SDL_bool io_list_check_add(struct io_node *node)
{
struct io_node *n;
SDL_bool ret = SDL_TRUE;
/* See if the node is already in the list */
// See if the node is already in the list
spa_list_for_each (n, &hotplug_io_list, link) {
if (n->id == node->id) {
ret = SDL_FALSE;
@ -305,7 +306,7 @@ static SDL_bool io_list_check_add(struct io_node *node)
}
}
/* Add to the list if the node doesn't already exist */
// Add to the list if the node doesn't already exist
spa_list_append(&hotplug_io_list, &node->link);
if (hotplug_events_enabled) {
@ -321,7 +322,7 @@ static void io_list_remove(Uint32 id)
{
struct io_node *n, *temp;
/* Find and remove the node from the list */
// Find and remove the node from the list
spa_list_for_each_safe (n, temp, &hotplug_io_list, link) {
if (n->id == id) {
spa_list_remove(&n->link);
@ -360,7 +361,7 @@ static struct io_node *io_list_get_by_id(Uint32 id)
static void node_object_destroy(struct node_object *node)
{
SDL_assert(node);
SDL_assert(node != NULL);
spa_list_remove(&node->link);
spa_hook_remove(&node->node_listener);
@ -369,10 +370,10 @@ static void node_object_destroy(struct node_object *node)
PIPEWIRE_pw_proxy_destroy(node->proxy);
}
/* The pending node list */
// The pending node list
static void pending_list_add(struct node_object *node)
{
SDL_assert(node);
SDL_assert(node != NULL);
spa_list_append(&hotplug_pending_list, &node->link);
}
@ -401,9 +402,9 @@ static void *node_object_new(Uint32 id, const char *type, Uint32 version, const
struct pw_proxy *proxy;
struct node_object *node;
/* Create the proxy object */
// Create the proxy object
proxy = pw_registry_bind(hotplug_registry, id, type, version, sizeof(struct node_object));
if (proxy == NULL) {
if (!proxy) {
SDL_SetError("Pipewire: Failed to create proxy object (%i)", errno);
return NULL;
}
@ -414,24 +415,24 @@ static void *node_object_new(Uint32 id, const char *type, Uint32 version, const
node->id = id;
node->proxy = proxy;
/* Add the callbacks */
// Add the callbacks
pw_core_add_listener(hotplug_core, &node->core_listener, core_events, node);
PIPEWIRE_pw_proxy_add_object_listener(node->proxy, &node->node_listener, funcs, node);
/* Add the node to the active list */
// Add the node to the active list
pending_list_add(node);
return node;
}
/* Core sync points */
// Core sync points
static void core_events_hotplug_init_callback(void *object, uint32_t id, int seq)
{
if (id == PW_ID_CORE && seq == hotplug_init_seq_val) {
/* This core listener is no longer needed. */
// This core listener is no longer needed.
spa_hook_remove(&hotplug_core_listener);
/* Signal that the initial I/O list is populated */
// Signal that the initial I/O list is populated
hotplug_init_complete = SDL_TRUE;
PIPEWIRE_pw_thread_loop_signal(hotplug_loop, false);
}
@ -483,7 +484,7 @@ static void hotplug_core_sync(struct node_object *node)
}
}
/* Helpers for retrieving values from params */
// Helpers for retrieving values from params
static SDL_bool get_range_param(const struct spa_pod *param, Uint32 key, int *def, int *min, int *max)
{
const struct spa_pod_prop *prop;
@ -535,7 +536,7 @@ static SDL_bool get_int_param(const struct spa_pod *param, Uint32 key, int *val)
return SDL_FALSE;
}
/* Interface node callbacks */
// Interface node callbacks
static void node_event_info(void *object, const struct pw_node_info *info)
{
struct node_object *node = object;
@ -549,7 +550,7 @@ static void node_event_info(void *object, const struct pw_node_info *info)
io->spec.channels = (Uint8)SDL_atoi(prop_val);
}
/* Need to parse the parameters to get the sample rate */
// Need to parse the parameters to get the sample rate
for (i = 0; i < info->n_params; ++i) {
pw_node_enum_params(node->proxy, 0, info->params[i].id, 0, 0, NULL);
}
@ -563,7 +564,7 @@ static void node_event_param(void *object, int seq, uint32_t id, uint32_t index,
struct node_object *node = object;
struct io_node *io = node->userdata;
/* Get the default frequency */
// Get the default frequency
if (io->spec.freq == 0) {
get_range_param(param, SPA_FORMAT_AUDIO_rate, &io->spec.freq, NULL, NULL);
}
@ -586,19 +587,19 @@ static const struct pw_node_events interface_node_events = { PW_VERSION_NODE_EVE
static char *get_name_from_json(const char *json)
{
struct spa_json parser[2];
char key[7]; /* "name" */
char key[7]; // "name"
char value[PW_MAX_IDENTIFIER_LENGTH];
spa_json_init(&parser[0], json, SDL_strlen(json));
if (spa_json_enter_object(&parser[0], &parser[1]) <= 0) {
/* Not actually JSON */
// Not actually JSON
return NULL;
}
if (spa_json_get_string(&parser[1], key, sizeof(key)) <= 0) {
/* Not actually a key/value pair */
// Not actually a key/value pair
return NULL;
}
if (spa_json_get_string(&parser[1], value, sizeof(value)) <= 0) {
/* Somehow had a key with no value? */
// Somehow had a key with no value?
return NULL;
}
return SDL_strdup(value);
@ -617,21 +618,21 @@ static void change_default_device(const char *path)
}
}
/* Metadata node callback */
// Metadata node callback
static int metadata_property(void *object, Uint32 subject, const char *key, const char *type, const char *value)
{
struct node_object *node = object;
if (subject == PW_ID_CORE && key != NULL && value != NULL) {
if (subject == PW_ID_CORE && key && value) {
if (!SDL_strcmp(key, "default.audio.sink")) {
if (pipewire_default_sink_id != NULL) {
if (pipewire_default_sink_id) {
SDL_free(pipewire_default_sink_id);
}
pipewire_default_sink_id = get_name_from_json(value);
node->persist = SDL_TRUE;
change_default_device(pipewire_default_sink_id);
} else if (!SDL_strcmp(key, "default.audio.source")) {
if (pipewire_default_source_id != NULL) {
if (pipewire_default_source_id) {
SDL_free(pipewire_default_source_id);
}
pipewire_default_source_id = get_name_from_json(value);
@ -645,13 +646,13 @@ static int metadata_property(void *object, Uint32 subject, const char *key, cons
static const struct pw_metadata_events metadata_node_events = { PW_VERSION_METADATA_EVENTS, .property = metadata_property };
/* Global registry callbacks */
// Global registry callbacks
static void registry_event_global_callback(void *object, uint32_t id, uint32_t permissions, const char *type, uint32_t version,
const struct spa_dict *props)
{
struct node_object *node;
/* We're only interested in interface and metadata nodes. */
// We're only interested in interface and metadata nodes.
if (!SDL_strcmp(type, PW_TYPE_INTERFACE_Node)) {
const char *media_class = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS);
@ -663,7 +664,7 @@ static void registry_event_global_callback(void *object, uint32_t id, uint32_t p
int desc_buffer_len;
int path_buffer_len;
/* Just want sink and capture */
// Just want sink and capture
if (!SDL_strcasecmp(media_class, "Audio/Sink")) {
is_capture = SDL_FALSE;
} else if (!SDL_strcasecmp(media_class, "Audio/Source")) {
@ -677,42 +678,41 @@ static void registry_event_global_callback(void *object, uint32_t id, uint32_t p
if (node_desc && node_path) {
node = node_object_new(id, type, version, &interface_node_events, &interface_core_events);
if (node == NULL) {
if (!node) {
SDL_SetError("Pipewire: Failed to allocate interface node");
return;
}
/* Allocate and initialize the I/O node information struct */
// Allocate and initialize the I/O node information struct
desc_buffer_len = SDL_strlen(node_desc) + 1;
path_buffer_len = SDL_strlen(node_path) + 1;
node->userdata = io = SDL_calloc(1, sizeof(struct io_node) + desc_buffer_len + path_buffer_len);
if (io == NULL) {
if (!io) {
node_object_destroy(node);
SDL_OutOfMemory();
return;
}
/* Begin setting the node properties */
// Begin setting the node properties
io->id = id;
io->is_capture = is_capture;
io->spec.format = SDL_AUDIO_F32; /* Pipewire uses floats internally, other formats require conversion. */
io->spec.format = SDL_AUDIO_F32; // Pipewire uses floats internally, other formats require conversion.
io->name = io->buf;
io->path = io->buf + desc_buffer_len;
SDL_strlcpy(io->buf, node_desc, desc_buffer_len);
SDL_strlcpy(io->buf + desc_buffer_len, node_path, path_buffer_len);
/* Update sync points */
// Update sync points
hotplug_core_sync(node);
}
}
} else if (!SDL_strcmp(type, PW_TYPE_INTERFACE_Metadata)) {
node = node_object_new(id, type, version, &metadata_node_events, &metadata_core_events);
if (node == NULL) {
if (!node) {
SDL_SetError("Pipewire: Failed to allocate metadata node");
return;
}
/* Update sync points */
// Update sync points
hotplug_core_sync(node);
}
}
@ -726,7 +726,7 @@ static void registry_event_remove_callback(void *object, uint32_t id)
static const struct pw_registry_events registry_events = { PW_VERSION_REGISTRY_EVENTS, .global = registry_event_global_callback,
.global_remove = registry_event_remove_callback };
/* The hotplug thread */
// The hotplug thread
static int hotplug_loop_init(void)
{
int res;
@ -735,22 +735,22 @@ static int hotplug_loop_init(void)
spa_list_init(&hotplug_io_list);
hotplug_loop = PIPEWIRE_pw_thread_loop_new("SDLAudioHotplug", NULL);
if (hotplug_loop == NULL) {
if (!hotplug_loop) {
return SDL_SetError("Pipewire: Failed to create hotplug detection loop (%i)", errno);
}
hotplug_context = PIPEWIRE_pw_context_new(PIPEWIRE_pw_thread_loop_get_loop(hotplug_loop), NULL, 0);
if (hotplug_context == NULL) {
if (!hotplug_context) {
return SDL_SetError("Pipewire: Failed to create hotplug detection context (%i)", errno);
}
hotplug_core = PIPEWIRE_pw_context_connect(hotplug_context, NULL, 0);
if (hotplug_core == NULL) {
if (!hotplug_core) {
return SDL_SetError("Pipewire: Failed to connect hotplug detection context (%i)", errno);
}
hotplug_registry = pw_core_get_registry(hotplug_core, PW_VERSION_REGISTRY, 0);
if (hotplug_registry == NULL) {
if (!hotplug_registry) {
return SDL_SetError("Pipewire: Failed to acquire hotplug detection registry (%i)", errno);
}
@ -782,11 +782,11 @@ static void hotplug_loop_destroy(void)
hotplug_init_complete = SDL_FALSE;
hotplug_events_enabled = SDL_FALSE;
if (pipewire_default_sink_id != NULL) {
if (pipewire_default_sink_id) {
SDL_free(pipewire_default_sink_id);
pipewire_default_sink_id = NULL;
}
if (pipewire_default_source_id != NULL) {
if (pipewire_default_source_id) {
SDL_free(pipewire_default_source_id);
pipewire_default_source_id = NULL;
}
@ -818,17 +818,17 @@ static void PIPEWIRE_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDe
PIPEWIRE_pw_thread_loop_lock(hotplug_loop);
/* Wait until the initial registry enumeration is complete */
// Wait until the initial registry enumeration is complete
if (!hotplug_init_complete) {
PIPEWIRE_pw_thread_loop_wait(hotplug_loop);
}
spa_list_for_each (io, &hotplug_io_list, link) {
SDL_AudioDevice *device = SDL_AddAudioDevice(io->is_capture, io->name, &io->spec, PW_ID_TO_HANDLE(io->id));
if (pipewire_default_sink_id != NULL && SDL_strcmp(io->path, pipewire_default_sink_id) == 0) {
if (pipewire_default_sink_id && SDL_strcmp(io->path, pipewire_default_sink_id) == 0) {
SDL_assert(!io->is_capture);
*default_output = device;
} else if (pipewire_default_source_id != NULL && SDL_strcmp(io->path, pipewire_default_source_id) == 0) {
} else if (pipewire_default_source_id && SDL_strcmp(io->path, pipewire_default_source_id) == 0) {
SDL_assert(io->is_capture);
*default_capture = device;
}
@ -839,7 +839,7 @@ static void PIPEWIRE_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDe
PIPEWIRE_pw_thread_loop_unlock(hotplug_loop);
}
/* Channel maps that match the order in SDL_Audio.h */
// Channel maps that match the order in SDL_Audio.h
static const enum spa_audio_channel PIPEWIRE_channel_map_1[] = { SPA_AUDIO_CHANNEL_MONO };
static const enum spa_audio_channel PIPEWIRE_channel_map_2[] = { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR };
static const enum spa_audio_channel PIPEWIRE_channel_map_3[] = { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_LFE };
@ -890,7 +890,7 @@ static void initialize_spa_info(const SDL_AudioSpec *spec, struct spa_audio_info
break;
}
/* Pipewire natively supports all of SDL's sample formats */
// Pipewire natively supports all of SDL's sample formats
switch (spec->format) {
case SDL_AUDIO_U8:
info->format = SPA_AUDIO_FORMAT_U8;
@ -964,7 +964,7 @@ static void PIPEWIRE_FlushCapture(SDL_AudioDevice *device)
{
struct pw_stream *stream = device->hidden->stream;
struct pw_buffer *pw_buf = PIPEWIRE_pw_stream_dequeue_buffer(stream);
if (pw_buf != NULL) { // just requeue it without any further thought.
if (pw_buf) { // just requeue it without any further thought.
PIPEWIRE_pw_stream_queue_buffer(stream, pw_buf);
}
}
@ -1061,27 +1061,27 @@ static int PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
struct SDL_PrivateAudioData *priv;
struct pw_properties *props;
const char *app_name, *app_id, *stream_name, *stream_role, *error;
Uint32 node_id = device->handle == NULL ? PW_ID_ANY : PW_HANDLE_TO_ID(device->handle);
Uint32 node_id = !device->handle ? PW_ID_ANY : PW_HANDLE_TO_ID(device->handle);
const SDL_bool iscapture = device->iscapture;
int res;
/* Clamp the period size to sane values */
// Clamp the period size to sane values
const int min_period = PW_MIN_SAMPLES * SPA_MAX(device->spec.freq / PW_BASE_CLOCK_RATE, 1);
/* Get the hints for the application name, stream name and role */
// Get the hints for the application name, stream name and role
app_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME);
if (app_name == NULL || *app_name == '\0') {
if (!app_name || *app_name == '\0') {
app_name = SDL_GetHint(SDL_HINT_APP_NAME);
if (app_name == NULL || *app_name == '\0') {
if (!app_name || *app_name == '\0') {
app_name = "SDL Application";
}
}
/* App ID. Default to NULL if not available. */
// App ID. Default to NULL if not available.
app_id = SDL_GetHint(SDL_HINT_APP_ID);
stream_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME);
if (stream_name == NULL || *stream_name == '\0') {
if (!stream_name || *stream_name == '\0') {
stream_name = "Audio Stream";
}
@ -1090,24 +1090,24 @@ static int PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
* but 'Game' seems more appropriate for the majority of SDL applications.
*/
stream_role = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_STREAM_ROLE);
if (stream_role == NULL || *stream_role == '\0') {
if (!stream_role || *stream_role == '\0') {
stream_role = "Game";
}
/* Initialize the Pipewire stream info from the SDL audio spec */
// Initialize the Pipewire stream info from the SDL audio spec
initialize_spa_info(&device->spec, &spa_info);
params = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &spa_info);
if (params == NULL) {
if (!params) {
return SDL_SetError("Pipewire: Failed to set audio format parameters");
}
priv = SDL_calloc(1, sizeof(struct SDL_PrivateAudioData));
device->hidden = priv;
if (priv == NULL) {
return SDL_OutOfMemory();
if (!priv) {
return -1;
}
/* Size of a single audio frame in bytes */
// Size of a single audio frame in bytes
priv->stride = SDL_AUDIO_FRAMESIZE(device->spec);
if (device->sample_frames < min_period) {
@ -1118,23 +1118,23 @@ static int PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
SDL_GetAudioThreadName(device, thread_name, sizeof(thread_name));
priv->loop = PIPEWIRE_pw_thread_loop_new(thread_name, NULL);
if (priv->loop == NULL) {
if (!priv->loop) {
return SDL_SetError("Pipewire: Failed to create stream loop (%i)", errno);
}
/* Load the realtime module so Pipewire can set the loop thread to the appropriate priority. */
// Load the realtime module so Pipewire can set the loop thread to the appropriate priority.
props = PIPEWIRE_pw_properties_new(PW_KEY_CONFIG_NAME, "client-rt.conf", NULL);
if (props == NULL) {
if (!props) {
return SDL_SetError("Pipewire: Failed to create stream context properties (%i)", errno);
}
priv->context = PIPEWIRE_pw_context_new(PIPEWIRE_pw_thread_loop_get_loop(priv->loop), props, 0);
if (priv->context == NULL) {
if (!priv->context) {
return SDL_SetError("Pipewire: Failed to create stream context (%i)", errno);
}
props = PIPEWIRE_pw_properties_new(NULL, NULL);
if (props == NULL) {
if (!props) {
return SDL_SetError("Pipewire: Failed to create stream properties (%i)", errno);
}
@ -1142,7 +1142,7 @@ static int PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
PIPEWIRE_pw_properties_set(props, PW_KEY_MEDIA_CATEGORY, iscapture ? "Capture" : "Playback");
PIPEWIRE_pw_properties_set(props, PW_KEY_MEDIA_ROLE, stream_role);
PIPEWIRE_pw_properties_set(props, PW_KEY_APP_NAME, app_name);
if (app_id != NULL) {
if (app_id) {
PIPEWIRE_pw_properties_set(props, PW_KEY_APP_ID, app_id);
}
PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_NAME, stream_name);
@ -1164,7 +1164,7 @@ static int PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
PIPEWIRE_pw_thread_loop_lock(hotplug_loop);
node = io_list_get_by_id(node_id);
if (node != NULL) {
if (node) {
PIPEWIRE_pw_properties_set(props, PW_KEY_TARGET_OBJECT, node->path);
}
PIPEWIRE_pw_thread_loop_unlock(hotplug_loop);
@ -1173,10 +1173,10 @@ static int PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
}
}
/* Create the new stream */
// Create the new stream
priv->stream = PIPEWIRE_pw_stream_new_simple(PIPEWIRE_pw_thread_loop_get_loop(priv->loop), stream_name, props,
iscapture ? &stream_input_events : &stream_output_events, device);
if (priv->stream == NULL) {
if (!priv->stream) {
return SDL_SetError("Pipewire: Failed to create stream (%i)", errno);
}
@ -1191,7 +1191,7 @@ static int PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
return SDL_SetError("Pipewire: Failed to start stream loop");
}
/* Wait until all init flags are set or the stream has failed. */
// Wait until all init flags are set or the stream has failed.
PIPEWIRE_pw_thread_loop_lock(priv->loop);
while (priv->stream_init_status != PW_READY_FLAG_ALL_BITS &&
PIPEWIRE_pw_stream_get_state(priv->stream, NULL) != PW_STREAM_STATE_ERROR) {
@ -1234,10 +1234,16 @@ static void PIPEWIRE_CloseDevice(SDL_AudioDevice *device)
SDL_AudioThreadFinalize(device);
}
static void PIPEWIRE_Deinitialize(void)
static void PIPEWIRE_DeinitializeStart(void)
{
if (pipewire_initialized) {
hotplug_loop_destroy();
}
}
static void PIPEWIRE_Deinitialize(void)
{
if (pipewire_initialized) {
deinit_pipewire_library();
pipewire_initialized = SDL_FALSE;
}
@ -1258,9 +1264,9 @@ static SDL_bool PIPEWIRE_Init(SDL_AudioDriverImpl *impl)
}
}
/* Set the function pointers */
impl->DetectDevices = PIPEWIRE_DetectDevices;
impl->OpenDevice = PIPEWIRE_OpenDevice;
impl->DeinitializeStart = PIPEWIRE_DeinitializeStart;
impl->Deinitialize = PIPEWIRE_Deinitialize;
impl->PlayDevice = PIPEWIRE_PlayDevice;
impl->GetDeviceBuf = PIPEWIRE_GetDeviceBuf;
@ -1276,4 +1282,4 @@ static SDL_bool PIPEWIRE_Init(SDL_AudioDriverImpl *impl)
AudioBootStrap PIPEWIRE_bootstrap = { "pipewire", "Pipewire", PIPEWIRE_Init, SDL_FALSE };
#endif /* SDL_AUDIO_DRIVER_PIPEWIRE */
#endif // SDL_AUDIO_DRIVER_PIPEWIRE

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -33,11 +33,11 @@ struct SDL_PrivateAudioData
struct pw_stream *stream;
struct pw_context *context;
Sint32 stride; /* Bytes-per-frame */
Sint32 stride; // Bytes-per-frame
int stream_init_status;
// Set in GetDeviceBuf, filled in AudioThreadIterate, queued in PlayDevice
struct pw_buffer *pw_buf;
};
#endif /* SDL_pipewire_h_ */
#endif // SDL_pipewire_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -20,7 +20,7 @@
*/
#include "SDL_internal.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_ps2audio.h"
#include <kernel.h>
@ -30,8 +30,8 @@
static int PS2AUDIO_OpenDevice(SDL_AudioDevice *device)
{
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
if (!device->hidden) {
return -1;
}
// These are the native supported audio PS2 configs
@ -73,7 +73,7 @@ static int PS2AUDIO_OpenDevice(SDL_AudioDevice *device)
64, so spec->size should be a multiple of 64 as well. */
const int mixlen = device->buffer_size * NUM_BUFFERS;
device->hidden->rawbuf = (Uint8 *)SDL_aligned_alloc(64, mixlen);
if (device->hidden->rawbuf == NULL) {
if (!device->hidden->rawbuf) {
return SDL_SetError("Couldn't allocate mixing buffer");
}
@ -91,9 +91,10 @@ static int PS2AUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int
return (audsrv_play_audio((char *)buffer, buflen) != buflen) ? -1 : 0;
}
static void PS2AUDIO_WaitDevice(SDL_AudioDevice *device)
static int PS2AUDIO_WaitDevice(SDL_AudioDevice *device)
{
audsrv_wait_audio(device->buffer_size);
return 0;
}
static Uint8 *PS2AUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
@ -111,7 +112,7 @@ static void PS2AUDIO_CloseDevice(SDL_AudioDevice *device)
device->hidden->channel = -1;
}
if (device->hidden->rawbuf != NULL) {
if (device->hidden->rawbuf) {
SDL_aligned_free(device->hidden->rawbuf);
device->hidden->rawbuf = NULL;
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -29,14 +29,14 @@
struct SDL_PrivateAudioData
{
/* The hardware output channel. */
// The hardware output channel.
int channel;
/* The raw allocated mixing buffer. */
// The raw allocated mixing buffer.
Uint8 *rawbuf;
/* Individual mixing buffers. */
// Individual mixing buffers.
Uint8 *mixbufs[NUM_BUFFERS];
/* Index of the next available mixing buffer. */
// Index of the next available mixing buffer.
int next_buffer;
};
#endif /* SDL_ps2audio_h_ */
#endif // SDL_ps2audio_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -26,7 +26,6 @@
#include <string.h>
#include <stdlib.h>
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_pspaudio.h"
@ -42,8 +41,8 @@ static inline SDL_bool isBasicAudioConfig(const SDL_AudioSpec *spec)
static int PSPAUDIO_OpenDevice(SDL_AudioDevice *device)
{
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
if (!device->hidden) {
return -1;
}
// device only natively supports S16LSB
@ -94,7 +93,7 @@ static int PSPAUDIO_OpenDevice(SDL_AudioDevice *device)
64, so spec->size should be a multiple of 64 as well. */
const int mixlen = device->buffer_size * NUM_BUFFERS;
device->hidden->rawbuf = (Uint8 *)SDL_aligned_alloc(64, mixlen);
if (device->hidden->rawbuf == NULL) {
if (!device->hidden->rawbuf) {
return SDL_SetError("Couldn't allocate mixing buffer");
}
@ -118,9 +117,9 @@ static int PSPAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int
return (rc == 0) ? 0 : -1;
}
static void PSPAUDIO_WaitDevice(SDL_AudioDevice *device)
static int PSPAUDIO_WaitDevice(SDL_AudioDevice *device)
{
// Because we block when sending audio, there's no need for this function to do anything.
return 0; // Because we block when sending audio, there's no need for this function to do anything.
}
static Uint8 *PSPAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
@ -142,7 +141,7 @@ static void PSPAUDIO_CloseDevice(SDL_AudioDevice *device)
device->hidden->channel = -1;
}
if (device->hidden->rawbuf != NULL) {
if (device->hidden->rawbuf) {
SDL_aligned_free(device->hidden->rawbuf);
device->hidden->rawbuf = NULL;
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -28,14 +28,14 @@
struct SDL_PrivateAudioData
{
/* The hardware output channel. */
// The hardware output channel.
int channel;
/* The raw allocated mixing buffer. */
// The raw allocated mixing buffer.
Uint8 *rawbuf;
/* Individual mixing buffers. */
// Individual mixing buffers.
Uint8 *mixbufs[NUM_BUFFERS];
/* Index of the next available mixing buffer. */
// Index of the next available mixing buffer.
int next_buffer;
};
#endif /* SDL_pspaudio_h_ */
#endif // SDL_pspaudio_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -23,7 +23,7 @@
#ifdef SDL_AUDIO_DRIVER_PULSEAUDIO
/* Allow access to a raw mixing buffer */
// Allow access to a raw mixing buffer
#ifdef HAVE_SIGNAL_H
#include <signal.h>
@ -31,11 +31,21 @@
#include <unistd.h>
#include <sys/types.h>
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_pulseaudio.h"
#include "../../thread/SDL_systhread.h"
/* should we include monitors in the device list? Set at SDL_Init time */
#if (PA_PROTOCOL_VERSION < 28)
typedef void (*pa_operation_notify_cb_t) (pa_operation *o, void *userdata);
#endif
typedef struct PulseDeviceHandle
{
char *device_path;
uint32_t device_index;
} PulseDeviceHandle;
// should we include monitors in the device list? Set at SDL_Init time
static SDL_bool include_monitors = SDL_FALSE;
static pa_threaded_mainloop *pulseaudio_threaded_mainloop = NULL;
@ -43,12 +53,14 @@ static pa_context *pulseaudio_context = NULL;
static SDL_Thread *pulseaudio_hotplug_thread = NULL;
static SDL_AtomicInt pulseaudio_hotplug_thread_active;
// These are the OS identifiers (i.e. ALSA strings)...
// These are the OS identifiers (i.e. ALSA strings)...these are allocated in a callback
// when the default changes, and noticed by the hotplug thread when it alerts SDL
// to the change.
static char *default_sink_path = NULL;
static char *default_source_path = NULL;
// ... and these are the PulseAudio device indices of the default devices.
static uint32_t default_sink_index = 0;
static uint32_t default_source_index = 0;
static SDL_bool default_sink_changed = SDL_FALSE;
static SDL_bool default_source_changed = SDL_FALSE;
static const char *(*PULSEAUDIO_pa_get_library_version)(void);
static pa_channel_map *(*PULSEAUDIO_pa_channel_map_init_auto)(
@ -94,11 +106,13 @@ static int (*PULSEAUDIO_pa_stream_connect_playback)(pa_stream *, const char *,
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 const pa_buffer_attr *(*PULSEAUDIO_pa_stream_get_buffer_attr)(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_write)(pa_stream *, const void *, size_t,
pa_free_cb_t, int64_t, pa_seek_mode_t);
static int (*PULSEAUDIO_pa_stream_begin_write)(pa_stream *, void **, size_t *);
static pa_operation *(*PULSEAUDIO_pa_stream_drain)(pa_stream *,
pa_stream_success_cb_t, void *);
static int (*PULSEAUDIO_pa_stream_peek)(pa_stream *, const void **, size_t *);
@ -121,22 +135,22 @@ static void *pulseaudio_handle = NULL;
static int load_pulseaudio_sym(const char *fn, void **addr)
{
*addr = SDL_LoadFunction(pulseaudio_handle, fn);
if (*addr == NULL) {
/* Don't call SDL_SetError(): SDL_LoadFunction already did. */
if (!*addr) {
// Don't call SDL_SetError(): SDL_LoadFunction already did.
return 0;
}
return 1;
}
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
// cast funcs to char* first, to please GCC's strict aliasing rules.
#define SDL_PULSEAUDIO_SYM(x) \
if (!load_pulseaudio_sym(#x, (void **)(char *)&PULSEAUDIO_##x)) \
return -1
static void UnloadPulseAudioLibrary(void)
{
if (pulseaudio_handle != NULL) {
if (pulseaudio_handle) {
SDL_UnloadObject(pulseaudio_handle);
pulseaudio_handle = NULL;
}
@ -145,11 +159,11 @@ static void UnloadPulseAudioLibrary(void)
static int LoadPulseAudioLibrary(void)
{
int retval = 0;
if (pulseaudio_handle == NULL) {
if (!pulseaudio_handle) {
pulseaudio_handle = SDL_LoadObject(pulseaudio_library);
if (pulseaudio_handle == NULL) {
if (!pulseaudio_handle) {
retval = -1;
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
// Don't call SDL_SetError(): SDL_LoadObject already did.
} else {
retval = load_pulseaudio_syms();
if (retval < 0) {
@ -174,7 +188,7 @@ static int LoadPulseAudioLibrary(void)
return 0;
}
#endif /* SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC */
#endif // SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC
static int load_pulseaudio_syms(void)
{
@ -188,10 +202,8 @@ static int load_pulseaudio_syms(void)
SDL_PULSEAUDIO_SYM(pa_threaded_mainloop_wait);
SDL_PULSEAUDIO_SYM(pa_threaded_mainloop_signal);
SDL_PULSEAUDIO_SYM(pa_threaded_mainloop_free);
SDL_PULSEAUDIO_SYM(pa_threaded_mainloop_set_name);
SDL_PULSEAUDIO_SYM(pa_operation_get_state);
SDL_PULSEAUDIO_SYM(pa_operation_cancel);
SDL_PULSEAUDIO_SYM(pa_operation_set_state_callback);
SDL_PULSEAUDIO_SYM(pa_operation_unref);
SDL_PULSEAUDIO_SYM(pa_context_new);
SDL_PULSEAUDIO_SYM(pa_context_set_state_callback);
@ -209,9 +221,11 @@ static int load_pulseaudio_syms(void)
SDL_PULSEAUDIO_SYM(pa_stream_set_state_callback);
SDL_PULSEAUDIO_SYM(pa_stream_connect_playback);
SDL_PULSEAUDIO_SYM(pa_stream_connect_record);
SDL_PULSEAUDIO_SYM(pa_stream_get_buffer_attr);
SDL_PULSEAUDIO_SYM(pa_stream_get_state);
SDL_PULSEAUDIO_SYM(pa_stream_writable_size);
SDL_PULSEAUDIO_SYM(pa_stream_readable_size);
SDL_PULSEAUDIO_SYM(pa_stream_begin_write);
SDL_PULSEAUDIO_SYM(pa_stream_write);
SDL_PULSEAUDIO_SYM(pa_stream_drain);
SDL_PULSEAUDIO_SYM(pa_stream_disconnect);
@ -225,6 +239,21 @@ static int load_pulseaudio_syms(void)
SDL_PULSEAUDIO_SYM(pa_stream_set_read_callback);
SDL_PULSEAUDIO_SYM(pa_context_get_server_info);
// optional
#ifdef SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC
load_pulseaudio_sym("pa_operation_set_state_callback", (void **)(char *)&PULSEAUDIO_pa_operation_set_state_callback); // needs pulseaudio 4.0
load_pulseaudio_sym("pa_threaded_mainloop_set_name", (void **)(char *)&PULSEAUDIO_pa_threaded_mainloop_set_name); // needs pulseaudio 5.0
#elif (PA_PROTOCOL_VERSION >= 29)
PULSEAUDIO_pa_operation_set_state_callback = pa_operation_set_state_callback;
PULSEAUDIO_pa_threaded_mainloop_set_name = pa_threaded_mainloop_set_name;
#elif (PA_PROTOCOL_VERSION >= 28)
PULSEAUDIO_pa_operation_set_state_callback = pa_operation_set_state_callback;
PULSEAUDIO_pa_threaded_mainloop_set_name = NULL;
#else
PULSEAUDIO_pa_operation_set_state_callback = NULL;
PULSEAUDIO_pa_threaded_mainloop_set_name = NULL;
#endif
return 0;
}
@ -233,7 +262,7 @@ static SDL_INLINE int squashVersion(const int major, const int minor, const int
return ((major & 0xFF) << 16) | ((minor & 0xFF) << 8) | (patch & 0xFF);
}
/* Workaround for older pulse: pa_context_new() must have non-NULL appname */
// Workaround for older pulse: pa_context_new() must have non-NULL appname
static const char *getAppName(void)
{
const char *retval = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME);
@ -245,12 +274,12 @@ static const char *getAppName(void)
return retval;
} else {
const char *verstr = PULSEAUDIO_pa_get_library_version();
retval = "SDL Application"; /* the "oh well" default. */
if (verstr != NULL) {
retval = "SDL Application"; // the "oh well" default.
if (verstr) {
int maj, min, patch;
if (SDL_sscanf(verstr, "%d.%d.%d", &maj, &min, &patch) == 3) {
if (squashVersion(maj, min, patch) >= squashVersion(0, 9, 15)) {
retval = NULL; /* 0.9.15+ handles NULL correctly. */
retval = NULL; // 0.9.15+ handles NULL correctly.
}
}
}
@ -267,12 +296,18 @@ static void OperationStateChangeCallback(pa_operation *o, void *userdata)
you did the work in the callback and just want to know it's done, though. */
static void WaitForPulseOperation(pa_operation *o)
{
/* This checks for NO errors currently. Either fix that, check results elsewhere, or do things you don't care about. */
// This checks for NO errors currently. Either fix that, check results elsewhere, or do things you don't care about.
SDL_assert(pulseaudio_threaded_mainloop != NULL);
if (o) {
PULSEAUDIO_pa_operation_set_state_callback(o, OperationStateChangeCallback, NULL);
// note that if PULSEAUDIO_pa_operation_set_state_callback == NULL, then `o` must have a callback that will signal pulseaudio_threaded_mainloop.
// If not, on really old (earlier PulseAudio 4.0, from the year 2013!) installs, this call will block forever.
// On more modern installs, we won't ever block forever, and maybe be more efficient, thanks to pa_operation_set_state_callback.
// WARNING: at the time of this writing: the Steam Runtime is still on PulseAudio 1.1!
if (PULSEAUDIO_pa_operation_set_state_callback) {
PULSEAUDIO_pa_operation_set_state_callback(o, OperationStateChangeCallback, NULL);
}
while (PULSEAUDIO_pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
PULSEAUDIO_pa_threaded_mainloop_wait(pulseaudio_threaded_mainloop); /* this releases the lock and blocks on an internal condition variable. */
PULSEAUDIO_pa_threaded_mainloop_wait(pulseaudio_threaded_mainloop); // this releases the lock and blocks on an internal condition variable.
}
PULSEAUDIO_pa_operation_unref(o);
}
@ -280,13 +315,15 @@ static void WaitForPulseOperation(pa_operation *o)
static void DisconnectFromPulseServer(void)
{
if (pulseaudio_threaded_mainloop) {
PULSEAUDIO_pa_threaded_mainloop_stop(pulseaudio_threaded_mainloop);
}
if (pulseaudio_context) {
PULSEAUDIO_pa_context_disconnect(pulseaudio_context);
PULSEAUDIO_pa_context_unref(pulseaudio_context);
pulseaudio_context = NULL;
}
if (pulseaudio_threaded_mainloop != NULL) {
PULSEAUDIO_pa_threaded_mainloop_stop(pulseaudio_threaded_mainloop);
if (pulseaudio_threaded_mainloop) {
PULSEAUDIO_pa_threaded_mainloop_free(pulseaudio_threaded_mainloop);
pulseaudio_threaded_mainloop = NULL;
}
@ -294,7 +331,7 @@ static void DisconnectFromPulseServer(void)
static void PulseContextStateChangeCallback(pa_context *context, void *userdata)
{
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); /* just signal any waiting code, it can look up the details. */
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); // just signal any waiting code, it can look up the details.
}
static int ConnectToPulseServer(void)
@ -305,12 +342,14 @@ static int ConnectToPulseServer(void)
SDL_assert(pulseaudio_threaded_mainloop == NULL);
SDL_assert(pulseaudio_context == NULL);
/* Set up a new main loop */
// Set up a new main loop
if (!(pulseaudio_threaded_mainloop = PULSEAUDIO_pa_threaded_mainloop_new())) {
return SDL_SetError("pa_threaded_mainloop_new() failed");
}
PULSEAUDIO_pa_threaded_mainloop_set_name(pulseaudio_threaded_mainloop, "PulseMainloop");
if (PULSEAUDIO_pa_threaded_mainloop_set_name) {
PULSEAUDIO_pa_threaded_mainloop_set_name(pulseaudio_threaded_mainloop, "PulseMainloop");
}
if (PULSEAUDIO_pa_threaded_mainloop_start(pulseaudio_threaded_mainloop) < 0) {
PULSEAUDIO_pa_threaded_mainloop_free(pulseaudio_threaded_mainloop);
@ -321,17 +360,17 @@ static int ConnectToPulseServer(void)
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop);
mainloop_api = PULSEAUDIO_pa_threaded_mainloop_get_api(pulseaudio_threaded_mainloop);
SDL_assert(mainloop_api); /* this never fails, right? */
SDL_assert(mainloop_api != NULL); // this never fails, right?
pulseaudio_context = PULSEAUDIO_pa_context_new(mainloop_api, getAppName());
if (pulseaudio_context == NULL) {
if (!pulseaudio_context) {
SDL_SetError("pa_context_new() failed");
goto failed;
}
PULSEAUDIO_pa_context_set_state_callback(pulseaudio_context, PulseContextStateChangeCallback, NULL);
/* Connect to the PulseAudio server */
// Connect to the PulseAudio server
if (PULSEAUDIO_pa_context_connect(pulseaudio_context, NULL, 0, NULL) < 0) {
SDL_SetError("Could not setup connection to PulseAudio");
goto failed;
@ -350,7 +389,7 @@ static int ConnectToPulseServer(void)
PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop);
return 0; /* connected and ready! */
return 0; // connected and ready!
failed:
PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop);
@ -361,38 +400,42 @@ failed:
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);*/
//SDL_Log("PULSEAUDIO WRITE CALLBACK! nbytes=%u", (unsigned int) nbytes);
h->bytes_requested += nbytes;
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
}
/* This function waits until it is possible to write a full sound buffer */
static void PULSEAUDIO_WaitDevice(SDL_AudioDevice *device)
// This function waits until it is possible to write a full sound buffer
static int PULSEAUDIO_WaitDevice(SDL_AudioDevice *device)
{
struct SDL_PrivateAudioData *h = device->hidden;
int retval = 0;
/*printf("PULSEAUDIO PLAYDEVICE START! mixlen=%d\n", available);*/
//SDL_Log("PULSEAUDIO PLAYDEVICE START! mixlen=%d", available);
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop);
while (!SDL_AtomicGet(&device->shutdown) && (h->bytes_requested < (device->buffer_size / 2))) {
/*printf("PULSEAUDIO WAIT IN WAITDEVICE!\n");*/
while (!SDL_AtomicGet(&device->shutdown) && (h->bytes_requested == 0)) {
//SDL_Log("PULSEAUDIO WAIT IN WAITDEVICE!");
PULSEAUDIO_pa_threaded_mainloop_wait(pulseaudio_threaded_mainloop);
if ((PULSEAUDIO_pa_context_get_state(pulseaudio_context) != PA_CONTEXT_READY) || (PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY)) {
/*printf("PULSEAUDIO DEVICE FAILURE IN WAITDEVICE!\n");*/
SDL_AudioDeviceDisconnected(device);
//SDL_Log("PULSEAUDIO DEVICE FAILURE IN WAITDEVICE!");
retval = -1;
break;
}
}
PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop);
return retval;
}
static int PULSEAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size)
{
struct SDL_PrivateAudioData *h = device->hidden;
/*printf("PULSEAUDIO PLAYDEVICE START! mixlen=%d\n", available);*/
//SDL_Log("PULSEAUDIO PLAYDEVICE START! mixlen=%d", available);
SDL_assert(h->bytes_requested >= buffer_size);
@ -404,41 +447,52 @@ static int PULSEAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, i
return -1;
}
/*printf("PULSEAUDIO FEED! nbytes=%d\n", buffer_size);*/
//SDL_Log("PULSEAUDIO FEED! nbytes=%d", buffer_size);
h->bytes_requested -= buffer_size;
/*printf("PULSEAUDIO PLAYDEVICE END! written=%d\n", written);*/
//SDL_Log("PULSEAUDIO PLAYDEVICE END! written=%d", written);
return 0;
}
static Uint8 *PULSEAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
{
struct SDL_PrivateAudioData *h = device->hidden;
*buffer_size = SDL_min(*buffer_size, h->bytes_requested);
const size_t reqsize = (size_t) SDL_min(*buffer_size, h->bytes_requested);
size_t nbytes = reqsize;
void *data = NULL;
if (PULSEAUDIO_pa_stream_begin_write(h->stream, &data, &nbytes) == 0) {
*buffer_size = (int) nbytes;
return (Uint8 *) data;
}
// don't know why this would fail, but we'll fall back just in case.
*buffer_size = (int) reqsize;
return device->hidden->mixbuf;
}
static void ReadCallback(pa_stream *p, size_t nbytes, void *userdata)
{
/*printf("PULSEAUDIO READ CALLBACK! nbytes=%u\n", (unsigned int) nbytes);*/
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); /* the capture code queries what it needs, we just need to signal to end any wait */
//SDL_Log("PULSEAUDIO READ CALLBACK! nbytes=%u", (unsigned int) nbytes);
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); // the capture code queries what it needs, we just need to signal to end any wait
}
static void PULSEAUDIO_WaitCaptureDevice(SDL_AudioDevice *device)
static int PULSEAUDIO_WaitCaptureDevice(SDL_AudioDevice *device)
{
struct SDL_PrivateAudioData *h = device->hidden;
if (h->capturebuf != NULL) {
return; // there's still data available to read.
if (h->capturebuf) {
return 0; // there's still data available to read.
}
int retval = 0;
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop);
while (!SDL_AtomicGet(&device->shutdown)) {
PULSEAUDIO_pa_threaded_mainloop_wait(pulseaudio_threaded_mainloop);
if ((PULSEAUDIO_pa_context_get_state(pulseaudio_context) != PA_CONTEXT_READY) || (PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY)) {
//printf("PULSEAUDIO DEVICE FAILURE IN WAITCAPTUREDEVICE!\n");
SDL_AudioDeviceDisconnected(device);
//SDL_Log("PULSEAUDIO DEVICE FAILURE IN WAITCAPTUREDEVICE!");
retval = -1;
break;
} else if (PULSEAUDIO_pa_stream_readable_size(h->stream) > 0) {
// a new fragment is available!
@ -446,11 +500,11 @@ static void PULSEAUDIO_WaitCaptureDevice(SDL_AudioDevice *device)
size_t nbytes = 0;
PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes);
SDL_assert(nbytes > 0);
if (data == NULL) { // If NULL, then the buffer had a hole, ignore that
if (!data) { // If NULL, then the buffer had a hole, ignore that
PULSEAUDIO_pa_stream_drop(h->stream); // drop this fragment.
} else {
// store this fragment's data for use with CaptureFromDevice
//printf("PULSEAUDIO: captured %d new bytes\n", (int) nbytes);
//SDL_Log("PULSEAUDIO: captured %d new bytes", (int) nbytes);
h->capturebuf = (const Uint8 *)data;
h->capturelen = nbytes;
break;
@ -459,16 +513,18 @@ static void PULSEAUDIO_WaitCaptureDevice(SDL_AudioDevice *device)
}
PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop);
return retval;
}
static int PULSEAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
{
struct SDL_PrivateAudioData *h = device->hidden;
if (h->capturebuf != NULL) {
if (h->capturebuf) {
const int cpy = SDL_min(buflen, h->capturelen);
if (cpy > 0) {
//printf("PULSEAUDIO: fed %d captured bytes\n", cpy);
//SDL_Log("PULSEAUDIO: fed %d captured bytes", cpy);
SDL_memcpy(buffer, h->capturebuf, cpy);
h->capturebuf += cpy;
h->capturelen -= cpy;
@ -479,7 +535,7 @@ static int PULSEAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, i
PULSEAUDIO_pa_stream_drop(h->stream); // done with this fragment.
PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop);
}
return cpy; /* new data, return it. */
return cpy; // new data, return it.
}
return 0;
@ -493,7 +549,7 @@ static void PULSEAUDIO_FlushCapture(SDL_AudioDevice *device)
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop);
if (h->capturebuf != NULL) {
if (h->capturebuf) {
PULSEAUDIO_pa_stream_drop(h->stream);
h->capturebuf = NULL;
h->capturelen = 0;
@ -502,15 +558,15 @@ static void PULSEAUDIO_FlushCapture(SDL_AudioDevice *device)
while (!SDL_AtomicGet(&device->shutdown) && (PULSEAUDIO_pa_stream_readable_size(h->stream) > 0)) {
PULSEAUDIO_pa_threaded_mainloop_wait(pulseaudio_threaded_mainloop);
if ((PULSEAUDIO_pa_context_get_state(pulseaudio_context) != PA_CONTEXT_READY) || (PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY)) {
/*printf("PULSEAUDIO DEVICE FAILURE IN FLUSHCAPTURE!\n");*/
//SDL_Log("PULSEAUDIO DEVICE FAILURE IN FLUSHCAPTURE!");
SDL_AudioDeviceDisconnected(device);
break;
}
if (PULSEAUDIO_pa_stream_readable_size(h->stream) > 0) {
/* a new fragment is available! Just dump it. */
// a new fragment is available! Just dump it.
PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes);
PULSEAUDIO_pa_stream_drop(h->stream); /* drop this fragment. */
PULSEAUDIO_pa_stream_drop(h->stream); // drop this fragment.
}
}
@ -522,7 +578,7 @@ static void PULSEAUDIO_CloseDevice(SDL_AudioDevice *device)
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop);
if (device->hidden->stream) {
if (device->hidden->capturebuf != NULL) {
if (device->hidden->capturebuf) {
PULSEAUDIO_pa_stream_drop(device->hidden->stream);
}
PULSEAUDIO_pa_stream_disconnect(device->hidden->stream);
@ -532,46 +588,12 @@ static void PULSEAUDIO_CloseDevice(SDL_AudioDevice *device)
PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop);
SDL_free(device->hidden->mixbuf);
SDL_free(device->hidden->device_name);
SDL_free(device->hidden);
}
static void SinkDeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
{
if (i) {
char **devname = (char **)data;
*devname = SDL_strdup(i->name);
}
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
}
static void SourceDeviceNameCallback(pa_context *c, const pa_source_info *i, int is_last, void *data)
{
if (i) {
char **devname = (char **)data;
*devname = SDL_strdup(i->name);
}
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
}
static SDL_bool FindDeviceName(SDL_AudioDevice *device)
{
struct SDL_PrivateAudioData *h = device->hidden;
SDL_assert(device->handle != NULL); // this was a thing in SDL2, but shouldn't be in SDL3.
const uint32_t idx = ((uint32_t)((intptr_t)device->handle)) - 1;
if (device->iscapture) {
WaitForPulseOperation(PULSEAUDIO_pa_context_get_source_info_by_index(pulseaudio_context, idx, SourceDeviceNameCallback, &h->device_name));
} else {
WaitForPulseOperation(PULSEAUDIO_pa_context_get_sink_info_by_index(pulseaudio_context, idx, SinkDeviceNameCallback, &h->device_name));
}
return h->device_name != NULL;
}
static void PulseStreamStateChangeCallback(pa_stream *stream, void *userdata)
{
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); /* just signal any waiting code, it can look up the details. */
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0); // just signal any waiting code, it can look up the details.
}
static int PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
@ -590,17 +612,17 @@ static int PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
SDL_assert(pulseaudio_threaded_mainloop != NULL);
SDL_assert(pulseaudio_context != NULL);
/* Initialize all variables that we clean on shutdown */
// Initialize all variables that we clean on shutdown
h = device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
if (!device->hidden) {
return -1;
}
/* Try for a closest match on audio format */
// Try for a closest match on audio format
closefmts = SDL_ClosestAudioFormats(device->spec.format);
while ((test_format = *(closefmts++)) != 0) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
SDL_Log("pulseaudio: Trying format 0x%4.4x", test_format);
#endif
switch (test_format) {
case SDL_AUDIO_U8:
@ -635,14 +657,14 @@ static int PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
device->spec.format = test_format;
paspec.format = format;
/* Calculate the final parameters for this audio specification */
// Calculate the final parameters for this audio specification
SDL_UpdatedAudioDeviceFormat(device);
/* Allocate mixing buffer */
// Allocate mixing buffer
if (!iscapture) {
h->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
if (h->mixbuf == NULL) {
return SDL_OutOfMemory();
if (!h->mixbuf) {
return -1;
}
SDL_memset(h->mixbuf, device->silence_value, device->buffer_size);
}
@ -650,8 +672,8 @@ static int PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
paspec.channels = device->spec.channels;
paspec.rate = device->spec.freq;
/* Reduced prebuffering compared to the defaults. */
paattr.fragsize = device->buffer_size;
// Reduced prebuffering compared to the defaults.
paattr.fragsize = device->buffer_size; // despite the name, this is only used for capture devices, according to PulseAudio docs!
paattr.tlength = device->buffer_size;
paattr.prebuf = -1;
paattr.maxlength = -1;
@ -660,50 +682,55 @@ static int PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop);
if (!FindDeviceName(device)) {
retval = SDL_SetError("Requested PulseAudio sink/source missing?");
const char *name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME);
// The SDL ALSA output hints us that we use Windows' channel mapping
// https://bugzilla.libsdl.org/show_bug.cgi?id=110
PULSEAUDIO_pa_channel_map_init_auto(&pacmap, device->spec.channels, PA_CHANNEL_MAP_WAVEEX);
h->stream = PULSEAUDIO_pa_stream_new(
pulseaudio_context,
(name && *name) ? name : "Audio Stream", // stream description
&paspec, // sample format spec
&pacmap // channel map
);
if (!h->stream) {
retval = SDL_SetError("Could not set up PulseAudio stream");
} else {
const char *name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME);
/* The SDL ALSA output hints us that we use Windows' channel mapping */
/* https://bugzilla.libsdl.org/show_bug.cgi?id=110 */
PULSEAUDIO_pa_channel_map_init_auto(&pacmap, device->spec.channels, PA_CHANNEL_MAP_WAVEEX);
int rc;
h->stream = PULSEAUDIO_pa_stream_new(
pulseaudio_context,
(name && *name) ? name : "Audio Stream", /* stream description */
&paspec, /* sample format spec */
&pacmap /* channel map */
);
PULSEAUDIO_pa_stream_set_state_callback(h->stream, PulseStreamStateChangeCallback, NULL);
if (h->stream == NULL) {
retval = SDL_SetError("Could not set up PulseAudio stream");
// SDL manages device moves if the default changes, so don't ever let Pulse automatically migrate this stream.
flags |= PA_STREAM_DONT_MOVE;
const char *device_path = ((PulseDeviceHandle *) device->handle)->device_path;
if (iscapture) {
PULSEAUDIO_pa_stream_set_read_callback(h->stream, ReadCallback, h);
rc = PULSEAUDIO_pa_stream_connect_record(h->stream, device_path, &paattr, flags);
} else {
int rc;
PULSEAUDIO_pa_stream_set_write_callback(h->stream, WriteCallback, h);
rc = PULSEAUDIO_pa_stream_connect_playback(h->stream, device_path, &paattr, flags, NULL, NULL);
}
PULSEAUDIO_pa_stream_set_state_callback(h->stream, PulseStreamStateChangeCallback, NULL);
// SDL manages device moves if the default changes, so don't ever let Pulse automatically migrate this stream.
flags |= PA_STREAM_DONT_MOVE;
if (iscapture) {
PULSEAUDIO_pa_stream_set_read_callback(h->stream, ReadCallback, h);
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);
if (rc < 0) {
retval = SDL_SetError("Could not connect PulseAudio stream");
} else {
int state = PULSEAUDIO_pa_stream_get_state(h->stream);
while (PA_STREAM_IS_GOOD(state) && (state != PA_STREAM_READY)) {
PULSEAUDIO_pa_threaded_mainloop_wait(pulseaudio_threaded_mainloop);
state = PULSEAUDIO_pa_stream_get_state(h->stream);
}
if (rc < 0) {
if (!PA_STREAM_IS_GOOD(state)) {
retval = SDL_SetError("Could not connect PulseAudio stream");
} else {
int state = PULSEAUDIO_pa_stream_get_state(h->stream);
while (PA_STREAM_IS_GOOD(state) && (state != PA_STREAM_READY)) {
PULSEAUDIO_pa_threaded_mainloop_wait(pulseaudio_threaded_mainloop);
state = PULSEAUDIO_pa_stream_get_state(h->stream);
}
if (!PA_STREAM_IS_GOOD(state)) {
retval = SDL_SetError("Could not connect PulseAudio stream");
const pa_buffer_attr *actual_bufattr = PULSEAUDIO_pa_stream_get_buffer_attr(h->stream);
if (!actual_bufattr) {
retval = SDL_SetError("Could not determine connected PulseAudio stream's buffer attributes");
} else {
device->buffer_size = (int) iscapture ? actual_bufattr->tlength : actual_bufattr->fragsize;
device->sample_frames = device->buffer_size / SDL_AUDIO_FRAMESIZE(device->spec);
}
}
}
@ -711,11 +738,11 @@ static int PULSEAUDIO_OpenDevice(SDL_AudioDevice *device)
PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop);
/* We're (hopefully) ready to rock and roll. :-) */
// We're (hopefully) ready to rock and roll. :-)
return retval;
}
/* device handles are device index + 1, cast to void*, so we never pass a NULL. */
// device handles are device index + 1, cast to void*, so we never pass a NULL.
static SDL_AudioFormat PulseFormatToSDLFormat(pa_sample_format_t format)
{
@ -739,76 +766,90 @@ static SDL_AudioFormat PulseFormatToSDLFormat(pa_sample_format_t format)
}
}
static void AddPulseAudioDevice(const SDL_bool iscapture, const char *description, const char *name, const uint32_t index, const pa_sample_spec *sample_spec)
{
SDL_AudioSpec spec;
spec.format = PulseFormatToSDLFormat(sample_spec->format);
spec.channels = sample_spec->channels;
spec.freq = sample_spec->rate;
PulseDeviceHandle *handle = (PulseDeviceHandle *) SDL_malloc(sizeof (PulseDeviceHandle));
if (handle) {
handle->device_path = SDL_strdup(name);
if (!handle->device_path) {
SDL_free(handle);
} else {
handle->device_index = index;
}
SDL_AddAudioDevice(iscapture, description, &spec, handle);
}
}
// This is called when PulseAudio adds an output ("sink") device.
// !!! FIXME: this is almost identical to SourceInfoCallback, merge the two.
static void SinkInfoCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
{
if (i) {
const SDL_bool add = (SDL_bool) ((intptr_t)data);
if (add) {
SDL_AudioSpec spec;
spec.format = PulseFormatToSDLFormat(i->sample_spec.format);
spec.channels = i->sample_spec.channels;
spec.freq = i->sample_spec.rate;
SDL_AddAudioDevice(SDL_FALSE, i->description, &spec, (void *)((intptr_t)i->index + 1));
}
if (default_sink_path != NULL && SDL_strcmp(i->name, default_sink_path) == 0) {
default_sink_index = i->index;
}
AddPulseAudioDevice(SDL_FALSE, i->description, i->name, i->index, &i->sample_spec);
}
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
}
/* This is called when PulseAudio adds a capture ("source") device. */
// !!! FIXME: this is almost identical to SinkInfoCallback, merge the two.
// This is called when PulseAudio adds a capture ("source") device.
static void SourceInfoCallback(pa_context *c, const pa_source_info *i, int is_last, void *data)
{
/* Maybe skip "monitor" sources. These are just output from other sinks. */
// Maybe skip "monitor" sources. These are just output from other sinks.
if (i && (include_monitors || (i->monitor_of_sink == PA_INVALID_INDEX))) {
const SDL_bool add = (SDL_bool) ((intptr_t)data);
if (add) {
SDL_AudioSpec spec;
spec.format = PulseFormatToSDLFormat(i->sample_spec.format);
spec.channels = i->sample_spec.channels;
spec.freq = i->sample_spec.rate;
SDL_AddAudioDevice(SDL_TRUE, i->description, &spec, (void *)((intptr_t)i->index + 1));
}
if (default_source_path != NULL && SDL_strcmp(i->name, default_source_path) == 0) {
default_source_index = i->index;
}
AddPulseAudioDevice(SDL_TRUE, i->description, i->name, i->index, &i->sample_spec);
}
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
}
static void ServerInfoCallback(pa_context *c, const pa_server_info *i, void *data)
{
if (!default_sink_path || (SDL_strcmp(i->default_sink_name, default_sink_path) != 0)) {
/*printf("DEFAULT SINK PATH CHANGED TO '%s'\n", i->default_sink_name);*/
SDL_free(default_sink_path);
default_sink_path = SDL_strdup(i->default_sink_name);
//SDL_Log("PULSEAUDIO ServerInfoCallback!");
if (!default_sink_path || (SDL_strcmp(default_sink_path, i->default_sink_name) != 0)) {
char *str = SDL_strdup(i->default_sink_name);
if (str) {
SDL_free(default_sink_path);
default_sink_path = str;
default_sink_changed = SDL_TRUE;
}
}
if (!default_source_path || (SDL_strcmp(i->default_source_name, default_source_path) != 0)) {
/*printf("DEFAULT SOURCE PATH CHANGED TO '%s'\n", i->default_source_name);*/
SDL_free(default_source_path);
default_source_path = SDL_strdup(i->default_source_name);
if (!default_source_path || (SDL_strcmp(default_source_path, i->default_source_name) != 0)) {
char *str = SDL_strdup(i->default_source_name);
if (str) {
SDL_free(default_source_path);
default_source_path = str;
default_source_changed = SDL_TRUE;
}
}
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
}
// This is called when PulseAudio has a device connected/removed/changed. */
static SDL_bool FindAudioDeviceByIndex(SDL_AudioDevice *device, void *userdata)
{
const uint32_t idx = (uint32_t) (uintptr_t) userdata;
const PulseDeviceHandle *handle = (const PulseDeviceHandle *) device->handle;
return (handle->device_index == idx);
}
static SDL_bool FindAudioDeviceByPath(SDL_AudioDevice *device, void *userdata)
{
const char *path = (const char *) userdata;
const PulseDeviceHandle *handle = (const PulseDeviceHandle *) device->handle;
return (SDL_strcmp(handle->device_path, path) == 0);
}
// This is called when PulseAudio has a device connected/removed/changed.
static void HotplugCallback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *data)
{
const SDL_bool added = ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW);
const SDL_bool removed = ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE);
const SDL_bool changed = ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_CHANGE);
if (added || removed || changed) { /* we only care about add/remove events. */
if (added || removed || changed) { // we only care about add/remove events.
const SDL_bool sink = ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK);
const SDL_bool source = ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
@ -819,41 +860,44 @@ static void HotplugCallback(pa_context *c, pa_subscription_event_type_t t, uint3
/* adds need sink details from the PulseAudio server. Another callback...
(just unref all these operations right away, because we aren't going to wait on them
and their callbacks will handle any work, so they can free as soon as that happens.) */
if ((added || changed) && sink) {
PULSEAUDIO_pa_operation_unref(PULSEAUDIO_pa_context_get_sink_info_by_index(pulseaudio_context, idx, SinkInfoCallback, (void *)((intptr_t)added)));
} else if ((added || changed) && source) {
PULSEAUDIO_pa_operation_unref(PULSEAUDIO_pa_context_get_source_info_by_index(pulseaudio_context, idx, SourceInfoCallback, (void *)((intptr_t)added)));
if (added && sink) {
PULSEAUDIO_pa_operation_unref(PULSEAUDIO_pa_context_get_sink_info_by_index(pulseaudio_context, idx, SinkInfoCallback, NULL));
} else if (added && source) {
PULSEAUDIO_pa_operation_unref(PULSEAUDIO_pa_context_get_source_info_by_index(pulseaudio_context, idx, SourceInfoCallback, NULL));
} else if (removed && (sink || source)) {
// removes we can handle just with the device index.
SDL_AudioDeviceDisconnected(SDL_FindPhysicalAudioDeviceByHandle((void *)((intptr_t)idx + 1)));
SDL_AudioDeviceDisconnected(SDL_FindPhysicalAudioDeviceByCallback(FindAudioDeviceByIndex, (void *)(uintptr_t)idx));
}
}
PULSEAUDIO_pa_threaded_mainloop_signal(pulseaudio_threaded_mainloop, 0);
}
static void CheckDefaultDevice(uint32_t *prev_default, uint32_t new_default)
static SDL_bool CheckDefaultDevice(const SDL_bool changed, char *device_path)
{
if (*prev_default != new_default) {
SDL_AudioDevice *device = SDL_FindPhysicalAudioDeviceByHandle((void *)((intptr_t)new_default + 1));
if (device) {
*prev_default = new_default;
SDL_DefaultAudioDeviceChanged(device);
}
if (!changed) {
return SDL_FALSE; // nothing's happening, leave the flag marked as unchanged.
} else if (!device_path) {
return SDL_TRUE; // check again later, we don't have a device name...
}
SDL_AudioDevice *device = SDL_FindPhysicalAudioDeviceByCallback(FindAudioDeviceByPath, device_path);
if (device) { // if NULL, we might still be waiting for a SinkInfoCallback or something, we'll try later.
SDL_DefaultAudioDeviceChanged(device);
return SDL_FALSE; // changing complete, set flag to unchanged for future tests.
}
return SDL_TRUE; // couldn't find the changed device, leave it marked as changed to try again later.
}
// this runs as a thread while the Pulse target is initialized to catch hotplug events.
static int SDLCALL HotplugThread(void *data)
{
uint32_t prev_default_sink_index = default_sink_index;
uint32_t prev_default_source_index = default_source_index;
pa_operation *op;
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_LOW);
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop);
PULSEAUDIO_pa_context_set_subscribe_callback(pulseaudio_context, HotplugCallback, NULL);
/* don't WaitForPulseOperation on the subscription; when it's done we'll be able to get hotplug events, but waiting doesn't changing anything. */
// don't WaitForPulseOperation on the subscription; when it's done we'll be able to get hotplug events, but waiting doesn't changing anything.
op = PULSEAUDIO_pa_context_subscribe(pulseaudio_context, PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE | PA_SUBSCRIPTION_MASK_SERVER, NULL, NULL);
SDL_PostSemaphore((SDL_Semaphore *) data);
@ -866,11 +910,23 @@ static int SDLCALL HotplugThread(void *data)
}
// Update default devices; don't hold the pulse lock during this, since it could deadlock vs a playing device that we're about to lock here.
SDL_bool check_default_sink = default_sink_changed;
SDL_bool check_default_source = default_source_changed;
char *current_default_sink = check_default_sink ? SDL_strdup(default_sink_path) : NULL;
char *current_default_source = check_default_source ? SDL_strdup(default_source_path) : NULL;
default_sink_changed = default_source_changed = SDL_FALSE;
PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop);
CheckDefaultDevice(&prev_default_sink_index, default_sink_index);
CheckDefaultDevice(&prev_default_source_index, default_source_index);
check_default_sink = CheckDefaultDevice(check_default_sink, current_default_sink);
check_default_source = CheckDefaultDevice(check_default_source, current_default_source);
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop);
// free our copies (which will be NULL if nothing changed)
SDL_free(current_default_sink);
SDL_free(current_default_source);
// set these to true if we didn't handle the change OR there was _another_ change while we were working unlocked.
default_sink_changed = (default_sink_changed || check_default_sink);
default_source_changed = (default_source_changed || check_default_source);
}
if (op) {
@ -880,8 +936,6 @@ static int SDLCALL HotplugThread(void *data)
PULSEAUDIO_pa_context_set_subscribe_callback(pulseaudio_context, NULL, NULL);
PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop);
return 0;
}
static void PULSEAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
@ -890,29 +944,33 @@ static void PULSEAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_Audio
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop);
WaitForPulseOperation(PULSEAUDIO_pa_context_get_server_info(pulseaudio_context, ServerInfoCallback, NULL));
WaitForPulseOperation(PULSEAUDIO_pa_context_get_sink_info_list(pulseaudio_context, SinkInfoCallback, (void *)((intptr_t)SDL_TRUE)));
WaitForPulseOperation(PULSEAUDIO_pa_context_get_source_info_list(pulseaudio_context, SourceInfoCallback, (void *)((intptr_t)SDL_TRUE)));
WaitForPulseOperation(PULSEAUDIO_pa_context_get_sink_info_list(pulseaudio_context, SinkInfoCallback, NULL));
WaitForPulseOperation(PULSEAUDIO_pa_context_get_source_info_list(pulseaudio_context, SourceInfoCallback, NULL));
PULSEAUDIO_pa_threaded_mainloop_unlock(pulseaudio_threaded_mainloop);
SDL_AudioDevice *device;
device = SDL_FindPhysicalAudioDeviceByHandle((void *)((intptr_t)default_sink_index + 1));
if (device) {
*default_output = device;
if (default_sink_path) {
*default_output = SDL_FindPhysicalAudioDeviceByCallback(FindAudioDeviceByPath, default_sink_path);
}
device = SDL_FindPhysicalAudioDeviceByHandle((void *)((intptr_t)default_source_index + 1));
if (device) {
*default_capture = device;
if (default_source_path) {
*default_capture = SDL_FindPhysicalAudioDeviceByCallback(FindAudioDeviceByPath, default_source_path);
}
/* ok, we have a sane list, let's set up hotplug notifications now... */
// ok, we have a sane list, let's set up hotplug notifications now...
SDL_AtomicSet(&pulseaudio_hotplug_thread_active, 1);
pulseaudio_hotplug_thread = SDL_CreateThreadInternal(HotplugThread, "PulseHotplug", 256 * 1024, ready_sem); // !!! FIXME: this can probably survive in significantly less stack space.
SDL_WaitSemaphore(ready_sem);
SDL_DestroySemaphore(ready_sem);
}
static void PULSEAUDIO_Deinitialize(void)
static void PULSEAUDIO_FreeDeviceHandle(SDL_AudioDevice *device)
{
PulseDeviceHandle *handle = (PulseDeviceHandle *) device->handle;
SDL_free(handle->device_path);
SDL_free(handle);
}
static void PULSEAUDIO_DeinitializeStart(void)
{
if (pulseaudio_hotplug_thread) {
PULSEAUDIO_pa_threaded_mainloop_lock(pulseaudio_threaded_mainloop);
@ -922,16 +980,18 @@ static void PULSEAUDIO_Deinitialize(void)
SDL_WaitThread(pulseaudio_hotplug_thread, NULL);
pulseaudio_hotplug_thread = NULL;
}
}
static void PULSEAUDIO_Deinitialize(void)
{
DisconnectFromPulseServer();
SDL_free(default_sink_path);
default_sink_path = NULL;
default_sink_changed = SDL_FALSE;
SDL_free(default_source_path);
default_source_path = NULL;
default_source_index = 0;
default_sink_index = 0;
default_source_changed = SDL_FALSE;
UnloadPulseAudioLibrary();
}
@ -947,25 +1007,26 @@ static SDL_bool PULSEAUDIO_Init(SDL_AudioDriverImpl *impl)
include_monitors = SDL_GetHintBoolean(SDL_HINT_AUDIO_INCLUDE_MONITORS, SDL_FALSE);
/* Set the function pointers */
impl->DetectDevices = PULSEAUDIO_DetectDevices;
impl->OpenDevice = PULSEAUDIO_OpenDevice;
impl->PlayDevice = PULSEAUDIO_PlayDevice;
impl->WaitDevice = PULSEAUDIO_WaitDevice;
impl->GetDeviceBuf = PULSEAUDIO_GetDeviceBuf;
impl->CloseDevice = PULSEAUDIO_CloseDevice;
impl->DeinitializeStart = PULSEAUDIO_DeinitializeStart;
impl->Deinitialize = PULSEAUDIO_Deinitialize;
impl->WaitCaptureDevice = PULSEAUDIO_WaitCaptureDevice;
impl->CaptureFromDevice = PULSEAUDIO_CaptureFromDevice;
impl->FlushCapture = PULSEAUDIO_FlushCapture;
impl->FreeDeviceHandle = PULSEAUDIO_FreeDeviceHandle;
impl->HasCaptureSupport = SDL_TRUE;
return SDL_TRUE; /* this audio target is available. */
return SDL_TRUE;
}
AudioBootStrap PULSEAUDIO_bootstrap = {
"pulseaudio", "PulseAudio", PULSEAUDIO_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_PULSEAUDIO */
#endif // SDL_AUDIO_DRIVER_PULSEAUDIO

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -29,18 +29,16 @@
struct SDL_PrivateAudioData
{
char *device_name;
/* pulseaudio structures */
// pulseaudio structures
pa_stream *stream;
/* Raw mixing buffer */
// Raw mixing buffer
Uint8 *mixbuf;
int bytes_requested; /* bytes of data the hardware wants _now_. */
int bytes_requested; // bytes of data the hardware wants _now_.
const Uint8 *capturebuf;
int capturelen;
};
#endif /* SDL_pulseaudio_h_ */
#endif // SDL_pulseaudio_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -39,7 +39,7 @@
#include "SDL3/SDL_timer.h"
#include "SDL3/SDL_audio.h"
#include "../../core/unix/SDL_poll.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_qsa_audio.h"
// default channel communication parameters
@ -86,21 +86,19 @@ static void QSA_InitAudioParams(snd_pcm_channel_params_t * cpars)
}
// This function waits until it is possible to write a full sound buffer
static void QSA_WaitDevice(SDL_AudioDevice *device)
static int QSA_WaitDevice(SDL_AudioDevice *device)
{
int result;
// Setup timeout for playing one fragment equal to 2 seconds
// If timeout occurred 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(device->hidden->audio_fd,
device->iscapture ? SDL_IOR_READ : SDL_IOR_WRITE,
2 * 1000);
const int result = SDL_IOReady(device->hidden->audio_fd,
device->iscapture ? SDL_IOR_READ : SDL_IOR_WRITE,
2 * 1000);
switch (result) {
case -1:
SDL_SetError("QSA: SDL_IOReady() failed: %s", strerror(errno)); // !!! FIXME: Should we just disconnect the device in this case?
break;
SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "QSA: SDL_IOReady() failed: %s", strerror(errno));
return -1;
case 0:
device->hidden->timeout_on_wait = SDL_TRUE; // !!! FIXME: Should we just disconnect the device in this case?
break;
@ -108,6 +106,8 @@ static void QSA_WaitDevice(SDL_AudioDevice *device)
device->hidden->timeout_on_wait = SDL_FALSE;
break;
}
return 0;
}
static int QSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
@ -176,7 +176,7 @@ static Uint8 *QSA_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
static void QSA_CloseDevice(SDL_AudioDevice *device)
{
if (device->hidden) {
if (device->hidden->audio_handle != NULL) {
if (device->hidden->audio_handle) {
#if _NTO_VERSION < 710
// Finish playing available samples or cancel unread samples during capture
snd_pcm_plugin_flush(device->hidden->audio_handle, device->iscapture ? SND_PCM_CHANNEL_CAPTURE : SND_PCM_CHANNEL_PLAYBACK);
@ -206,7 +206,7 @@ static int QSA_OpenDevice(SDL_AudioDevice *device)
// Initialize all variables that we clean on shutdown
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, (sizeof (struct SDL_PrivateAudioData)));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
return -1;
}
// Initialize channel transfer parameters to default
@ -275,7 +275,7 @@ static int QSA_OpenDevice(SDL_AudioDevice *device)
device->hidden->pcm_buf = (Uint8 *) SDL_malloc(device->buffer_size);
if (device->hidden->pcm_buf == NULL) {
return SDL_OutOfMemory();
return -1;
}
SDL_memset(device->hidden->pcm_buf, device->silence_value, device->buffer_size);

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -36,6 +36,5 @@ struct SDL_PrivateAudioData
Uint8 *pcm_buf; // Raw mixing buffer
};
#endif /* __SDL_QSA_AUDIO_H__ */
#endif // __SDL_QSA_AUDIO_H__
/* vi: set ts=4 sw=4 expandtab: */

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -36,7 +36,7 @@
#include <poll.h>
#include <unistd.h>
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_sndioaudio.h"
#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
@ -71,7 +71,7 @@ static void *sndio_handle = NULL;
static int load_sndio_sym(const char *fn, void **addr)
{
*addr = SDL_LoadFunction(sndio_handle, fn);
if (*addr == NULL) {
if (!*addr) {
return 0; // Don't call SDL_SetError(): SDL_LoadFunction already did.
}
@ -110,7 +110,7 @@ static int load_sndio_syms(void)
static void UnloadSNDIOLibrary(void)
{
if (sndio_handle != NULL) {
if (sndio_handle) {
SDL_UnloadObject(sndio_handle);
sndio_handle = NULL;
}
@ -119,9 +119,9 @@ static void UnloadSNDIOLibrary(void)
static int LoadSNDIOLibrary(void)
{
int retval = 0;
if (sndio_handle == NULL) {
if (!sndio_handle) {
sndio_handle = SDL_LoadObject(sndio_library);
if (sndio_handle == NULL) {
if (!sndio_handle) {
retval = -1; // Don't call SDL_SetError(): SDL_LoadObject already did.
} else {
retval = load_sndio_syms();
@ -147,32 +147,31 @@ static int LoadSNDIOLibrary(void)
#endif // SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
static void SNDIO_WaitDevice(SDL_AudioDevice *device)
static int SNDIO_WaitDevice(SDL_AudioDevice *device)
{
const SDL_bool iscapture = device->iscapture;
while (!SDL_AtomicGet(&device->shutdown)) {
if (SNDIO_sio_eof(device->hidden->dev)) {
SDL_AudioDeviceDisconnected(device);
return;
return -1;
}
const int nfds = SNDIO_sio_pollfd(device->hidden->dev, device->hidden->pfd, iscapture ? POLLIN : POLLOUT);
if (nfds <= 0 || poll(device->hidden->pfd, nfds, 10) < 0) {
SDL_AudioDeviceDisconnected(device);
return;
return -1;
}
const int revents = SNDIO_sio_revents(device->hidden->dev, device->hidden->pfd);
if (iscapture && (revents & POLLIN)) {
return;
break;
} else if (!iscapture && (revents & POLLOUT)) {
return;
break;
} else if (revents & POLLHUP) {
SDL_AudioDeviceDisconnected(device);
return;
return -1;
}
}
return 0;
}
static int SNDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
@ -214,7 +213,7 @@ static Uint8 *SNDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
static void SNDIO_CloseDevice(SDL_AudioDevice *device)
{
if (device->hidden) {
if (device->hidden->dev != NULL) {
if (device->hidden->dev) {
SNDIO_sio_stop(device->hidden->dev);
SNDIO_sio_close(device->hidden->dev);
}
@ -228,23 +227,23 @@ static void SNDIO_CloseDevice(SDL_AudioDevice *device)
static int SNDIO_OpenDevice(SDL_AudioDevice *device)
{
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
if (!device->hidden) {
return -1;
}
// !!! FIXME: we really should standardize this on a specific SDL hint.
const char *audiodev = SDL_getenv("AUDIODEV");
// Capture devices must be non-blocking for SNDIO_FlushCapture
device->hidden->dev = SNDIO_sio_open(audiodev != NULL ? audiodev : SIO_DEVANY,
device->hidden->dev = SNDIO_sio_open(audiodev ? audiodev : SIO_DEVANY,
device->iscapture ? SIO_REC : SIO_PLAY, device->iscapture);
if (device->hidden->dev == NULL) {
if (!device->hidden->dev) {
return SDL_SetError("sio_open() failed");
}
device->hidden->pfd = SDL_malloc(sizeof(struct pollfd) * SNDIO_sio_nfds(device->hidden->dev));
if (device->hidden->pfd == NULL) {
return SDL_OutOfMemory();
if (!device->hidden->pfd) {
return -1;
}
struct sio_par par;
@ -308,8 +307,8 @@ static int SNDIO_OpenDevice(SDL_AudioDevice *device)
// Allocate mixing buffer
device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
if (device->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
if (!device->hidden->mixbuf) {
return -1;
}
SDL_memset(device->hidden->mixbuf, device->silence_value, device->buffer_size);
@ -348,7 +347,6 @@ static SDL_bool SNDIO_Init(SDL_AudioDriverImpl *impl)
impl->Deinitialize = SNDIO_Deinitialize;
impl->DetectDevices = SNDIO_DetectDevices;
impl->AllowsArbitraryDeviceNames = SDL_TRUE;
impl->HasCaptureSupport = SDL_TRUE;
return SDL_TRUE;

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -35,4 +35,4 @@ struct SDL_PrivateAudioData
struct pollfd *pfd; // Polling structures for non-blocking sndio devices
};
#endif /* SDL_sndioaudio_h_ */
#endif // SDL_sndioaudio_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -26,7 +26,6 @@
#include <string.h>
#include <stdlib.h>
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_vitaaudio.h"
@ -63,11 +62,10 @@ static int VITAAUD_OpenDevice(SDL_AudioDevice *device)
const SDL_AudioFormat *closefmts;
device->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc(sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
SDL_calloc(1, sizeof(*device->hidden));
if (!device->hidden) {
return -1;
}
SDL_memset(device->hidden, 0, sizeof(*device->hidden));
closefmts = SDL_ClosestAudioFormats(device->spec.format);
while ((test_format = *(closefmts++)) != 0) {
@ -96,7 +94,7 @@ static int VITAAUD_OpenDevice(SDL_AudioDevice *device)
64, so spec->size should be a multiple of 64 as well. */
mixlen = device->buffer_size * NUM_BUFFERS;
device->hidden->rawbuf = (Uint8 *)SDL_aligned_alloc(64, mixlen);
if (device->hidden->rawbuf == NULL) {
if (!device->hidden->rawbuf) {
return SDL_SetError("Couldn't allocate mixing buffer");
}
@ -136,12 +134,13 @@ static int VITAAUD_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int
}
// This function waits until it is possible to write a full sound buffer
static void VITAAUD_WaitDevice(SDL_AudioDevice *device)
static int VITAAUD_WaitDevice(SDL_AudioDevice *device)
{
// !!! FIXME: we might just need to sleep roughly as long as playback buffers take to process, based on sample rate, etc.
while (!SDL_AtomicGet(&device->shutdown) && (sceAudioOutGetRestSample(device->hidden->port) >= device->buffer_size)) {
SDL_Delay(1);
}
return 0;
}
static Uint8 *VITAAUD_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
@ -163,8 +162,8 @@ static void VITAAUD_CloseDevice(SDL_AudioDevice *device)
device->hidden->port = -1;
}
if (!device->iscapture && device->hidden->rawbuf != NULL) {
SDL_aligned_free(device->hidden->rawbuf); // this uses memalign(), not SDL_malloc().
if (!device->iscapture && device->hidden->rawbuf) {
SDL_aligned_free(device->hidden->rawbuf); // this uses SDL_aligned_alloc(), not SDL_malloc()
device->hidden->rawbuf = NULL;
}
SDL_free(device->hidden);
@ -172,7 +171,7 @@ static void VITAAUD_CloseDevice(SDL_AudioDevice *device)
}
}
static void VITAAUD_WaitCaptureDevice(SDL_AudioDevice *device)
static int VITAAUD_WaitCaptureDevice(SDL_AudioDevice *device)
{
// there's only a blocking call to obtain more data, so we'll just sleep as
// long as a buffer would run.
@ -180,6 +179,7 @@ static void VITAAUD_WaitCaptureDevice(SDL_AudioDevice *device)
while (!SDL_AtomicGet(&device->shutdown) && (SDL_GetTicks() < endticks)) {
SDL_Delay(1);
}
return 0;
}
static int VITAAUD_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -28,14 +28,14 @@
struct SDL_PrivateAudioData
{
/* The hardware input/output port. */
// The hardware input/output port.
int port;
/* The raw allocated mixing buffer. */
// The raw allocated mixing buffer.
Uint8 *rawbuf;
/* Individual mixing buffers. */
// Individual mixing buffers.
Uint8 *mixbufs[NUM_BUFFERS];
/* Index of the next available mixing buffer. */
// Index of the next available mixing buffer.
int next_buffer;
};
#endif /* SDL_vitaaudio_h */
#endif // SDL_vitaaudio_h

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -25,7 +25,6 @@
#include "../../core/windows/SDL_windows.h"
#include "../../core/windows/SDL_immdevice.h"
#include "../../thread/SDL_systhread.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#define COBJMACROS
@ -94,7 +93,7 @@ static void ManagementThreadMainloop(void)
int WASAPI_ProxyToManagementThread(ManagementThreadTask task, void *userdata, int *wait_on_result)
{
// We want to block for a result, but we are already running from the management thread! Just run the task now so we don't deadlock.
if ((wait_on_result != NULL) && (SDL_ThreadID() == SDL_GetThreadID(ManagementThread))) {
if ((wait_on_result) && (SDL_ThreadID() == SDL_GetThreadID(ManagementThread))) {
*wait_on_result = task(userdata);
return 0; // completed!
}
@ -105,7 +104,7 @@ int WASAPI_ProxyToManagementThread(ManagementThreadTask task, void *userdata, in
ManagementThreadPendingTask *pending = SDL_calloc(1, sizeof(ManagementThreadPendingTask));
if (!pending) {
return SDL_OutOfMemory();
return -1;
}
pending->fn = task;
@ -125,11 +124,11 @@ int WASAPI_ProxyToManagementThread(ManagementThreadTask task, void *userdata, in
// add to end of task list.
ManagementThreadPendingTask *prev = NULL;
for (ManagementThreadPendingTask *i = SDL_AtomicGetPtr((void **) &ManagementThreadPendingTasks); i != NULL; i = i->next) {
for (ManagementThreadPendingTask *i = SDL_AtomicGetPtr((void **) &ManagementThreadPendingTasks); i; i = i->next) {
prev = i;
}
if (prev != NULL) {
if (prev) {
prev->next = pending;
} else {
SDL_AtomicSetPtr((void **) &ManagementThreadPendingTasks, pending);
@ -265,6 +264,7 @@ static int mgmtthrtask_DetectDevices(void *userdata)
static void WASAPI_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
{
int rc;
// this blocks because it needs to finish before the audio subsystem inits
mgmtthrtask_DetectDevicesData data = { default_output, default_capture };
WASAPI_ProxyToManagementThread(mgmtthrtask_DetectDevices, &data, &rc);
}
@ -277,26 +277,31 @@ static int mgmtthrtask_DisconnectDevice(void *userdata)
void WASAPI_DisconnectDevice(SDL_AudioDevice *device)
{
// this runs async, so it can hold the device lock from the management thread.
WASAPI_ProxyToManagementThread(mgmtthrtask_DisconnectDevice, device, NULL);
int rc; // block on this; don't disconnect while holding the device lock!
WASAPI_ProxyToManagementThread(mgmtthrtask_DisconnectDevice, device, &rc);
}
static SDL_bool WasapiFailed(SDL_AudioDevice *device, const HRESULT err)
{
if (err == S_OK) {
return SDL_FALSE;
}
if (err == AUDCLNT_E_DEVICE_INVALIDATED) {
} else if (err == AUDCLNT_E_DEVICE_INVALIDATED) {
device->hidden->device_lost = SDL_TRUE;
} else {
IAudioClient_Stop(device->hidden->client);
WASAPI_DisconnectDevice(device);
device->hidden->device_dead = SDL_TRUE;
}
return SDL_TRUE;
}
static int mgmtthrtask_StopAndReleaseClient(void *userdata)
{
IAudioClient *client = (IAudioClient *) userdata;
IAudioClient_Stop(client);
IAudioClient_Release(client);
return 0;
}
static int mgmtthrtask_ReleaseCaptureClient(void *userdata)
{
IAudioCaptureClient_Release((IAudioCaptureClient *)userdata);
@ -309,56 +314,68 @@ static int mgmtthrtask_ReleaseRenderClient(void *userdata)
return 0;
}
static int mgmtthrtask_ResetWasapiDevice(void *userdata)
static int mgmtthrtask_CoTaskMemFree(void *userdata)
{
SDL_AudioDevice *device = (SDL_AudioDevice *)userdata;
CoTaskMemFree(userdata);
return 0;
}
if (!device || !device->hidden) {
return 0;
}
if (device->hidden->client) {
IAudioClient_Stop(device->hidden->client);
IAudioClient_Release(device->hidden->client);
device->hidden->client = NULL;
}
if (device->hidden->render) {
// this is silly, but this will block indefinitely if you call it from SDLMMNotificationClient_OnDefaultDeviceChanged, so
// proxy this to the management thread to be released later.
WASAPI_ProxyToManagementThread(mgmtthrtask_ReleaseRenderClient, device->hidden->render, NULL);
device->hidden->render = NULL;
}
if (device->hidden->capture) {
// this is silly, but this will block indefinitely if you call it from SDLMMNotificationClient_OnDefaultDeviceChanged, so
// proxy this to the management thread to be released later.
WASAPI_ProxyToManagementThread(mgmtthrtask_ReleaseCaptureClient, device->hidden->capture, NULL);
device->hidden->capture = NULL;
}
if (device->hidden->waveformat) {
CoTaskMemFree(device->hidden->waveformat);
device->hidden->waveformat = NULL;
}
if (device->hidden->activation_handler) {
WASAPI_PlatformDeleteActivationHandler(device->hidden->activation_handler);
device->hidden->activation_handler = NULL;
}
if (device->hidden->event) {
CloseHandle(device->hidden->event);
device->hidden->event = NULL;
}
static int mgmtthrtask_PlatformDeleteActivationHandler(void *userdata)
{
WASAPI_PlatformDeleteActivationHandler(userdata);
return 0;
}
static int mgmtthrtask_CloseHandle(void *userdata)
{
CloseHandle((HANDLE) userdata);
return 0;
}
static void ResetWasapiDevice(SDL_AudioDevice *device)
{
int rc;
WASAPI_ProxyToManagementThread(mgmtthrtask_ResetWasapiDevice, device, &rc);
if (!device || !device->hidden) {
return;
}
// just queue up all the tasks in the management thread and don't block.
// We don't care when any of these actually get free'd.
if (device->hidden->client) {
IAudioClient *client = device->hidden->client;
device->hidden->client = NULL;
WASAPI_ProxyToManagementThread(mgmtthrtask_StopAndReleaseClient, client, NULL);
}
if (device->hidden->render) {
IAudioRenderClient *render = device->hidden->render;
device->hidden->render = NULL;
WASAPI_ProxyToManagementThread(mgmtthrtask_ReleaseRenderClient, render, NULL);
}
if (device->hidden->capture) {
IAudioCaptureClient *capture = device->hidden->capture;
device->hidden->capture = NULL;
WASAPI_ProxyToManagementThread(mgmtthrtask_ReleaseCaptureClient, capture, NULL);
}
if (device->hidden->waveformat) {
void *ptr = device->hidden->waveformat;
device->hidden->waveformat = NULL;
WASAPI_ProxyToManagementThread(mgmtthrtask_CoTaskMemFree, ptr, NULL);
}
if (device->hidden->activation_handler) {
void *activation_handler = device->hidden->activation_handler;
device->hidden->activation_handler = NULL;
WASAPI_ProxyToManagementThread(mgmtthrtask_PlatformDeleteActivationHandler, activation_handler, NULL);
}
if (device->hidden->event) {
HANDLE event = device->hidden->event;
device->hidden->event = NULL;
WASAPI_ProxyToManagementThread(mgmtthrtask_CloseHandle, (void *) event, NULL);
}
}
static int mgmtthrtask_ActivateDevice(void *userdata)
@ -368,10 +385,13 @@ static int mgmtthrtask_ActivateDevice(void *userdata)
static int ActivateWasapiDevice(SDL_AudioDevice *device)
{
int rc;
// this blocks because we're either being notified from a background thread or we're running during device open,
// both of which won't deadlock vs the device thread.
int rc = -1;
return ((WASAPI_ProxyToManagementThread(mgmtthrtask_ActivateDevice, device, &rc) < 0) || (rc < 0)) ? -1 : 0;
}
// do not call when holding the device lock!
static SDL_bool RecoverWasapiDevice(SDL_AudioDevice *device)
{
ResetWasapiDevice(device); // dump the lost device's handles.
@ -387,10 +407,18 @@ static SDL_bool RecoverWasapiDevice(SDL_AudioDevice *device)
return SDL_TRUE; // okay, carry on with new device details!
}
// do not call when holding the device lock!
static SDL_bool RecoverWasapiIfLost(SDL_AudioDevice *device)
{
if (SDL_AtomicGet(&device->shutdown)) {
return SDL_FALSE; // already failed.
} else if (device->hidden->device_dead) { // had a fatal error elsewhere, clean up and quit
IAudioClient_Stop(device->hidden->client);
WASAPI_DisconnectDevice(device);
SDL_assert(SDL_AtomicGet(&device->shutdown)); // so we don't come back through here.
return SDL_FALSE; // already failed.
} else if (SDL_AtomicGet(&device->zombie)) {
return SDL_FALSE; // we're already dead, so just leave and let the Zombie implementations take over.
} else if (!device->hidden->client) {
return SDL_TRUE; // still waiting for activation.
}
@ -403,9 +431,12 @@ static Uint8 *WASAPI_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
// get an endpoint buffer from WASAPI.
BYTE *buffer = NULL;
if (RecoverWasapiIfLost(device) && device->hidden->render) {
if (device->hidden->render) {
if (WasapiFailed(device, IAudioRenderClient_GetBuffer(device->hidden->render, device->sample_frames, &buffer))) {
SDL_assert(buffer == NULL);
if (device->hidden->device_lost) { // just use an available buffer, we won't be playing it anyhow.
*buffer_size = 0; // we'll recover during WaitDevice and try again.
}
}
}
@ -414,15 +445,16 @@ static Uint8 *WASAPI_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
static int WASAPI_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
{
if (device->hidden->render != NULL) { // definitely activated?
if (device->hidden->render) { // definitely activated?
// WasapiFailed() will mark the device for reacquisition or removal elsewhere.
WasapiFailed(device, IAudioRenderClient_ReleaseBuffer(device->hidden->render, device->sample_frames, 0));
}
return 0;
}
static void WASAPI_WaitDevice(SDL_AudioDevice *device)
static int WASAPI_WaitDevice(SDL_AudioDevice *device)
{
// WaitDevice does not hold the device lock, so check for recovery/disconnect details here.
while (RecoverWasapiIfLost(device) && device->hidden->client && device->hidden->event) {
DWORD waitResult = WaitForSingleObjectEx(device->hidden->event, 200, FALSE);
if (waitResult == WAIT_OBJECT_0) {
@ -439,9 +471,11 @@ static void WASAPI_WaitDevice(SDL_AudioDevice *device)
} else if (waitResult != WAIT_TIMEOUT) {
//SDL_Log("WASAPI FAILED EVENT!");*/
IAudioClient_Stop(device->hidden->client);
WASAPI_DisconnectDevice(device);
return -1;
}
}
return 0;
}
static int WASAPI_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
@ -450,10 +484,10 @@ static int WASAPI_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int b
UINT32 frames = 0;
DWORD flags = 0;
while (RecoverWasapiIfLost(device) && device->hidden->capture) {
HRESULT ret = IAudioCaptureClient_GetBuffer(device->hidden->capture, &ptr, &frames, &flags, NULL, NULL);
while (device->hidden->capture) {
const HRESULT ret = IAudioCaptureClient_GetBuffer(device->hidden->capture, &ptr, &frames, &flags, NULL, NULL);
if (ret == AUDCLNT_S_BUFFER_EMPTY) {
return 0; // in theory we should have waited until there was data, but oh well, we'll go back to waiting. Returning 0 is safe in SDL
return 0; // in theory we should have waited until there was data, but oh well, we'll go back to waiting. Returning 0 is safe in SDL3.
}
WasapiFailed(device, ret); // mark device lost/failed if necessary.
@ -472,8 +506,7 @@ static int WASAPI_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int b
SDL_memcpy(buffer, ptr, cpy);
}
ret = IAudioCaptureClient_ReleaseBuffer(device->hidden->capture, frames);
WasapiFailed(device, ret); // mark device lost/failed if necessary.
WasapiFailed(device, IAudioCaptureClient_ReleaseBuffer(device->hidden->capture, frames));
return cpy;
}
@ -537,7 +570,7 @@ static int mgmtthrtask_PrepDevice(void *userdata)
device->hidden->event = CreateEventW(NULL, 0, 0, NULL);
#endif
if (device->hidden->event == NULL) {
if (!device->hidden->event) {
return WIN_SetError("WASAPI can't create an event handle");
}
@ -666,8 +699,8 @@ static int WASAPI_OpenDevice(SDL_AudioDevice *device)
{
// Initialize all variables that we clean on shutdown
device->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof(*device->hidden));
if (device->hidden == NULL) {
return SDL_OutOfMemory();
if (!device->hidden) {
return -1;
} else if (ActivateWasapiDevice(device) < 0) {
return -1; // already set error.
}
@ -702,6 +735,18 @@ static void WASAPI_FreeDeviceHandle(SDL_AudioDevice *device)
WASAPI_ProxyToManagementThread(mgmtthrtask_FreeDeviceHandle, device, &rc);
}
static int mgmtthrtask_DeinitializeStart(void *userdata)
{
WASAPI_PlatformDeinitializeStart();
return 0;
}
static void WASAPI_DeinitializeStart(void)
{
int rc;
WASAPI_ProxyToManagementThread(mgmtthrtask_DeinitializeStart, NULL, &rc);
}
static void WASAPI_Deinitialize(void)
{
DeinitManagementThread();
@ -724,6 +769,7 @@ static SDL_bool WASAPI_Init(SDL_AudioDriverImpl *impl)
impl->CaptureFromDevice = WASAPI_CaptureFromDevice;
impl->FlushCapture = WASAPI_FlushCapture;
impl->CloseDevice = WASAPI_CloseDevice;
impl->DeinitializeStart = WASAPI_DeinitializeStart;
impl->Deinitialize = WASAPI_Deinitialize;
impl->FreeDeviceHandle = WASAPI_FreeDeviceHandle;

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -41,22 +41,24 @@ struct SDL_PrivateAudioData
SDL_bool coinitialized;
int framesize;
SDL_bool device_lost;
SDL_bool device_dead;
void *activation_handler;
};
/* win32 and winrt implementations call into these. */
// win32 and winrt implementations call into these.
int WASAPI_PrepDevice(SDL_AudioDevice *device);
void WASAPI_DisconnectDevice(SDL_AudioDevice *device);
void WASAPI_DisconnectDevice(SDL_AudioDevice *device); // don't hold the device lock when calling this!
// BE CAREFUL: if you are holding the device lock and proxy to the management thread with wait_until_complete, and grab the lock again, you will deadlock.
typedef int (*ManagementThreadTask)(void *userdata);
int WASAPI_ProxyToManagementThread(ManagementThreadTask task, void *userdata, int *wait_until_complete);
/* These are functions that are implemented differently for Windows vs WinRT. */
// These are functions that are implemented differently for Windows vs WinRT.
// UNLESS OTHERWISE NOTED THESE ALL HAPPEN ON THE MANAGEMENT THREAD.
int WASAPI_PlatformInit(void);
void WASAPI_PlatformDeinit(void);
void WASAPI_PlatformDeinitializeStart(void);
void WASAPI_EnumerateEndpoints(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture);
int WASAPI_ActivateDevice(SDL_AudioDevice *device);
void WASAPI_PlatformThreadInit(SDL_AudioDevice *device); // this happens on the audio device thread, not the management thread.
@ -68,4 +70,4 @@ void WASAPI_PlatformFreeDeviceHandle(SDL_AudioDevice *device);
}
#endif
#endif /* SDL_wasapi_h_ */
#endif // SDL_wasapi_h_

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -30,30 +30,70 @@
#include "../../core/windows/SDL_windows.h"
#include "../../core/windows/SDL_immdevice.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include <audioclient.h>
#include "SDL_wasapi.h"
/* handle to Avrt.dll--Vista and later!--for flagging the callback thread as "Pro Audio" (low latency). */
// 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)(LPCWSTR, LPDWORD);
typedef BOOL(WINAPI *pfnAvRevertMmThreadCharacteristics)(HANDLE);
static pfnAvSetMmThreadCharacteristicsW pAvSetMmThreadCharacteristicsW = NULL;
static pfnAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL;
/* Some GUIDs we need to know without linking to libraries that aren't available before Vista. */
static SDL_bool immdevice_initialized = SDL_FALSE;
// Some GUIDs we need to know without linking to libraries that aren't available before Vista.
static const IID SDL_IID_IAudioClient = { 0x1cb9ad4c, 0xdbfa, 0x4c32, { 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2 } };
static int mgmtthrtask_AudioDeviceDisconnected(void *userdata)
{
SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
SDL_AudioDeviceDisconnected(device);
UnrefPhysicalAudioDevice(device); // make sure this lived until the task completes.
return 0;
}
static void WASAPI_AudioDeviceDisconnected(SDL_AudioDevice *device)
{
// don't wait on this, IMMDevice's own thread needs to return or everything will deadlock.
if (device) {
RefPhysicalAudioDevice(device); // make sure this lives until the task completes.
WASAPI_ProxyToManagementThread(mgmtthrtask_AudioDeviceDisconnected, device, NULL);
}
}
static int mgmtthrtask_DefaultAudioDeviceChanged(void *userdata)
{
SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
SDL_DefaultAudioDeviceChanged(device);
UnrefPhysicalAudioDevice(device); // make sure this lived until the task completes.
return 0;
}
static void WASAPI_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device)
{
// don't wait on this, IMMDevice's own thread needs to return or everything will deadlock.
if (new_default_device) {
RefPhysicalAudioDevice(new_default_device); // make sure this lives until the task completes.
WASAPI_ProxyToManagementThread(mgmtthrtask_DefaultAudioDeviceChanged, new_default_device, NULL);
}
}
int WASAPI_PlatformInit(void)
{
if (SDL_IMMDevice_Init() < 0) { // this will call WIN_CoInitialize for us!
return -1; /* This is set by SDL_IMMDevice_Init */
const SDL_IMMDevice_callbacks callbacks = { WASAPI_AudioDeviceDisconnected, WASAPI_DefaultAudioDeviceChanged };
if (FAILED(WIN_CoInitialize())) {
return SDL_SetError("CoInitialize() failed");
} else if (SDL_IMMDevice_Init(&callbacks) < 0) {
return -1; // Error string is set by SDL_IMMDevice_Init
}
libavrt = LoadLibrary(TEXT("avrt.dll")); /* this library is available in Vista and later. No WinXP, so have to LoadLibrary to use it for now! */
immdevice_initialized = SDL_TRUE;
libavrt = LoadLibrary(TEXT("avrt.dll")); // this library is available in Vista and later. No WinXP, so have to LoadLibrary to use it for now!
if (libavrt) {
pAvSetMmThreadCharacteristicsW = (pfnAvSetMmThreadCharacteristicsW)GetProcAddress(libavrt, "AvSetMmThreadCharacteristicsW");
pAvRevertMmThreadCharacteristics = (pfnAvRevertMmThreadCharacteristics)GetProcAddress(libavrt, "AvRevertMmThreadCharacteristics");
@ -62,6 +102,14 @@ int WASAPI_PlatformInit(void)
return 0;
}
static void StopWasapiHotplug(void)
{
if (immdevice_initialized) {
SDL_IMMDevice_Quit();
immdevice_initialized = SDL_FALSE;
}
}
void WASAPI_PlatformDeinit(void)
{
if (libavrt) {
@ -72,17 +120,24 @@ void WASAPI_PlatformDeinit(void)
pAvSetMmThreadCharacteristicsW = NULL;
pAvRevertMmThreadCharacteristics = NULL;
SDL_IMMDevice_Quit(); // This will call WIN_CoUninitialize for us!
StopWasapiHotplug();
WIN_CoUninitialize();
}
void WASAPI_PlatformDeinitializeStart(void)
{
StopWasapiHotplug();
}
void WASAPI_PlatformThreadInit(SDL_AudioDevice *device)
{
/* this thread uses COM. */
if (SUCCEEDED(WIN_CoInitialize())) { /* can't report errors, hope it worked! */
// this thread uses COM.
if (SUCCEEDED(WIN_CoInitialize())) { // can't report errors, hope it worked!
device->hidden->coinitialized = SDL_TRUE;
}
/* Set this thread to very high "Pro Audio" priority. */
// Set this thread to very high "Pro Audio" priority.
if (pAvSetMmThreadCharacteristicsW) {
DWORD idx = 0;
device->hidden->task = pAvSetMmThreadCharacteristicsW(L"Pro Audio", &idx);
@ -94,7 +149,7 @@ void WASAPI_PlatformThreadInit(SDL_AudioDevice *device)
void WASAPI_PlatformThreadDeinit(SDL_AudioDevice *device)
{
/* Set this thread back to normal priority. */
// Set this thread back to normal priority.
if (device->hidden->task && pAvRevertMmThreadCharacteristics) {
pAvRevertMmThreadCharacteristics(device->hidden->task);
device->hidden->task = NULL;
@ -111,10 +166,10 @@ int WASAPI_ActivateDevice(SDL_AudioDevice *device)
IMMDevice *immdevice = NULL;
if (SDL_IMMDevice_Get(device, &immdevice, device->iscapture) < 0) {
device->hidden->client = NULL;
return -1; /* This is already set by SDL_IMMDevice_Get */
return -1; // This is already set by SDL_IMMDevice_Get
}
/* this is _not_ async in standard win32, yay! */
// this is _not_ async in standard win32, yay!
HRESULT ret = IMMDevice_Activate(immdevice, &SDL_IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&device->hidden->client);
IMMDevice_Release(immdevice);
@ -124,11 +179,11 @@ int WASAPI_ActivateDevice(SDL_AudioDevice *device)
}
SDL_assert(device->hidden->client != NULL);
if (WASAPI_PrepDevice(device) == -1) { /* not async, fire it right away. */
if (WASAPI_PrepDevice(device) == -1) { // not async, fire it right away.
return -1;
}
return 0; /* good to go. */
return 0; // good to go.
}
void WASAPI_EnumerateEndpoints(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
@ -138,7 +193,7 @@ void WASAPI_EnumerateEndpoints(SDL_AudioDevice **default_output, SDL_AudioDevice
void WASAPI_PlatformDeleteActivationHandler(void *handler)
{
/* not asynchronous. */
// not asynchronous.
SDL_assert(!"This function should have only been called on WinRT.");
}
@ -147,4 +202,4 @@ void WASAPI_PlatformFreeDeviceHandle(SDL_AudioDevice *device)
SDL_IMMDevice_FreeDeviceHandle(device);
}
#endif /* SDL_AUDIO_DRIVER_WASAPI && !defined(__WINRT__) */
#endif // SDL_AUDIO_DRIVER_WASAPI && !defined(__WINRT__)

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -36,7 +36,6 @@
extern "C" {
#include "../../core/windows/SDL_windows.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
}
@ -56,7 +55,7 @@ static Platform::String ^ SDL_PKEY_AudioEngine_DeviceFormat = L"{f19f064d-082c-4
static SDL_bool FindWinRTAudioDeviceCallback(SDL_AudioDevice *device, void *userdata)
{
return (SDL_wcscmp((LPCWSTR) device->handle, (LPCWSTR) userdata) == 0) ? SDL_TRUE : SDL_FALSE;
return (SDL_wcscmp((LPCWSTR) device->handle, (LPCWSTR) userdata) == 0);
}
static SDL_AudioDevice *FindWinRTAudioDevice(LPCWSTR devid)
@ -220,7 +219,7 @@ int WASAPI_PlatformInit(void)
return 0;
}
void WASAPI_PlatformDeinit(void)
static void StopWasapiHotplug(void)
{
delete playback_device_event_handler;
playback_device_event_handler = nullptr;
@ -228,6 +227,17 @@ void WASAPI_PlatformDeinit(void)
capture_device_event_handler = nullptr;
}
void WASAPI_PlatformDeinit(void)
{
StopWasapiHotplug();
}
void WASAPI_PlatformDeinitializeStart(void)
{
StopWasapiHotplug();
}
void WASAPI_EnumerateEndpoints(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
{
Platform::String ^ defdevid;

View File

@ -0,0 +1,235 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 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
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_VIDEO_DRIVER_X11
DECLSPEC void SDLCALL SDL_SetX11EventHook(SDL_X11EventHook callback, void *userdata)
{
}
#endif
#ifndef __LINUX__
DECLSPEC int SDLCALL SDL_LinuxSetThreadPriority(Sint64 threadID, int priority);
int SDL_LinuxSetThreadPriority(Sint64 threadID, int priority)
{
(void)threadID;
(void)priority;
return SDL_Unsupported();
}
DECLSPEC int SDLCALL SDL_LinuxSetThreadPriorityAndPolicy(Sint64 threadID, int sdlPriority, int schedPolicy);
int SDL_LinuxSetThreadPriorityAndPolicy(Sint64 threadID, int sdlPriority, int schedPolicy)
{
(void)threadID;
(void)sdlPriority;
(void)schedPolicy;
return SDL_Unsupported();
}
#endif
#ifndef __GDK__
DECLSPEC void SDLCALL SDL_GDKSuspendComplete(void);
void SDL_GDKSuspendComplete(void)
{
SDL_Unsupported();
}
DECLSPEC int SDLCALL SDL_GDKGetDefaultUser(void *outUserHandle); /* XUserHandle *outUserHandle */
int SDL_GDKGetDefaultUser(void *outUserHandle)
{
return SDL_Unsupported();
}
#endif
#if !(defined(__WIN32__) || defined(__WINRT__) || defined(__GDK__))
DECLSPEC int SDLCALL SDL_RegisterApp(const char *name, Uint32 style, void *hInst);
int SDL_RegisterApp(const char *name, Uint32 style, void *hInst)
{
(void)name;
(void)style;
(void)hInst;
return SDL_Unsupported();
}
DECLSPEC void SDLCALL SDL_SetWindowsMessageHook(void *callback, void *userdata); /* SDL_WindowsMessageHook callback */
void SDL_SetWindowsMessageHook(void *callback, void *userdata)
{
(void)callback;
(void)userdata;
SDL_Unsupported();
}
DECLSPEC void SDLCALL SDL_UnregisterApp(void);
void SDL_UnregisterApp(void)
{
SDL_Unsupported();
}
#endif
#ifndef __WINRT__
/* Returns SDL_WinRT_DeviceFamily enum */
DECLSPEC int SDLCALL SDL_WinRTGetDeviceFamily(void);
int SDL_WinRTGetDeviceFamily()
{
SDL_Unsupported();
return 0; /* SDL_WINRT_DEVICEFAMILY_UNKNOWN */
}
DECLSPEC const wchar_t *SDLCALL SDL_WinRTGetFSPathUNICODE(int pathType); /* SDL_WinRT_Path pathType */
const wchar_t *SDL_WinRTGetFSPathUNICODE(int pathType)
{
(void)pathType;
SDL_Unsupported();
return NULL;
}
DECLSPEC const char *SDLCALL SDL_WinRTGetFSPathUTF8(int pathType); /* SDL_WinRT_Path pathType */
const char *SDL_WinRTGetFSPathUTF8(int pathType)
{
(void)pathType;
SDL_Unsupported();
return NULL;
}
#endif
#ifndef __ANDROID__
DECLSPEC void SDLCALL SDL_AndroidBackButton(void);
void SDL_AndroidBackButton()
{
SDL_Unsupported();
}
DECLSPEC void *SDLCALL SDL_AndroidGetActivity(void);
void *SDL_AndroidGetActivity()
{
SDL_Unsupported();
return NULL;
}
DECLSPEC const char *SDLCALL SDL_AndroidGetExternalStoragePath(void);
const char* SDL_AndroidGetExternalStoragePath()
{
SDL_Unsupported();
return NULL;
}
DECLSPEC int SDLCALL SDL_AndroidGetExternalStorageState(Uint32 *state);
int SDL_AndroidGetExternalStorageState(Uint32 *state)
{
(void)state;
return SDL_Unsupported();
}
DECLSPEC const char *SDLCALL SDL_AndroidGetInternalStoragePath(void);
const char *SDL_AndroidGetInternalStoragePath()
{
SDL_Unsupported();
return NULL;
}
DECLSPEC void *SDLCALL SDL_AndroidGetJNIEnv(void);
void *SDL_AndroidGetJNIEnv()
{
SDL_Unsupported();
return NULL;
}
DECLSPEC SDL_bool SDLCALL SDL_AndroidRequestPermission(const char *permission);
SDL_bool SDL_AndroidRequestPermission(const char *permission)
{
(void)permission;
SDL_Unsupported();
return SDL_FALSE;
}
DECLSPEC int SDLCALL SDL_AndroidSendMessage(Uint32 command, int param);
int SDL_AndroidSendMessage(Uint32 command, int param)
{
(void)command;
(void)param;
return SDL_Unsupported();
}
DECLSPEC int SDLCALL SDL_AndroidShowToast(const char* message, int duration, int gravity, int xoffset, int yoffset);
int SDL_AndroidShowToast(const char* message, int duration, int gravity, int xoffset, int yoffset)
{
(void)message;
(void)duration;
(void)gravity;
(void)xoffset;
(void)yoffset;
return SDL_Unsupported();
}
DECLSPEC int SDLCALL SDL_GetAndroidSDKVersion(void);
int SDL_GetAndroidSDKVersion()
{
return SDL_Unsupported();
}
DECLSPEC SDL_bool SDLCALL SDL_IsAndroidTV(void);
SDL_bool SDL_IsAndroidTV()
{
SDL_Unsupported();
return SDL_FALSE;
}
DECLSPEC SDL_bool SDLCALL SDL_IsChromebook(void);
SDL_bool SDL_IsChromebook()
{
SDL_Unsupported();
return SDL_FALSE;
}
DECLSPEC SDL_bool SDLCALL SDL_IsDeXMode(void);
SDL_bool SDL_IsDeXMode(void)
{
SDL_Unsupported();
return SDL_FALSE;
}
DECLSPEC Sint32 SDLCALL JNI_OnLoad(void *vm, void *reserved);
Sint32 JNI_OnLoad(void *vm, void *reserved)
{
(void)vm;
(void)reserved;
SDL_Unsupported();
return -1; /* JNI_ERR */
}
#endif
#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
char *SDL_GetUserFolder(SDL_Folder folder)
{
(void)folder;
SDL_Unsupported();
return NULL;
}
#endif

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -27,15 +27,14 @@
DECLSPEC int
SDL_RunApp(int argc, char* argv[], SDL_main_func mainFunction, void * reserved)
{
char empty[1] = {0};
char* argvdummy[2] = { empty, NULL };
(void)reserved;
if(argv == NULL)
if(!argv)
{
argc = 0;
/* make sure argv isn't NULL, in case some user code doesn't like that */
static char dummyargv0[] = { 'S', 'D', 'L', '_', 'a', 'p', 'p', '\0' };
static char* argvdummy[2] = { dummyargv0, NULL };
argc = 1;
argv = argvdummy;
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -434,12 +434,12 @@ JNIEnv *Android_JNI_GetEnv(void)
{
/* Get JNIEnv from the Thread local storage */
JNIEnv *env = pthread_getspecific(mThreadKey);
if (env == NULL) {
if (!env) {
/* If it fails, try to attach ! (e.g the thread isn't created with SDL_CreateThread() */
int status;
/* There should be a JVM */
if (mJavaVM == NULL) {
if (!mJavaVM) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "Failed, there is no JavaVM");
return NULL;
}
@ -468,7 +468,7 @@ int Android_JNI_SetupThread(void)
int status;
/* There should be a JVM */
if (mJavaVM == NULL) {
if (!mJavaVM) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "Failed, there is no JavaVM");
return 0;
}
@ -494,7 +494,7 @@ static void Android_JNI_ThreadDestroyed(void *value)
{
/* The thread is being destroyed, detach it from the Java VM and set the mThreadKey value to NULL as required */
JNIEnv *env = (JNIEnv *)value;
if (env != NULL) {
if (env) {
(*mJavaVM)->DetachCurrentThread(mJavaVM);
Android_JNI_SetEnv(NULL);
}
@ -520,7 +520,7 @@ static void Android_JNI_CreateKey_once(void)
static void register_methods(JNIEnv *env, const char *classname, JNINativeMethod *methods, int nb)
{
jclass clazz = (*env)->FindClass(env, classname);
if (clazz == NULL || (*env)->RegisterNatives(env, clazz, methods, nb) < 0) {
if (!clazz || (*env)->RegisterNatives(env, clazz, methods, nb) < 0) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "Failed to register methods of %s", classname);
return;
}
@ -573,6 +573,9 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
{
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeSetupJNI()");
/* Start with a clean slate */
SDL_ClearError();
/*
* Create mThreadKey so we can keep track of the JNIEnv assigned to each thread
* Refer to http://developer.android.com/guide/practices/design/jni.html for the rationale behind this
@ -582,28 +585,28 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
/* Save JNIEnv of SDLActivity */
Android_JNI_SetEnv(env);
if (mJavaVM == NULL) {
if (!mJavaVM) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to found a JavaVM");
}
/* Use a mutex to prevent concurrency issues between Java Activity and Native thread code, when using 'Android_Window'.
* (Eg. Java sending Touch events, while native code is destroying the main SDL_Window. )
*/
if (Android_ActivityMutex == NULL) {
if (!Android_ActivityMutex) {
Android_ActivityMutex = SDL_CreateMutex(); /* Could this be created twice if onCreate() is called a second time ? */
}
if (Android_ActivityMutex == NULL) {
if (!Android_ActivityMutex) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to create Android_ActivityMutex mutex");
}
Android_PauseSem = SDL_CreateSemaphore(0);
if (Android_PauseSem == NULL) {
if (!Android_PauseSem) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to create Android_PauseSem semaphore");
}
Android_ResumeSem = SDL_CreateSemaphore(0);
if (Android_ResumeSem == NULL) {
if (!Android_ResumeSem) {
__android_log_print(ANDROID_LOG_ERROR, "SDL", "failed to create Android_ResumeSem semaphore");
}
@ -878,7 +881,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeDropFile)(
jstring filename)
{
const char *path = (*env)->GetStringUTFChars(env, filename, NULL);
SDL_SendDropFile(NULL, path);
SDL_SendDropFile(NULL, NULL, path);
(*env)->ReleaseStringUTFChars(env, filename, path);
SDL_SendDropComplete(NULL);
}
@ -1006,24 +1009,28 @@ JNIEXPORT void JNICALL
SDL_JAVA_AUDIO_INTERFACE(addAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture,
jstring name, jint device_id)
{
#if ALLOW_MULTIPLE_ANDROID_AUDIO_DEVICES
if (SDL_GetCurrentAudioDriver() != NULL) {
void *handle = (void *)((size_t)device_id);
if (!SDL_FindPhysicalAudioDeviceByHandle(handle)) {
const char *utf8name = (*env)->GetStringUTFChars(env, name, NULL);
SDL_AddAudioDevice(is_capture ? SDL_TRUE : SDL_FALSE, SDL_strdup(utf8name), NULL, handle);
SDL_AddAudioDevice(is_capture, SDL_strdup(utf8name), NULL, handle);
(*env)->ReleaseStringUTFChars(env, name, utf8name);
}
}
#endif
}
JNIEXPORT void JNICALL
SDL_JAVA_AUDIO_INTERFACE(removeAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture,
jint device_id)
{
#if ALLOW_MULTIPLE_ANDROID_AUDIO_DEVICES
if (SDL_GetCurrentAudioDriver() != NULL) {
SDL_Log("Removing device with handle %d, capture %d", device_id, is_capture);
SDL_AudioDeviceDisconnected(SDL_FindPhysicalAudioDeviceByHandle((void *)((size_t)device_id)));
}
#endif
}
/* Paddown */
@ -1068,7 +1075,7 @@ JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
const char *name = (*env)->GetStringUTFChars(env, device_name, NULL);
const char *desc = (*env)->GetStringUTFChars(env, device_desc, NULL);
retval = Android_AddJoystick(device_id, name, desc, vendor_id, product_id, is_accelerometer ? SDL_TRUE : SDL_FALSE, button_mask, naxes, axis_mask, nhats);
retval = Android_AddJoystick(device_id, name, desc, vendor_id, product_id, is_accelerometer, button_mask, naxes, axis_mask, nhats);
(*env)->ReleaseStringUTFChars(env, device_name, name);
(*env)->ReleaseStringUTFChars(env, device_desc, desc);
@ -1610,7 +1617,7 @@ int Android_JNI_OpenAudioDevice(SDL_AudioDevice *device)
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for output");
result = (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midAudioOpen, spec->freq, audioformat, spec->channels, device->sample_frames, device_id);
}
if (result == NULL) {
if (!result) {
/* Error during audio initialization, error printed from Java */
return SDL_SetError("Java-side initialization failed");
}
@ -1671,7 +1678,7 @@ int Android_JNI_OpenAudioDevice(SDL_AudioDevice *device)
return SDL_SetError("Unexpected audio format from Java: %d\n", audioformat);
}
if (jbufobj == NULL) {
if (!jbufobj) {
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: could not allocate an audio buffer");
return SDL_OutOfMemory();
}
@ -1942,7 +1949,7 @@ static void Internal_Android_Create_AssetManager()
javaAssetManagerRef = (*env)->NewGlobalRef(env, javaAssetManager);
asset_manager = AAssetManager_fromJava(env, javaAssetManagerRef);
if (asset_manager == NULL) {
if (!asset_manager) {
(*env)->DeleteGlobalRef(env, javaAssetManagerRef);
Android_JNI_ExceptionOccurred(SDL_TRUE);
}
@ -1966,17 +1973,17 @@ int Android_JNI_FileOpen(SDL_RWops *ctx,
AAsset *asset = NULL;
ctx->hidden.androidio.asset = NULL;
if (asset_manager == NULL) {
if (!asset_manager) {
Internal_Android_Create_AssetManager();
}
if (asset_manager == NULL) {
return -1;
if (!asset_manager) {
return SDL_SetError("Couldn't create asset manager");
}
asset = AAssetManager_open(asset_manager, fileName, AASSET_MODE_UNKNOWN);
if (asset == NULL) {
return -1;
if (!asset) {
return SDL_SetError("Couldn't open asset '%s'", fileName);
}
ctx->hidden.androidio.asset = (void *)asset;
@ -2047,14 +2054,13 @@ char *Android_JNI_GetClipboardText(void)
(*env)->DeleteLocalRef(env, string);
}
return (text == NULL) ? SDL_strdup("") : text;
return (!text) ? SDL_strdup("") : text;
}
SDL_bool Android_JNI_HasClipboardText(void)
{
JNIEnv *env = Android_JNI_GetEnv();
jboolean retval = (*env)->CallStaticBooleanMethod(env, mActivityClass, midClipboardHasText);
return (retval == JNI_TRUE) ? SDL_TRUE : SDL_FALSE;
return (*env)->CallStaticBooleanMethod(env, mActivityClass, midClipboardHasText);
}
/* returns 0 on success or -1 on error (others undefined then)
@ -2233,7 +2239,7 @@ int Android_JNI_SuspendScreenSaver(SDL_bool suspend)
return Android_JNI_SendMessage(COMMAND_SET_KEEP_SCREEN_ON, (suspend == SDL_FALSE) ? 0 : 1);
}
void Android_JNI_ShowTextInput(SDL_Rect *inputRect)
void Android_JNI_ShowScreenKeyboard(SDL_Rect *inputRect)
{
JNIEnv *env = Android_JNI_GetEnv();
(*env)->CallStaticBooleanMethod(env, mActivityClass, midShowTextInput,
@ -2243,7 +2249,7 @@ void Android_JNI_ShowTextInput(SDL_Rect *inputRect)
inputRect->h);
}
void Android_JNI_HideTextInput(void)
void Android_JNI_HideScreenKeyboard(void)
{
/* has to match Activity constant */
const int COMMAND_TEXTEDIT_HIDE = 3;
@ -2368,7 +2374,7 @@ void *SDL_AndroidGetActivity(void)
/* See SDL_system.h for caveats on using this function. */
JNIEnv *env = Android_JNI_GetEnv();
if (env == NULL) {
if (!env) {
return NULL;
}
@ -2422,7 +2428,7 @@ const char *SDL_AndroidGetInternalStoragePath(void)
{
static char *s_AndroidInternalFilesPath = NULL;
if (s_AndroidInternalFilesPath == NULL) {
if (!s_AndroidInternalFilesPath) {
struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
jmethodID mid;
jobject context;
@ -2521,7 +2527,7 @@ const char *SDL_AndroidGetExternalStoragePath(void)
{
static char *s_AndroidExternalFilesPath = NULL;
if (s_AndroidExternalFilesPath == NULL) {
if (!s_AndroidExternalFilesPath) {
struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
jmethodID mid;
jobject context;
@ -2677,16 +2683,16 @@ int Android_JNI_GetLocale(char *buf, size_t buflen)
/* Need to re-create the asset manager if locale has changed (SDL_EVENT_LOCALE_CHANGED) */
Internal_Android_Destroy_AssetManager();
if (asset_manager == NULL) {
if (!asset_manager) {
Internal_Android_Create_AssetManager();
}
if (asset_manager == NULL) {
if (!asset_manager) {
return -1;
}
cfg = AConfiguration_new();
if (cfg == NULL) {
if (!cfg) {
return -1;
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -32,6 +32,9 @@ extern "C" {
#include "../../audio/SDL_sysaudio.h"
// this appears to be broken right now (on Android, not SDL, I think...?).
#define ALLOW_MULTIPLE_ANDROID_AUDIO_DEVICES 0
/* Interface from the SDL library into the Android Java activity */
extern void Android_JNI_SetActivityTitle(const char *title);
extern void Android_JNI_SetWindowStyle(SDL_bool fullscreen);
@ -40,8 +43,8 @@ extern void Android_JNI_MinizeWindow(void);
extern SDL_bool Android_JNI_ShouldMinimizeOnFocusLoss(void);
extern SDL_bool Android_JNI_GetAccelerometerValues(float values[3]);
extern void Android_JNI_ShowTextInput(SDL_Rect *inputRect);
extern void Android_JNI_HideTextInput(void);
extern void Android_JNI_ShowScreenKeyboard(SDL_Rect *inputRect);
extern void Android_JNI_HideScreenKeyboard(void);
extern SDL_bool Android_JNI_IsScreenKeyboardShown(void);
extern ANativeWindow *Android_JNI_GetNativeWindow(void);

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -87,7 +87,7 @@ static void kbd_cleanup(void)
{
struct mouse_info mData;
SDL_EVDEV_keyboard_state *kbd = kbd_cleanup_state;
if (kbd == NULL) {
if (!kbd) {
return;
}
kbd_cleanup_state = NULL;
@ -178,7 +178,7 @@ static void kbd_register_emerg_cleanup(SDL_EVDEV_keyboard_state *kbd)
{
int tabidx;
if (kbd_cleanup_state != NULL) {
if (kbd_cleanup_state) {
return;
}
kbd_cleanup_state = kbd;
@ -230,7 +230,7 @@ SDL_EVDEV_keyboard_state *SDL_EVDEV_kbd_init(void)
SDL_zero(mData);
mData.operation = MOUSE_HIDE;
kbd = (SDL_EVDEV_keyboard_state *)SDL_calloc(1, sizeof(SDL_EVDEV_keyboard_state));
if (kbd == NULL) {
if (!kbd) {
return NULL;
}
@ -296,7 +296,7 @@ void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *kbd)
{
struct mouse_info mData;
if (kbd == NULL) {
if (!kbd) {
return;
}
SDL_zero(mData);
@ -320,6 +320,18 @@ void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *kbd)
SDL_free(kbd);
}
void SDL_EVDEV_kbd_set_muted(SDL_EVDEV_keyboard_state *state, SDL_bool muted)
{
}
void SDL_EVDEV_kbd_set_vt_switch_callbacks(SDL_EVDEV_keyboard_state *state, void (*release_callback)(void*), void *release_callback_data, void (*acquire_callback)(void*), void *acquire_callback_data)
{
}
void SDL_EVDEV_kbd_update(SDL_EVDEV_keyboard_state *state)
{
}
/*
* Helper Functions.
*/
@ -474,7 +486,7 @@ void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode,
unsigned int final_key_state;
unsigned int map_from_key_sym;
if (kbd == NULL) {
if (!kbd) {
return;
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -69,7 +69,7 @@ public:
entry_ref entryRef;
for (int32 i = 0; message->FindRef("refs", i, &entryRef) == B_OK; i++) {
BPath referencePath = BPath(&entryRef);
SDL_SendDropFile(NULL, referencePath.Path());
SDL_SendDropFile(NULL, NULL, referencePath.Path());
}
return;
}
@ -108,13 +108,13 @@ static int StartBeLooper()
{
if (!be_app) {
SDL_AppThread = SDL_CreateThreadInternal(StartBeApp, "SDLApplication", 0, NULL);
if (SDL_AppThread == NULL) {
if (!SDL_AppThread) {
return SDL_SetError("Couldn't create BApplication thread");
}
do {
SDL_Delay(10);
} while ((be_app == NULL) || be_app->IsLaunching());
} while ((!be_app) || be_app->IsLaunching());
}
/* Change working directory to that of executable */
@ -167,7 +167,7 @@ void SDL_QuitBeApp(void)
SDL_Looper->Lock();
SDL_Looper->Quit();
SDL_Looper = NULL;
if (SDL_AppThread != NULL) {
if (SDL_AppThread) {
if (be_app != NULL) { /* Not tested */
be_app->PostMessage(B_QUIT_REQUESTED);
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -96,7 +96,7 @@ static int LoadDBUSSyms(void)
static void UnloadDBUSLibrary(void)
{
if (dbus_handle != NULL) {
if (dbus_handle) {
SDL_UnloadObject(dbus_handle);
dbus_handle = NULL;
}
@ -105,9 +105,9 @@ static void UnloadDBUSLibrary(void)
static int LoadDBUSLibrary(void)
{
int retval = 0;
if (dbus_handle == NULL) {
if (!dbus_handle) {
dbus_handle = SDL_LoadObject(dbus_library);
if (dbus_handle == NULL) {
if (!dbus_handle) {
retval = -1;
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
} else {
@ -183,14 +183,13 @@ void SDL_DBus_Quit(void)
dbus.connection_close(dbus.session_conn);
dbus.connection_unref(dbus.session_conn);
}
/* Don't do this - bug 3950
dbus_shutdown() is a debug feature which closes all global resources in the dbus library. Calling this should be done by the app, not a library, because if there are multiple users of dbus in the process then SDL could shut it down even though another part is using it.
*/
#if 0
if (dbus.shutdown) {
dbus.shutdown();
if (SDL_GetHintBoolean(SDL_HINT_SHUTDOWN_DBUS_ON_QUIT, SDL_FALSE)) {
if (dbus.shutdown) {
dbus.shutdown();
}
}
#endif
SDL_zero(dbus);
UnloadDBUSLibrary();
SDL_free(inhibit_handle);
@ -199,7 +198,7 @@ void SDL_DBus_Quit(void)
SDL_DBusContext *SDL_DBus_GetContext(void)
{
if (dbus_handle == NULL || !dbus.session_conn) {
if (!dbus_handle || !dbus.session_conn) {
SDL_DBus_Init();
}
@ -360,7 +359,7 @@ SDL_bool SDL_DBus_QueryProperty(const char *node, const char *path, const char *
void SDL_DBus_ScreensaverTickle(void)
{
if (screensaver_cookie == 0 && inhibit_handle == NULL) { /* no need to tickle if we're inhibiting. */
if (screensaver_cookie == 0 && !inhibit_handle) { /* no need to tickle if we're inhibiting. */
/* org.gnome.ScreenSaver is the legacy interface, but it'll either do nothing or just be a second harmless tickle on newer systems, so we leave it for now. */
SDL_DBus_CallVoidMethod("org.gnome.ScreenSaver", "/org/gnome/ScreenSaver", "org.gnome.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
SDL_DBus_CallVoidMethod("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
@ -428,7 +427,7 @@ SDL_bool SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
{
const char *default_inhibit_reason = "Playing a game";
if ((inhibit && (screensaver_cookie != 0 || inhibit_handle != NULL)) || (!inhibit && (screensaver_cookie == 0 && inhibit_handle == NULL))) {
if ((inhibit && (screensaver_cookie != 0 || inhibit_handle)) || (!inhibit && (screensaver_cookie == 0 && !inhibit_handle))) {
return SDL_TRUE;
}
@ -452,12 +451,12 @@ SDL_bool SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
const char *key = "reason";
const char *reply = NULL;
const char *reason = SDL_GetHint(SDL_HINT_SCREENSAVER_INHIBIT_ACTIVITY_NAME);
if (reason == NULL || !reason[0]) {
if (!reason || !reason[0]) {
reason = default_inhibit_reason;
}
msg = dbus.message_new_method_call(bus_name, path, interface, "Inhibit");
if (msg == NULL) {
if (!msg) {
return SDL_FALSE;
}
@ -496,10 +495,10 @@ SDL_bool SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
if (inhibit) {
const char *app = SDL_GetHint(SDL_HINT_APP_NAME);
const char *reason = SDL_GetHint(SDL_HINT_SCREENSAVER_INHIBIT_ACTIVITY_NAME);
if (app == NULL || !app[0]) {
if (!app || !app[0]) {
app = "My SDL application";
}
if (reason == NULL || !reason[0]) {
if (!reason || !reason[0]) {
reason = default_inhibit_reason;
}
@ -508,7 +507,7 @@ SDL_bool SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
return SDL_FALSE;
}
return (screensaver_cookie != 0) ? SDL_TRUE : SDL_FALSE;
return (screensaver_cookie != 0);
} else {
if (!SDL_DBus_CallVoidMethod(bus_name, path, interface, "UnInhibit", DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
return SDL_FALSE;

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -73,6 +73,7 @@ typedef struct SDL_evdevlist_item
{
char *path;
int fd;
int udev_class;
/* TODO: use this for every device, not just touchscreen */
SDL_bool out_of_sync;
@ -155,12 +156,21 @@ static int SDL_EVDEV_SetRelativeMouseMode(SDL_bool enabled)
return 0;
}
static void SDL_EVDEV_UpdateKeyboardMute(void)
{
if (SDL_EVDEV_GetDeviceCount(SDL_UDEV_DEVICE_KEYBOARD) > 0) {
SDL_EVDEV_kbd_set_muted(_this->kbd, SDL_TRUE);
} else {
SDL_EVDEV_kbd_set_muted(_this->kbd, SDL_FALSE);
}
}
int SDL_EVDEV_Init(void)
{
if (_this == NULL) {
if (!_this) {
_this = (SDL_EVDEV_PrivateData *)SDL_calloc(1, sizeof(*_this));
if (_this == NULL) {
return SDL_OutOfMemory();
if (!_this) {
return -1;
}
#ifdef SDL_USE_LIBUDEV
@ -208,6 +218,8 @@ int SDL_EVDEV_Init(void)
#endif /* SDL_USE_LIBUDEV */
_this->kbd = SDL_EVDEV_kbd_init();
SDL_EVDEV_UpdateKeyboardMute();
}
SDL_GetMouse()->SetRelativeMouseMode = SDL_EVDEV_SetRelativeMouseMode;
@ -219,7 +231,7 @@ int SDL_EVDEV_Init(void)
void SDL_EVDEV_Quit(void)
{
if (_this == NULL) {
if (!_this) {
return;
}
@ -231,13 +243,13 @@ void SDL_EVDEV_Quit(void)
SDL_UDEV_Quit();
#endif /* SDL_USE_LIBUDEV */
SDL_EVDEV_kbd_quit(_this->kbd);
/* Remove existing devices */
while (_this->first != NULL) {
while (_this->first) {
SDL_EVDEV_device_removed(_this->first->path);
}
SDL_EVDEV_kbd_quit(_this->kbd);
SDL_assert(_this->first == NULL);
SDL_assert(_this->last == NULL);
SDL_assert(_this->num_devices == 0);
@ -251,7 +263,7 @@ void SDL_EVDEV_Quit(void)
static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_class,
const char *dev_path)
{
if (dev_path == NULL) {
if (!dev_path) {
return;
}
@ -276,6 +288,27 @@ static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_cl
}
#endif /* SDL_USE_LIBUDEV */
void SDL_EVDEV_SetVTSwitchCallbacks(void (*release_callback)(void*), void *release_callback_data,
void (*acquire_callback)(void*), void *acquire_callback_data)
{
SDL_EVDEV_kbd_set_vt_switch_callbacks(_this->kbd,
release_callback, release_callback_data,
acquire_callback, acquire_callback_data);
}
int SDL_EVDEV_GetDeviceCount(int device_class)
{
SDL_evdevlist_item *item;
int count = 0;
for (item = _this->first; item; item = item->next) {
if ((item->udev_class & device_class) == device_class) {
++count;
}
}
return count;
}
void SDL_EVDEV_Poll(void)
{
struct input_event events[32];
@ -294,9 +327,11 @@ void SDL_EVDEV_Poll(void)
SDL_UDEV_Poll();
#endif
SDL_EVDEV_kbd_update(_this->kbd);
mouse = SDL_GetMouse();
for (item = _this->first; item != NULL; item = item->next) {
for (item = _this->first; item; item = item->next) {
while ((len = read(item->fd, events, sizeof(events))) > 0) {
len /= sizeof(events[0]);
for (i = 0; i < len; ++i) {
@ -608,8 +643,8 @@ static int SDL_EVDEV_init_touchscreen(SDL_evdevlist_item *item, int udev_class)
}
item->touchscreen_data = SDL_calloc(1, sizeof(*item->touchscreen_data));
if (item->touchscreen_data == NULL) {
return SDL_OutOfMemory();
if (!item->touchscreen_data) {
return -1;
}
ret = ioctl(item->fd, EVIOCGNAME(sizeof(name)), name);
@ -619,9 +654,9 @@ static int SDL_EVDEV_init_touchscreen(SDL_evdevlist_item *item, int udev_class)
}
item->touchscreen_data->name = SDL_strdup(name);
if (item->touchscreen_data->name == NULL) {
if (!item->touchscreen_data->name) {
SDL_free(item->touchscreen_data);
return SDL_OutOfMemory();
return -1;
}
ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
@ -674,10 +709,10 @@ static int SDL_EVDEV_init_touchscreen(SDL_evdevlist_item *item, int udev_class)
item->touchscreen_data->slots = SDL_calloc(
item->touchscreen_data->max_slots,
sizeof(*item->touchscreen_data->slots));
if (item->touchscreen_data->slots == NULL) {
if (!item->touchscreen_data->slots) {
SDL_free(item->touchscreen_data->name);
SDL_free(item->touchscreen_data);
return SDL_OutOfMemory();
return -1;
}
for (i = 0; i < item->touchscreen_data->max_slots; i++) {
@ -735,7 +770,7 @@ static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
sizeof(*mt_req_values) * item->touchscreen_data->max_slots;
mt_req_code = SDL_calloc(1, mt_req_size);
if (mt_req_code == NULL) {
if (!mt_req_code) {
return;
}
@ -840,15 +875,15 @@ static int SDL_EVDEV_device_added(const char *dev_path, int udev_class)
unsigned long relbit[NBITS(REL_MAX)] = { 0 };
/* Check to make sure it's not already in list. */
for (item = _this->first; item != NULL; item = item->next) {
for (item = _this->first; item; item = item->next) {
if (SDL_strcmp(dev_path, item->path) == 0) {
return -1; /* already have this one */
}
}
item = (SDL_evdevlist_item *)SDL_calloc(1, sizeof(SDL_evdevlist_item));
if (item == NULL) {
return SDL_OutOfMemory();
if (!item) {
return -1;
}
item->fd = open(dev_path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
@ -858,12 +893,14 @@ static int SDL_EVDEV_device_added(const char *dev_path, int udev_class)
}
item->path = SDL_strdup(dev_path);
if (item->path == NULL) {
if (!item->path) {
close(item->fd);
SDL_free(item);
return SDL_OutOfMemory();
return -1;
}
item->udev_class = udev_class;
if (ioctl(item->fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0) {
item->relative_mouse = test_bit(REL_X, relbit) && test_bit(REL_Y, relbit);
item->high_res_wheel = test_bit(REL_WHEEL_HI_RES, relbit);
@ -891,7 +928,7 @@ static int SDL_EVDEV_device_added(const char *dev_path, int udev_class)
}
}
if (_this->last == NULL) {
if (!_this->last) {
_this->first = _this->last = item;
} else {
_this->last->next = item;
@ -900,6 +937,8 @@ static int SDL_EVDEV_device_added(const char *dev_path, int udev_class)
SDL_EVDEV_sync_device(item);
SDL_EVDEV_UpdateKeyboardMute();
return _this->num_devices++;
}
@ -908,10 +947,10 @@ static int SDL_EVDEV_device_removed(const char *dev_path)
SDL_evdevlist_item *item;
SDL_evdevlist_item *prev = NULL;
for (item = _this->first; item != NULL; item = item->next) {
for (item = _this->first; item; item = item->next) {
/* found it, remove it. */
if (SDL_strcmp(dev_path, item->path) == 0) {
if (prev != NULL) {
if (prev) {
prev->next = item->next;
} else {
SDL_assert(_this->first == item);
@ -926,6 +965,7 @@ static int SDL_EVDEV_device_removed(const char *dev_path)
close(item->fd);
SDL_free(item->path);
SDL_free(item);
SDL_EVDEV_UpdateKeyboardMute();
_this->num_devices--;
return 0;
}

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 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
@ -30,6 +30,9 @@ struct input_event;
extern int SDL_EVDEV_Init(void);
extern void SDL_EVDEV_Quit(void);
extern void SDL_EVDEV_SetVTSwitchCallbacks(void (*release_callback)(void*), void *release_callback_data,
void (*acquire_callback)(void*), void *acquire_callback_data);
extern int SDL_EVDEV_GetDeviceCount(int device_class);
extern void SDL_EVDEV_Poll(void);
extern Uint64 SDL_EVDEV_GetEventTimestamp(struct input_event *event);

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 2020 Collabora Ltd.
This software is provided 'as-is', without any express or implied

View File

@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 2020 Collabora Ltd.
This software is provided 'as-is', without any express or implied
@ -53,6 +53,7 @@ typedef enum
SDL_UDEV_DEVICE_ACCELEROMETER = 0x0020,
SDL_UDEV_DEVICE_TOUCHPAD = 0x0040,
SDL_UDEV_DEVICE_HAS_KEYS = 0x0080,
SDL_UDEV_DEVICE_VIDEO_CAPTURE = 0x0100,
} SDL_UDEV_deviceclass;
#define BITS_PER_LONG (sizeof(unsigned long) * 8)

Some files were not shown because too many files have changed in this diff Show More