release 0.1.0

This commit is contained in:
InoriRus
2022-05-21 22:04:50 +10:00
parent bc02c0560e
commit a37a9ca253
1056 changed files with 222884 additions and 41332 deletions
+124 -31
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -22,6 +22,23 @@
#if defined(__WIN32__)
#include "core/windows/SDL_windows.h"
#elif defined(__OS2__)
#include <stdlib.h> /* _exit() */
#elif !defined(__WINRT__)
#include <unistd.h> /* _exit(), etc. */
#endif
#if defined(__OS2__)
#include "core/os2/SDL_os2.h"
#if SDL_THREAD_OS2
#include "thread/os2/SDL_systls_c.h"
#endif
#endif
/* this checks for HAVE_DBUS_DBUS_H internally. */
#include "core/linux/SDL_dbus.h"
#if defined(__EMSCRIPTEN__)
#include <emscripten.h>
#endif
/* Initialization code for SDL */
@@ -45,6 +62,34 @@ extern int SDL_HelperWindowDestroy(void);
#endif
/* This is not declared in any header, although it is shared between some
parts of SDL, because we don't want anything calling it without an
extremely good reason. */
extern SDL_NORETURN void SDL_ExitProcess(int exitcode);
SDL_NORETURN void SDL_ExitProcess(int exitcode)
{
#ifdef __WIN32__
/* "if you do not know the state of all threads in your process, it is
better to call TerminateProcess than ExitProcess"
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx */
TerminateProcess(GetCurrentProcess(), exitcode);
/* MingW doesn't have TerminateProcess marked as noreturn, so add an
ExitProcess here that will never be reached but make MingW happy. */
ExitProcess(exitcode);
#elif defined(__EMSCRIPTEN__)
emscripten_cancel_main_loop(); /* this should "kill" the app. */
emscripten_force_exit(exitcode); /* this should "kill" the app. */
exit(exitcode);
#elif defined(__HAIKU__) /* Haiku has _Exit, but it's not marked noreturn. */
_exit(exitcode);
#elif defined(HAVE__EXIT) /* Upper case _Exit() */
_Exit(exitcode);
#else
_exit(exitcode);
#endif
}
/* The initialized subsystems */
#ifdef SDL_MAIN_NEEDED
static SDL_bool SDL_MainIsReady = SDL_FALSE;
@@ -105,28 +150,37 @@ SDL_SetMainReady(void)
int
SDL_InitSubSystem(Uint32 flags)
{
Uint32 flags_initialized = 0;
if (!SDL_MainIsReady) {
SDL_SetError("Application didn't initialize properly, did you include SDL_main.h in the file containing your main() function?");
return -1;
return SDL_SetError("Application didn't initialize properly, did you include SDL_main.h in the file containing your main() function?");
}
/* Clear the error message */
SDL_ClearError();
#if SDL_USE_LIBDBUS
SDL_DBus_Init();
#endif
if ((flags & SDL_INIT_GAMECONTROLLER)) {
/* game controller implies joystick */
flags |= SDL_INIT_JOYSTICK;
}
if ((flags & (SDL_INIT_VIDEO|SDL_INIT_JOYSTICK))) {
/* video or joystick implies events */
if ((flags & (SDL_INIT_VIDEO|SDL_INIT_JOYSTICK|SDL_INIT_AUDIO))) {
/* video or joystick or audio implies events */
flags |= SDL_INIT_EVENTS;
}
#if SDL_THREAD_OS2
SDL_OS2TLSAlloc(); /* thread/os2/SDL_systls.c */
#endif
#if SDL_VIDEO_DRIVER_WINDOWS
if ((flags & (SDL_INIT_HAPTIC|SDL_INIT_JOYSTICK))) {
if (SDL_HelperWindowCreate() < 0) {
return -1;
goto quit_and_error;
}
}
#endif
@@ -139,28 +193,31 @@ SDL_InitSubSystem(Uint32 flags)
if ((flags & SDL_INIT_EVENTS)) {
#if !SDL_EVENTS_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_EVENTS)) {
if (SDL_StartEventLoop() < 0) {
return (-1);
if (SDL_EventsInit() < 0) {
goto quit_and_error;
}
SDL_QuitInit();
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_EVENTS);
flags_initialized |= SDL_INIT_EVENTS;
#else
return SDL_SetError("SDL not built with events support");
SDL_SetError("SDL not built with events support");
goto quit_and_error;
#endif
}
/* Initialize the timer subsystem */
if ((flags & SDL_INIT_TIMER)){
#if !SDL_TIMERS_DISABLED
#if !SDL_TIMERS_DISABLED && !SDL_TIMER_DUMMY
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_TIMER)) {
if (SDL_TimerInit() < 0) {
return (-1);
goto quit_and_error;
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_TIMER);
flags_initialized |= SDL_INIT_TIMER;
#else
return SDL_SetError("SDL not built with timer support");
SDL_SetError("SDL not built with timer support");
goto quit_and_error;
#endif
}
@@ -169,12 +226,14 @@ SDL_InitSubSystem(Uint32 flags)
#if !SDL_VIDEO_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_VIDEO)) {
if (SDL_VideoInit(NULL) < 0) {
return (-1);
goto quit_and_error;
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_VIDEO);
flags_initialized |= SDL_INIT_VIDEO;
#else
return SDL_SetError("SDL not built with video support");
SDL_SetError("SDL not built with video support");
goto quit_and_error;
#endif
}
@@ -183,12 +242,14 @@ SDL_InitSubSystem(Uint32 flags)
#if !SDL_AUDIO_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_AUDIO)) {
if (SDL_AudioInit(NULL) < 0) {
return (-1);
goto quit_and_error;
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_AUDIO);
flags_initialized |= SDL_INIT_AUDIO;
#else
return SDL_SetError("SDL not built with audio support");
SDL_SetError("SDL not built with audio support");
goto quit_and_error;
#endif
}
@@ -197,12 +258,14 @@ SDL_InitSubSystem(Uint32 flags)
#if !SDL_JOYSTICK_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_JOYSTICK)) {
if (SDL_JoystickInit() < 0) {
return (-1);
goto quit_and_error;
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_JOYSTICK);
flags_initialized |= SDL_INIT_JOYSTICK;
#else
return SDL_SetError("SDL not built with joystick support");
SDL_SetError("SDL not built with joystick support");
goto quit_and_error;
#endif
}
@@ -210,12 +273,14 @@ SDL_InitSubSystem(Uint32 flags)
#if !SDL_JOYSTICK_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_GAMECONTROLLER)) {
if (SDL_GameControllerInit() < 0) {
return (-1);
goto quit_and_error;
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_GAMECONTROLLER);
flags_initialized |= SDL_INIT_GAMECONTROLLER;
#else
return SDL_SetError("SDL not built with joystick support");
SDL_SetError("SDL not built with joystick support");
goto quit_and_error;
#endif
}
@@ -224,12 +289,14 @@ SDL_InitSubSystem(Uint32 flags)
#if !SDL_HAPTIC_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_HAPTIC)) {
if (SDL_HapticInit() < 0) {
return (-1);
goto quit_and_error;
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_HAPTIC);
flags_initialized |= SDL_INIT_HAPTIC;
#else
return SDL_SetError("SDL not built with haptic (force feedback) support");
SDL_SetError("SDL not built with haptic (force feedback) support");
goto quit_and_error;
#endif
}
@@ -238,16 +305,24 @@ SDL_InitSubSystem(Uint32 flags)
#if !SDL_SENSOR_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_SENSOR)) {
if (SDL_SensorInit() < 0) {
return (-1);
goto quit_and_error;
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_SENSOR);
flags_initialized |= SDL_INIT_SENSOR;
#else
return SDL_SetError("SDL not built with sensor support");
SDL_SetError("SDL not built with sensor support");
goto quit_and_error;
#endif
}
(void) flags_initialized; /* make static analysis happy, since this only gets used in error cases. */
return (0);
quit_and_error:
SDL_QuitSubSystem(flags_initialized);
return (-1);
}
int
@@ -259,6 +334,13 @@ SDL_Init(Uint32 flags)
void
SDL_QuitSubSystem(Uint32 flags)
{
#if defined(__OS2__)
#if SDL_THREAD_OS2
SDL_OS2TLSFree(); /* thread/os2/SDL_systls.c */
#endif
SDL_OS2Quit();
#endif
/* Shut down requested initialized subsystems */
#if !SDL_SENSOR_DISABLED
if ((flags & SDL_INIT_SENSOR)) {
@@ -321,7 +403,7 @@ SDL_QuitSubSystem(Uint32 flags)
}
#endif
#if !SDL_TIMERS_DISABLED
#if !SDL_TIMERS_DISABLED && !SDL_TIMER_DUMMY
if ((flags & SDL_INIT_TIMER)) {
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_TIMER)) {
SDL_TimerQuit();
@@ -333,8 +415,7 @@ SDL_QuitSubSystem(Uint32 flags)
#if !SDL_EVENTS_DISABLED
if ((flags & SDL_INIT_EVENTS)) {
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_EVENTS)) {
SDL_QuitQuit();
SDL_StopEventLoop();
SDL_EventsQuit();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_EVENTS);
}
@@ -348,6 +429,12 @@ SDL_WasInit(Uint32 flags)
int num_subsystems = SDL_arraysize(SDL_SubsystemRefCount);
Uint32 initialized = 0;
/* Fast path for checking one flag */
if (SDL_HasExactlyOneBitSet32(flags)) {
int subsystem_index = SDL_MostSignificantBitIndex32(flags);
return SDL_SubsystemRefCount[subsystem_index] ? flags : 0;
}
if (!flags) {
flags = SDL_INIT_EVERYTHING;
}
@@ -385,6 +472,10 @@ SDL_Quit(void)
SDL_AssertionsQuit();
SDL_LogResetPriorities();
#if SDL_USE_LIBDBUS
SDL_DBus_Quit();
#endif
/* Now that every subsystem has been quit, we reset the subsystem refcount
* and the list of initialized subsystems.
*/
@@ -411,12 +502,12 @@ SDL_GetRevision(void)
int
SDL_GetRevisionNumber(void)
{
return SDL_REVISION_NUMBER;
return 0; /* doesn't make sense without Mercurial. */
}
/* Get the name of the platform */
const char *
SDL_GetPlatform()
SDL_GetPlatform(void)
{
#if __AIX__
return "AIX";
@@ -470,13 +561,15 @@ SDL_GetPlatform()
return "iOS";
#elif __PSP__
return "PlayStation Portable";
#elif __VITA__
return "PlayStation Vita";
#else
return "Unknown (see SDL_platform.h)";
#endif
}
SDL_bool
SDL_IsTablet()
SDL_IsTablet(void)
{
#if __ANDROID__
extern SDL_bool SDL_IsAndroidTablet(void);
+15 -27
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -36,12 +36,9 @@
#ifndef WS_OVERLAPPEDWINDOW
#define WS_OVERLAPPEDWINDOW 0
#endif
#else /* fprintf, _exit(), etc. */
#else /* fprintf, etc. */
#include <stdio.h>
#include <stdlib.h>
#if ! defined(__WINRT__)
#include <unistd.h>
#endif
#endif
#if defined(__EMSCRIPTEN__)
@@ -120,31 +117,21 @@ static void SDL_GenerateAssertionReport(void)
}
/* This is not declared in any header, although it is shared between some
parts of SDL, because we don't want anything calling it without an
extremely good reason. */
#if defined(__WATCOMC__)
extern void SDL_ExitProcess(int exitcode);
#pragma aux SDL_ExitProcess aborts;
#endif
static void SDL_ExitProcess(int exitcode)
{
#ifdef __WIN32__
/* "if you do not know the state of all threads in your process, it is
better to call TerminateProcess than ExitProcess"
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx */
TerminateProcess(GetCurrentProcess(), exitcode);
#elif defined(__EMSCRIPTEN__)
emscripten_cancel_main_loop(); /* this should "kill" the app. */
emscripten_force_exit(exitcode); /* this should "kill" the app. */
exit(exitcode);
#else
_exit(exitcode);
#endif
}
extern SDL_NORETURN void SDL_ExitProcess(int exitcode);
#if defined(__WATCOMC__)
static void SDL_AbortAssertion (void);
#pragma aux SDL_AbortAssertion aborts;
#endif
static void SDL_AbortAssertion(void)
static SDL_NORETURN void SDL_AbortAssertion(void)
{
SDL_Quit();
SDL_ExitProcess(42);
@@ -178,6 +165,7 @@ SDL_PromptAssertion(const SDL_assert_data *data, void *userdata)
(void) userdata; /* unused in default handler. */
/* !!! FIXME: why is this using SDL_stack_alloc and not just "char message[SDL_MAX_LOG_MESSAGE];" ? */
message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
if (!message) {
/* Uh oh, we're in real trouble now... */
@@ -249,7 +237,7 @@ SDL_PromptAssertion(const SDL_assert_data *data, void *userdata)
SDL_bool okay = SDL_TRUE;
char *buf = (char *) EM_ASM_INT({
var str =
Pointer_stringify($0) + '\n\n' +
UTF8ToString($0) + '\n\n' +
'Abort/Retry/Ignore/AlwaysIgnore? [ariA] :';
var reply = window.prompt(str, "i");
if (reply === null) {
@@ -369,10 +357,6 @@ SDL_ReportAssertion(SDL_assert_data *data, const char *func, const char *file,
switch (state)
{
case SDL_ASSERTION_ABORT:
SDL_AbortAssertion();
return SDL_ASSERTION_IGNORE; /* shouldn't return, but oh well. */
case SDL_ASSERTION_ALWAYS_IGNORE:
state = SDL_ASSERTION_IGNORE;
data->always_ignore = 1;
@@ -382,6 +366,10 @@ SDL_ReportAssertion(SDL_assert_data *data, const char *func, const char *file,
case SDL_ASSERTION_RETRY:
case SDL_ASSERTION_BREAK:
break; /* macro handles these. */
case SDL_ASSERTION_ABORT:
SDL_AbortAssertion();
/*break; ...shouldn't return, but oh well. */
}
assertion_running--;
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+3 -4
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -18,11 +18,10 @@
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.h"
#include "./SDL_dataqueue.h"
#include "SDL_assert.h"
typedef struct SDL_DataQueuePacket
{
@@ -122,7 +121,7 @@ SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack)
queue->queued_bytes = 0;
queue->pool = packet;
/* Optionally keep some slack in the pool to reduce malloc pressure. */
/* Optionally keep some slack in the pool to reduce memory allocation pressure. */
for (i = 0; packet && (i < slackpackets); i++) {
prev = packet;
packet = packet->next;
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+22 -222
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -22,116 +22,31 @@
/* Simple error handling in SDL */
#include "SDL_log.h"
#include "SDL_error.h"
#include "SDL_error_c.h"
/* Routine to get the thread-specific error variable */
#if SDL_THREADS_DISABLED
/* The default (non-thread-safe) global error variable */
static SDL_error SDL_global_error;
#define SDL_GetErrBuf() (&SDL_global_error)
#else
extern SDL_error *SDL_GetErrBuf(void);
#endif /* SDL_THREADS_DISABLED */
#define SDL_ERRBUFIZE 1024
/* Private functions */
static const char *
SDL_LookupString(const char *key)
{
/* FIXME: Add code to lookup key in language string hash-table */
return key;
}
/* Public functions */
static char *SDL_GetErrorMsg(char *errstr, int maxlen);
int
SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
{
va_list ap;
SDL_error *error;
/* Ignore call if invalid format pointer was passed */
if (fmt == NULL) return -1;
if (fmt != NULL) {
va_list ap;
SDL_error *error = SDL_GetErrBuf();
/* Copy in the key, mark error as valid */
error = SDL_GetErrBuf();
error->error = 1;
SDL_strlcpy((char *) error->key, fmt, sizeof(error->key));
error->error = 1; /* mark error as valid */
va_start(ap, fmt);
error->argc = 0;
while (*fmt) {
if (*fmt++ == '%') {
while (*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) {
++fmt;
}
switch (*fmt++) {
case 0: /* Malformed format string.. */
--fmt;
break;
case 'l':
switch (*fmt++) {
case 0: /* Malformed format string.. */
--fmt;
break;
case 'i': case 'd': case 'u':
error->args[error->argc++].value_l = va_arg(ap, long);
break;
}
break;
case 'c':
case 'i':
case 'd':
case 'u':
case 'o':
case 'x':
case 'X':
error->args[error->argc++].value_i = va_arg(ap, int);
break;
case 'f':
error->args[error->argc++].value_f = va_arg(ap, double);
break;
case 'p':
error->args[error->argc++].value_ptr = va_arg(ap, void *);
break;
case 's':
{
int i = error->argc;
const char *str = va_arg(ap, const char *);
if (str == NULL)
str = "(null)";
SDL_strlcpy((char *) error->args[i].buf, str,
ERR_MAX_STRLEN);
error->argc++;
}
break;
default:
break;
}
if (error->argc >= ERR_MAX_ARGS) {
break;
}
va_start(ap, fmt);
SDL_vsnprintf(error->str, ERR_MAX_STRLEN, fmt, ap);
va_end(ap);
if (SDL_LogGetPriority(SDL_LOG_CATEGORY_ERROR) <= SDL_LOG_PRIORITY_DEBUG) {
/* If we are in debug mode, print out the error message */
SDL_LogDebug(SDL_LOG_CATEGORY_ERROR, "%s", error->str);
}
}
va_end(ap);
if (SDL_LogGetPriority(SDL_LOG_CATEGORY_ERROR) <= SDL_LOG_PRIORITY_DEBUG) {
/* If we are in debug mode, print out an error message
* Avoid stomping on the static buffer in GetError, just
* in case this is called while processing a ShowMessageBox to
* show an error already in that static buffer.
*/
char errmsg[SDL_ERRBUFIZE];
SDL_GetErrorMsg(errmsg, sizeof(errmsg));
SDL_LogDebug(SDL_LOG_CATEGORY_ERROR, "%s", errmsg);
}
return -1;
}
@@ -139,18 +54,14 @@ SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
const char *
SDL_GetError(void)
{
static char errmsg[SDL_ERRBUFIZE];
return SDL_GetErrorMsg(errmsg, SDL_ERRBUFIZE);
const SDL_error *error = SDL_GetErrBuf();
return error->error ? error->str : "";
}
void
SDL_ClearError(void)
{
SDL_error *error;
error = SDL_GetErrBuf();
error->error = 0;
SDL_GetErrBuf()->error = 0;
}
/* Very common errors go here */
@@ -191,129 +102,18 @@ main(int argc, char *argv[])
#endif
/* keep this at the end of the file so it works with GCC builds that don't
support "#pragma GCC diagnostic push" ... we'll just leave the warning
disabled after this. */
/* this pragma arrived in GCC 4.2 and causes a warning on older GCCs! Sigh. */
#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 2))))
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif
/* This function has a bit more overhead than most error functions
so that it supports internationalization and thread-safe errors.
*/
static char *
char *
SDL_GetErrorMsg(char *errstr, int maxlen)
{
SDL_error *error;
const SDL_error *error = SDL_GetErrBuf();
/* Clear the error string */
*errstr = '\0';
--maxlen;
/* Get the thread-safe error, and print it out */
error = SDL_GetErrBuf();
if (error->error) {
const char *fmt;
char *msg = errstr;
int len;
int argi;
fmt = SDL_LookupString(error->key);
argi = 0;
while (*fmt && (maxlen > 0)) {
if (*fmt == '%') {
char tmp[32], *spot = tmp;
*spot++ = *fmt++;
while ((*fmt == '.' || (*fmt >= '0' && *fmt <= '9'))
&& spot < (tmp + SDL_arraysize(tmp) - 2)) {
*spot++ = *fmt++;
}
if (*fmt == 'l') {
*spot++ = *fmt++;
*spot++ = *fmt++;
*spot++ = '\0';
switch (spot[-2]) {
case 'i': case 'd': case 'u':
len = SDL_snprintf(msg, maxlen, tmp,
error->args[argi++].value_l);
if (len > 0) {
msg += len;
maxlen -= len;
}
break;
}
continue;
}
*spot++ = *fmt++;
*spot++ = '\0';
switch (spot[-2]) {
case '%':
*msg++ = '%';
maxlen -= 1;
break;
case 'c':
case 'i':
case 'd':
case 'u':
case 'o':
case 'x':
case 'X':
len =
SDL_snprintf(msg, maxlen, tmp,
error->args[argi++].value_i);
if (len > 0) {
msg += len;
maxlen -= len;
}
break;
case 'f':
len =
SDL_snprintf(msg, maxlen, tmp,
error->args[argi++].value_f);
if (len > 0) {
msg += len;
maxlen -= len;
}
break;
case 'p':
len =
SDL_snprintf(msg, maxlen, tmp,
error->args[argi++].value_ptr);
if (len > 0) {
msg += len;
maxlen -= len;
}
break;
case 's':
len =
SDL_snprintf(msg, maxlen, tmp,
SDL_LookupString(error->args[argi++].
buf));
if (len > 0) {
msg += len;
maxlen -= len;
}
break;
}
} else {
*msg++ = *fmt++;
maxlen -= 1;
}
}
/* slide back if we've overshot the end of our buffer. */
if (maxlen < 0) {
msg -= (-maxlen) + 1;
}
*msg = 0; /* NULL terminate the string */
SDL_strlcpy(errstr, error->str, maxlen);
} else {
*errstr = '\0';
}
return (errstr);
return errstr;
}
/* vi: set ts=4 sw=4 expandtab: */
+3 -25
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -28,33 +28,11 @@
#define SDL_error_c_h_
#define ERR_MAX_STRLEN 128
#define ERR_MAX_ARGS 5
typedef struct SDL_error
{
/* This is a numeric value corresponding to the current error */
int error;
/* This is a key used to index into a language hashtable containing
internationalized versions of the SDL error messages. If the key
is not in the hashtable, or no hashtable is available, the key is
used directly as an error message format string.
*/
char key[ERR_MAX_STRLEN];
/* These are the arguments for the error functions */
int argc;
union
{
void *value_ptr;
#if 0 /* What is a character anyway? (UNICODE issues) */
unsigned char value_c;
#endif
int value_i;
long value_l;
double value_f;
char buf[ERR_MAX_STRLEN];
} args[ERR_MAX_ARGS];
int error; /* This is a numeric value corresponding to the current error */
char str[ERR_MAX_STRLEN];
} SDL_error;
/* Defined in SDL_thread.c */
+17 -5
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -22,6 +22,7 @@
#include "SDL_hints.h"
#include "SDL_error.h"
#include "SDL_hints_c.h"
/* Assuming there aren't many hints set and they aren't being queried in
@@ -119,18 +120,24 @@ SDL_GetHint(const char *name)
}
SDL_bool
SDL_GetHintBoolean(const char *name, SDL_bool default_value)
SDL_GetStringBoolean(const char *value, SDL_bool default_value)
{
const char *hint = SDL_GetHint(name);
if (!hint || !*hint) {
if (!value || !*value) {
return default_value;
}
if (*hint == '0' || SDL_strcasecmp(hint, "false") == 0) {
if (*value == '0' || SDL_strcasecmp(value, "false") == 0) {
return SDL_FALSE;
}
return SDL_TRUE;
}
SDL_bool
SDL_GetHintBoolean(const char *name, SDL_bool default_value)
{
const char *hint = SDL_GetHint(name);
return SDL_GetStringBoolean(hint, default_value);
}
void
SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata)
{
@@ -171,6 +178,11 @@ SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata)
return;
}
hint->name = SDL_strdup(name);
if (!hint->name) {
SDL_free(hint);
SDL_OutOfMemory();
return;
}
hint->value = NULL;
hint->priority = SDL_HINT_DEFAULT;
hint->callbacks = NULL;
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -18,20 +18,15 @@
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "./SDL_internal.h"
/*
Contributed by Brandon Schaefer, <brandon.schaefer@canonical.com>
*/
/* This file defines useful function for working with SDL hints */
#ifndef SDL_mirevents_h_
#define SDL_mirevents_h_
#ifndef SDL_hints_c_h_
#define SDL_hints_c_h_
#include <mir_toolkit/mir_client_library.h>
extern SDL_bool SDL_GetStringBoolean(const char *value, SDL_bool default_value);
extern void
MIR_HandleEvent(MirWindow*, MirEvent const* ev, void* context);
#endif /* SDL_mirevents_h_ */
#endif /* SDL_hints_c_h_ */
/* vi: set ts=4 sw=4 expandtab: */
+78 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -35,6 +35,10 @@
#define SDL_VARIABLE_LENGTH_ARRAY
#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) if ((isstack)) { SDL_stack_free(ptr); } else { SDL_free(ptr); }
#include "dynapi/SDL_dynapi.h"
#if SDL_DYNAMIC_API
@@ -47,6 +51,79 @@
#include "SDL_config.h"
/* If you run into a warning that O_CLOEXEC is redefined, update the SDL configuration header for your platform to add HAVE_O_CLOEXEC */
#ifndef HAVE_O_CLOEXEC
#define O_CLOEXEC 0
#endif
/* A few #defines to reduce SDL2 footprint.
Only effective when library is statically linked.
You have to manually edit this file. */
#ifndef SDL_LEAN_AND_MEAN
#define SDL_LEAN_AND_MEAN 0
#endif
/* Optimized functions from 'SDL_blit_0.c'
- blit with source BitsPerPixel < 8, palette */
#ifndef SDL_HAVE_BLIT_0
#define SDL_HAVE_BLIT_0 !SDL_LEAN_AND_MEAN
#endif
/* Optimized functions from 'SDL_blit_1.c'
- blit with source BytesPerPixel == 1, palette */
#ifndef SDL_HAVE_BLIT_1
#define SDL_HAVE_BLIT_1 !SDL_LEAN_AND_MEAN
#endif
/* Optimized functions from 'SDL_blit_A.c'
- blit with 'SDL_BLENDMODE_BLEND' blending mode */
#ifndef SDL_HAVE_BLIT_A
#define SDL_HAVE_BLIT_A !SDL_LEAN_AND_MEAN
#endif
/* Optimized functions from 'SDL_blit_N.c'
- blit with COLORKEY mode, or nothing */
#ifndef SDL_HAVE_BLIT_N
#define SDL_HAVE_BLIT_N !SDL_LEAN_AND_MEAN
#endif
/* Optimized functions from 'SDL_blit_N.c'
- RGB565 conversion with Lookup tables */
#ifndef SDL_HAVE_BLIT_N_RGB565
#define SDL_HAVE_BLIT_N_RGB565 !SDL_LEAN_AND_MEAN
#endif
/* Optimized functions from 'SDL_blit_AUTO.c'
- blit with modulate color, modulate alpha, any blending mode
- scaling or not */
#ifndef SDL_HAVE_BLIT_AUTO
#define SDL_HAVE_BLIT_AUTO !SDL_LEAN_AND_MEAN
#endif
/* Run-Length-Encoding
- SDL_SetColorKey() called with SDL_RLEACCEL flag */
#ifndef SDL_HAVE_RLE
#define SDL_HAVE_RLE !SDL_LEAN_AND_MEAN
#endif
/* Software SDL_Renderer
- creation of software renderer
- *not* general blitting functions
- {blend,draw}{fillrect,line,point} internal functions */
#ifndef SDL_VIDEO_RENDER_SW
#define SDL_VIDEO_RENDER_SW !SDL_LEAN_AND_MEAN
#endif
/* YUV formats
- handling of YUV surfaces
- blitting and conversion functions */
#ifndef SDL_HAVE_YUV
#define SDL_HAVE_YUV !SDL_LEAN_AND_MEAN
#endif
#include "SDL_assert.h"
#include "SDL_log.h"
#endif /* SDL_internal_h_ */
/* vi: set ts=4 sw=4 expandtab: */
+93
View File
@@ -0,0 +1,93 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
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.h"
#include "./SDL_list.h"
/* Push */
int
SDL_ListAdd(SDL_ListNode **head, void *ent)
{
SDL_ListNode *node = SDL_malloc(sizeof (*node));
if (node == NULL) {
return SDL_OutOfMemory();
}
node->entry = ent;
node->next = *head;
*head = node;
return 0;
}
/* Pop from end as a FIFO (if add with SDL_ListAdd) */
void
SDL_ListPop(SDL_ListNode **head, void **ent)
{
SDL_ListNode **ptr = head;
/* Invalid or empty */
if (head == NULL || *head == NULL) {
return;
}
while ((*ptr)->next) {
ptr = &(*ptr)->next;
}
if (ent) {
*ent = (*ptr)->entry;
}
SDL_free(*ptr);
*ptr = NULL;
}
void
SDL_ListRemove(SDL_ListNode **head, void *ent)
{
SDL_ListNode **ptr = head;
while (*ptr) {
if ((*ptr)->entry == ent) {
SDL_ListNode *tmp = *ptr;
*ptr = (*ptr)->next;
SDL_free(tmp);
return;
}
ptr = &(*ptr)->next;
}
}
void
SDL_ListClear(SDL_ListNode **head)
{
SDL_ListNode *l = *head;
*head = NULL;
while (l) {
SDL_ListNode *tmp = l;
l = l->next;
SDL_free(tmp);
}
}
/* vi: set ts=4 sw=4 expandtab: */
+39
View File
@@ -0,0 +1,39 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
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_list_h_
#define SDL_list_h_
typedef struct SDL_ListNode
{
void *entry;
struct SDL_ListNode *next;
} SDL_ListNode;
int SDL_ListAdd(SDL_ListNode **head, void *ent);
void SDL_ListPop(SDL_ListNode **head, void **ent);
void SDL_ListRemove(SDL_ListNode **head, void *ent);
void SDL_ListClear(SDL_ListNode **head);
#endif /* SDL_list_h_ */
/* vi: set ts=4 sw=4 expandtab: */
+18 -9
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -282,6 +282,7 @@ SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list
return;
}
/* !!! FIXME: why not just "char message[SDL_MAX_LOG_MESSAGE];" ? */
message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
if (!message) {
return;
@@ -321,11 +322,12 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
char *output;
size_t length;
LPTSTR tstr;
SDL_bool isstack;
#if !defined(HAVE_STDIO_H) && !defined(__WINRT__)
BOOL attachResult;
DWORD attachError;
unsigned long charsWritten;
DWORD charsWritten;
DWORD consoleMode;
/* Maybe attach console and get stderr handle */
@@ -364,7 +366,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
#endif /* !defined(HAVE_STDIO_H) && !defined(__WINRT__) */
length = SDL_strlen(SDL_priority_prefixes[priority]) + 2 + SDL_strlen(message) + 1 + 1 + 1;
output = SDL_stack_alloc(char, length);
output = SDL_small_alloc(char, length, &isstack);
SDL_snprintf(output, length, "%s: %s\r\n", SDL_priority_prefixes[priority], message);
tstr = WIN_UTF8ToString(output);
@@ -374,7 +376,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
#if !defined(HAVE_STDIO_H) && !defined(__WINRT__)
/* Screen output to stderr, if console was attached. */
if (consoleAttached == 1) {
if (!WriteConsole(stderrHandle, tstr, lstrlen(tstr), &charsWritten, NULL)) {
if (!WriteConsole(stderrHandle, tstr, (DWORD) SDL_tcslen(tstr), &charsWritten, NULL)) {
OutputDebugString(TEXT("Error calling WriteConsole\r\n"));
if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
OutputDebugString(TEXT("Insufficient heap memory to write message\r\n"));
@@ -382,14 +384,14 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
}
} else if (consoleAttached == 2) {
if (!WriteFile(stderrHandle, output, lstrlenA(output), &charsWritten, NULL)) {
if (!WriteFile(stderrHandle, output, (DWORD) SDL_strlen(output), &charsWritten, NULL)) {
OutputDebugString(TEXT("Error calling WriteFile\r\n"));
}
}
#endif /* !defined(HAVE_STDIO_H) && !defined(__WINRT__) */
SDL_free(tstr);
SDL_stack_free(output);
SDL_small_free(output, isstack);
}
#elif defined(__ANDROID__)
{
@@ -398,13 +400,13 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
SDL_snprintf(tag, SDL_arraysize(tag), "SDL/%s", GetCategoryPrefix(category));
__android_log_write(SDL_android_priority[priority], tag, message);
}
#elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA)
/* Technically we don't need SDL_VIDEO_DRIVER_COCOA, but that's where this function is defined for now.
#elif defined(__APPLE__) && (defined(SDL_VIDEO_DRIVER_COCOA) || defined(SDL_VIDEO_DRIVER_UIKIT))
/* Technically we don't need Cocoa/UIKit, but that's where this function is defined for now.
*/
extern void SDL_NSLog(const char *text);
{
char *text;
/* !!! FIXME: why not just "char text[SDL_MAX_LOG_MESSAGE];" ? */
text = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
if (text) {
SDL_snprintf(text, SDL_MAX_LOG_MESSAGE, "%s: %s", SDL_priority_prefixes[priority], message);
@@ -420,6 +422,13 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
fprintf(pFile, "%s: %s\n", SDL_priority_prefixes[priority], message);
fclose (pFile);
}
#elif defined(__VITA__)
{
FILE* pFile;
pFile = fopen ("ux0:/data/SDL_Log.txt", "a");
fprintf(pFile, "%s: %s\n", SDL_priority_prefixes[priority], message);
fclose (pFile);
}
#endif
#if HAVE_STDIO_H
fprintf(stderr, "%s: %s\n", SDL_priority_prefixes[priority], message);
+17 -15
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -36,33 +36,31 @@
#endif
/* The __atomic_load_n() intrinsic showed up in different times for different compilers. */
#if defined(HAVE_GCC_ATOMICS)
# if defined(__clang__)
# if __has_builtin(__atomic_load_n)
/* !!! FIXME: this advertises as available in the NDK but uses an external symbol we don't have.
It might be in a later NDK or we might need an extra library? --ryan. */
# if !defined(__ANDROID__)
# define HAVE_ATOMIC_LOAD_N 1
# endif
# endif
# elif defined(__GNUC__)
#if defined(__clang__)
# if __has_builtin(__atomic_load_n) || defined(HAVE_GCC_ATOMICS)
/* !!! FIXME: this advertises as available in the NDK but uses an external symbol we don't have.
It might be in a later NDK or we might need an extra library? --ryan. */
# if !defined(__ANDROID__)
# define HAVE_ATOMIC_LOAD_N 1
# endif
# endif
#elif defined(__GNUC__)
# if (__GNUC__ >= 5)
# define HAVE_ATOMIC_LOAD_N 1
# endif
# endif
#endif
#if defined(__WATCOMC__) && defined(__386__)
SDL_COMPILE_TIME_ASSERT(intsize, 4==sizeof(int));
#define HAVE_WATCOM_ATOMICS
extern _inline int _SDL_xchg_watcom(volatile int *a, int v);
extern __inline int _SDL_xchg_watcom(volatile int *a, int v);
#pragma aux _SDL_xchg_watcom = \
"lock xchg [ecx], eax" \
parm [ecx] [eax] \
value [eax] \
modify exact [eax];
extern _inline unsigned char _SDL_cmpxchg_watcom(volatile int *a, int newval, int oldval);
extern __inline unsigned char _SDL_cmpxchg_watcom(volatile int *a, int newval, int oldval);
#pragma aux _SDL_cmpxchg_watcom = \
"lock cmpxchg [edx], ecx" \
"setz al" \
@@ -70,7 +68,7 @@ extern _inline unsigned char _SDL_cmpxchg_watcom(volatile int *a, int newval, in
value [al] \
modify exact [eax];
extern _inline int _SDL_xadd_watcom(volatile int *a, int v);
extern __inline int _SDL_xadd_watcom(volatile int *a, int v);
#pragma aux _SDL_xadd_watcom = \
"lock xadd [ecx], eax" \
parm [ecx] [eax] \
@@ -289,6 +287,10 @@ SDL_AtomicGetPtr(void **a)
#endif
}
#ifdef SDL_MEMORY_BARRIER_USES_FUNCTION
#error This file should be built in arm mode so the mcr instruction is available for memory barriers
#endif
void
SDL_MemoryBarrierReleaseFunction(void)
{
+38 -11
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -32,13 +32,17 @@
#include <atomic.h>
#endif
#if !defined(HAVE_GCC_ATOMICS) && defined(__RISCOS__)
#include <unixlib/local.h>
#endif
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
#include <xmmintrin.h>
#endif
#if defined(__WATCOMC__) && defined(__386__)
SDL_COMPILE_TIME_ASSERT(locksize, 4==sizeof(SDL_SpinLock));
extern _inline int _SDL_xchg_watcom(volatile int *a, int v);
extern __inline int _SDL_xchg_watcom(volatile int *a, int v);
#pragma aux _SDL_xchg_watcom = \
"lock xchg [ecx], eax" \
parm [ecx] [eax] \
@@ -68,6 +72,12 @@ SDL_AtomicTryLock(SDL_SpinLock *lock)
return SDL_FALSE;
}
#elif HAVE_GCC_ATOMICS || HAVE_GCC_SYNC_LOCK_TEST_AND_SET
return (__sync_lock_test_and_set(lock, 1) == 0);
#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
return (_InterlockedExchange_acq(lock, 1) == 0);
#elif defined(_MSC_VER)
SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long));
return (InterlockedExchange((long*)lock, 1) == 0);
@@ -75,14 +85,22 @@ SDL_AtomicTryLock(SDL_SpinLock *lock)
#elif defined(__WATCOMC__) && defined(__386__)
return _SDL_xchg_watcom(lock, 1) == 0;
#elif HAVE_GCC_ATOMICS || HAVE_GCC_SYNC_LOCK_TEST_AND_SET
return (__sync_lock_test_and_set(lock, 1) == 0);
#elif defined(__GNUC__) && defined(__arm__) && \
(defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \
(defined(__ARM_ARCH_3__) || defined(__ARM_ARCH_3M__) || \
defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \
defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5TE__) || \
defined(__ARM_ARCH_5TEJ__))
int result;
#if defined(__RISCOS__)
if (__cpucap_have_rex()) {
__asm__ __volatile__ (
"ldrex %0, [%2]\nteq %0, #0\nstrexeq %0, %1, [%2]"
: "=&r" (result) : "r" (1), "r" (lock) : "cc", "memory");
return (result == 0);
}
#endif
__asm__ __volatile__ (
"swp %0, %1, [%2]\n"
: "=&r,&r" (result) : "r,0" (1), "r,r" (lock) : "memory");
@@ -123,11 +141,17 @@ SDL_AtomicTryLock(SDL_SpinLock *lock)
/* "REP NOP" is PAUSE, coded for tools that don't know it by that name. */
#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
#define PAUSE_INSTRUCTION() __asm__ __volatile__("pause\n") /* Some assemblers can't do REP NOP, so go with PAUSE. */
#elif (defined(__arm__) && __ARM_ARCH__ >= 7) || defined(__aarch64__)
#define PAUSE_INSTRUCTION() __asm__ __volatile__("yield" ::: "memory")
#elif (defined(__powerpc__) || defined(__powerpc64__))
#define PAUSE_INSTRUCTION() __asm__ __volatile__("or 27,27,27");
#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
#define PAUSE_INSTRUCTION() _mm_pause() /* this is actually "rep nop" and not a SIMD instruction. No inline asm in MSVC x86-64! */
#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
#define PAUSE_INSTRUCTION() __yield()
#elif defined(__WATCOMC__) && defined(__386__)
/* watcom assembler rejects PAUSE if CPU < i686, and it refuses REP NOP as an invalid combination. Hardcode the bytes. */
extern _inline void PAUSE_INSTRUCTION(void);
extern __inline void PAUSE_INSTRUCTION(void);
#pragma aux PAUSE_INSTRUCTION = "db 0f3h,90h"
#else
#define PAUSE_INSTRUCTION()
@@ -152,7 +176,13 @@ SDL_AtomicLock(SDL_SpinLock *lock)
void
SDL_AtomicUnlock(SDL_SpinLock *lock)
{
#if defined(_MSC_VER)
#if HAVE_GCC_ATOMICS || HAVE_GCC_SYNC_LOCK_TEST_AND_SET
__sync_lock_release(lock);
#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
_InterlockedExchange_rel(lock, 0);
#elif defined(_MSC_VER)
_ReadWriteBarrier();
*lock = 0;
@@ -160,9 +190,6 @@ SDL_AtomicUnlock(SDL_SpinLock *lock)
SDL_CompilerBarrier ();
*lock = 0;
#elif HAVE_GCC_ATOMICS || HAVE_GCC_SYNC_LOCK_TEST_AND_SET
__sync_lock_release(lock);
#elif defined(__SOLARIS__)
/* Used for Solaris when not using gcc. */
*lock = 0;
+178 -123
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -47,9 +47,6 @@ static const AudioBootStrap *const bootstrap[] = {
#if SDL_AUDIO_DRIVER_NETBSD
&NETBSDAUDIO_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_OSS
&DSP_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_QSA
&QSAAUDIO_bootstrap,
#endif
@@ -89,18 +86,36 @@ static const AudioBootStrap *const bootstrap[] = {
#if SDL_AUDIO_DRIVER_FUSIONSOUND
&FUSIONSOUND_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_AAUDIO
&aaudio_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_OPENSLES
&openslES_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_ANDROID
&ANDROIDAUDIO_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_PSP
&PSPAUDIO_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_VITA
&VITAAUD_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_EMSCRIPTEN
&EMSCRIPTENAUDIO_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_JACK
&JACK_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_PIPEWIRE
&PIPEWIRE_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_OSS
&DSP_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_OS2
&OS2AUDIO_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_DISK
&DISKAUDIO_bootstrap,
#endif
@@ -214,9 +229,9 @@ SDL_AudioDetectDevices_Default(void)
SDL_assert(current_audio.impl.OnlyHasDefaultOutputDevice);
SDL_assert(current_audio.impl.OnlyHasDefaultCaptureDevice || !current_audio.impl.HasCaptureSupport);
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) ((size_t) 0x1));
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, NULL, (void *) ((size_t) 0x1));
if (current_audio.impl.HasCaptureSupport) {
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) ((size_t) 0x2));
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, NULL, (void *) ((size_t) 0x2));
}
}
@@ -230,11 +245,6 @@ SDL_AudioThreadDeinit_Default(_THIS)
{ /* no-op. */
}
static void
SDL_AudioBeginLoopIteration_Default(_THIS)
{ /* no-op. */
}
static void
SDL_AudioWaitDevice_Default(_THIS)
{ /* no-op. */
@@ -245,12 +255,6 @@ SDL_AudioPlayDevice_Default(_THIS)
{ /* no-op. */
}
static int
SDL_AudioGetPendingBytes_Default(_THIS)
{
return 0;
}
static Uint8 *
SDL_AudioGetDeviceBuf_Default(_THIS)
{
@@ -268,11 +272,6 @@ SDL_AudioFlushCapture_Default(_THIS)
{ /* no-op. */
}
static void
SDL_AudioPrepareToClose_Default(_THIS)
{ /* no-op. */
}
static void
SDL_AudioCloseDevice_Default(_THIS)
{ /* no-op. */
@@ -290,7 +289,7 @@ SDL_AudioFreeDeviceHandle_Default(void *handle)
static int
SDL_AudioOpenDevice_Default(_THIS, void *handle, const char *devname, int iscapture)
SDL_AudioOpenDevice_Default(_THIS, const char *devname)
{
return SDL_Unsupported();
}
@@ -325,11 +324,6 @@ SDL_AudioUnlockDevice_Default(SDL_AudioDevice * device)
}
}
static void
SDL_AudioLockOrUnlockDeviceWithNoMixerLock(SDL_AudioDevice * device)
{
}
static void
finish_audio_entry_points_init(void)
{
@@ -338,14 +332,6 @@ finish_audio_entry_points_init(void)
* blindly call them without having to check for validity first.
*/
if (current_audio.impl.SkipMixerLock) {
if (current_audio.impl.LockDevice == NULL) {
current_audio.impl.LockDevice = SDL_AudioLockOrUnlockDeviceWithNoMixerLock;
}
if (current_audio.impl.UnlockDevice == NULL) {
current_audio.impl.UnlockDevice = SDL_AudioLockOrUnlockDeviceWithNoMixerLock;
}
}
#define FILL_STUB(x) \
if (current_audio.impl.x == NULL) { \
@@ -355,14 +341,11 @@ finish_audio_entry_points_init(void)
FILL_STUB(OpenDevice);
FILL_STUB(ThreadInit);
FILL_STUB(ThreadDeinit);
FILL_STUB(BeginLoopIteration);
FILL_STUB(WaitDevice);
FILL_STUB(PlayDevice);
FILL_STUB(GetPendingBytes);
FILL_STUB(GetDeviceBuf);
FILL_STUB(CaptureFromDevice);
FILL_STUB(FlushCapture);
FILL_STUB(PrepareToClose);
FILL_STUB(CloseDevice);
FILL_STUB(LockDevice);
FILL_STUB(UnlockDevice);
@@ -375,7 +358,7 @@ finish_audio_entry_points_init(void)
/* device hotplug support... */
static int
add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices, int *devCount)
add_audio_device(const char *name, SDL_AudioSpec *spec, void *handle, SDL_AudioDeviceItem **devices, int *devCount)
{
int retval = -1;
SDL_AudioDeviceItem *item;
@@ -398,6 +381,11 @@ add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices,
item->dupenum = 0;
item->name = item->original_name;
if (spec != NULL) {
SDL_memcpy(&item->spec, spec, sizeof(SDL_AudioSpec));
} else {
SDL_zero(item->spec);
}
item->handle = handle;
SDL_LockMutex(current_audio.detectionLock);
@@ -416,8 +404,7 @@ add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices,
SDL_UnlockMutex(current_audio.detectionLock);
SDL_free(item->original_name);
SDL_free(item);
SDL_OutOfMemory();
return -1;
return SDL_OutOfMemory();
}
SDL_snprintf(replacement, len, "%s (%d)", name, dupenum + 1);
@@ -435,16 +422,16 @@ add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices,
}
static SDL_INLINE int
add_capture_device(const char *name, void *handle)
add_capture_device(const char *name, SDL_AudioSpec *spec, void *handle)
{
SDL_assert(current_audio.impl.HasCaptureSupport);
return add_audio_device(name, handle, &current_audio.inputDevices, &current_audio.inputDeviceCount);
return add_audio_device(name, spec, handle, &current_audio.inputDevices, &current_audio.inputDeviceCount);
}
static SDL_INLINE int
add_output_device(const char *name, void *handle)
add_output_device(const char *name, SDL_AudioSpec *spec, void *handle)
{
return add_audio_device(name, handle, &current_audio.outputDevices, &current_audio.outputDeviceCount);
return add_audio_device(name, spec, handle, &current_audio.outputDevices, &current_audio.outputDeviceCount);
}
static void
@@ -470,9 +457,9 @@ free_device_list(SDL_AudioDeviceItem **devices, int *devCount)
/* The audio backends call this when a new device is plugged in. */
void
SDL_AddAudioDevice(const int iscapture, const char *name, void *handle)
SDL_AddAudioDevice(const SDL_bool iscapture, const char *name, SDL_AudioSpec *spec, void *handle)
{
const int device_index = iscapture ? add_capture_device(name, handle) : add_output_device(name, handle);
const int device_index = iscapture ? add_capture_device(name, spec, handle) : add_output_device(name, spec, handle);
if (device_index != -1) {
/* Post the event, if desired */
if (SDL_GetEventState(SDL_AUDIODEVICEADDED) == SDL_ENABLE) {
@@ -532,7 +519,7 @@ mark_device_removed(void *handle, SDL_AudioDeviceItem *devices, SDL_bool *remove
/* The audio backends call this when a device is removed from the system. */
void
SDL_RemoveAudioDevice(const int iscapture, void *handle)
SDL_RemoveAudioDevice(const SDL_bool iscapture, void *handle)
{
int device_index;
SDL_AudioDevice *device = NULL;
@@ -578,7 +565,7 @@ SDL_BufferQueueDrainCallback(void *userdata, Uint8 *stream, int len)
if (len > 0) { /* fill any remaining space in the stream with silence. */
SDL_assert(SDL_CountDataQueue(device->buffer_queue) == 0);
SDL_memset(stream, device->spec.silence, len);
SDL_memset(stream, device->callbackspec.silence, len);
}
}
@@ -651,11 +638,9 @@ SDL_GetQueuedAudioSize(SDL_AudioDeviceID devid)
}
/* Nothing to do unless we're set up for queueing. */
if (device->callbackspec.callback == SDL_BufferQueueDrainCallback) {
current_audio.impl.LockDevice(device);
retval = ((Uint32) SDL_CountDataQueue(device->buffer_queue)) + current_audio.impl.GetPendingBytes(device);
current_audio.impl.UnlockDevice(device);
} else if (device->callbackspec.callback == SDL_BufferQueueFillCallback) {
if (device->callbackspec.callback == SDL_BufferQueueDrainCallback ||
device->callbackspec.callback == SDL_BufferQueueFillCallback)
{
current_audio.impl.LockDevice(device);
retval = (Uint32) SDL_CountDataQueue(device->buffer_queue);
current_audio.impl.UnlockDevice(device);
@@ -676,7 +661,7 @@ SDL_ClearQueuedAudio(SDL_AudioDeviceID devid)
/* Blank out the device and release the mutex. Free it afterwards. */
current_audio.impl.LockDevice(device);
/* Keep up to two packets in the pool to reduce future malloc pressure. */
/* Keep up to two packets in the pool to reduce future memory allocation pressure. */
SDL_ClearDataQueue(device->buffer_queue, SDL_AUDIOBUFFERQUEUE_PACKETLEN * 2);
current_audio.impl.UnlockDevice(device);
@@ -695,8 +680,16 @@ SDL_RunAudio(void *devicep)
SDL_assert(!device->iscapture);
#if SDL_AUDIO_DRIVER_ANDROID
{
/* Set thread priority to THREAD_PRIORITY_AUDIO */
extern void Android_JNI_AudioSetThreadPriority(int, int);
Android_JNI_AudioSetThreadPriority(device->iscapture, device->id);
}
#else
/* The audio mixing is always a high priority thread */
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_TIME_CRITICAL);
#endif
/* Perform any thread setup */
device->threadid = SDL_ThreadID();
@@ -704,7 +697,6 @@ SDL_RunAudio(void *devicep)
/* Loop, filling the audio buffers */
while (!SDL_AtomicGet(&device->shutdown)) {
current_audio.impl.BeginLoopIteration(device);
data_len = device->callbackspec.size;
/* Fill the current buffer with sound */
@@ -728,7 +720,7 @@ SDL_RunAudio(void *devicep)
/* !!! FIXME: this should be LockDevice. */
SDL_LockMutex(device->mixer_lock);
if (SDL_AtomicGet(&device->paused)) {
SDL_memset(data, device->spec.silence, data_len);
SDL_memset(data, device->callbackspec.silence, data_len);
} else {
callback(udata, data, data_len);
}
@@ -743,7 +735,7 @@ SDL_RunAudio(void *devicep)
int got;
data = SDL_AtomicGet(&device->enabled) ? current_audio.impl.GetDeviceBuf(device) : NULL;
got = SDL_AudioStreamGet(device->stream, data ? data : device->work_buffer, device->spec.size);
SDL_assert((got < 0) || (got == device->spec.size));
SDL_assert((got <= 0) || (got == device->spec.size));
if (data == NULL) { /* device is having issues... */
const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq);
@@ -767,8 +759,6 @@ SDL_RunAudio(void *devicep)
}
}
current_audio.impl.PrepareToClose(device);
/* Wait for the audio to drain. */
SDL_Delay(((device->spec.samples * 1000) / device->spec.freq) * 2);
@@ -792,8 +782,16 @@ SDL_CaptureAudio(void *devicep)
SDL_assert(device->iscapture);
#if SDL_AUDIO_DRIVER_ANDROID
{
/* Set thread priority to THREAD_PRIORITY_AUDIO */
extern void Android_JNI_AudioSetThreadPriority(int, int);
Android_JNI_AudioSetThreadPriority(device->iscapture, device->id);
}
#else
/* The audio mixing is always a high priority thread */
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
#endif
/* Perform any thread setup */
device->threadid = SDL_ThreadID();
@@ -804,8 +802,6 @@ SDL_CaptureAudio(void *devicep)
int still_need;
Uint8 *ptr;
current_audio.impl.BeginLoopIteration(device);
if (SDL_AtomicGet(&device->paused)) {
SDL_Delay(delay); /* just so we don't cook the CPU. */
if (device->stream) {
@@ -877,8 +873,6 @@ SDL_CaptureAudio(void *devicep)
}
}
current_audio.impl.PrepareToClose(device);
current_audio.impl.FlushCapture(device);
current_audio.impl.ThreadDeinit(device);
@@ -931,35 +925,61 @@ SDL_GetAudioDriver(int index)
int
SDL_AudioInit(const char *driver_name)
{
int i = 0;
int initialized = 0;
int tried_to_init = 0;
int i;
SDL_bool initialized = SDL_FALSE, tried_to_init = SDL_FALSE;
if (SDL_WasInit(SDL_INIT_AUDIO)) {
if (SDL_GetCurrentAudioDriver()) {
SDL_AudioQuit(); /* shutdown driver if already running. */
}
SDL_zero(current_audio);
SDL_zero(open_devices);
SDL_zeroa(open_devices);
/* Select the proper audio driver */
if (driver_name == NULL) {
driver_name = SDL_getenv("SDL_AUDIODRIVER");
driver_name = SDL_GetHint(SDL_HINT_AUDIODRIVER);
}
for (i = 0; (!initialized) && (bootstrap[i]); ++i) {
/* make sure we should even try this driver before doing so... */
const AudioBootStrap *backend = bootstrap[i];
if ((driver_name && (SDL_strncasecmp(backend->name, driver_name, SDL_strlen(driver_name)) != 0)) ||
(!driver_name && backend->demand_only)) {
continue;
}
if (driver_name != NULL && *driver_name != 0) {
const char *driver_attempt = driver_name;
while (driver_attempt != NULL && *driver_attempt != 0 && !initialized) {
const char *driver_attempt_end = SDL_strchr(driver_attempt, ',');
size_t driver_attempt_len = (driver_attempt_end != NULL) ? (driver_attempt_end - driver_attempt)
: SDL_strlen(driver_attempt);
#if SDL_AUDIO_DRIVER_PULSEAUDIO
/* SDL 1.2 uses the name "pulse", so we'll support both. */
if (driver_attempt_len == SDL_strlen("pulse") &&
(SDL_strncasecmp(driver_attempt, "pulse", driver_attempt_len) == 0)) {
driver_attempt = "pulseaudio";
driver_attempt_len = SDL_strlen("pulseaudio");
}
#endif
tried_to_init = 1;
SDL_zero(current_audio);
current_audio.name = backend->name;
current_audio.desc = backend->desc;
initialized = backend->init(&current_audio.impl);
for (i = 0; bootstrap[i]; ++i) {
if ((driver_attempt_len == SDL_strlen(bootstrap[i]->name)) &&
(SDL_strncasecmp(bootstrap[i]->name, driver_attempt, driver_attempt_len) == 0)) {
tried_to_init = SDL_TRUE;
SDL_zero(current_audio);
current_audio.name = bootstrap[i]->name;
current_audio.desc = bootstrap[i]->desc;
initialized = bootstrap[i]->init(&current_audio.impl);
break;
}
}
driver_attempt = (driver_attempt_end != NULL) ? (driver_attempt_end + 1) : NULL;
}
} else {
for (i = 0; (!initialized) && (bootstrap[i]); ++i) {
if(bootstrap[i]->demand_only) {
continue;
}
tried_to_init = SDL_TRUE;
SDL_zero(current_audio);
current_audio.name = bootstrap[i]->name;
current_audio.desc = bootstrap[i]->desc;
initialized = bootstrap[i]->init(&current_audio.impl);
}
}
if (!initialized) {
@@ -1038,7 +1058,7 @@ SDL_GetNumAudioDevices(int iscapture)
{
int retval = 0;
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (!SDL_GetCurrentAudioDriver()) {
return -1;
}
@@ -1061,39 +1081,63 @@ SDL_GetNumAudioDevices(int iscapture)
const char *
SDL_GetAudioDeviceName(int index, int iscapture)
{
const char *retval = NULL;
SDL_AudioDeviceItem *item;
int i;
const char *retval;
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (!SDL_GetCurrentAudioDriver()) {
SDL_SetError("Audio subsystem is not initialized");
return NULL;
}
if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
SDL_SetError("No capture support");
return NULL;
}
if (index >= 0) {
SDL_AudioDeviceItem *item;
int i;
SDL_LockMutex(current_audio.detectionLock);
item = iscapture ? current_audio.inputDevices : current_audio.outputDevices;
i = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount;
if (index < i) {
for (i--; i > index; i--, item = item->next) {
SDL_assert(item != NULL);
}
SDL_LockMutex(current_audio.detectionLock);
item = iscapture ? current_audio.inputDevices : current_audio.outputDevices;
i = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount;
if (index >= 0 && index < i) {
for (i--; i > index; i--, item = item->next) {
SDL_assert(item != NULL);
retval = item->name;
}
SDL_UnlockMutex(current_audio.detectionLock);
SDL_assert(item != NULL);
retval = item->name;
} else {
SDL_InvalidParamError("index");
retval = NULL;
}
SDL_UnlockMutex(current_audio.detectionLock);
return retval;
}
int
SDL_GetAudioDeviceSpec(int index, int iscapture, SDL_AudioSpec *spec)
{
SDL_AudioDeviceItem *item;
int i, retval;
if (spec == NULL) {
return SDL_InvalidParamError("spec");
}
if (retval == NULL) {
SDL_SetError("No such device");
if (!SDL_GetCurrentAudioDriver()) {
return SDL_SetError("Audio subsystem is not initialized");
}
SDL_LockMutex(current_audio.detectionLock);
item = iscapture ? current_audio.inputDevices : current_audio.outputDevices;
i = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount;
if (index >= 0 && index < i) {
for (i--; i > index; i--, item = item->next) {
SDL_assert(item != NULL);
}
SDL_assert(item != NULL);
SDL_memcpy(spec, &item->spec, sizeof(SDL_AudioSpec));
retval = 0;
} else {
retval = SDL_InvalidParamError("index");
}
SDL_UnlockMutex(current_audio.detectionLock);
return retval;
}
@@ -1170,13 +1214,14 @@ prepare_audiospec(const SDL_AudioSpec * orig, SDL_AudioSpec * prepared)
const char *env = SDL_getenv("SDL_AUDIO_CHANNELS");
if ((!env) || ((prepared->channels = (Uint8) SDL_atoi(env)) == 0)) {
prepared->channels = 2; /* a reasonable default */
break;
}
break;
}
case 1: /* Mono */
case 2: /* Stereo */
case 4: /* Quadrophonic */
case 6: /* 5.1 surround */
case 7: /* 6.1 surround */
case 8: /* 7.1 surround */
break;
default:
@@ -1217,12 +1262,12 @@ open_audio_device(const char *devname, int iscapture,
void *handle = NULL;
int i = 0;
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (!SDL_GetCurrentAudioDriver()) {
SDL_SetError("Audio subsystem is not initialized");
return 0;
}
if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
if (iscapture && !current_audio.impl.HasCaptureSupport) {
SDL_SetError("No capture support");
return 0;
}
@@ -1329,7 +1374,7 @@ open_audio_device(const char *devname, int iscapture,
SDL_AtomicSet(&device->enabled, 1);
/* Create a mutex for locking the sound buffers */
if (!current_audio.impl.SkipMixerLock) {
if (current_audio.impl.LockDevice == SDL_AudioLockDevice_Default) {
device->mixer_lock = SDL_CreateMutex();
if (device->mixer_lock == NULL) {
close_audio_device(device);
@@ -1338,7 +1383,7 @@ open_audio_device(const char *devname, int iscapture,
}
}
if (current_audio.impl.OpenDevice(device, handle, devname, iscapture) < 0) {
if (current_audio.impl.OpenDevice(device, devname) < 0) {
close_audio_device(device);
return 0;
}
@@ -1463,8 +1508,7 @@ SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained)
/* SDL_OpenAudio() is legacy and can only act on Device ID #1. */
if (open_devices[0] != NULL) {
SDL_SetError("Audio device is already opened");
return -1;
return SDL_SetError("Audio device is already opened");
}
if (obtained) {
@@ -1600,7 +1644,7 @@ SDL_AudioQuit(void)
SDL_DestroyMutex(current_audio.detectionLock);
SDL_zero(current_audio);
SDL_zero(open_devices);
SDL_zeroa(open_devices);
#ifdef HAVE_LIBSAMPLERATE_H
UnloadLibSampleRate();
@@ -1656,17 +1700,28 @@ SDL_NextAudioFormat(void)
return format_list[format_idx][format_idx_sub++];
}
Uint8
SDL_SilenceValueForFormat(const SDL_AudioFormat format)
{
switch (format) {
/* !!! FIXME: 0x80 isn't perfect for U16, but we can't fit 0x8000 in a
!!! FIXME: byte for SDL_memset() use. This is actually 0.1953 percent
!!! FIXME: off from silence. Maybe just don't use U16. */
case AUDIO_U16LSB:
case AUDIO_U16MSB:
case AUDIO_U8:
return 0x80;
default: break;
}
return 0x00;
}
void
SDL_CalculateAudioSpec(SDL_AudioSpec * spec)
{
switch (spec->format) {
case AUDIO_U8:
spec->silence = 0x80;
break;
default:
spec->silence = 0x00;
break;
}
spec->silence = SDL_SilenceValueForFormat(spec->format);
spec->size = SDL_AUDIO_BITSIZE(spec->format) / 8;
spec->size *= spec->channels;
spec->size *= spec->samples;
+2 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -52,6 +52,7 @@ extern SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format);
extern SDL_AudioFormat SDL_NextAudioFormat(void);
/* Function to calculate the size and silence for a SDL_AudioSpec */
extern Uint8 SDL_SilenceValueForFormat(const SDL_AudioFormat format);
extern void SDL_CalculateAudioSpec(SDL_AudioSpec * spec);
/* Choose the audio filter functions below */
+476 -64
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -30,21 +30,45 @@
#include "SDL_audio_c.h"
#include "SDL_loadso.h"
#include "SDL_assert.h"
#include "../SDL_dataqueue.h"
#include "SDL_cpuinfo.h"
#define DEBUG_AUDIOSTREAM 0
#ifdef __ARM_NEON
#define HAVE_NEON_INTRINSICS 1
#endif
#ifdef __SSE__
#define HAVE_SSE_INTRINSICS 1
#endif
#ifdef __SSE3__
#define HAVE_SSE3_INTRINSICS 1
#endif
#if defined(HAVE_IMMINTRIN_H) && !defined(SDL_DISABLE_IMMINTRIN_H)
#define HAVE_AVX_INTRINSICS 1
#endif
#if defined __clang__
# if (!__has_attribute(target))
# undef HAVE_AVX_INTRINSICS
# endif
# if (defined(_MSC_VER) || defined(__SCE__)) && !defined(__AVX__)
# undef HAVE_AVX_INTRINSICS
# endif
#elif defined __GNUC__
# if (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 9)
# undef HAVE_AVX_INTRINSICS
# endif
#endif
#if HAVE_SSE3_INTRINSICS
/* Convert from stereo to mono. Average left and right. */
static void SDLCALL
SDL_ConvertStereoToMono_SSE3(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
const __m128 divby2 = _mm_set1_ps(0.5f);
float *dst = (float *) cvt->buf;
const float *src = dst;
int i = cvt->len_cvt / 8;
@@ -52,15 +76,12 @@ SDL_ConvertStereoToMono_SSE3(SDL_AudioCVT * cvt, SDL_AudioFormat format)
LOG_DEBUG_CONVERT("stereo", "mono (using SSE3)");
SDL_assert(format == AUDIO_F32SYS);
/* We can only do this if dst is aligned to 16 bytes; since src is the
same pointer and it moves by 2, it can't be forcibly aligned. */
if ((((size_t) dst) & 15) == 0) {
/* Aligned! Do SSE blocks as long as we have 16 bytes available. */
const __m128 divby2 = _mm_set1_ps(0.5f);
while (i >= 4) { /* 4 * float32 */
_mm_store_ps(dst, _mm_mul_ps(_mm_hadd_ps(_mm_load_ps(src), _mm_load_ps(src+4)), divby2));
i -= 4; src += 8; dst += 4;
}
/* Do SSE blocks as long as we have 16 bytes available.
Just use unaligned load/stores, if the memory at runtime is
aligned it'll be just as fast on modern processors */
while (i >= 4) { /* 4 * float32 */
_mm_storeu_ps(dst, _mm_mul_ps(_mm_hadd_ps(_mm_loadu_ps(src), _mm_loadu_ps(src+4)), divby2));
i -= 4; src += 8; dst += 4;
}
/* Finish off any leftovers with scalar operations. */
@@ -97,6 +118,191 @@ SDL_ConvertStereoToMono(SDL_AudioCVT * cvt, SDL_AudioFormat format)
}
}
#if HAVE_AVX_INTRINSICS
/* MSVC will always accept AVX intrinsics when compiling for x64 */
#if defined(__clang__) || defined(__GNUC__)
__attribute__((target("avx")))
#endif
/* Convert from 5.1 to stereo. Average left and right, distribute center, discard LFE. */
static void SDLCALL
SDL_Convert51ToStereo_AVX(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
float *dst = (float *) cvt->buf;
const float *src = dst;
int i = cvt->len_cvt / (sizeof (float) * 6);
const float two_fifths_f = 1.0f / 2.5f;
const __m256 two_fifths_v = _mm256_set1_ps(two_fifths_f);
const __m256 half = _mm256_set1_ps(0.5f);
LOG_DEBUG_CONVERT("5.1", "stereo (using AVX)");
SDL_assert(format == AUDIO_F32SYS);
/* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
while (i >= 4) {
__m256 in0 = _mm256_loadu_ps(src + 0); /* 0FL 0FR 0FC 0LF 0BL 0BR 1FL 1FR */
__m256 in1 = _mm256_loadu_ps(src + 8); /* 1FC 1LF 1BL 1BR 2FL 2FR 2FC 2LF */
__m256 in2 = _mm256_loadu_ps(src + 16); /* 2BL 2BR 3FL 3FR 3FC 3LF 3BL 3BR */
/* 0FL 0FR 0FC 0LF 2FL 2FR 2FC 2LF */
__m256 temp0 = _mm256_blend_ps(in0, in1, 0xF0);
/* 1FC 1LF 1BL 1BR 3FC 3LF 3BL 3BR */
__m256 temp1 = _mm256_blend_ps(in1, in2, 0xF0);
/* 0FC 0FC 1FC 1FC 2FC 2FC 3FC 3FC */
__m256 fc_distributed = _mm256_mul_ps(half, _mm256_shuffle_ps(temp0, temp1, _MM_SHUFFLE(0, 0, 2, 2)));
/* 0FL 0FR 1BL 1BR 2FL 2FR 3BL 3BR */
__m256 permuted0 = _mm256_blend_ps(temp0, temp1, 0xCC);
/* 0BL 0BR 1FL 1FR 2BL 2BR 3FL 3FR */
__m256 permuted1 = _mm256_permute2f128_ps(in0, in2, 0x21);
/* 0FL 0FR 1BL 1BR 2FL 2FR 3BL 3BR */
/* + 0BL 0BR 1FL 1FR 2BL 2BR 3FL 3FR */
/* = 0L 0R 1L 1R 2L 2R 3L 3R */
__m256 out = _mm256_add_ps(permuted0, permuted1);
out = _mm256_add_ps(out, fc_distributed);
out = _mm256_mul_ps(out, two_fifths_v);
_mm256_storeu_ps(dst, out);
i -= 4; src += 24; dst += 8;
}
/* Finish off any leftovers with scalar operations. */
while (i) {
const float front_center_distributed = src[2] * 0.5f;
dst[0] = (src[0] + front_center_distributed + src[4]) * two_fifths_f; /* left */
dst[1] = (src[1] + front_center_distributed + src[5]) * two_fifths_f; /* right */
i--; src += 6; dst+=2;
}
cvt->len_cvt /= 3;
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index] (cvt, format);
}
}
#endif
#if HAVE_SSE_INTRINSICS
/* Convert from 5.1 to stereo. Average left and right, distribute center, discard LFE. */
static void SDLCALL
SDL_Convert51ToStereo_SSE(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
float *dst = (float *) cvt->buf;
const float *src = dst;
int i = cvt->len_cvt / (sizeof (float) * 6);
const float two_fifths_f = 1.0f / 2.5f;
const __m128 two_fifths_v = _mm_set1_ps(two_fifths_f);
const __m128 half = _mm_set1_ps(0.5f);
LOG_DEBUG_CONVERT("5.1", "stereo (using SSE)");
SDL_assert(format == AUDIO_F32SYS);
/* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
/* Just use unaligned load/stores, if the memory at runtime is */
/* aligned it'll be just as fast on modern processors */
while (i >= 2) {
/* Two 5.1 samples (12 floats) fit nicely in three 128bit */
/* registers. Using shuffles they can be rearranged so that */
/* the conversion math can be vectorized. */
__m128 in0 = _mm_loadu_ps(src); /* 0FL 0FR 0FC 0LF */
__m128 in1 = _mm_loadu_ps(src + 4); /* 0BL 0BR 1FL 1FR */
__m128 in2 = _mm_loadu_ps(src + 8); /* 1FC 1LF 1BL 1BR */
/* 0FC 0FC 1FC 1FC */
__m128 fc_distributed = _mm_mul_ps(half, _mm_shuffle_ps(in0, in2, _MM_SHUFFLE(0, 0, 2, 2)));
/* 0FL 0FR 1BL 1BR */
__m128 blended = _mm_shuffle_ps(in0, in2, _MM_SHUFFLE(3, 2, 1, 0));
/* 0FL 0FR 1BL 1BR */
/* + 0BL 0BR 1FL 1FR */
/* = 0L 0R 1L 1R */
__m128 out = _mm_add_ps(blended, in1);
out = _mm_add_ps(out, fc_distributed);
out = _mm_mul_ps(out, two_fifths_v);
_mm_storeu_ps(dst, out);
i -= 2; src += 12; dst += 4;
}
/* Finish off any leftovers with scalar operations. */
while (i) {
const float front_center_distributed = src[2] * 0.5f;
dst[0] = (src[0] + front_center_distributed + src[4]) * two_fifths_f; /* left */
dst[1] = (src[1] + front_center_distributed + src[5]) * two_fifths_f; /* right */
i--; src += 6; dst+=2;
}
cvt->len_cvt /= 3;
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index] (cvt, format);
}
}
#endif
#if HAVE_NEON_INTRINSICS
/* Convert from 5.1 to stereo. Average left and right, distribute center, discard LFE. */
static void SDLCALL
SDL_Convert51ToStereo_NEON(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
float *dst = (float *) cvt->buf;
const float *src = dst;
int i = cvt->len_cvt / (sizeof (float) * 6);
const float two_fifths_f = 1.0f / 2.5f;
const float32x4_t two_fifths_v = vdupq_n_f32(two_fifths_f);
const float32x4_t half = vdupq_n_f32(0.5f);
LOG_DEBUG_CONVERT("5.1", "stereo (using NEON)");
SDL_assert(format == AUDIO_F32SYS);
/* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
/* Just use unaligned load/stores, it's the same NEON instructions and
hopefully even unaligned NEON is faster than the scalar fallback. */
while (i >= 2) {
/* Two 5.1 samples (12 floats) fit nicely in three 128bit */
/* registers. Using shuffles they can be rearranged so that */
/* the conversion math can be vectorized. */
const float32x4_t in0 = vld1q_f32(src); /* 0FL 0FR 0FC 0LF */
const float32x4_t in1 = vld1q_f32(src + 4); /* 0BL 0BR 1FL 1FR */
const float32x4_t in2 = vld1q_f32(src + 8); /* 1FC 1LF 1BL 1BR */
/* 0FC 0FC 1FC 1FC */
const float32x4_t fc_distributed = vmulq_f32(half, vcombine_f32(vdup_lane_f32(vget_high_f32(in0), 0), vdup_lane_f32(vget_low_f32(in2), 0)));
/* 0FL 0FR 1BL 1BR */
const float32x4_t blended = vcombine_f32(vget_low_f32(in0), vget_high_f32(in2));
/* 0FL 0FR 1BL 1BR */
/* + 0BL 0BR 1FL 1FR */
/* = 0L 0R 1L 1R */
float32x4_t out = vaddq_f32(blended, in1);
out = vaddq_f32(out, fc_distributed);
out = vmulq_f32(out, two_fifths_v);
vst1q_f32(dst, out);
i -= 2; src += 12; dst += 4;
}
/* Finish off any leftovers with scalar operations. */
while (i) {
const float front_center_distributed = src[2] * 0.5f;
dst[0] = (src[0] + front_center_distributed + src[4]) * two_fifths_f; /* left */
dst[1] = (src[1] + front_center_distributed + src[5]) * two_fifths_f; /* right */
i--; src += 6; dst+=2;
}
cvt->len_cvt /= 3;
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index] (cvt, format);
}
}
#endif
/* Convert from 5.1 to stereo. Average left and right, distribute center, discard LFE. */
static void SDLCALL
@@ -105,6 +311,7 @@ SDL_Convert51ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
float *dst = (float *) cvt->buf;
const float *src = dst;
int i;
const float two_fifths = 1.0f / 2.5f;
LOG_DEBUG_CONVERT("5.1", "stereo");
SDL_assert(format == AUDIO_F32SYS);
@@ -112,8 +319,8 @@ SDL_Convert51ToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
/* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 2) {
const float front_center_distributed = src[2] * 0.5f;
dst[0] = (src[0] + front_center_distributed + src[4]) / 2.5f; /* left */
dst[1] = (src[1] + front_center_distributed + src[5]) / 2.5f; /* right */
dst[0] = (src[0] + front_center_distributed + src[4]) * two_fifths; /* left */
dst[1] = (src[1] + front_center_distributed + src[5]) * two_fifths; /* right */
}
cvt->len_cvt /= 3;
@@ -153,6 +360,7 @@ SDL_Convert71To51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
float *dst = (float *) cvt->buf;
const float *src = dst;
int i;
const float two_thirds = 1.0f / 1.5f;
LOG_DEBUG_CONVERT("7.1", "5.1");
SDL_assert(format == AUDIO_F32SYS);
@@ -160,12 +368,12 @@ SDL_Convert71To51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8, dst += 6) {
const float surround_left_distributed = src[6] * 0.5f;
const float surround_right_distributed = src[7] * 0.5f;
dst[0] = (src[0] + surround_left_distributed) / 1.5f; /* FL */
dst[1] = (src[1] + surround_right_distributed) / 1.5f; /* FR */
dst[2] = src[2] / 1.5f; /* CC */
dst[3] = src[3] / 1.5f; /* LFE */
dst[4] = (src[4] + surround_left_distributed) / 1.5f; /* BL */
dst[5] = (src[5] + surround_right_distributed) / 1.5f; /* BR */
dst[0] = (src[0] + surround_left_distributed) * two_thirds; /* FL */
dst[1] = (src[1] + surround_right_distributed) * two_thirds; /* FR */
dst[2] = src[2] * two_thirds; /* CC */
dst[3] = src[3] * two_thirds; /* LFE */
dst[4] = (src[4] + surround_left_distributed) * two_thirds; /* BL */
dst[5] = (src[5] + surround_right_distributed) * two_thirds; /* BR */
}
cvt->len_cvt /= 8;
@@ -175,6 +383,125 @@ SDL_Convert71To51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
}
}
/* Convert from 7.1 to 6.1 */
/* SDL's 6.1 layout: LFE+FC+FR+SR+BackSurround+SL+FL */
/* SDL's 7.1 layout: FL+FR+FC+LFE+BL+BR+SL+SR */
static void SDLCALL
SDL_Convert71To61(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
float *dst = (float *) cvt->buf;
const float *src = dst;
int i;
LOG_DEBUG_CONVERT("7.1", "6.1");
SDL_assert(format == AUDIO_F32SYS);
for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8, dst += 7) {
dst[0] = src[3]; /* LFE */
dst[1] = src[2]; /* FC */
dst[2] = src[1]; /* FR */
dst[3] = src[7]; /* SR */
dst[4] = (src[4] + src[5]) / 0.2f; /* BackSurround */
dst[5] = src[6]; /* SL */
dst[6] = src[0]; /* FL */
}
cvt->len_cvt /= 8;
cvt->len_cvt *= 7;
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index] (cvt, format);
}
}
/* Convert from 6.1 to 7.1 */
/* SDL's 6.1 layout: LFE+FC+FR+SR+BackSurround+SL+FL */
/* SDL's 7.1 layout: FL+FR+FC+LFE+BL+BR+SL+SR */
static void SDLCALL
SDL_Convert61To71(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
float *dst = (float *) cvt->buf;
const float *src = dst;
int i;
LOG_DEBUG_CONVERT("6.1", "7.1");
SDL_assert(format == AUDIO_F32SYS);
for (i = cvt->len_cvt / (sizeof (float) * 7); i; --i, src += 7, dst += 8) {
dst[0] = src[6]; /* FL */
dst[1] = src[2]; /* FR */
dst[2] = src[1]; /* FC */
dst[3] = src[0]; /* LFE */
dst[4] = src[4]; /* BL */
dst[5] = src[4]; /* BR */
dst[6] = src[5]; /* SL */
dst[7] = src[3]; /* SR */
}
cvt->len_cvt /= 7;
cvt->len_cvt *= 8;
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index] (cvt, format);
}
}
/* Convert from 5.1 to 6.1 */
/* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
/* SDL's 6.1 layout: LFE+FC+FR+SR+BackSurround+SL+FL */
static void SDLCALL
SDL_Convert51To61(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
float *dst = (float *) cvt->buf;
const float *src = dst;
int i;
LOG_DEBUG_CONVERT("5.1", "6.1");
SDL_assert(format == AUDIO_F32SYS);
for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 7) {
dst[0] = src[3]; /* LFE */
dst[1] = src[2]; /* FC */
dst[2] = src[1]; /* FR */
dst[3] = src[5]; /* SR */
dst[4] = (src[4] + src[5]) / 0.2f; /* BackSurround */
dst[5] = src[4]; /* SL */
dst[6] = src[0]; /* FL */
}
cvt->len_cvt /= 6;
cvt->len_cvt *= 7;
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index] (cvt, format);
}
}
/* Convert from 6.1 to 5.1 */
/* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
/* SDL's 6.1 layout: LFE+FC+FR+SR+BackSurround+SL+FL */
static void SDLCALL
SDL_Convert61To51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
float *dst = (float *) cvt->buf;
const float *src = dst;
int i;
LOG_DEBUG_CONVERT("6.1", "5.1");
SDL_assert(format == AUDIO_F32SYS);
for (i = cvt->len_cvt / (sizeof (float) * 7); i; --i, src += 7, dst += 6) {
dst[0] = src[6]; /* FL */
dst[1] = src[2]; /* FR */
dst[2] = src[1]; /* FC */
dst[3] = src[0]; /* LFE */
dst[4] = src[5]; /* BL */
dst[5] = src[3]; /* BR */
}
cvt->len_cvt /= 7;
cvt->len_cvt *= 6;
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index] (cvt, format);
}
}
/* Convert from 5.1 to quad. Distribute center across front, discard LFE. */
static void SDLCALL
@@ -183,6 +510,7 @@ SDL_Convert51ToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
float *dst = (float *) cvt->buf;
const float *src = dst;
int i;
const float two_thirds = 1.0f / 1.5f;
LOG_DEBUG_CONVERT("5.1", "quad");
SDL_assert(format == AUDIO_F32SYS);
@@ -191,10 +519,10 @@ SDL_Convert51ToQuad(SDL_AudioCVT * cvt, SDL_AudioFormat format)
/* SDL's 5.1 layout: FL+FR+FC+LFE+BL+BR */
for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 4) {
const float front_center_distributed = src[2] * 0.5f;
dst[0] = (src[0] + front_center_distributed) / 1.5f; /* FL */
dst[1] = (src[1] + front_center_distributed) / 1.5f; /* FR */
dst[2] = src[4] / 1.5f; /* BL */
dst[3] = src[5] / 1.5f; /* BR */
dst[0] = (src[0] + front_center_distributed) * two_thirds; /* FL */
dst[1] = (src[1] + front_center_distributed) * two_thirds; /* FR */
dst[2] = src[4] * two_thirds; /* BL */
dst[3] = src[5] * two_thirds; /* BR */
}
cvt->len_cvt /= 6;
@@ -247,9 +575,9 @@ SDL_ConvertStereoTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
lf = src[0];
rf = src[1];
ce = (lf + rf) * 0.5f;
/* !!! FIXME: FL and FR may clip */
dst[0] = lf + (lf - ce); /* FL */
dst[1] = rf + (rf - ce); /* FR */
/* Constant 0.571f is approx 4/7 not to saturate */
dst[0] = 0.571f * (lf + (lf - 0.5f * ce)); /* FL */
dst[1] = 0.571f * (rf + (rf - 0.5f * ce)); /* FR */
dst[2] = ce; /* FC */
dst[3] = 0; /* LFE (only meant for special LFE effects) */
dst[4] = lf; /* BL */
@@ -284,9 +612,9 @@ SDL_ConvertQuadTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format)
lb = src[2];
rb = src[3];
ce = (lf + rf) * 0.5f;
/* !!! FIXME: FL and FR may clip */
dst[0] = lf + (lf - ce); /* FL */
dst[1] = rf + (rf - ce); /* FR */
/* Constant 0.571f is approx 4/7 not to saturate */
dst[0] = 0.571f * (lf + (lf - 0.5f * ce)); /* FL */
dst[1] = 0.571f * (rf + (rf - 0.5f * ce)); /* FR */
dst[2] = ce; /* FC */
dst[3] = 0; /* LFE (only meant for special LFE effects) */
dst[4] = lb; /* BL */
@@ -352,19 +680,18 @@ SDL_Convert51To71(SDL_AudioCVT * cvt, SDL_AudioFormat format)
rb = src[5];
ls = (lf + lb) * 0.5f;
rs = (rf + rb) * 0.5f;
/* !!! FIXME: these four may clip */
lf += lf - ls;
rf += rf - ls;
rf += rf - rs;
lb += lb - ls;
rb += rb - ls;
rb += rb - rs;
dst[3] = src[3]; /* LFE */
dst[2] = src[2]; /* FC */
dst[7] = rs; /* SR */
dst[6] = ls; /* SL */
dst[5] = rb; /* BR */
dst[4] = lb; /* BL */
dst[1] = rf; /* FR */
dst[0] = lf; /* FL */
dst[5] = 0.5f * rb; /* BR */
dst[4] = 0.5f * lb; /* BL */
dst[1] = 0.5f * rf; /* FR */
dst[0] = 0.5f * lf; /* FL */
}
cvt->len_cvt = cvt->len_cvt * 4 / 3;
@@ -474,7 +801,8 @@ ResamplerPadding(const int inrate, const int outrate)
{
if (inrate == outrate) {
return 0;
} else if (inrate > outrate) {
}
if (inrate > outrate) {
return (int) SDL_ceil(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate)));
}
return RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
@@ -603,9 +931,7 @@ SDL_AddAudioCVTFilter(SDL_AudioCVT *cvt, const SDL_AudioFilter filter)
if (cvt->filter_index >= SDL_AUDIOCVT_MAX_FILTERS) {
return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS);
}
if (filter == NULL) {
return SDL_SetError("Audio filter pointer is NULL");
}
SDL_assert(filter != NULL);
cvt->filters[cvt->filter_index++] = filter;
cvt->filters[cvt->filter_index] = NULL; /* Moving terminator */
return 0;
@@ -616,7 +942,7 @@ SDL_BuildAudioTypeCVTToFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat src_fmt)
{
int retval = 0; /* 0 == no conversion necessary. */
if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN) && SDL_AUDIO_BITSIZE(src_fmt) > 8) {
if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
return -1;
}
@@ -677,7 +1003,7 @@ SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
}
if (!filter) {
return SDL_SetError("No conversion from float to destination format available");
return SDL_SetError("No conversion from float to format 0x%.4x available", dst_fmt);
}
if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
@@ -693,7 +1019,7 @@ SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
retval = 1; /* added a converter. */
}
if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) {
if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN) && SDL_AUDIO_BITSIZE(dst_fmt) > 8) {
if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
return -1;
}
@@ -718,9 +1044,15 @@ SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format
/* !!! FIXME: remove this if we can get the resampler to work in-place again. */
float *dst = (float *) (cvt->buf + srclen);
const int dstlen = (cvt->len * cvt->len_mult) - srclen;
const int paddingsamples = (ResamplerPadding(inrate, outrate) * chans);
const int requestedpadding = ResamplerPadding(inrate, outrate);
int paddingsamples;
float *padding;
if (requestedpadding < SDL_MAX_SINT32 / chans) {
paddingsamples = requestedpadding * chans;
} else {
paddingsamples = 0;
}
SDL_assert(format == AUDIO_F32SYS);
/* we keep no streaming state here, so pad with silence on both ends. */
@@ -802,8 +1134,8 @@ SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
if (cvt->filter_index >= (SDL_AUDIOCVT_MAX_FILTERS-2)) {
return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS-2);
}
cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1] = (SDL_AudioFilter) (size_t) src_rate;
cvt->filters[SDL_AUDIOCVT_MAX_FILTERS] = (SDL_AudioFilter) (size_t) dst_rate;
cvt->filters[SDL_AUDIOCVT_MAX_FILTERS-1] = (SDL_AudioFilter) (uintptr_t) src_rate;
cvt->filters[SDL_AUDIOCVT_MAX_FILTERS] = (SDL_AudioFilter) (uintptr_t) dst_rate;
if (src_rate < dst_rate) {
const double mult = ((double) dst_rate) / ((double) src_rate);
@@ -852,6 +1184,7 @@ SDL_SupportedChannelCount(const int channels)
case 2: /* stereo */
case 4: /* quad */
case 6: /* 5.1 */
case 7: /* 6.1 */
case 8: /* 7.1 */
return SDL_TRUE; /* supported. */
@@ -883,16 +1216,27 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
if (!SDL_SupportedAudioFormat(src_fmt)) {
return SDL_SetError("Invalid source format");
} else if (!SDL_SupportedAudioFormat(dst_fmt)) {
}
if (!SDL_SupportedAudioFormat(dst_fmt)) {
return SDL_SetError("Invalid destination format");
} else if (!SDL_SupportedChannelCount(src_channels)) {
}
if (!SDL_SupportedChannelCount(src_channels)) {
return SDL_SetError("Invalid source channels");
} else if (!SDL_SupportedChannelCount(dst_channels)) {
}
if (!SDL_SupportedChannelCount(dst_channels)) {
return SDL_SetError("Invalid destination channels");
} else if (src_rate == 0) {
return SDL_SetError("Source rate is zero");
} else if (dst_rate == 0) {
return SDL_SetError("Destination rate is zero");
}
if (src_rate <= 0) {
return SDL_SetError("Source rate is equal to or less than zero");
}
if (dst_rate <= 0) {
return SDL_SetError("Destination rate is equal to or less than zero");
}
if (src_rate >= SDL_MAX_SINT32 / RESAMPLER_SAMPLES_PER_ZERO_CROSSING) {
return SDL_SetError("Source rate is too high");
}
if (dst_rate >= SDL_MAX_SINT32 / RESAMPLER_SAMPLES_PER_ZERO_CROSSING) {
return SDL_SetError("Destination rate is too high");
}
#if DEBUG_CONVERT
@@ -905,7 +1249,7 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
cvt->dst_format = dst_fmt;
cvt->needed = 0;
cvt->filter_index = 0;
SDL_zero(cvt->filters);
SDL_zeroa(cvt->filters);
cvt->len_mult = 1;
cvt->len_ratio = 1.0;
cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
@@ -935,6 +1279,9 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
/* just a byteswap needed? */
if ((src_fmt & ~SDL_AUDIO_MASK_ENDIAN) == (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN)) {
if (SDL_AUDIO_BITSIZE(dst_fmt) == 8) {
return 0;
}
if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) {
return -1;
}
@@ -951,6 +1298,16 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
/* Channel conversion */
if (src_channels < dst_channels) {
/* Upmixing */
/* 6.1 -> 7.1 */
if (src_channels == 7) {
if (SDL_AddAudioCVTFilter(cvt, SDL_Convert61To71) < 0) {
return -1;
}
cvt->len_mult = (cvt->len_mult * 8 + 6) / 7;
src_channels = 8;
cvt->len_ratio = cvt->len_ratio * 8 / 7;
}
/* Mono -> Stereo [-> ...] */
if ((src_channels == 1) && (dst_channels > 1)) {
if (SDL_AddAudioCVTFilter(cvt, SDL_ConvertMonoToStereo) < 0) {
@@ -978,6 +1335,15 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
cvt->len_mult = (cvt->len_mult * 3 + 1) / 2;
cvt->len_ratio *= 1.5;
}
/* 5.1 -> 6.1 */
if (src_channels == 6 && dst_channels == 7) {
if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51To61) < 0) {
return -1;
}
src_channels = 7;
cvt->len_mult = (cvt->len_mult * 7 + 5) / 6;
cvt->len_ratio = cvt->len_ratio * 7 / 6;
}
/* [[Mono ->] Stereo ->] 5.1 -> 7.1 */
if ((src_channels == 6) && (dst_channels == 8)) {
if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51To71) < 0) {
@@ -1000,6 +1366,22 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
}
} else if (src_channels > dst_channels) {
/* Downmixing */
/* 7.1 -> 6.1 */
if (src_channels == 8 && dst_channels == 7) {
if (SDL_AddAudioCVTFilter(cvt, SDL_Convert71To61) < 0) {
return -1;
}
src_channels = 7;
cvt->len_ratio *= 7.0f / 8.0f;
}
/* 6.1 -> 5.1 [->...] */
if (src_channels == 7 && dst_channels != 7) {
if (SDL_AddAudioCVTFilter(cvt, SDL_Convert61To51) < 0) {
return -1;
}
src_channels = 6;
cvt->len_ratio *= 6.0f / 7.0f;
}
/* 7.1 -> 5.1 [-> Stereo [-> Mono]] */
/* 7.1 -> 5.1 [-> Quad] */
if ((src_channels == 8) && (dst_channels <= 6)) {
@@ -1011,7 +1393,31 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
}
/* [7.1 ->] 5.1 -> Stereo [-> Mono] */
if ((src_channels == 6) && (dst_channels <= 2)) {
if (SDL_AddAudioCVTFilter(cvt, SDL_Convert51ToStereo) < 0) {
SDL_AudioFilter filter = NULL;
#if HAVE_AVX_INTRINSICS
if (SDL_HasAVX()) {
filter = SDL_Convert51ToStereo_AVX;
}
#endif
#if HAVE_SSE_INTRINSICS
if (!filter && SDL_HasSSE()) {
filter = SDL_Convert51ToStereo_SSE;
}
#endif
#if HAVE_NEON_INTRINSICS
if (!filter && SDL_HasNEON()) {
filter = SDL_Convert51ToStereo_NEON;
}
#endif
if (!filter) {
filter = SDL_Convert51ToStereo;
}
if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
return -1;
}
src_channels = 2;
@@ -1061,7 +1467,7 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
handled by now, but let's be defensive */
return SDL_SetError("Invalid channel combination");
}
/* Do rate conversion, if necessary. Updates (cvt). */
if (SDL_BuildAudioResampleCVT(cvt, dst_channels, src_rate, dst_rate) < 0) {
return -1; /* shouldn't happen, but just in case... */
@@ -1269,6 +1675,7 @@ SDL_NewAudioStream(const SDL_AudioFormat src_format,
retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream));
if (!retval) {
SDL_OutOfMemory();
return NULL;
}
@@ -1510,11 +1917,14 @@ SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len)
if (!stream) {
return SDL_InvalidParamError("stream");
} else if (!buf) {
}
if (!buf) {
return SDL_InvalidParamError("buf");
} else if (len == 0) {
}
if (len == 0) {
return 0; /* nothing to do. */
} else if ((len % stream->src_sample_frame_size) != 0) {
}
if ((len % stream->src_sample_frame_size) != 0) {
return SDL_SetError("Can't add partial sample frames");
}
@@ -1543,7 +1953,7 @@ SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len)
stream->staging_buffer_filled += len;
return 0;
}
/* Fill the staging buffer, process it, and continue */
amount = (stream->staging_buffer_size - stream->staging_buffer_filled);
SDL_assert(amount > 0);
@@ -1620,11 +2030,14 @@ SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len)
if (!stream) {
return SDL_InvalidParamError("stream");
} else if (!buf) {
}
if (!buf) {
return SDL_InvalidParamError("buf");
} else if (len <= 0) {
}
if (len <= 0) {
return 0; /* nothing to do. */
} else if ((len % stream->dst_sample_frame_size) != 0) {
}
if ((len % stream->dst_sample_frame_size) != 0) {
return SDL_SetError("Can't request partial sample frames");
}
@@ -1670,4 +2083,3 @@ SDL_FreeAudioStream(SDL_AudioStream *stream)
}
/* vi: set ts=4 sw=4 expandtab: */
+9 -3
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -51,7 +51,7 @@ test_device(const int iscapture, const char *fname, int flags, int (*test) (int
{
struct stat sb;
if ((stat(fname, &sb) == 0) && (S_ISCHR(sb.st_mode))) {
const int audio_fd = open(fname, flags, 0);
const int audio_fd = open(fname, flags | O_CLOEXEC, 0);
if (audio_fd >= 0) {
const int okay = test(audio_fd);
close(audio_fd);
@@ -59,7 +59,13 @@ test_device(const int iscapture, const char *fname, int flags, int (*test) (int
static size_t dummyhandle = 0;
dummyhandle++;
SDL_assert(dummyhandle != 0);
SDL_AddAudioDevice(iscapture, fname, (void *) dummyhandle);
/* Note that spec is NULL; while we are opening the device
* endpoint here, the endpoint does not provide any mix format
* information, making this information inaccessible at
* enumeration time
*/
SDL_AddAudioDevice(iscapture, fname, NULL, (void *) (uintptr_t) dummyhandle);
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+23 -25
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -18,15 +18,13 @@
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_audio.h"
#include "SDL_audio_c.h"
#include "SDL_cpuinfo.h"
#include "SDL_assert.h"
/* !!! FIXME: disabled until we fix https://bugzilla.libsdl.org/show_bug.cgi?id=4186 */
#if 0 /*def __ARM_NEON__*/
#ifdef __ARM_NEON
#define HAVE_NEON_INTRINSICS 1
#endif
@@ -483,7 +481,7 @@ SDL_Convert_U16_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
if ((((size_t) src) & 15) == 0) {
/* Aligned! Do SSE blocks as long as we have 16 bytes available. */
const __m128 divby32768 = _mm_set1_ps(DIVBY32768);
const __m128 minus1 = _mm_set1_ps(1.0f);
const __m128 minus1 = _mm_set1_ps(-1.0f);
while (i >= 8) { /* 8 * 16-bit */
const __m128i ints = _mm_load_si128((__m128i const *) src); /* get 8 sint16 into an XMM register. */
/* treat as int32, shift left to clear every other sint16, then back right with zero-extend. Now sint32. */
@@ -526,9 +524,9 @@ SDL_Convert_S32_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
}
SDL_assert(!i || ((((size_t) dst) & 15) == 0));
SDL_assert(!i || ((((size_t) src) & 15) == 0));
{
/* Make sure src is aligned too. */
if ((((size_t) src) & 15) == 0) {
/* Aligned! Do SSE blocks as long as we have 16 bytes available. */
const __m128 divby8388607 = _mm_set1_ps(DIVBY8388607);
const __m128i *mmsrc = (const __m128i *) src;
@@ -615,7 +613,7 @@ static void SDLCALL
SDL_Convert_F32_to_U8_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
{
const float *src = (const float *) cvt->buf;
Uint8 *dst = (Uint8 *) cvt->buf;
Uint8 *dst = cvt->buf;
int i;
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U8 (using SSE2)");
@@ -880,10 +878,10 @@ SDL_Convert_S8_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
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_high_s16(int16hi))), divby128));
vst1q_f32(dst+4, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(int16hi))), divby128));
vst1q_f32(dst+8, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(int16lo))), divby128));
vst1q_f32(dst+12, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(int16lo))), divby128));
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));
vst1q_f32(dst+12, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(int16hi))), divby128));
i -= 16; mmsrc -= 16; dst -= 16;
}
@@ -926,16 +924,16 @@ SDL_Convert_U8_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
/* 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 one = vdupq_n_f32(1.0f);
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. */
vst1q_f32(dst, vmlsq_f32(vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16hi))), divby128, one));
vst1q_f32(dst+4, vmlsq_f32(vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16hi))), divby128, one));
vst1q_f32(dst+8, vmlsq_f32(vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16lo))), divby128, one));
vst1q_f32(dst+12, vmlsq_f32(vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16lo))), divby128, one));
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));
vst1q_f32(dst+12, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16hi))), divby128));
i -= 16; mmsrc -= 16; dst -= 16;
}
@@ -1021,12 +1019,12 @@ SDL_Convert_U16_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
if ((((size_t) src) & 15) == 0) {
/* Aligned! Do NEON blocks as long as we have 16 bytes available. */
const float32x4_t divby32768 = vdupq_n_f32(DIVBY32768);
const float32x4_t one = vdupq_n_f32(1.0f);
const float32x4_t negone = vdupq_n_f32(-1.0f);
while (i >= 8) { /* 8 * 16-bit */
const uint16x8_t uints = vld1q_u16((uint16_t const *) src); /* get 8 uint16 into a NEON register. */
/* split uint16 to two int32, then convert to float, then multiply to normalize, subtract for sign, store. */
vst1q_f32(dst, vmlsq_f32(one, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uints))), divby32768));
vst1q_f32(dst+4, vmlsq_f32(one, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uints))), divby32768));
vst1q_f32(dst, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uints))), divby32768));
vst1q_f32(dst+4, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uints))), divby32768));
i -= 8; src -= 8; dst -= 8;
}
}
@@ -1060,9 +1058,9 @@ SDL_Convert_S32_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
}
SDL_assert(!i || ((((size_t) dst) & 15) == 0));
SDL_assert(!i || ((((size_t) src) & 15) == 0));
{
/* Make sure src is aligned too. */
if ((((size_t) src) & 15) == 0) {
/* 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;
@@ -1341,7 +1339,7 @@ SDL_Convert_F32_to_S32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
if (sample >= 1.0f) {
*dst = 2147483647;
} else if (sample <= -1.0f) {
*dst = -2147483648;
*dst = (-2147483647) - 1;
} else {
*dst = ((Sint32)(sample * 8388607.0f)) << 8;
}
@@ -1369,7 +1367,7 @@ SDL_Convert_F32_to_S32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
if (sample >= 1.0f) {
*dst = 2147483647;
} else if (sample <= -1.0f) {
*dst = -2147483648;
*dst = (-2147483647) - 1;
} else {
*dst = ((Sint32)(sample * 8388607.0f)) << 8;
}
+54 -66
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -29,7 +29,6 @@
/* This table is used to add two sound values together and pin
* the value to avoid overflow. (used with permission from ARDI)
* Changed to use 0xFE instead of 0xFF for better sound quality.
*/
static const Uint8 mix8[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -66,24 +65,25 @@ static const Uint8 mix8[] = {
0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5,
0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFE, 0xFE,
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE
0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
/* The volume ranges from 0 - 128 */
#define ADJUST_VOLUME(s, v) (s = (s*v)/SDL_MIX_MAXVOLUME)
#define ADJUST_VOLUME_U8(s, v) (s = (((s-128)*v)/SDL_MIX_MAXVOLUME)+128)
#define ADJUST_VOLUME_U16(s, v) (s = (((s-32768)*v)/SDL_MIX_MAXVOLUME)+32768)
void
@@ -98,11 +98,6 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
case AUDIO_U8:
{
#if defined(__GNUC__) && defined(__M68000__) && !defined(__mcoldfire__) && defined(SDL_ASSEMBLY_ROUTINES)
SDL_MixAudio_m68k_U8((char *) dst, (char *) src,
(unsigned long) len, (long) volume,
(char *) mix8);
#else
Uint8 src_sample;
while (len--) {
@@ -112,7 +107,6 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
++dst;
++src;
}
#endif
}
break;
@@ -121,8 +115,8 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
Sint8 *dst8, *src8;
Sint8 src_sample;
int dst_sample;
const int max_audioval = ((1 << (8 - 1)) - 1);
const int min_audioval = -(1 << (8 - 1));
const int max_audioval = SDL_MAX_SINT8;
const int min_audioval = SDL_MIN_SINT8;
src8 = (Sint8 *) src;
dst8 = (Sint8 *) dst;
@@ -131,12 +125,11 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
ADJUST_VOLUME(src_sample, volume);
dst_sample = *dst8 + src_sample;
if (dst_sample > max_audioval) {
*dst8 = max_audioval;
dst_sample = max_audioval;
} else if (dst_sample < min_audioval) {
*dst8 = min_audioval;
} else {
*dst8 = dst_sample;
dst_sample = min_audioval;
}
*dst8 = dst_sample;
++dst8;
++src8;
}
@@ -147,14 +140,14 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
{
Sint16 src1, src2;
int dst_sample;
const int max_audioval = ((1 << (16 - 1)) - 1);
const int min_audioval = -(1 << (16 - 1));
const int max_audioval = SDL_MAX_SINT16;
const int min_audioval = SDL_MIN_SINT16;
len /= 2;
while (len--) {
src1 = ((src[1]) << 8 | src[0]);
src1 = SDL_SwapLE16(*(Sint16 *)src);
ADJUST_VOLUME(src1, volume);
src2 = ((dst[1]) << 8 | dst[0]);
src2 = SDL_SwapLE16(*(Sint16 *)dst);
src += 2;
dst_sample = src1 + src2;
if (dst_sample > max_audioval) {
@@ -162,9 +155,7 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
} else if (dst_sample < min_audioval) {
dst_sample = min_audioval;
}
dst[0] = dst_sample & 0xFF;
dst_sample >>= 8;
dst[1] = dst_sample & 0xFF;
*(Sint16 *)dst = SDL_SwapLE16(dst_sample);
dst += 2;
}
}
@@ -172,20 +163,16 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
case AUDIO_S16MSB:
{
#if defined(__GNUC__) && defined(__M68000__) && !defined(__mcoldfire__) && defined(SDL_ASSEMBLY_ROUTINES)
SDL_MixAudio_m68k_S16MSB((short *) dst, (short *) src,
(unsigned long) len, (long) volume);
#else
Sint16 src1, src2;
int dst_sample;
const int max_audioval = ((1 << (16 - 1)) - 1);
const int min_audioval = -(1 << (16 - 1));
const int max_audioval = SDL_MAX_SINT16;
const int min_audioval = SDL_MIN_SINT16;
len /= 2;
while (len--) {
src1 = ((src[0]) << 8 | src[1]);
src1 = SDL_SwapBE16(*(Sint16 *)src);
ADJUST_VOLUME(src1, volume);
src2 = ((dst[0]) << 8 | dst[1]);
src2 = SDL_SwapBE16(*(Sint16 *)dst);
src += 2;
dst_sample = src1 + src2;
if (dst_sample > max_audioval) {
@@ -193,12 +180,9 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
} else if (dst_sample < min_audioval) {
dst_sample = min_audioval;
}
dst[1] = dst_sample & 0xFF;
dst_sample >>= 8;
dst[0] = dst_sample & 0xFF;
*(Sint16 *)dst = SDL_SwapBE16(dst_sample);
dst += 2;
}
#endif
}
break;
@@ -206,21 +190,23 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
{
Uint16 src1, src2;
int dst_sample;
const int max_audioval = 0xFFFF;
const int max_audioval = SDL_MAX_SINT16;
const int min_audioval = SDL_MIN_SINT16;
len /= 2;
while (len--) {
src1 = ((src[1]) << 8 | src[0]);
ADJUST_VOLUME(src1, volume);
src2 = ((dst[1]) << 8 | dst[0]);
src1 = SDL_SwapLE16(*(Uint16 *)src);
ADJUST_VOLUME_U16(src1, volume);
src2 = SDL_SwapLE16(*(Uint16 *)dst);
src += 2;
dst_sample = src1 + src2;
dst_sample = src1 + src2 - 32768 * 2;
if (dst_sample > max_audioval) {
dst_sample = max_audioval;
} else if (dst_sample < min_audioval) {
dst_sample = min_audioval;
}
dst[0] = dst_sample & 0xFF;
dst_sample >>= 8;
dst[1] = dst_sample & 0xFF;
dst_sample += 32768;
*(Uint16 *)dst = SDL_SwapLE16(dst_sample);
dst += 2;
}
}
@@ -230,21 +216,23 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
{
Uint16 src1, src2;
int dst_sample;
const int max_audioval = 0xFFFF;
const int max_audioval = SDL_MAX_SINT16;
const int min_audioval = SDL_MIN_SINT16;
len /= 2;
while (len--) {
src1 = ((src[0]) << 8 | src[1]);
ADJUST_VOLUME(src1, volume);
src2 = ((dst[0]) << 8 | dst[1]);
src1 = SDL_SwapBE16(*(Uint16 *)src);
ADJUST_VOLUME_U16(src1, volume);
src2 = SDL_SwapBE16(*(Uint16 *)dst);
src += 2;
dst_sample = src1 + src2;
dst_sample = src1 + src2 - 32768 * 2;
if (dst_sample > max_audioval) {
dst_sample = max_audioval;
} else if (dst_sample < min_audioval) {
dst_sample = min_audioval;
}
dst[1] = dst_sample & 0xFF;
dst_sample >>= 8;
dst[0] = dst_sample & 0xFF;
dst_sample += 32768;
*(Uint16 *)dst = SDL_SwapBE16(dst_sample);
dst += 2;
}
}
@@ -256,8 +244,8 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
Uint32 *dst32 = (Uint32 *) dst;
Sint64 src1, src2;
Sint64 dst_sample;
const Sint64 max_audioval = ((((Sint64) 1) << (32 - 1)) - 1);
const Sint64 min_audioval = -(((Sint64) 1) << (32 - 1));
const Sint64 max_audioval = SDL_MAX_SINT32;
const Sint64 min_audioval = SDL_MIN_SINT32;
len /= 4;
while (len--) {
@@ -282,8 +270,8 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
Uint32 *dst32 = (Uint32 *) dst;
Sint64 src1, src2;
Sint64 dst_sample;
const Sint64 max_audioval = ((((Sint64) 1) << (32 - 1)) - 1);
const Sint64 min_audioval = -(((Sint64) 1) << (32 - 1));
const Sint64 max_audioval = SDL_MAX_SINT32;
const Sint64 min_audioval = SDL_MIN_SINT32;
len /= 4;
while (len--) {
+17 -16
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -39,11 +39,11 @@ typedef struct SDL_AudioDevice SDL_AudioDevice;
/* Audio targets should call this as devices are added to the system (such as
a USB headset being plugged in), and should also be called for
for every device found during DetectDevices(). */
extern void SDL_AddAudioDevice(const int iscapture, const char *name, void *handle);
extern void SDL_AddAudioDevice(const SDL_bool iscapture, const char *name, SDL_AudioSpec *spec, void *handle);
/* Audio targets should call this as devices are removed, so SDL can update
its list of available devices. */
extern void SDL_RemoveAudioDevice(const int iscapture, void *handle);
extern void SDL_RemoveAudioDevice(const SDL_bool iscapture, void *handle);
/* Audio targets should call this if an opened audio device is lost while
being used. This can happen due to i/o errors, or a device being unplugged,
@@ -65,17 +65,14 @@ extern void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device);
typedef struct SDL_AudioDriverImpl
{
void (*DetectDevices) (void);
int (*OpenDevice) (_THIS, void *handle, const char *devname, int iscapture);
int (*OpenDevice) (_THIS, const char *devname);
void (*ThreadInit) (_THIS); /* Called by audio thread at start */
void (*ThreadDeinit) (_THIS); /* Called by audio thread at end */
void (*BeginLoopIteration)(_THIS); /* Called by audio thread at top of loop */
void (*WaitDevice) (_THIS);
void (*PlayDevice) (_THIS);
int (*GetPendingBytes) (_THIS);
Uint8 *(*GetDeviceBuf) (_THIS);
int (*CaptureFromDevice) (_THIS, void *buffer, int buflen);
void (*FlushCapture) (_THIS);
void (*PrepareToClose) (_THIS); /**< Called between run and draining wait for playback devices */
void (*CloseDevice) (_THIS);
void (*LockDevice) (_THIS);
void (*UnlockDevice) (_THIS);
@@ -85,13 +82,11 @@ typedef struct SDL_AudioDriverImpl
/* !!! FIXME: add pause(), so we can optimize instead of mixing silence. */
/* Some flags to push duplicate code into the core and reduce #ifdefs. */
/* !!! FIXME: these should be SDL_bool */
int ProvidesOwnCallbackThread;
int SkipMixerLock;
int HasCaptureSupport;
int OnlyHasDefaultOutputDevice;
int OnlyHasDefaultCaptureDevice;
int AllowsArbitraryDeviceNames;
SDL_bool ProvidesOwnCallbackThread;
SDL_bool HasCaptureSupport;
SDL_bool OnlyHasDefaultOutputDevice;
SDL_bool OnlyHasDefaultCaptureDevice;
SDL_bool AllowsArbitraryDeviceNames;
} SDL_AudioDriverImpl;
@@ -100,6 +95,7 @@ typedef struct SDL_AudioDeviceItem
void *handle;
char *name;
char *original_name;
SDL_AudioSpec spec;
int dupenum;
struct SDL_AudioDeviceItem *next;
} SDL_AudioDeviceItem;
@@ -178,11 +174,12 @@ typedef struct AudioBootStrap
{
const char *name;
const char *desc;
int (*init) (SDL_AudioDriverImpl * impl);
int demand_only; /* 1==request explicitly, or it won't be available. */
SDL_bool (*init) (SDL_AudioDriverImpl * impl);
SDL_bool demand_only; /* 1==request explicitly, or it won't be available. */
} AudioBootStrap;
/* Not all of these are available in a given build. Use #ifdefs, etc. */
extern AudioBootStrap PIPEWIRE_bootstrap;
extern AudioBootStrap PULSEAUDIO_bootstrap;
extern AudioBootStrap ALSA_bootstrap;
extern AudioBootStrap JACK_bootstrap;
@@ -204,9 +201,13 @@ extern AudioBootStrap COREAUDIO_bootstrap;
extern AudioBootStrap DISKAUDIO_bootstrap;
extern AudioBootStrap DUMMYAUDIO_bootstrap;
extern AudioBootStrap FUSIONSOUND_bootstrap;
extern AudioBootStrap aaudio_bootstrap;
extern AudioBootStrap openslES_bootstrap;
extern AudioBootStrap ANDROIDAUDIO_bootstrap;
extern AudioBootStrap PSPAUDIO_bootstrap;
extern AudioBootStrap VITAAUD_bootstrap;
extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
extern AudioBootStrap OS2AUDIO_bootstrap;
#endif /* SDL_sysaudio_h_ */
+1990 -529
View File
File diff suppressed because it is too large Load Diff
+104 -32
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -20,11 +20,12 @@
*/
#include "../SDL_internal.h"
/* WAVE files are little-endian */
/* RIFF WAVE files are little-endian */
/*******************************************/
/* Define values for Microsoft WAVE format */
/*******************************************/
/* FOURCC */
#define RIFF 0x46464952 /* "RIFF" */
#define WAVE 0x45564157 /* "WAVE" */
#define FACT 0x74636166 /* "fact" */
@@ -33,45 +34,116 @@
#define JUNK 0x4B4E554A /* "JUNK" */
#define FMT 0x20746D66 /* "fmt " */
#define DATA 0x61746164 /* "data" */
/* Format tags */
#define UNKNOWN_CODE 0x0000
#define PCM_CODE 0x0001
#define MS_ADPCM_CODE 0x0002
#define IEEE_FLOAT_CODE 0x0003
#define ALAW_CODE 0x0006
#define MULAW_CODE 0x0007
#define IMA_ADPCM_CODE 0x0011
#define MP3_CODE 0x0055
#define MPEG_CODE 0x0050
#define MPEGLAYER3_CODE 0x0055
#define EXTENSIBLE_CODE 0xFFFE
#define WAVE_MONO 1
#define WAVE_STEREO 2
/* Normally, these three chunks come consecutively in a WAVE file */
typedef struct WaveFMT
/* Stores the WAVE format information. */
typedef struct WaveFormat
{
/* Not saved in the chunk we read:
Uint32 FMTchunk;
Uint32 fmtlen;
*/
Uint16 encoding;
Uint16 channels; /* 1 = mono, 2 = stereo */
Uint32 frequency; /* One of 11025, 22050, or 44100 Hz */
Uint32 byterate; /* Average bytes per second */
Uint16 blockalign; /* Bytes per sample block */
Uint16 bitspersample; /* One of 8, 12, 16, or 4 for ADPCM */
} WaveFMT;
Uint16 formattag; /* Raw value of the first field in the fmt chunk data. */
Uint16 encoding; /* Actual encoding, possibly from the extensible header. */
Uint16 channels; /* Number of channels. */
Uint32 frequency; /* Sampling rate in Hz. */
Uint32 byterate; /* Average bytes per second. */
Uint16 blockalign; /* Bytes per block. */
Uint16 bitspersample; /* Currently supported are 8, 16, 24, 32, and 4 for ADPCM. */
/* The general chunk found in the WAVE file */
typedef struct Chunk
{
Uint32 magic;
Uint32 length;
Uint8 *data;
} Chunk;
/* Extra information size. Number of extra bytes starting at byte 18 in the
* fmt chunk data. This is at least 22 for the extensible header.
*/
Uint16 extsize;
typedef struct WaveExtensibleFMT
{
WaveFMT format;
Uint16 size;
Uint16 validbits;
/* Extensible WAVE header fields */
Uint16 validsamplebits;
Uint32 samplesperblock; /* For compressed formats. Can be zero. Actually 16 bits in the header. */
Uint32 channelmask;
Uint8 subformat[16]; /* a GUID. */
} WaveExtensibleFMT;
Uint8 subformat[16]; /* A format GUID. */
} WaveFormat;
/* Stores information on the fact chunk. */
typedef struct WaveFact {
/* Represents the state of the fact chunk in the WAVE file.
* Set to -1 if the fact chunk is invalid.
* Set to 0 if the fact chunk is not present
* Set to 1 if the fact chunk is present and valid.
* Set to 2 if samplelength is going to be used as the number of sample frames.
*/
Sint32 status;
/* Version 1 of the RIFF specification calls the field in the fact chunk
* dwFileSize. The Standards Update then calls it dwSampleLength and specifies
* that it is 'the length of the data in samples'. WAVE files from Windows
* with this chunk have it set to the samples per channel (sample frames).
* This is useful to truncate compressed audio to a specific sample count
* because a compressed block is usually decoded to a fixed number of
* sample frames.
*/
Uint32 samplelength; /* Raw sample length value from the fact chunk. */
} WaveFact;
/* Generic struct for the chunks in the WAVE file. */
typedef struct WaveChunk
{
Uint32 fourcc; /* FOURCC of the chunk. */
Uint32 length; /* Size of the chunk data. */
Sint64 position; /* Position of the data in the stream. */
Uint8 *data; /* When allocated, this points to the chunk data. length is used for the memory allocation size. */
size_t size; /* Number of bytes in data that could be read from the stream. Can be smaller than length. */
} WaveChunk;
/* Controls how the size of the RIFF chunk affects the loading of a WAVE file. */
typedef enum WaveRiffSizeHint {
RiffSizeNoHint,
RiffSizeForce,
RiffSizeIgnoreZero,
RiffSizeIgnore,
RiffSizeMaximum
} WaveRiffSizeHint;
/* Controls how a truncated WAVE file is handled. */
typedef enum WaveTruncationHint {
TruncNoHint,
TruncVeryStrict,
TruncStrict,
TruncDropFrame,
TruncDropBlock
} WaveTruncationHint;
/* Controls how the fact chunk affects the loading of a WAVE file. */
typedef enum WaveFactChunkHint {
FactNoHint,
FactTruncate,
FactStrict,
FactIgnoreZero,
FactIgnore
} WaveFactChunkHint;
typedef struct WaveFile
{
WaveChunk chunk;
WaveFormat format;
WaveFact fact;
/* Number of sample frames that will be decoded. Calculated either with the
* size of the data chunk or, if the appropriate hint is enabled, with the
* sample length value from the fact chunk.
*/
Sint64 sampleframes;
void *decoderdata; /* Some decoders require extra data for a state. */
WaveRiffSizeHint riffhint;
WaveTruncationHint trunchint;
WaveFactChunkHint facthint;
} WaveFile;
/* vi: set ts=4 sw=4 expandtab: */
+462
View File
@@ -0,0 +1,462 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
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"
#if SDL_AUDIO_DRIVER_AAUDIO
#include "SDL_audio.h"
#include "SDL_loadso.h"
#include "../SDL_audio_c.h"
#include "../../core/android/SDL_android.h"
#include "SDL_aaudio.h"
/* Debug */
#if 0
# define LOGI(...) SDL_Log(__VA_ARGS__);
#else
# define LOGI(...)
#endif
typedef struct AAUDIO_Data
{
AAudioStreamBuilder *builder;
void *handle;
#define SDL_PROC(ret,func,params) ret (*func) params;
# include "SDL_aaudiofuncs.h"
#undef SDL_PROC
} AAUDIO_Data;
static AAUDIO_Data ctx;
static SDL_AudioDevice *audioDevice = NULL;
static SDL_AudioDevice *captureDevice = NULL;
static int aaudio_LoadFunctions(AAUDIO_Data *data)
{
#define SDL_PROC(ret,func,params) \
do { \
data->func = SDL_LoadFunction(data->handle, #func); \
if (! data->func) { \
return SDL_SetError("Couldn't load AAUDIO function %s: %s", #func, SDL_GetError()); \
} \
} while (0);
#include "SDL_aaudiofuncs.h"
#undef SDL_PROC
return 0;
}
void aaudio_errorCallback( AAudioStream *stream, void *userData, aaudio_result_t error );
void aaudio_errorCallback( AAudioStream *stream, void *userData, aaudio_result_t error )
{
LOGI( "SDL aaudio_errorCallback: %d - %s", error, ctx.AAudio_convertResultToText( error ) );
}
#define LIB_AAUDIO_SO "libaaudio.so"
static int
aaudio_OpenDevice(_THIS, const char *devname)
{
struct SDL_PrivateAudioData *private;
SDL_bool iscapture = this->iscapture;
aaudio_result_t res;
LOGI(__func__);
SDL_assert((captureDevice == NULL) || !iscapture);
SDL_assert((audioDevice == NULL) || iscapture);
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");
}
}
if (iscapture) {
captureDevice = this;
} else {
audioDevice = this;
}
this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *this->hidden));
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
private = this->hidden;
ctx.AAudioStreamBuilder_setSampleRate(ctx.builder, this->spec.freq);
ctx.AAudioStreamBuilder_setChannelCount(ctx.builder, this->spec.channels);
{
aaudio_direction_t direction = (iscapture ? AAUDIO_DIRECTION_INPUT : AAUDIO_DIRECTION_OUTPUT);
ctx.AAudioStreamBuilder_setDirection(ctx.builder, direction);
}
{
aaudio_format_t format = AAUDIO_FORMAT_PCM_FLOAT;
if (this->spec.format == AUDIO_S16SYS) {
format = AAUDIO_FORMAT_PCM_I16;
} else if (this->spec.format == AUDIO_S16SYS) {
format = AAUDIO_FORMAT_PCM_FLOAT;
}
ctx.AAudioStreamBuilder_setFormat(ctx.builder, format);
}
ctx.AAudioStreamBuilder_setErrorCallback( ctx.builder, aaudio_errorCallback, private );
LOGI("AAudio Try to open %u hz %u bit chan %u %s samples %u",
this->spec.freq, SDL_AUDIO_BITSIZE(this->spec.format),
this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples);
res = ctx.AAudioStreamBuilder_openStream(ctx.builder, &private->stream);
if (res != AAUDIO_OK) {
LOGI("SDL Failed AAudioStreamBuilder_openStream %d", res);
return SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
}
this->spec.freq = ctx.AAudioStream_getSampleRate(private->stream);
this->spec.channels = ctx.AAudioStream_getChannelCount(private->stream);
{
aaudio_format_t fmt = ctx.AAudioStream_getFormat(private->stream);
if (fmt == AAUDIO_FORMAT_PCM_I16) {
this->spec.format = AUDIO_S16SYS;
} else if (fmt == AAUDIO_FORMAT_PCM_FLOAT) {
this->spec.format = AUDIO_F32SYS;
}
}
LOGI("AAudio Try to open %u hz %u bit chan %u %s samples %u",
this->spec.freq, SDL_AUDIO_BITSIZE(this->spec.format),
this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples);
SDL_CalculateAudioSpec(&this->spec);
/* Allocate mixing buffer */
if (!iscapture) {
private->mixlen = this->spec.size;
private->mixbuf = (Uint8 *) SDL_malloc(private->mixlen);
if (private->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(private->mixbuf, this->spec.silence, this->spec.size);
}
private->frame_size = this->spec.channels * (SDL_AUDIO_BITSIZE(this->spec.format) / 8);
res = ctx.AAudioStream_requestStart(private->stream);
if (res != AAUDIO_OK) {
LOGI("SDL Failed AAudioStream_requestStart %d iscapture:%d", res, iscapture);
return SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
}
LOGI("SDL AAudioStream_requestStart OK");
return 0;
}
static void
aaudio_CloseDevice(_THIS)
{
struct SDL_PrivateAudioData *private = this->hidden;
aaudio_result_t res;
LOGI(__func__);
if (private->stream) {
res = ctx.AAudioStream_requestStop(private->stream);
if (res != AAUDIO_OK) {
LOGI("SDL Failed AAudioStream_requestStop %d", res);
SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
return;
}
res = ctx.AAudioStream_close(private->stream);
if (res != AAUDIO_OK) {
LOGI("SDL Failed AAudioStreamBuilder_delete %d", res);
SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
return;
}
}
if (this->iscapture) {
SDL_assert(captureDevice == this);
captureDevice = NULL;
} else {
SDL_assert(audioDevice == this);
audioDevice = NULL;
}
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
}
static Uint8 *
aaudio_GetDeviceBuf(_THIS)
{
struct SDL_PrivateAudioData *private = this->hidden;
return private->mixbuf;
}
static void
aaudio_PlayDevice(_THIS)
{
struct SDL_PrivateAudioData *private = this->hidden;
aaudio_result_t res;
int64_t timeoutNanoseconds = 1 * 1000 * 1000; /* 8 ms */
res = ctx.AAudioStream_write(private->stream, private->mixbuf, private->mixlen / private->frame_size, timeoutNanoseconds);
if (res < 0) {
LOGI("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
} else {
LOGI("SDL AAudio play: %d frames, wanted:%d frames", (int)res, private->mixlen / private->frame_size);
}
#if 0
/* Log under-run count */
{
static int prev = 0;
int32_t cnt = ctx.AAudioStream_getXRunCount(private->stream);
if (cnt != prev) {
SDL_Log("AAudio underrun: %d - total: %d", cnt - prev, cnt);
prev = cnt;
}
}
#endif
}
static int
aaudio_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
struct SDL_PrivateAudioData *private = this->hidden;
aaudio_result_t res;
int64_t timeoutNanoseconds = 8 * 1000 * 1000; /* 8 ms */
res = ctx.AAudioStream_read(private->stream, buffer, buflen / private->frame_size, timeoutNanoseconds);
if (res < 0) {
LOGI("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
return -1;
}
LOGI("SDL AAudio capture:%d frames, wanted:%d frames", (int)res, buflen / private->frame_size);
return res * private->frame_size;
}
static void
aaudio_Deinitialize(void)
{
LOGI(__func__);
if (ctx.handle) {
if (ctx.builder) {
aaudio_result_t res;
res = ctx.AAudioStreamBuilder_delete(ctx.builder);
if (res != AAUDIO_OK) {
SDL_SetError("Failed AAudioStreamBuilder_delete %s", ctx.AAudio_convertResultToText(res));
}
}
SDL_UnloadObject(ctx.handle);
}
ctx.handle = NULL;
ctx.builder = NULL;
LOGI("End AAUDIO %s", SDL_GetError());
}
static SDL_bool
aaudio_Init(SDL_AudioDriverImpl *impl)
{
aaudio_result_t res;
LOGI(__func__);
/* AAudio was introduced in Android 8.0, but has reference counting crash issues in that release,
* so don't use it until 8.1.
*
* See https://github.com/google/oboe/issues/40 for more information.
*/
if (SDL_GetAndroidSDKVersion() < 27) {
return SDL_FALSE;
}
SDL_zero(ctx);
ctx.handle = SDL_LoadObject(LIB_AAUDIO_SO);
if (ctx.handle == NULL) {
LOGI("SDL couldn't find " LIB_AAUDIO_SO);
goto failure;
}
if (aaudio_LoadFunctions(&ctx) < 0) {
goto failure;
}
res = ctx.AAudio_createStreamBuilder(&ctx.builder);
if (res != AAUDIO_OK) {
LOGI("SDL Failed AAudio_createStreamBuilder %d", res);
goto failure;
}
if (ctx.builder == NULL) {
LOGI("SDL Failed AAudio_createStreamBuilder - builder NULL");
goto failure;
}
impl->Deinitialize = aaudio_Deinitialize;
impl->OpenDevice = aaudio_OpenDevice;
impl->CloseDevice = aaudio_CloseDevice;
impl->PlayDevice = aaudio_PlayDevice;
impl->GetDeviceBuf = aaudio_GetDeviceBuf;
impl->CaptureFromDevice = aaudio_CaptureFromDevice;
/* and the capabilities */
impl->HasCaptureSupport = SDL_TRUE;
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
/* this audio target is available. */
LOGI("SDL aaudio_Init OK");
return SDL_TRUE;
failure:
if (ctx.handle) {
if (ctx.builder) {
ctx.AAudioStreamBuilder_delete(ctx.builder);
}
SDL_UnloadObject(ctx.handle);
}
ctx.handle = NULL;
ctx.builder = NULL;
return SDL_FALSE;
}
AudioBootStrap aaudio_bootstrap = {
"AAudio", "AAudio audio driver", aaudio_Init, SDL_FALSE
};
/* Pause (block) all non already paused audio devices by taking their mixer lock */
void aaudio_PauseDevices(void)
{
/* TODO: Handle multiple devices? */
struct SDL_PrivateAudioData *private;
if (audioDevice != NULL && audioDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
if (private->stream) {
aaudio_result_t res = ctx.AAudioStream_requestPause(private->stream);
if (res != AAUDIO_OK) {
LOGI("SDL Failed AAudioStream_requestPause %d", res);
SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
}
}
if (SDL_AtomicGet(&audioDevice->paused)) {
/* The device is already paused, leave it alone */
private->resume = SDL_FALSE;
} else {
SDL_LockMutex(audioDevice->mixer_lock);
SDL_AtomicSet(&audioDevice->paused, 1);
private->resume = SDL_TRUE;
}
}
if (captureDevice != NULL && captureDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *) captureDevice->hidden;
if (private->stream) {
/* Pause() isn't implemented for 'capture', use Stop() */
aaudio_result_t res = ctx.AAudioStream_requestStop(private->stream);
if (res != AAUDIO_OK) {
LOGI("SDL Failed AAudioStream_requestStop %d", res);
SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
}
}
if (SDL_AtomicGet(&captureDevice->paused)) {
/* The device is already paused, leave it alone */
private->resume = SDL_FALSE;
} else {
SDL_LockMutex(captureDevice->mixer_lock);
SDL_AtomicSet(&captureDevice->paused, 1);
private->resume = SDL_TRUE;
}
}
}
/* Resume (unblock) all non already paused audio devices by releasing their mixer lock */
void aaudio_ResumeDevices(void)
{
/* TODO: Handle multiple devices? */
struct SDL_PrivateAudioData *private;
if (audioDevice != NULL && audioDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
if (private->resume) {
SDL_AtomicSet(&audioDevice->paused, 0);
private->resume = SDL_FALSE;
SDL_UnlockMutex(audioDevice->mixer_lock);
}
if (private->stream) {
aaudio_result_t res = ctx.AAudioStream_requestStart(private->stream);
if (res != AAUDIO_OK) {
LOGI("SDL Failed AAudioStream_requestStart %d", res);
SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
}
}
}
if (captureDevice != NULL && captureDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *) captureDevice->hidden;
if (private->resume) {
SDL_AtomicSet(&captureDevice->paused, 0);
private->resume = SDL_FALSE;
SDL_UnlockMutex(captureDevice->mixer_lock);
}
if (private->stream) {
aaudio_result_t res = ctx.AAudioStream_requestStart(private->stream);
if (res != AAUDIO_OK) {
LOGI("SDL Failed AAudioStream_requestStart %d", res);
SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
}
}
}
}
/*
We can sometimes get into a state where AAudioStream_write() will just block forever until we pause and unpause.
None of the standard state queries indicate any problem in my testing. And the error callback doesn't actually get called.
But, AAudioStream_getTimestamp() does return AAUDIO_ERROR_INVALID_STATE
*/
SDL_bool aaudio_DetectBrokenPlayState( void )
{
if ( !audioDevice || !audioDevice->hidden ) {
return SDL_FALSE;
}
struct SDL_PrivateAudioData *private = audioDevice->hidden;
int64_t framePosition, timeNanoseconds;
aaudio_result_t res = ctx.AAudioStream_getTimestamp( private->stream, CLOCK_MONOTONIC, &framePosition, &timeNanoseconds );
if ( res == AAUDIO_ERROR_INVALID_STATE ) {
aaudio_stream_state_t currentState = ctx.AAudioStream_getState( private->stream );
/* AAudioStream_getTimestamp() will also return AAUDIO_ERROR_INVALID_STATE while the stream is still initially starting. But we only care if it silently went invalid while playing. */
if ( currentState == AAUDIO_STREAM_STATE_STARTED ) {
LOGI( "SDL aaudio_DetectBrokenPlayState: detected invalid audio device state: AAudioStream_getTimestamp result=%d, framePosition=%lld, timeNanoseconds=%lld, getState=%d", (int)res, (long long)framePosition, (long long)timeNanoseconds, (int)currentState );
return SDL_TRUE;
}
}
return SDL_FALSE;
}
#endif /* SDL_AUDIO_DRIVER_AAUDIO */
/* vi: set ts=4 sw=4 expandtab: */
+53
View File
@@ -0,0 +1,53 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
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_aaudio_h
#define _SDL_aaudio_h
#include "../SDL_sysaudio.h"
#include <stdbool.h>
#include <aaudio/AAudio.h>
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
AAudioStream *stream;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
int frame_size;
/* Resume device if it was paused automatically */
int resume;
};
void aaudio_ResumeDevices(void);
void aaudio_PauseDevices(void);
SDL_bool aaudio_DetectBrokenPlayState(void);
#endif /* _SDL_aaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
+80
View File
@@ -0,0 +1,80 @@
/*
Simple DirectMedia Layer
Copyright , (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
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.
*/
#define SDL_PROC_UNUSED(ret,func,params)
SDL_PROC(const char *, AAudio_convertResultToText, (aaudio_result_t returnCode))
SDL_PROC(const char *, AAudio_convertStreamStateToText, (aaudio_stream_state_t state))
SDL_PROC(aaudio_result_t, AAudio_createStreamBuilder, (AAudioStreamBuilder** builder))
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setDeviceId, (AAudioStreamBuilder* builder, int32_t deviceId))
SDL_PROC(void, AAudioStreamBuilder_setSampleRate, (AAudioStreamBuilder* builder, int32_t sampleRate))
SDL_PROC(void, AAudioStreamBuilder_setChannelCount, (AAudioStreamBuilder* builder, int32_t channelCount))
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSamplesPerFrame, (AAudioStreamBuilder* builder, int32_t samplesPerFrame))
SDL_PROC(void, AAudioStreamBuilder_setFormat, (AAudioStreamBuilder* builder, aaudio_format_t format))
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setSharingMode, (AAudioStreamBuilder* builder, aaudio_sharing_mode_t sharingMode))
SDL_PROC(void, AAudioStreamBuilder_setDirection, (AAudioStreamBuilder* builder, aaudio_direction_t direction))
SDL_PROC_UNUSED(void, AAudioStreamBuilder_setBufferCapacityInFrames, (AAudioStreamBuilder* builder, int32_t numFrames))
SDL_PROC_UNUSED(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_setDataCallback, (AAudioStreamBuilder* builder, AAudioStream_dataCallback callback, void *userData))
SDL_PROC_UNUSED(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(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))
SDL_PROC_UNUSED(aaudio_result_t , AAudioStream_requestFlush, (AAudioStream* stream))
SDL_PROC(aaudio_result_t , AAudioStream_requestStop, (AAudioStream* stream))
SDL_PROC(aaudio_stream_state_t, AAudioStream_getState, (AAudioStream* stream))
SDL_PROC_UNUSED(aaudio_result_t, AAudioStream_waitForStateChange, (AAudioStream* stream, aaudio_stream_state_t inputState, aaudio_stream_state_t *nextState, int64_t timeoutNanoseconds))
SDL_PROC(aaudio_result_t, AAudioStream_read, (AAudioStream* stream, void *buffer, int32_t numFrames, int64_t timeoutNanoseconds))
SDL_PROC(aaudio_result_t, AAudioStream_write, (AAudioStream* stream, const void *buffer, int32_t numFrames, int64_t timeoutNanoseconds))
SDL_PROC_UNUSED(aaudio_result_t, AAudioStream_setBufferSizeInFrames, (AAudioStream* stream, int32_t numFrames))
SDL_PROC_UNUSED(int32_t, AAudioStream_getBufferSizeInFrames, (AAudioStream* stream))
SDL_PROC_UNUSED(int32_t, AAudioStream_getFramesPerBurst, (AAudioStream* stream))
SDL_PROC_UNUSED(int32_t, AAudioStream_getBufferCapacityInFrames, (AAudioStream* stream))
SDL_PROC_UNUSED(int32_t, AAudioStream_getFramesPerDataCallback, (AAudioStream* stream))
SDL_PROC(int32_t, AAudioStream_getXRunCount, (AAudioStream* stream))
SDL_PROC(int32_t, AAudioStream_getSampleRate, (AAudioStream* stream))
SDL_PROC(int32_t, AAudioStream_getChannelCount, (AAudioStream* stream))
SDL_PROC_UNUSED(int32_t, AAudioStream_getSamplesPerFrame, (AAudioStream* stream))
SDL_PROC_UNUSED(int32_t, AAudioStream_getDeviceId, (AAudioStream* stream))
SDL_PROC(aaudio_format_t, AAudioStream_getFormat, (AAudioStream* stream))
SDL_PROC_UNUSED(aaudio_sharing_mode_t, AAudioStream_getSharingMode, (AAudioStream* stream))
SDL_PROC_UNUSED(aaudio_performance_mode_t, AAudioStream_getPerformanceMode, (AAudioStream* stream))
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(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 */
+259 -226
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -26,13 +26,17 @@
#define SDL_ALSA_NON_BLOCKING 0
#endif
/* without the thread, you will detect devices on startup, but will not get futher hotplug events. But that might be okay. */
#ifndef SDL_ALSA_HOTPLUG_THREAD
#define SDL_ALSA_HOTPLUG_THREAD 1
#endif
/* Allow access to a raw mixing buffer */
#include <sys/types.h>
#include <signal.h> /* For kill() */
#include <string.h>
#include "SDL_assert.h"
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
@@ -72,7 +76,9 @@ static int (*ALSA_snd_pcm_hw_params_set_period_size_near)
(snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_uframes_t *, int *);
static int (*ALSA_snd_pcm_hw_params_get_period_size)
(const snd_pcm_hw_params_t *, snd_pcm_uframes_t *, int *);
static int (*ALSA_snd_pcm_hw_params_set_periods_near)
static int (*ALSA_snd_pcm_hw_params_set_periods_min)
(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *);
static int (*ALSA_snd_pcm_hw_params_set_periods_first)
(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *);
static int (*ALSA_snd_pcm_hw_params_get_periods)
(const snd_pcm_hw_params_t *, unsigned int *, int *);
@@ -148,7 +154,8 @@ load_alsa_syms(void)
SDL_ALSA_SYM(snd_pcm_hw_params_set_rate_near);
SDL_ALSA_SYM(snd_pcm_hw_params_set_period_size_near);
SDL_ALSA_SYM(snd_pcm_hw_params_get_period_size);
SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_near);
SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_min);
SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_first);
SDL_ALSA_SYM(snd_pcm_hw_params_get_periods);
SDL_ALSA_SYM(snd_pcm_hw_params_set_buffer_size_near);
SDL_ALSA_SYM(snd_pcm_hw_params_get_buffer_size);
@@ -272,44 +279,61 @@ ALSA_WaitDevice(_THIS)
/* !!! FIXME: is there a channel swizzler in alsalib instead? */
/*
* http://bugzilla.libsdl.org/show_bug.cgi?id=110
* https://bugzilla.libsdl.org/show_bug.cgi?id=110
* "For Linux ALSA, this is FL-FR-RL-RR-C-LFE
* and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR"
*/
#define SWIZ6(T, buf, numframes) \
T *ptr = (T *) buf; \
#define SWIZ6(T) \
static void swizzle_alsa_channels_6_##T(void *buffer, const Uint32 bufferlen) { \
T *ptr = (T *) buffer; \
Uint32 i; \
for (i = 0; i < numframes; i++, ptr += 6) { \
for (i = 0; i < bufferlen; i++, ptr += 6) { \
T tmp; \
tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \
tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \
}
static void
swizzle_alsa_channels_6_64bit(void *buffer, Uint32 bufferlen)
{
SWIZ6(Uint64, buffer, bufferlen);
} \
}
static void
swizzle_alsa_channels_6_32bit(void *buffer, Uint32 bufferlen)
{
SWIZ6(Uint32, buffer, bufferlen);
/* !!! FIXME: is there a channel swizzler in alsalib instead? */
/* !!! FIXME: this screams for a SIMD shuffle operation. */
/*
* https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/mapping-stream-formats-to-speaker-configurations
* For Linux ALSA, this appears to be FL-FR-RL-RR-C-LFE-SL-SR
* and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-SL-SR-RL-RR"
*/
#define SWIZ8(T) \
static void swizzle_alsa_channels_8_##T(void *buffer, const Uint32 bufferlen) { \
T *ptr = (T *) buffer; \
Uint32 i; \
for (i = 0; i < bufferlen; i++, ptr += 6) { \
const T center = ptr[2]; \
const T subwoofer = ptr[3]; \
const T side_left = ptr[4]; \
const T side_right = ptr[5]; \
const T rear_left = ptr[6]; \
const T rear_right = ptr[7]; \
ptr[2] = rear_left; \
ptr[3] = rear_right; \
ptr[4] = center; \
ptr[5] = subwoofer; \
ptr[6] = side_left; \
ptr[7] = side_right; \
} \
}
static void
swizzle_alsa_channels_6_16bit(void *buffer, Uint32 bufferlen)
{
SWIZ6(Uint16, buffer, bufferlen);
}
#define CHANNEL_SWIZZLE(x) \
x(Uint64) \
x(Uint32) \
x(Uint16) \
x(Uint8)
static void
swizzle_alsa_channels_6_8bit(void *buffer, Uint32 bufferlen)
{
SWIZ6(Uint8, buffer, bufferlen);
}
CHANNEL_SWIZZLE(SWIZ6)
CHANNEL_SWIZZLE(SWIZ8)
#undef CHANNEL_SWIZZLE
#undef SWIZ6
#undef SWIZ8
/*
@@ -319,17 +343,23 @@ swizzle_alsa_channels_6_8bit(void *buffer, Uint32 bufferlen)
static void
swizzle_alsa_channels(_THIS, void *buffer, Uint32 bufferlen)
{
if (this->spec.channels == 6) {
switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
case 8: swizzle_alsa_channels_6_8bit(buffer, bufferlen); break;
case 16: swizzle_alsa_channels_6_16bit(buffer, bufferlen); break;
case 32: swizzle_alsa_channels_6_32bit(buffer, bufferlen); break;
case 64: swizzle_alsa_channels_6_64bit(buffer, bufferlen); break;
default: SDL_assert(!"unhandled bitsize"); break;
}
}
switch (this->spec.channels) {
#define CHANSWIZ(chans) \
case chans: \
switch ((this->spec.format & (0xFF))) { \
case 8: swizzle_alsa_channels_##chans##_Uint8(buffer, bufferlen); break; \
case 16: swizzle_alsa_channels_##chans##_Uint16(buffer, bufferlen); break; \
case 32: swizzle_alsa_channels_##chans##_Uint32(buffer, bufferlen); break; \
case 64: swizzle_alsa_channels_##chans##_Uint64(buffer, bufferlen); break; \
default: SDL_assert(!"unhandled bitsize"); break; \
} \
return;
/* !!! FIXME: update this for 7.1 if needed, later. */
CHANSWIZ(6);
CHANSWIZ(8);
#undef CHANSWIZ
default: break;
}
}
#ifdef SND_CHMAP_API_VERSION
@@ -337,7 +367,6 @@ swizzle_alsa_channels(_THIS, void *buffer, Uint32 bufferlen)
static void
no_swizzle(_THIS, void *buffer, Uint32 bufferlen)
{
return;
}
#endif /* SND_CHMAP_API_VERSION */
@@ -346,7 +375,7 @@ static void
ALSA_PlayDevice(_THIS)
{
const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf;
const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
const int frame_size = ((SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
this->spec.channels;
snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples);
@@ -395,7 +424,7 @@ static int
ALSA_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
Uint8 *sample_buf = (Uint8 *) buffer;
const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
const int frame_size = ((SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
this->spec.channels;
const int total_frames = buflen / frame_size;
snd_pcm_uframes_t frames_left = total_frames;
@@ -462,14 +491,14 @@ ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params)
{
int status;
snd_pcm_hw_params_t *hwparams;
snd_pcm_uframes_t bufsize;
snd_pcm_uframes_t persize;
unsigned int periods;
/* Copy the hardware parameters for this setup */
snd_pcm_hw_params_alloca(&hwparams);
ALSA_snd_pcm_hw_params_copy(hwparams, params);
/* Prioritize matching the period size to the requested buffer size */
/* Attempt to match the period size to the requested buffer size */
persize = this->spec.samples;
status = ALSA_snd_pcm_hw_params_set_period_size_near(
this->hidden->pcm_handle, hwparams, &persize, NULL);
@@ -477,10 +506,16 @@ ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params)
return(-1);
}
/* Next try to restrict the parameters to having only two periods */
bufsize = this->spec.samples * 2;
status = ALSA_snd_pcm_hw_params_set_buffer_size_near(
this->hidden->pcm_handle, hwparams, &bufsize);
/* Need to at least double buffer */
periods = 2;
status = ALSA_snd_pcm_hw_params_set_periods_min(
this->hidden->pcm_handle, hwparams, &periods, NULL);
if ( status < 0 ) {
return(-1);
}
status = ALSA_snd_pcm_hw_params_set_periods_first(
this->hidden->pcm_handle, hwparams, &periods, NULL);
if ( status < 0 ) {
return(-1);
}
@@ -495,9 +530,9 @@ ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params)
/* This is useful for debugging */
if ( SDL_getenv("SDL_AUDIO_ALSA_DEBUG") ) {
unsigned int periods = 0;
snd_pcm_uframes_t bufsize;
ALSA_snd_pcm_hw_params_get_periods(hwparams, &periods, NULL);
ALSA_snd_pcm_hw_params_get_buffer_size(hwparams, &bufsize);
fprintf(stderr,
"ALSA: period size = %ld, periods = %u, buffer size = %lu\n",
@@ -508,9 +543,10 @@ ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params)
}
static int
ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
ALSA_OpenDevice(_THIS, const char *devname)
{
int status = 0;
SDL_bool iscapture = this->iscapture;
snd_pcm_t *pcm_handle = NULL;
snd_pcm_hw_params_t *hwparams = NULL;
snd_pcm_sw_params_t *swparams = NULL;
@@ -534,7 +570,7 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Open the audio device */
/* Name of device should depend on # channels in spec */
status = ALSA_snd_pcm_open(&pcm_handle,
get_audio_device(handle, this->spec.channels),
get_audio_device(this->handle, this->spec.channels),
iscapture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK);
@@ -562,10 +598,7 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
/* Try for a closest match on audio format */
status = -1;
for (test_format = SDL_FirstAudioFormat(this->spec.format);
test_format && (status < 0);) {
status = 0; /* if we can't support a format, it'll become -1. */
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
switch (test_format) {
case AUDIO_U8:
format = SND_PCM_FORMAT_U8;
@@ -598,19 +631,14 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
format = SND_PCM_FORMAT_FLOAT_BE;
break;
default:
status = -1;
continue;
}
if (ALSA_snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) >= 0) {
break;
}
if (status >= 0) {
status = ALSA_snd_pcm_hw_params_set_format(pcm_handle,
hwparams, format);
}
if (status < 0) {
test_format = SDL_NextAudioFormat();
}
}
if (status < 0) {
return SDL_SetError("ALSA: Couldn't find any hardware audio formats");
if (!test_format) {
return SDL_SetError("%s: Unsupported audio format", "alsa");
}
this->spec.format = test_format;
@@ -621,10 +649,11 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
#ifdef SND_CHMAP_API_VERSION
chmap = ALSA_snd_pcm_get_chmap(pcm_handle);
if (chmap) {
ALSA_snd_pcm_chmap_print(chmap, sizeof(chmap_str), chmap_str);
if (SDL_strcmp("FL FR FC LFE RL RR", chmap_str) == 0 ||
SDL_strcmp("FL FR FC LFE SL SR", chmap_str) == 0) {
this->hidden->swizzle_func = no_swizzle;
if (ALSA_snd_pcm_chmap_print(chmap, sizeof(chmap_str), chmap_str) > 0) {
if (SDL_strcmp("FL FR FC LFE RL RR", chmap_str) == 0 ||
SDL_strcmp("FL FR FC LFE SL SR", chmap_str) == 0) {
this->hidden->swizzle_func = no_swizzle;
}
}
free(chmap);
}
@@ -743,7 +772,7 @@ add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSee
/* some strings have newlines, like "HDA NVidia, HDMI 0\nHDMI Audio Output".
just chop the extra lines off, this seems to get a reasonable device
name without extra details. */
if ((ptr = strchr(desc, '\n')) != NULL) {
if ((ptr = SDL_strchr(desc, '\n')) != NULL) {
*ptr = '\0';
}
@@ -758,7 +787,11 @@ add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSee
return;
}
SDL_AddAudioDevice(iscapture, desc, 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, handle);
if (hint)
free(desc);
dev->name = handle;
@@ -768,200 +801,200 @@ add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSee
}
static ALSA_Device *hotplug_devices = NULL;
static void
ALSA_HotplugIteration(void)
{
void **hints = NULL;
ALSA_Device *dev;
ALSA_Device *unseen;
ALSA_Device *seen;
ALSA_Device *next;
ALSA_Device *prev;
if (ALSA_snd_device_name_hint(-1, "pcm", &hints) == 0) {
int i, j;
const char *match = NULL;
int bestmatch = 0xFFFF;
size_t match_len = 0;
int defaultdev = -1;
static const char * const prefixes[] = {
"hw:", "sysdefault:", "default:", NULL
};
unseen = hotplug_devices;
seen = NULL;
/* Apparently there are several different ways that ALSA lists
actual hardware. It could be prefixed with "hw:" or "default:"
or "sysdefault:" and maybe others. Go through the list and see
if we can find a preferred prefix for the system. */
for (i = 0; hints[i]; i++) {
char *name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
if (!name) {
continue;
}
/* full name, not a prefix */
if ((defaultdev == -1) && (SDL_strcmp(name, "default") == 0)) {
defaultdev = i;
}
for (j = 0; prefixes[j]; j++) {
const char *prefix = prefixes[j];
const size_t prefixlen = SDL_strlen(prefix);
if (SDL_strncmp(name, prefix, prefixlen) == 0) {
if (j < bestmatch) {
bestmatch = j;
match = prefix;
match_len = prefixlen;
}
}
}
free(name);
}
/* look through the list of device names to find matches */
for (i = 0; hints[i]; i++) {
char *name;
/* if we didn't find a device name prefix we like at all... */
if ((!match) && (defaultdev != i)) {
continue; /* ...skip anything that isn't the default device. */
}
name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
if (!name) {
continue;
}
/* only want physical hardware interfaces */
if (!match || (SDL_strncmp(name, match, match_len) == 0)) {
char *ioid = ALSA_snd_device_name_get_hint(hints[i], "IOID");
const SDL_bool isoutput = (ioid == NULL) || (SDL_strcmp(ioid, "Output") == 0);
const SDL_bool isinput = (ioid == NULL) || (SDL_strcmp(ioid, "Input") == 0);
SDL_bool have_output = SDL_FALSE;
SDL_bool have_input = SDL_FALSE;
free(ioid);
if (!isoutput && !isinput) {
free(name);
continue;
}
prev = NULL;
for (dev = unseen; dev; dev = next) {
next = dev->next;
if ( (SDL_strcmp(dev->name, name) == 0) && (((isinput) && dev->iscapture) || ((isoutput) && !dev->iscapture)) ) {
if (prev) {
prev->next = next;
} else {
unseen = next;
}
dev->next = seen;
seen = dev;
if (isinput) have_input = SDL_TRUE;
if (isoutput) have_output = SDL_TRUE;
} else {
prev = dev;
}
}
if (isinput && !have_input) {
add_device(SDL_TRUE, name, hints[i], &seen);
}
if (isoutput && !have_output) {
add_device(SDL_FALSE, name, hints[i], &seen);
}
}
free(name);
}
ALSA_snd_device_name_free_hint(hints);
hotplug_devices = seen; /* now we have a known-good list of attached devices. */
/* report anything still in unseen as removed. */
for (dev = unseen; dev; dev = next) {
/*printf("ALSA: removing usb %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
next = dev->next;
SDL_RemoveAudioDevice(dev->iscapture, dev->name);
SDL_free(dev->name);
SDL_free(dev);
}
}
}
#if SDL_ALSA_HOTPLUG_THREAD
static SDL_atomic_t ALSA_hotplug_shutdown;
static SDL_Thread *ALSA_hotplug_thread;
static int SDLCALL
ALSA_HotplugThread(void *arg)
{
SDL_sem *first_run_semaphore = (SDL_sem *) arg;
ALSA_Device *devices = NULL;
ALSA_Device *next;
ALSA_Device *dev;
Uint32 ticks;
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_LOW);
while (!SDL_AtomicGet(&ALSA_hotplug_shutdown)) {
void **hints = NULL;
ALSA_Device *unseen;
ALSA_Device *seen;
ALSA_Device *prev;
if (ALSA_snd_device_name_hint(-1, "pcm", &hints) != -1) {
int i, j;
const char *match = NULL;
int bestmatch = 0xFFFF;
size_t match_len = 0;
int defaultdev = -1;
static const char * const prefixes[] = {
"hw:", "sysdefault:", "default:", NULL
};
unseen = devices;
seen = NULL;
/* Apparently there are several different ways that ALSA lists
actual hardware. It could be prefixed with "hw:" or "default:"
or "sysdefault:" and maybe others. Go through the list and see
if we can find a preferred prefix for the system. */
for (i = 0; hints[i]; i++) {
char *name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
if (!name) {
continue;
}
/* full name, not a prefix */
if ((defaultdev == -1) && (SDL_strcmp(name, "default") == 0)) {
defaultdev = i;
}
for (j = 0; prefixes[j]; j++) {
const char *prefix = prefixes[j];
const size_t prefixlen = SDL_strlen(prefix);
if (SDL_strncmp(name, prefix, prefixlen) == 0) {
if (j < bestmatch) {
bestmatch = j;
match = prefix;
match_len = prefixlen;
}
}
}
free(name);
}
/* look through the list of device names to find matches */
for (i = 0; hints[i]; i++) {
char *name;
/* if we didn't find a device name prefix we like at all... */
if ((!match) && (defaultdev != i)) {
continue; /* ...skip anything that isn't the default device. */
}
name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
if (!name) {
continue;
}
/* only want physical hardware interfaces */
if (!match || (SDL_strncmp(name, match, match_len) == 0)) {
char *ioid = ALSA_snd_device_name_get_hint(hints[i], "IOID");
const SDL_bool isoutput = (ioid == NULL) || (SDL_strcmp(ioid, "Output") == 0);
const SDL_bool isinput = (ioid == NULL) || (SDL_strcmp(ioid, "Input") == 0);
SDL_bool have_output = SDL_FALSE;
SDL_bool have_input = SDL_FALSE;
free(ioid);
if (!isoutput && !isinput) {
free(name);
continue;
}
prev = NULL;
for (dev = unseen; dev; dev = next) {
next = dev->next;
if ( (SDL_strcmp(dev->name, name) == 0) && (((isinput) && dev->iscapture) || ((isoutput) && !dev->iscapture)) ) {
if (prev) {
prev->next = next;
} else {
unseen = next;
}
dev->next = seen;
seen = dev;
if (isinput) have_input = SDL_TRUE;
if (isoutput) have_output = SDL_TRUE;
} else {
prev = dev;
}
}
if (isinput && !have_input) {
add_device(SDL_TRUE, name, hints[i], &seen);
}
if (isoutput && !have_output) {
add_device(SDL_FALSE, name, hints[i], &seen);
}
}
free(name);
}
ALSA_snd_device_name_free_hint(hints);
devices = seen; /* now we have a known-good list of attached devices. */
/* report anything still in unseen as removed. */
for (dev = unseen; dev; dev = next) {
/*printf("ALSA: removing usb %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
next = dev->next;
SDL_RemoveAudioDevice(dev->iscapture, dev->name);
SDL_free(dev->name);
SDL_free(dev);
}
}
/* On first run, tell ALSA_DetectDevices() that we have a complete device list so it can return. */
if (first_run_semaphore) {
SDL_SemPost(first_run_semaphore);
first_run_semaphore = NULL; /* let other thread clean it up. */
}
/* Block awhile before checking again, unless we're told to stop. */
ticks = SDL_GetTicks() + 5000;
const Uint32 ticks = SDL_GetTicks() + 5000;
while (!SDL_AtomicGet(&ALSA_hotplug_shutdown) && !SDL_TICKS_PASSED(SDL_GetTicks(), ticks)) {
SDL_Delay(100);
}
}
/* Shutting down! Clean up any data we've gathered. */
for (dev = devices; dev; dev = next) {
/*printf("ALSA: at shutdown, removing %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
next = dev->next;
SDL_free(dev->name);
SDL_free(dev);
ALSA_HotplugIteration(); /* run the check. */
}
return 0;
}
#endif
static void
ALSA_DetectDevices(void)
{
/* Start the device detection thread here, wait for an initial iteration to complete. */
SDL_sem *semaphore = SDL_CreateSemaphore(0);
if (!semaphore) {
return; /* oh well. */
}
ALSA_HotplugIteration(); /* run once now before a thread continues to check. */
#if SDL_ALSA_HOTPLUG_THREAD
SDL_AtomicSet(&ALSA_hotplug_shutdown, 0);
ALSA_hotplug_thread = SDL_CreateThread(ALSA_HotplugThread, "SDLHotplugALSA", semaphore);
if (ALSA_hotplug_thread) {
SDL_SemWait(semaphore); /* wait for the first iteration to finish. */
}
SDL_DestroySemaphore(semaphore);
ALSA_hotplug_thread = SDL_CreateThread(ALSA_HotplugThread, "SDLHotplugALSA", NULL);
/* if the thread doesn't spin, oh well, you just don't get further hotplug events. */
#endif
}
static void
ALSA_Deinitialize(void)
{
ALSA_Device *dev;
ALSA_Device *next;
#if SDL_ALSA_HOTPLUG_THREAD
if (ALSA_hotplug_thread != NULL) {
SDL_AtomicSet(&ALSA_hotplug_shutdown, 1);
SDL_WaitThread(ALSA_hotplug_thread, NULL);
ALSA_hotplug_thread = NULL;
}
#endif
/* Shutting down! Clean up any data we've gathered. */
for (dev = hotplug_devices; dev; dev = next) {
/*printf("ALSA: at shutdown, removing %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
next = dev->next;
SDL_free(dev->name);
SDL_free(dev);
}
hotplug_devices = NULL;
UnloadALSALibrary();
}
static int
static SDL_bool
ALSA_Init(SDL_AudioDriverImpl * impl)
{
if (LoadALSALibrary() < 0) {
return 0;
return SDL_FALSE;
}
/* Set the function pointers */
@@ -977,12 +1010,12 @@ ALSA_Init(SDL_AudioDriverImpl * impl)
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap ALSA_bootstrap = {
"alsa", "ALSA PCM audio", ALSA_Init, 0
"alsa", "ALSA PCM audio", ALSA_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_ALSA */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+13 -15
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -24,7 +24,6 @@
/* Output audio to Android */
#include "SDL_assert.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "SDL_androidaudio.h"
@@ -37,9 +36,10 @@ static SDL_AudioDevice* audioDevice = NULL;
static SDL_AudioDevice* captureDevice = NULL;
static int
ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
ANDROIDAUDIO_OpenDevice(_THIS, const char *devname)
{
SDL_AudioFormat test_format;
SDL_bool iscapture = this->iscapture;
SDL_assert((captureDevice == NULL) || !iscapture);
SDL_assert((audioDevice == NULL) || iscapture);
@@ -55,20 +55,18 @@ ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
return SDL_OutOfMemory();
}
test_format = SDL_FirstAudioFormat(this->spec.format);
while (test_format != 0) { /* no "UNKNOWN" constant */
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
if ((test_format == AUDIO_U8) ||
(test_format == AUDIO_S16) ||
(test_format == AUDIO_F32)) {
(test_format == AUDIO_S16) ||
(test_format == AUDIO_F32)) {
this->spec.format = test_format;
break;
}
test_format = SDL_NextAudioFormat();
}
if (test_format == 0) {
if (!test_format) {
/* Didn't find a compatible format :( */
return SDL_SetError("No compatible audio format!");
return SDL_SetError("%s: Unsupported audio format", "android");
}
if (Android_JNI_OpenAudioDevice(iscapture, &this->spec) < 0) {
@@ -121,7 +119,7 @@ ANDROIDAUDIO_CloseDevice(_THIS)
SDL_free(this->hidden);
}
static int
static SDL_bool
ANDROIDAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
@@ -134,14 +132,14 @@ ANDROIDAUDIO_Init(SDL_AudioDriverImpl * impl)
/* and the capabilities */
impl->HasCaptureSupport = SDL_TRUE;
impl->OnlyHasDefaultOutputDevice = 1;
impl->OnlyHasDefaultCaptureDevice = 1;
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap ANDROIDAUDIO_bootstrap = {
"android", "SDL Android audio driver", ANDROIDAUDIO_Init, 0
"android", "SDL Android audio driver", ANDROIDAUDIO_Init, SDL_FALSE
};
/* Pause (block) all non already paused audio devices by taking their mixer lock */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+16 -24
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -216,11 +216,11 @@ ARTS_Suspend(void)
}
static int
ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
ARTS_OpenDevice(_THIS, const char *devname)
{
int rc = 0;
int bits = 0, frag_spec = 0;
SDL_AudioFormat test_format = 0, format = 0;
int bits, frag_spec = 0;
SDL_AudioFormat test_format = 0;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
@@ -231,32 +231,24 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SDL_zerop(this->hidden);
/* Try for a closest match on audio format */
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!format && test_format;) {
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
#endif
switch (test_format) {
case AUDIO_U8:
bits = 8;
format = 1;
break;
case AUDIO_S16LSB:
bits = 16;
format = 1;
break;
default:
format = 0;
break;
}
if (!format) {
test_format = SDL_NextAudioFormat();
continue;
}
break;
}
if (format == 0) {
return SDL_SetError("Couldn't find any hardware audio formats");
if (!test_format) {
return SDL_SetError("%s: Unsupported audio format", "arts");
}
this->spec.format = test_format;
bits = SDL_AUDIO_BITSIZE(test_format);
if ((rc = SDL_NAME(arts_init) ()) != 0) {
return SDL_SetError("Unable to initialize ARTS: %s",
@@ -320,16 +312,16 @@ ARTS_Deinitialize(void)
}
static int
static SDL_bool
ARTS_Init(SDL_AudioDriverImpl * impl)
{
if (LoadARTSLibrary() < 0) {
return 0;
return SDL_FALSE;
} else {
if (SDL_NAME(arts_init) () != 0) {
UnloadARTSLibrary();
SDL_SetError("ARTS: arts_init failed (no audio server?)");
return 0;
return SDL_FALSE;
}
/* Play a stream so aRts doesn't crash */
@@ -350,14 +342,14 @@ ARTS_Init(SDL_AudioDriverImpl * impl)
impl->GetDeviceBuf = ARTS_GetDeviceBuf;
impl->CloseDevice = ARTS_CloseDevice;
impl->Deinitialize = ARTS_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1;
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap ARTS_bootstrap = {
"arts", "Analog RealTime Synthesizer", ARTS_Init, 0
"arts", "Analog RealTime Synthesizer", ARTS_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_ARTS */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+7 -4
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -31,7 +31,6 @@
#if MACOSX_COREAUDIO
#include <CoreAudio/CoreAudio.h>
#include <CoreServices/CoreServices.h>
#else
#import <AVFoundation/AVFoundation.h>
#import <UIKit/UIApplication.h>
@@ -45,16 +44,20 @@
struct SDL_PrivateAudioData
{
SDL_Thread *thread;
AudioQueueRef audioQueue;
int numAudioBuffers;
AudioQueueBufferRef *audioBuffer;
void *buffer;
UInt32 bufferOffset;
UInt32 bufferSize;
AudioStreamBasicDescription strdesc;
SDL_bool refill;
SDL_AudioStream *capturestream;
SDL_sem *ready_semaphore;
char *thread_error;
SDL_atomic_t shutdown;
#if MACOSX_COREAUDIO
AudioDeviceID deviceID;
SDL_atomic_t device_change_flag;
#else
SDL_bool interrupted;
CFTypeRef interruption_listener;
File diff suppressed because it is too large Load Diff
+27 -27
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -24,7 +24,6 @@
/* Allow access to a raw mixing buffer */
#include "SDL_assert.h"
#include "SDL_timer.h"
#include "SDL_loadso.h"
#include "SDL_audio.h"
@@ -99,10 +98,8 @@ DSOUND_Load(void)
static int
SetDSerror(const char *function, int code)
{
static const char *error;
static char errbuf[1024];
const char *error;
errbuf[0] = 0;
switch (code) {
case E_NOINTERFACE:
error = "Unsupported interface -- Is DirectX 8.0 or later installed?";
@@ -138,15 +135,11 @@ SetDSerror(const char *function, int code)
error = "Function not supported";
break;
default:
SDL_snprintf(errbuf, SDL_arraysize(errbuf),
"%s: Unknown DirectSound error: 0x%x", function, code);
error = "Unknown DirectSound error";
break;
}
if (!errbuf[0]) {
SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
error);
}
return SDL_SetError("%s", errbuf);
return SDL_SetError("%s: %s (0x%x)", function, error, code);
}
static void
@@ -164,7 +157,12 @@ FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data)
if (str != NULL) {
LPGUID cpyguid = (LPGUID) SDL_malloc(sizeof (GUID));
SDL_memcpy(cpyguid, guid, sizeof (GUID));
SDL_AddAudioDevice(iscapture, str, cpyguid);
/* Note that spec is NULL, because we are required to connect to the
* device before getting the channel mask and output format, making
* this information inaccessible at enumeration time
*/
SDL_AddAudioDevice(iscapture, str, NULL, cpyguid);
SDL_free(str); /* addfn() makes a copy of this string. */
}
}
@@ -469,14 +467,14 @@ CreateCaptureBuffer(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
}
static int
DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
DSOUND_OpenDevice(_THIS, const char *devname)
{
const DWORD numchunks = 8;
HRESULT result;
SDL_bool valid_format = SDL_FALSE;
SDL_bool tried_format = SDL_FALSE;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
LPGUID guid = (LPGUID) handle;
SDL_bool iscapture = this->iscapture;
SDL_AudioFormat test_format;
LPGUID guid = (LPGUID) this->handle;
DWORD bufsize;
/* Initialize all variables that we clean on shutdown */
@@ -506,7 +504,7 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
}
while ((!valid_format) && (test_format)) {
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
switch (test_format) {
case AUDIO_U8:
case AUDIO_S16:
@@ -543,19 +541,21 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
rc = iscapture ? CreateCaptureBuffer(this, bufsize, &wfmt) : CreateSecondary(this, bufsize, &wfmt);
if (rc == 0) {
this->hidden->num_buffers = numchunks;
valid_format = SDL_TRUE;
break;
}
}
break;
continue;
default:
continue;
}
test_format = SDL_NextAudioFormat();
break;
}
if (!valid_format) {
if (!test_format) {
if (tried_format) {
return -1; /* CreateSecondary() should have called SDL_SetError(). */
}
return SDL_SetError("DirectSound: Unsupported audio format");
return SDL_SetError("%s: Unsupported audio format", "directsound");
}
/* Playback buffers will auto-start playing in DSOUND_WaitDevice() */
@@ -571,11 +571,11 @@ DSOUND_Deinitialize(void)
}
static int
static SDL_bool
DSOUND_Init(SDL_AudioDriverImpl * impl)
{
if (!DSOUND_Load()) {
return 0;
return SDL_FALSE;
}
/* Set the function pointers */
@@ -592,11 +592,11 @@ DSOUND_Init(SDL_AudioDriverImpl * impl)
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap DSOUND_bootstrap = {
"directsound", "DirectSound", DSOUND_Init, 0
"directsound", "DirectSound", DSOUND_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_DSOUND */
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+35 -34
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -33,7 +33,6 @@
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "SDL_diskaudio.h"
#include "SDL_log.h"
/* !!! FIXME: these should be SDL hints, not environment variables. */
/* environment variables and defaults. */
@@ -47,19 +46,19 @@
static void
DISKAUDIO_WaitDevice(_THIS)
{
SDL_Delay(this->hidden->io_delay);
SDL_Delay(_this->hidden->io_delay);
}
static void
DISKAUDIO_PlayDevice(_THIS)
{
const size_t written = SDL_RWwrite(this->hidden->io,
this->hidden->mixbuf,
1, this->spec.size);
const size_t written = SDL_RWwrite(_this->hidden->io,
_this->hidden->mixbuf,
1, _this->spec.size);
/* If we couldn't write, assume fatal error for now */
if (written != this->spec.size) {
SDL_OpenedAudioDeviceDisconnected(this);
if (written != _this->spec.size) {
SDL_OpenedAudioDeviceDisconnected(_this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
@@ -69,13 +68,13 @@ DISKAUDIO_PlayDevice(_THIS)
static Uint8 *
DISKAUDIO_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
return (_this->hidden->mixbuf);
}
static int
DISKAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
struct SDL_PrivateAudioData *h = this->hidden;
struct SDL_PrivateAudioData *h = _this->hidden;
const int origbuflen = buflen;
SDL_Delay(h->io_delay);
@@ -91,7 +90,7 @@ DISKAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
}
/* if we ran out of file, just write silence. */
SDL_memset(buffer, this->spec.silence, buflen);
SDL_memset(buffer, _this->spec.silence, buflen);
return origbuflen;
}
@@ -106,16 +105,16 @@ DISKAUDIO_FlushCapture(_THIS)
static void
DISKAUDIO_CloseDevice(_THIS)
{
if (this->hidden->io != NULL) {
SDL_RWclose(this->hidden->io);
if (_this->hidden->io != NULL) {
SDL_RWclose(_this->hidden->io);
}
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
SDL_free(_this->hidden->mixbuf);
SDL_free(_this->hidden);
}
static const char *
get_filename(const int iscapture, const char *devname)
get_filename(const SDL_bool iscapture, const char *devname)
{
if (devname == NULL) {
devname = SDL_getenv(iscapture ? DISKENVR_INFILE : DISKENVR_OUTFILE);
@@ -127,38 +126,40 @@ get_filename(const int iscapture, const char *devname)
}
static int
DISKAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
DISKAUDIO_OpenDevice(_THIS, const char *devname)
{
void *handle = _this->handle;
/* handle != NULL means "user specified the placeholder name on the fake detected device list" */
SDL_bool iscapture = _this->iscapture;
const char *fname = get_filename(iscapture, handle ? NULL : devname);
const char *envr = SDL_getenv(DISKENVR_IODELAY);
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc(sizeof(*this->hidden));
if (this->hidden == NULL) {
_this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc(sizeof(*_this->hidden));
if (_this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_zerop(this->hidden);
SDL_zerop(_this->hidden);
if (envr != NULL) {
this->hidden->io_delay = SDL_atoi(envr);
_this->hidden->io_delay = SDL_atoi(envr);
} else {
this->hidden->io_delay = ((this->spec.samples * 1000) / this->spec.freq);
_this->hidden->io_delay = ((_this->spec.samples * 1000) / _this->spec.freq);
}
/* Open the audio device */
this->hidden->io = SDL_RWFromFile(fname, iscapture ? "rb" : "wb");
if (this->hidden->io == NULL) {
_this->hidden->io = SDL_RWFromFile(fname, iscapture ? "rb" : "wb");
if (_this->hidden->io == NULL) {
return -1;
}
/* Allocate mixing buffer */
if (!iscapture) {
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size);
if (this->hidden->mixbuf == NULL) {
_this->hidden->mixbuf = (Uint8 *) SDL_malloc(_this->spec.size);
if (_this->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
SDL_memset(_this->hidden->mixbuf, _this->spec.silence, _this->spec.size);
}
SDL_LogCritical(SDL_LOG_CATEGORY_AUDIO,
@@ -174,11 +175,11 @@ DISKAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
static void
DISKAUDIO_DetectDevices(void)
{
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) 0x1);
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) 0x2);
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, NULL, (void *) 0x1);
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, NULL, (void *) 0x2);
}
static int
static SDL_bool
DISKAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
@@ -192,14 +193,14 @@ DISKAUDIO_Init(SDL_AudioDriverImpl * impl)
impl->CloseDevice = DISKAUDIO_CloseDevice;
impl->DetectDevices = DISKAUDIO_DetectDevices;
impl->AllowsArbitraryDeviceNames = 1;
impl->AllowsArbitraryDeviceNames = SDL_TRUE;
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap DISKAUDIO_bootstrap = {
"disk", "direct-to-disk audio", DISKAUDIO_Init, 1
"disk", "direct-to-disk audio", DISKAUDIO_Init, SDL_TRUE
};
#endif /* SDL_AUDIO_DRIVER_DISK */
+2 -2
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -27,7 +27,7 @@
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
#define _THIS SDL_AudioDevice *_this
struct SDL_PrivateAudioData
{
+23 -6
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -68,8 +68,9 @@ DSP_CloseDevice(_THIS)
static int
DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
DSP_OpenDevice(_THIS, const char *devname)
{
SDL_bool iscapture = this->iscapture;
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
int format;
int value;
@@ -103,7 +104,7 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SDL_zerop(this->hidden);
/* Open the audio device */
this->hidden->audio_fd = open(devname, flags, 0);
this->hidden->audio_fd = open(devname, flags | O_CLOEXEC, 0);
if (this->hidden->audio_fd < 0) {
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
}
@@ -292,9 +293,25 @@ DSP_FlushCapture(_THIS)
}
}
static SDL_bool InitTimeDevicesExist = SDL_FALSE;
static int
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. */
return 0;
}
static SDL_bool
DSP_Init(SDL_AudioDriverImpl * impl)
{
InitTimeDevicesExist = SDL_FALSE;
SDL_EnumUnixAudioDevices(0, look_for_devices_test);
if (!InitTimeDevicesExist) {
SDL_SetError("dsp: No such audio device");
return SDL_FALSE; /* maybe try a different backend. */
}
/* Set the function pointers */
impl->DetectDevices = DSP_DetectDevices;
impl->OpenDevice = DSP_OpenDevice;
@@ -304,15 +321,15 @@ DSP_Init(SDL_AudioDriverImpl * impl)
impl->CaptureFromDevice = DSP_CaptureFromDevice;
impl->FlushCapture = DSP_FlushCapture;
impl->AllowsArbitraryDeviceNames = 1;
impl->AllowsArbitraryDeviceNames = SDL_TRUE;
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap DSP_bootstrap = {
"dsp", "OSS /dev/dsp standard audio", DSP_Init, 0
"dsp", "OSS /dev/dsp standard audio", DSP_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_OSS */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+10 -9
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -28,8 +28,9 @@
#include "SDL_dummyaudio.h"
static int
DUMMYAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
DUMMYAUDIO_OpenDevice(_THIS, const char *devname)
{
_this->hidden = (void *) 0x1; /* just something non-NULL */
return 0; /* always succeeds. */
}
@@ -37,29 +38,29 @@ static int
DUMMYAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
/* Delay to make this sort of simulate real audio input. */
SDL_Delay((this->spec.samples * 1000) / this->spec.freq);
SDL_Delay((_this->spec.samples * 1000) / _this->spec.freq);
/* always return a full buffer of silence. */
SDL_memset(buffer, this->spec.silence, buflen);
SDL_memset(buffer, _this->spec.silence, buflen);
return buflen;
}
static int
static SDL_bool
DUMMYAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->OpenDevice = DUMMYAUDIO_OpenDevice;
impl->CaptureFromDevice = DUMMYAUDIO_CaptureFromDevice;
impl->OnlyHasDefaultOutputDevice = 1;
impl->OnlyHasDefaultCaptureDevice = 1;
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap DUMMYAUDIO_bootstrap = {
"dummy", "SDL dummy audio driver", DUMMYAUDIO_Init, 1
"dummy", "SDL dummy audio driver", DUMMYAUDIO_Init, SDL_TRUE
};
/* vi: set ts=4 sw=4 expandtab: */
+2 -2
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -26,7 +26,7 @@
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
#define _THIS SDL_AudioDevice *_this
struct SDL_PrivateAudioData
{
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -23,10 +23,8 @@
#if SDL_AUDIO_DRIVER_EMSCRIPTEN
#include "SDL_audio.h"
#include "SDL_log.h"
#include "../SDL_audio_c.h"
#include "SDL_emscriptenaudio.h"
#include "SDL_assert.h"
#include <emscripten/emscripten.h>
@@ -34,7 +32,8 @@ static void
FeedAudioDevice(_THIS, const void *buf, const int buflen)
{
const int framelen = (SDL_AUDIO_BITSIZE(this->spec.format) / 8) * this->spec.channels;
EM_ASM_ARGS({
MAIN_THREAD_EM_ASM({
var SDL2 = Module['SDL2'];
var numChannels = SDL2.audio.currentOutputBuffer['numberOfChannels'];
for (var c = 0; c < numChannels; ++c) {
var channelData = SDL2.audio.currentOutputBuffer['getChannelData'](c);
@@ -60,6 +59,9 @@ HandleAudioProcess(_THIS)
if (this->stream) {
SDL_AudioStreamClear(this->stream);
}
SDL_memset(this->work_buffer, this->spec.silence, this->spec.size);
FeedAudioDevice(this, this->work_buffer, this->spec.size);
return;
}
@@ -99,7 +101,8 @@ HandleCaptureProcess(_THIS)
return;
}
EM_ASM_ARGS({
MAIN_THREAD_EM_ASM({
var SDL2 = Module['SDL2'];
var numChannels = SDL2.capture.currentCaptureBuffer.numberOfChannels;
for (var c = 0; c < numChannels; ++c) {
var channelData = SDL2.capture.currentCaptureBuffer.getChannelData(c);
@@ -144,7 +147,8 @@ HandleCaptureProcess(_THIS)
static void
EMSCRIPTENAUDIO_CloseDevice(_THIS)
{
EM_ASM_({
MAIN_THREAD_EM_ASM({
var SDL2 = Module['SDL2'];
if ($0) {
if (SDL2.capture.silenceTimer !== undefined) {
clearTimeout(SDL2.capture.silenceTimer);
@@ -188,19 +192,20 @@ EMSCRIPTENAUDIO_CloseDevice(_THIS)
}
static int
EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname)
{
SDL_bool valid_format = SDL_FALSE;
SDL_AudioFormat test_format;
SDL_bool iscapture = this->iscapture;
int result;
/* based on parts of library_sdl.js */
/* create context (TODO: this puts stuff in the global namespace...)*/
result = EM_ASM_INT({
if(typeof(SDL2) === 'undefined') {
SDL2 = {};
/* create context */
result = MAIN_THREAD_EM_ASM_INT({
if(typeof(Module['SDL2']) === 'undefined') {
Module['SDL2'] = {};
}
var SDL2 = Module['SDL2'];
if (!$0) {
SDL2.audio = {};
} else {
@@ -213,6 +218,9 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscaptu
} else if (typeof(webkitAudioContext) !== 'undefined') {
SDL2.audioContext = new webkitAudioContext();
}
if (SDL2.audioContext) {
autoResumeAudioContext(SDL2.audioContext);
}
}
return SDL2.audioContext === undefined ? -1 : 0;
}, iscapture);
@@ -220,22 +228,21 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscaptu
return SDL_SetError("Web Audio API is not available!");
}
test_format = SDL_FirstAudioFormat(this->spec.format);
while ((!valid_format) && (test_format)) {
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
switch (test_format) {
case AUDIO_F32: /* web audio only supports floats */
this->spec.format = test_format;
valid_format = SDL_TRUE;
break;
default:
continue;
}
test_format = SDL_NextAudioFormat();
break;
}
if (!valid_format) {
if (!test_format) {
/* Didn't find a compatible format :( */
return SDL_SetError("No compatible audio format!");
return SDL_SetError("%s: Unsupported audio format", "emscripten");
}
this->spec.format = test_format;
/* Initialize all variables that we clean on shutdown */
#if 0 /* !!! FIXME: currently not used. Can we move some stuff off the SDL2 namespace? --ryan. */
@@ -246,9 +253,13 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscaptu
}
SDL_zerop(this->hidden);
#endif
this->hidden = (struct SDL_PrivateAudioData *)0x1;
/* limit to native freq */
this->spec.freq = EM_ASM_INT_V({ return SDL2.audioContext.sampleRate; });
this->spec.freq = EM_ASM_INT_V({
var SDL2 = Module['SDL2'];
return SDL2.audioContext.sampleRate;
});
SDL_CalculateAudioSpec(&this->spec);
@@ -269,7 +280,8 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscaptu
feels like it's a pretty inefficient tapdance in similar ways,
to be honest. */
EM_ASM_({
MAIN_THREAD_EM_ASM({
var SDL2 = Module['SDL2'];
var have_microphone = function(stream) {
//console.log('SDL audio capture: we have a microphone! Replacing silence callback.');
if (SDL2.capture.silenceTimer !== undefined) {
@@ -282,7 +294,7 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscaptu
if ((SDL2 === undefined) || (SDL2.capture === undefined)) { return; }
audioProcessingEvent.outputBuffer.getChannelData(0).fill(0.0);
SDL2.capture.currentCaptureBuffer = audioProcessingEvent.inputBuffer;
Runtime.dynCall('vi', $2, [$3]);
dynCall('vi', $2, [$3]);
};
SDL2.capture.mediaStreamNode.connect(SDL2.capture.scriptProcessorNode);
SDL2.capture.scriptProcessorNode.connect(SDL2.audioContext.destination);
@@ -298,7 +310,7 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscaptu
SDL2.capture.silenceBuffer.getChannelData(0).fill(0.0);
var silence_callback = function() {
SDL2.capture.currentCaptureBuffer = SDL2.capture.silenceBuffer;
Runtime.dynCall('vi', $2, [$3]);
dynCall('vi', $2, [$3]);
};
SDL2.capture.silenceTimer = setTimeout(silence_callback, ($1 / SDL2.audioContext.sampleRate) * 1000);
@@ -311,12 +323,13 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscaptu
}, this->spec.channels, this->spec.samples, HandleCaptureProcess, this);
} else {
/* setup a ScriptProcessorNode */
EM_ASM_ARGS({
MAIN_THREAD_EM_ASM({
var SDL2 = Module['SDL2'];
SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0);
SDL2.audio.scriptProcessorNode['onaudioprocess'] = function (e) {
if ((SDL2 === undefined) || (SDL2.audio === undefined)) { return; }
SDL2.audio.currentOutputBuffer = e['outputBuffer'];
Runtime.dynCall('vi', $2, [$3]);
dynCall('vi', $2, [$3]);
};
SDL2.audio.scriptProcessorNode['connect'](SDL2.audioContext['destination']);
}, this->spec.channels, this->spec.samples, HandleAudioProcess, this);
@@ -325,43 +338,47 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscaptu
return 0;
}
static int
static void
EMSCRIPTENAUDIO_LockOrUnlockDeviceWithNoMixerLock(SDL_AudioDevice * device)
{
}
static SDL_bool
EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl * impl)
{
int available;
int capture_available;
SDL_bool available, capture_available;
/* Set the function pointers */
impl->OpenDevice = EMSCRIPTENAUDIO_OpenDevice;
impl->CloseDevice = EMSCRIPTENAUDIO_CloseDevice;
impl->OnlyHasDefaultOutputDevice = 1;
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
/* no threads here */
impl->SkipMixerLock = 1;
impl->ProvidesOwnCallbackThread = 1;
impl->LockDevice = impl->UnlockDevice = EMSCRIPTENAUDIO_LockOrUnlockDeviceWithNoMixerLock;
impl->ProvidesOwnCallbackThread = SDL_TRUE;
/* check availability */
available = EM_ASM_INT_V({
available = MAIN_THREAD_EM_ASM_INT({
if (typeof(AudioContext) !== 'undefined') {
return 1;
return true;
} else if (typeof(webkitAudioContext) !== 'undefined') {
return 1;
return true;
}
return 0;
return false;
});
if (!available) {
SDL_SetError("No audio context available");
}
capture_available = available && EM_ASM_INT_V({
capture_available = available && MAIN_THREAD_EM_ASM_INT({
if ((typeof(navigator.mediaDevices) !== 'undefined') && (typeof(navigator.mediaDevices.getUserMedia) !== 'undefined')) {
return 1;
return true;
} else if (typeof(navigator.webkitGetUserMedia) !== 'undefined') {
return 1;
return true;
}
return 0;
return false;
});
impl->HasCaptureSupport = capture_available ? SDL_TRUE : SDL_FALSE;
@@ -371,7 +388,7 @@ EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl * impl)
}
AudioBootStrap EMSCRIPTENAUDIO_bootstrap = {
"emscripten", "SDL emscripten audio driver", EMSCRIPTENAUDIO_Init, 0
"emscripten", "SDL emscripten audio driver", EMSCRIPTENAUDIO_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_EMSCRIPTEN */
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+8 -8
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -208,7 +208,7 @@ get_progname(void)
static int
ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
ESD_OpenDevice(_THIS, const char *devname)
{
esd_format_t format = (ESD_STREAM | ESD_PLAY);
SDL_AudioFormat test_format = 0;
@@ -293,11 +293,11 @@ ESD_Deinitialize(void)
UnloadESDLibrary();
}
static int
static SDL_bool
ESD_Init(SDL_AudioDriverImpl * impl)
{
if (LoadESDLibrary() < 0) {
return 0;
return SDL_FALSE;
} else {
int connection = 0;
@@ -308,7 +308,7 @@ ESD_Init(SDL_AudioDriverImpl * impl)
if (connection < 0) {
UnloadESDLibrary();
SDL_SetError("ESD: esd_open_sound failed (no audio server?)");
return 0;
return SDL_FALSE;
}
SDL_NAME(esd_close) (connection);
}
@@ -320,14 +320,14 @@ ESD_Init(SDL_AudioDriverImpl * impl)
impl->GetDeviceBuf = ESD_GetDeviceBuf;
impl->CloseDevice = ESD_CloseDevice;
impl->Deinitialize = ESD_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1;
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap ESD_bootstrap = {
"esd", "Enlightened Sound Daemon", ESD_Init, 0
"esd", "Enlightened Sound Daemon", ESD_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_ESD */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+15 -26
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -174,10 +174,10 @@ SDL_FS_CloseDevice(_THIS)
static int
SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SDL_FS_OpenDevice(_THIS, const char *devname)
{
int bytes;
SDL_AudioFormat test_format = 0, format = 0;
SDL_AudioFormat test_format;
FSSampleFormat fs_format;
FSStreamDescription desc;
DirectResult ret;
@@ -191,45 +191,34 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SDL_zerop(this->hidden);
/* Try for a closest match on audio format */
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!format && test_format;) {
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
#endif
switch (test_format) {
case AUDIO_U8:
fs_format = FSSF_U8;
bytes = 1;
format = 1;
break;
case AUDIO_S16SYS:
fs_format = FSSF_S16;
bytes = 2;
format = 1;
break;
case AUDIO_S32SYS:
fs_format = FSSF_S32;
bytes = 4;
format = 1;
break;
case AUDIO_F32SYS:
fs_format = FSSF_FLOAT;
bytes = 4;
format = 1;
break;
default:
format = 0;
break;
}
if (!format) {
test_format = SDL_NextAudioFormat();
continue;
}
break;
}
if (format == 0) {
return SDL_SetError("Couldn't find any hardware audio formats");
if (!test_format) {
return SDL_SetError("%s: Unsupported audio format", "fusionsound");
}
this->spec.format = test_format;
bytes = SDL_AUDIO_BITSIZE(test_format) / 8;
/* Retrieve the main sound interface. */
ret = SDL_NAME(FusionSoundCreate) (&this->hidden->fs);
@@ -288,11 +277,11 @@ SDL_FS_Deinitialize(void)
}
static int
static SDL_bool
SDL_FS_Init(SDL_AudioDriverImpl * impl)
{
if (LoadFusionSoundLibrary() < 0) {
return 0;
return SDL_FALSE;
} else {
DirectResult ret;
@@ -302,7 +291,7 @@ SDL_FS_Init(SDL_AudioDriverImpl * impl)
SDL_SetError
("FusionSound: SDL_FS_init failed (FusionSoundInit: %d)",
ret);
return 0;
return SDL_FALSE;
}
}
@@ -313,14 +302,14 @@ SDL_FS_Init(SDL_AudioDriverImpl * impl)
impl->GetDeviceBuf = SDL_FS_GetDeviceBuf;
impl->CloseDevice = SDL_FS_CloseDevice;
impl->Deinitialize = SDL_FS_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1;
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap FUSIONSOUND_bootstrap = {
"fusionsound", "FusionSound", SDL_FS_Init, 0
"fusionsound", "FusionSound", SDL_FS_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_FUSIONSOUND */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+15 -19
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -36,7 +36,6 @@ extern "C"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_haikuaudio.h"
#include "SDL_assert.h"
}
@@ -121,11 +120,10 @@ UnmaskSignals(sigset_t * omask)
static int
HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
HAIKUAUDIO_OpenDevice(_THIS, const char *devname)
{
int valid_datatype = 0;
media_raw_audio_format format;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(_this->spec.format);
SDL_AudioFormat test_format;
/* Initialize all variables that we clean on shutdown */
_this->hidden = new SDL_PrivateAudioData;
@@ -139,9 +137,7 @@ HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
format.byte_order = B_MEDIA_LITTLE_ENDIAN;
format.frame_rate = (float) _this->spec.freq;
format.channel_count = _this->spec.channels; /* !!! FIXME: support > 2? */
while ((!valid_datatype) && (test_format)) {
valid_datatype = 1;
_this->spec.format = test_format;
for (test_format = SDL_FirstAudioFormat(_this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
switch (test_format) {
case AUDIO_S8:
format.format = media_raw_audio_format::B_AUDIO_CHAR;
@@ -179,15 +175,15 @@ HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
break;
default:
valid_datatype = 0;
test_format = SDL_NextAudioFormat();
break;
continue;
}
break;
}
if (!valid_datatype) { /* shouldn't happen, but just in case... */
return SDL_SetError("Unsupported audio format");
if (!test_format) { /* shouldn't happen, but just in case... */
return SDL_SetError("%s: Unsupported audio format", "haiku");
}
_this->spec.format = test_format;
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&_this->spec);
@@ -217,22 +213,22 @@ HAIKUAUDIO_Deinitialize(void)
SDL_QuitBeApp();
}
static int
static SDL_bool
HAIKUAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Initialize the Be Application, if it's not already started */
if (SDL_InitBeApp() < 0) {
return 0;
return SDL_FALSE;
}
/* Set the function pointers */
impl->OpenDevice = HAIKUAUDIO_OpenDevice;
impl->CloseDevice = HAIKUAUDIO_CloseDevice;
impl->Deinitialize = HAIKUAUDIO_Deinitialize;
impl->ProvidesOwnCallbackThread = 1;
impl->OnlyHasDefaultOutputDevice = 1;
impl->ProvidesOwnCallbackThread = SDL_TRUE;
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
extern "C"
@@ -240,7 +236,7 @@ extern "C"
extern AudioBootStrap HAIKUAUDIO_bootstrap;
}
AudioBootStrap HAIKUAUDIO_bootstrap = {
"haiku", "Haiku BSoundPlayer", HAIKUAUDIO_Init, 0
"haiku", "Haiku BSoundPlayer", HAIKUAUDIO_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_HAIKU */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+9 -9
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -18,12 +18,10 @@
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#if SDL_AUDIO_DRIVER_JACK
#include "SDL_assert.h"
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
@@ -278,15 +276,17 @@ JACK_CloseDevice(_THIS)
}
SDL_free(this->hidden->iobuffer);
SDL_free(this->hidden);
}
static int
JACK_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
JACK_OpenDevice(_THIS, const char *devname)
{
/* Note that JACK uses "output" for capture devices (they output audio
data to us) and "input" for playback (we input audio data to them).
Likewise, SDL's playback port will be "output" (we write data out)
and capture will be "input" (we read data in). */
SDL_bool iscapture = this->iscapture;
const unsigned long sysportflags = iscapture ? JackPortIsOutput : JackPortIsInput;
const unsigned long sdlportflags = iscapture ? JackPortIsInput : JackPortIsOutput;
const JackProcessCallback callback = iscapture ? jackProcessCaptureCallback : jackProcessPlaybackCallback;
@@ -406,18 +406,18 @@ JACK_Deinitialize(void)
UnloadJackLibrary();
}
static int
static SDL_bool
JACK_Init(SDL_AudioDriverImpl * impl)
{
if (LoadJackLibrary() < 0) {
return 0;
return SDL_FALSE;
} else {
/* 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) {
UnloadJackLibrary();
return 0;
return SDL_FALSE;
}
JACK_jack_client_close(client);
}
@@ -434,11 +434,11 @@ JACK_Init(SDL_AudioDriverImpl * impl)
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap JACK_bootstrap = {
"jack", "JACK Audio Connection Kit", JACK_Init, 0
"jack", "JACK Audio Connection Kit", JACK_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_JACK */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+8 -8
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -99,7 +99,7 @@ static void NACLAUDIO_CloseDevice(SDL_AudioDevice *device) {
}
static int
NACLAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) {
NACLAUDIO_OpenDevice(_THIS, const char *devname) {
PP_Instance instance = PSGetInstanceId();
const PPB_Audio *ppb_audio = PSInterfaceAudio();
const PPB_AudioConfig *ppb_audiocfg = PSInterfaceAudioConfig();
@@ -133,18 +133,18 @@ NACLAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) {
return 0;
}
static int
static SDL_bool
NACLAUDIO_Init(SDL_AudioDriverImpl * impl)
{
if (PSGetInstanceId() == 0) {
return 0;
return SDL_FALSE;
}
/* Set the function pointers */
impl->OpenDevice = NACLAUDIO_OpenDevice;
impl->CloseDevice = NACLAUDIO_CloseDevice;
impl->OnlyHasDefaultOutputDevice = 1;
impl->ProvidesOwnCallbackThread = 1;
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
impl->ProvidesOwnCallbackThread = SDL_TRUE;
/*
* impl->WaitDevice = NACLAUDIO_WaitDevice;
* impl->GetDeviceBuf = NACLAUDIO_GetDeviceBuf;
@@ -152,12 +152,12 @@ NACLAUDIO_Init(SDL_AudioDriverImpl * impl)
* impl->Deinitialize = NACLAUDIO_Deinitialize;
*/
return 1;
return SDL_TRUE;
}
AudioBootStrap NACLAUDIO_bootstrap = {
NACLAUDIO_DRIVER_NAME, "SDL NaCl Audio Driver",
NACLAUDIO_Init, 0
NACLAUDIO_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_NACL */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+39 -41
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -113,11 +113,11 @@ LoadNASLibrary(void)
/* Copy error string so we can use it in a new SDL_SetError(). */
const char *origerr = SDL_GetError();
const size_t len = SDL_strlen(origerr) + 1;
char *err = (char *) alloca(len);
char *err = SDL_stack_alloc(char, len);
SDL_strlcpy(err, origerr, len);
SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s", nas_library, err);
SDL_stack_free(err);
retval = -1;
SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s",
nas_library, err);
} else {
retval = load_nas_syms();
if (retval < 0) {
@@ -237,26 +237,6 @@ NAS_CloseDevice(_THIS)
SDL_free(this->hidden);
}
static unsigned char
sdlformat_to_auformat(unsigned int fmt)
{
switch (fmt) {
case AUDIO_U8:
return AuFormatLinearUnsigned8;
case AUDIO_S8:
return AuFormatLinearSigned8;
case AUDIO_U16LSB:
return AuFormatLinearUnsigned16LSB;
case AUDIO_U16MSB:
return AuFormatLinearUnsigned16MSB;
case AUDIO_S16LSB:
return AuFormatLinearSigned16LSB;
case AUDIO_S16MSB:
return AuFormatLinearSigned16MSB;
}
return AuNone;
}
static AuBool
event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
{
@@ -331,11 +311,12 @@ find_device(_THIS)
}
static int
NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
NAS_OpenDevice(_THIS, const char *devname)
{
AuElement elms[3];
int buffer_size;
SDL_AudioFormat test_format, format;
SDL_bool iscapture = this->iscapture;
SDL_AudioFormat test_format, format = 0;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
@@ -346,16 +327,33 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SDL_zerop(this->hidden);
/* Try for a closest match on audio format */
format = 0;
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!format && test_format;) {
format = sdlformat_to_auformat(test_format);
if (format == AuNone) {
test_format = SDL_NextAudioFormat();
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
switch (test_format) {
case AUDIO_U8:
format = AuFormatLinearUnsigned8;
break;
case AUDIO_S8:
format = AuFormatLinearSigned8;
break;
case AUDIO_U16LSB:
format = AuFormatLinearUnsigned16LSB;
break;
case AUDIO_U16MSB:
format = AuFormatLinearUnsigned16MSB;
break;
case AUDIO_S16LSB:
format = AuFormatLinearSigned16LSB;
break;
case AUDIO_S16MSB:
format = AuFormatLinearSigned16MSB;
break;
default:
continue;
}
break;
}
if (format == 0) {
return SDL_SetError("NAS: Couldn't find any hardware audio formats");
if (!test_format) {
return SDL_SetError("%s: Unsupported audio format", "nas");
}
this->spec.format = test_format;
@@ -423,16 +421,16 @@ NAS_Deinitialize(void)
UnloadNASLibrary();
}
static int
static SDL_bool
NAS_Init(SDL_AudioDriverImpl * impl)
{
if (LoadNASLibrary() < 0) {
return 0;
return SDL_FALSE;
} else {
AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
if (aud == NULL) {
SDL_SetError("NAS: AuOpenServer() failed (no audio server?)");
return 0;
return SDL_FALSE;
}
NAS_AuCloseServer(aud);
}
@@ -447,15 +445,15 @@ NAS_Init(SDL_AudioDriverImpl * impl)
impl->CloseDevice = NAS_CloseDevice;
impl->Deinitialize = NAS_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1;
impl->OnlyHasDefaultCaptureDevice = 1;
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap NAS_bootstrap = {
"nas", "Network Audio System", NAS_Init, 0
"nas", "Network Audio System", NAS_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_NAS */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+87 -151
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -24,7 +24,7 @@
/*
* Driver for native NetBSD audio(4).
* vedge@vedge.com.ar.
* nia@NetBSD.org
*/
#include <errno.h>
@@ -43,12 +43,7 @@
#include "../SDL_audiodev_c.h"
#include "SDL_netbsdaudio.h"
/* Use timer for synchronization */
/* #define USE_TIMER_SYNC */
/* #define DEBUG_AUDIO */
/* #define DEBUG_AUDIO_STREAM */
static void
NETBSDAUDIO_DetectDevices(void)
@@ -63,14 +58,14 @@ NETBSDAUDIO_Status(_THIS)
#ifdef DEBUG_AUDIO
/* *INDENT-OFF* */
audio_info_t info;
const audio_prinfo *prinfo;
const struct audio_prinfo *prinfo;
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
fprintf(stderr, "AUDIO_GETINFO failed.\n");
return;
}
prinfo = this->iscapture ? &info.play : &info.record;
prinfo = this->iscapture ? &info.record : &info.play;
fprintf(stderr, "\n"
"[%s info]\n"
@@ -115,90 +110,37 @@ NETBSDAUDIO_Status(_THIS)
(info.mode == AUMODE_PLAY) ? "PLAY"
: (info.mode = AUMODE_RECORD) ? "RECORD"
: (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL" : "?"));
fprintf(stderr, "\n"
"[audio spec]\n"
"format : 0x%x\n"
"size : %u\n"
"",
this->spec.format,
this->spec.size);
/* *INDENT-ON* */
#endif /* DEBUG_AUDIO */
}
/* This function waits until it is possible to write a full sound buffer */
static void
NETBSDAUDIO_WaitDevice(_THIS)
{
#ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */
/* See if we need to use timed audio synchronization */
if (this->hidden->frame_ticks) {
/* Use timer for general audio synchronization */
Sint32 ticks;
ticks = ((Sint32) (this->hidden->next_frame - SDL_GetTicks())) - FUDGE_TICKS;
if (ticks > 0) {
SDL_Delay(ticks);
}
} else {
/* Use SDL_IOReady() for audio synchronization */
#ifdef DEBUG_AUDIO
fprintf(stderr, "Waiting for audio to get ready\n");
#endif
if (SDL_IOReady(this->hidden->audio_fd, SDL_TRUE, 10 * 1000)
<= 0) {
const char *message =
"Audio timeout - buggy audio driver? (disabled)";
/* In general we should never print to the screen,
but in this case we have no other way of letting
the user know what happened.
*/
fprintf(stderr, "SDL: %s\n", message);
SDL_OpenedAudioDeviceDisconnected(this);
/* Don't try to close - may hang */
this->hidden->audio_fd = -1;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Done disabling audio\n");
#endif
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Ready!\n");
#endif
}
#endif /* !USE_BLOCKING_WRITES */
}
static void
NETBSDAUDIO_PlayDevice(_THIS)
{
int written, p = 0;
struct SDL_PrivateAudioData *h = this->hidden;
int written;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
written = write(this->hidden->audio_fd,
&this->hidden->mixbuf[p], this->hidden->mixlen - p);
if (written > 0)
p += written;
if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) {
/* Non recoverable error has occurred. It should be reported!!! */
perror("audio");
break;
}
/* Write the audio data */
written = write(h->audio_fd, h->mixbuf, h->mixlen);
if (written == -1) {
/* Non recoverable error has occurred. It should be reported!!! */
SDL_OpenedAudioDeviceDisconnected(this);
perror("audio");
return;
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
if (p < this->hidden->mixlen
|| ((written < 0) && ((errno == 0) || (errno == EAGAIN)))) {
SDL_Delay(1); /* Let a little CPU time go by */
}
} while (p < this->hidden->mixlen);
/* If timer synchronization is enabled, set the next write frame */
if (this->hidden->frame_ticks) {
this->hidden->next_frame += this->hidden->frame_ticks;
}
/* If we couldn't write, assume fatal error for now */
if (written < 0) {
SDL_OpenedAudioDeviceDisconnected(this);
}
}
static Uint8 *
@@ -212,28 +154,19 @@ static int
NETBSDAUDIO_CaptureFromDevice(_THIS, void *_buffer, int buflen)
{
Uint8 *buffer = (Uint8 *) _buffer;
int br, p = 0;
int br;
/* Capture the audio data, checking for EAGAIN on broken audio drivers */
do {
br = read(this->hidden->audio_fd, buffer + p, buflen - p);
if (br > 0)
p += br;
if (br == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) {
/* Non recoverable error has occurred. It should be reported!!! */
perror("audio");
return p ? p : -1;
}
br = read(this->hidden->audio_fd, buffer, buflen);
if (br == -1) {
/* Non recoverable error has occurred. It should be reported!!! */
perror("audio");
return -1;
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Captured %d bytes of audio data\n", br);
fprintf(stderr, "Captured %d bytes of audio data\n", br);
#endif
if (p < buflen
|| ((br < 0) && ((errno == 0) || (errno == EAGAIN)))) {
SDL_Delay(1); /* Let a little CPU time go by */
}
} while (p < buflen);
return 0;
}
static void
@@ -269,12 +202,13 @@ NETBSDAUDIO_CloseDevice(_THIS)
}
static int
NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
NETBSDAUDIO_OpenDevice(_THIS, const char *devname)
{
const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT;
SDL_AudioFormat format = 0;
audio_info_t info;
audio_prinfo *prinfo = iscapture ? &info.play : &info.record;
SDL_bool iscapture = this->iscapture;
SDL_AudioFormat test_format;
int encoding = AUDIO_ENCODING_NONE;
audio_info_t info, hwinfo;
struct audio_prinfo *prinfo = iscapture ? &info.record : &info.play;
/* We don't care what the devname is...we'll try to open anything. */
/* ...but default to first name in the list... */
@@ -294,78 +228,81 @@ NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SDL_zerop(this->hidden);
/* Open the audio device */
this->hidden->audio_fd = open(devname, flags, 0);
this->hidden->audio_fd = open(devname, (iscapture ? O_RDONLY : O_WRONLY) | O_CLOEXEC);
if (this->hidden->audio_fd < 0) {
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
}
AUDIO_INITINFO(&info);
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&this->spec);
/* Set to play mode */
info.mode = iscapture ? AUMODE_RECORD : AUMODE_PLAY;
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
return SDL_SetError("Couldn't put device into play mode");
#ifdef AUDIO_GETFORMAT /* Introduced in NetBSD 9.0 */
if (ioctl(this->hidden->audio_fd, AUDIO_GETFORMAT, &hwinfo) != -1) {
/*
* Use the device's native sample rate so the kernel doesn't have to
* resample.
*/
this->spec.freq = iscapture ?
hwinfo.record.sample_rate : hwinfo.play.sample_rate;
}
#endif
AUDIO_INITINFO(&info);
for (format = SDL_FirstAudioFormat(this->spec.format);
format; format = SDL_NextAudioFormat()) {
switch (format) {
prinfo->sample_rate = this->spec.freq;
prinfo->channels = this->spec.channels;
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
switch (test_format) {
case AUDIO_U8:
prinfo->encoding = AUDIO_ENCODING_ULINEAR;
prinfo->precision = 8;
encoding = AUDIO_ENCODING_ULINEAR;
break;
case AUDIO_S8:
prinfo->encoding = AUDIO_ENCODING_SLINEAR;
prinfo->precision = 8;
encoding = AUDIO_ENCODING_SLINEAR;
break;
case AUDIO_S16LSB:
prinfo->encoding = AUDIO_ENCODING_SLINEAR_LE;
prinfo->precision = 16;
encoding = AUDIO_ENCODING_SLINEAR_LE;
break;
case AUDIO_S16MSB:
prinfo->encoding = AUDIO_ENCODING_SLINEAR_BE;
prinfo->precision = 16;
encoding = AUDIO_ENCODING_SLINEAR_BE;
break;
case AUDIO_U16LSB:
prinfo->encoding = AUDIO_ENCODING_ULINEAR_LE;
prinfo->precision = 16;
encoding = AUDIO_ENCODING_ULINEAR_LE;
break;
case AUDIO_U16MSB:
prinfo->encoding = AUDIO_ENCODING_ULINEAR_BE;
prinfo->precision = 16;
encoding = AUDIO_ENCODING_ULINEAR_BE;
break;
case AUDIO_S32LSB:
encoding = AUDIO_ENCODING_SLINEAR_LE;
break;
case AUDIO_S32MSB:
encoding = AUDIO_ENCODING_SLINEAR_BE;
break;
default:
continue;
}
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == 0) {
break;
}
break;
}
if (!format) {
return SDL_SetError("No supported encoding for 0x%x", this->spec.format);
if (!test_format) {
return SDL_SetError("%s: Unsupported audio format", "netbsd");
}
prinfo->encoding = encoding;
prinfo->precision = SDL_AUDIO_BITSIZE(test_format);
this->spec.format = format;
AUDIO_INITINFO(&info);
prinfo->channels = this->spec.channels;
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) {
this->spec.channels = 1;
}
AUDIO_INITINFO(&info);
prinfo->sample_rate = this->spec.freq;
info.blocksize = this->spec.size;
info.hiwat = 5;
info.lowat = 3;
(void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info);
(void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info);
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
return SDL_SetError("AUDIO_SETINFO failed for %s: %s", devname, strerror(errno));
}
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
return SDL_SetError("AUDIO_GETINFO failed for %s: %s", devname, strerror(errno));
}
/* Final spec used for the device. */
this->spec.format = test_format;
this->spec.freq = prinfo->sample_rate;
this->spec.channels = prinfo->channels;
SDL_CalculateAudioSpec(&this->spec);
if (!iscapture) {
/* Allocate mixing buffer */
@@ -383,28 +320,27 @@ NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
return 0;
}
static int
static SDL_bool
NETBSDAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->DetectDevices = NETBSDAUDIO_DetectDevices;
impl->OpenDevice = NETBSDAUDIO_OpenDevice;
impl->PlayDevice = NETBSDAUDIO_PlayDevice;
impl->WaitDevice = NETBSDAUDIO_WaitDevice;
impl->GetDeviceBuf = NETBSDAUDIO_GetDeviceBuf;
impl->CloseDevice = NETBSDAUDIO_CloseDevice;
impl->CaptureFromDevice = NETBSDAUDIO_CaptureFromDevice;
impl->FlushCapture = NETBSDAUDIO_FlushCapture;
impl->HasCaptureSupport = SDL_TRUE;
impl->AllowsArbitraryDeviceNames = 1;
impl->AllowsArbitraryDeviceNames = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap NETBSDAUDIO_bootstrap = {
"netbsd", "NetBSD audio", NETBSDAUDIO_Init, 0
"netbsd", "NetBSD audio", NETBSDAUDIO_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_NETBSD */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+789
View File
@@ -0,0 +1,789 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
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"
#if SDL_AUDIO_DRIVER_OPENSLES
/* For more discussion of low latency audio on Android, see this:
https://googlesamples.github.io/android-audio-high-performance/guides/opensl_es.html
*/
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../../core/android/SDL_android.h"
#include "SDL_openslES.h"
/* for native audio */
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include <android/log.h>
#if 0
#define LOG_TAG "SDL_openslES"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
//#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__)
#define LOGV(...)
#else
#define LOGE(...)
#define LOGI(...)
#define LOGV(...)
#endif
/*
#define SL_SPEAKER_FRONT_LEFT ((SLuint32) 0x00000001)
#define SL_SPEAKER_FRONT_RIGHT ((SLuint32) 0x00000002)
#define SL_SPEAKER_FRONT_CENTER ((SLuint32) 0x00000004)
#define SL_SPEAKER_LOW_FREQUENCY ((SLuint32) 0x00000008)
#define SL_SPEAKER_BACK_LEFT ((SLuint32) 0x00000010)
#define SL_SPEAKER_BACK_RIGHT ((SLuint32) 0x00000020)
#define SL_SPEAKER_FRONT_LEFT_OF_CENTER ((SLuint32) 0x00000040)
#define SL_SPEAKER_FRONT_RIGHT_OF_CENTER ((SLuint32) 0x00000080)
#define SL_SPEAKER_BACK_CENTER ((SLuint32) 0x00000100)
#define SL_SPEAKER_SIDE_LEFT ((SLuint32) 0x00000200)
#define SL_SPEAKER_SIDE_RIGHT ((SLuint32) 0x00000400)
#define SL_SPEAKER_TOP_CENTER ((SLuint32) 0x00000800)
#define SL_SPEAKER_TOP_FRONT_LEFT ((SLuint32) 0x00001000)
#define SL_SPEAKER_TOP_FRONT_CENTER ((SLuint32) 0x00002000)
#define SL_SPEAKER_TOP_FRONT_RIGHT ((SLuint32) 0x00004000)
#define SL_SPEAKER_TOP_BACK_LEFT ((SLuint32) 0x00008000)
#define SL_SPEAKER_TOP_BACK_CENTER ((SLuint32) 0x00010000)
#define SL_SPEAKER_TOP_BACK_RIGHT ((SLuint32) 0x00020000)
*/
#define SL_ANDROID_SPEAKER_STEREO (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT)
#define SL_ANDROID_SPEAKER_QUAD (SL_ANDROID_SPEAKER_STEREO | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT)
#define SL_ANDROID_SPEAKER_5DOT1 (SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY)
#define SL_ANDROID_SPEAKER_7DOT1 (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT)
/* engine interfaces */
static SLObjectItf engineObject = NULL;
static SLEngineItf engineEngine = NULL;
/* output mix interfaces */
static SLObjectItf outputMixObject = NULL;
/* buffer queue player interfaces */
static SLObjectItf bqPlayerObject = NULL;
static SLPlayItf bqPlayerPlay = NULL;
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue = NULL;
#if 0
static SLVolumeItf bqPlayerVolume;
#endif
/* recorder interfaces */
static SLObjectItf recorderObject = NULL;
static SLRecordItf recorderRecord = NULL;
static SLAndroidSimpleBufferQueueItf recorderBufferQueue = NULL;
#if 0
static const char *sldevaudiorecorderstr = "SLES Audio Recorder";
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 )
{
LOGI( "openSLES_DetectDevices()" );
if ( iscapture )
addfn( SLES_DEV_AUDIO_RECORDER );
else
addfn( SLES_DEV_AUDIO_PLAYER );
}
#endif
static void openslES_DestroyEngine(void)
{
LOGI("openslES_DestroyEngine()");
/* destroy output mix object, and invalidate all associated interfaces */
if (outputMixObject != NULL) {
(*outputMixObject)->Destroy(outputMixObject);
outputMixObject = NULL;
}
/* destroy engine object, and invalidate all associated interfaces */
if (engineObject != NULL) {
(*engineObject)->Destroy(engineObject);
engineObject = NULL;
engineEngine = NULL;
}
}
static int
openslES_CreateEngine(void)
{
SLresult result;
LOGI("openSLES_CreateEngine()");
/* create engine */
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
if (SL_RESULT_SUCCESS != result) {
LOGE("slCreateEngine failed: %d", result);
goto error;
}
LOGI("slCreateEngine OK");
/* realize the engine */
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
if (SL_RESULT_SUCCESS != result) {
LOGE("RealizeEngine failed: %d", result);
goto error;
}
LOGI("RealizeEngine OK");
/* get the engine interface, which is needed in order to create other objects */
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
if (SL_RESULT_SUCCESS != result) {
LOGE("EngineGetInterface failed: %d", result);
goto error;
}
LOGI("EngineGetInterface OK");
/* create output mix */
const SLInterfaceID ids[1] = { SL_IID_VOLUME };
const SLboolean req[1] = { SL_BOOLEAN_FALSE };
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);
if (SL_RESULT_SUCCESS != result) {
LOGE("CreateOutputMix failed: %d", result);
goto error;
}
LOGI("CreateOutputMix OK");
/* realize the output mix */
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
if (SL_RESULT_SUCCESS != result) {
LOGE("RealizeOutputMix failed: %d", result);
goto error;
}
return 1;
error:
openslES_DestroyEngine();
return 0;
}
/* this callback handler is called every time a buffer finishes recording */
static void
bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) context;
LOGV("SLES: Recording Callback");
SDL_SemPost(audiodata->playsem);
}
static void
openslES_DestroyPCMRecorder(_THIS)
{
struct SDL_PrivateAudioData *audiodata = this->hidden;
SLresult result;
/* stop recording */
if (recorderRecord != NULL) {
result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
if (SL_RESULT_SUCCESS != result) {
LOGE("SetRecordState stopped: %d", result);
}
}
/* destroy audio recorder object, and invalidate all associated interfaces */
if (recorderObject != NULL) {
(*recorderObject)->Destroy(recorderObject);
recorderObject = NULL;
recorderRecord = NULL;
recorderBufferQueue = NULL;
}
if (audiodata->playsem) {
SDL_DestroySemaphore(audiodata->playsem);
audiodata->playsem = NULL;
}
if (audiodata->mixbuff) {
SDL_free(audiodata->mixbuff);
}
}
static int
openslES_CreatePCMRecorder(_THIS)
{
struct SDL_PrivateAudioData *audiodata = this->hidden;
SLDataFormat_PCM format_pcm;
SLresult result;
int i;
if (!Android_JNI_RequestPermission("android.permission.RECORD_AUDIO")) {
LOGE("This app doesn't have RECORD_AUDIO permission");
return SDL_SetError("This app doesn't have RECORD_AUDIO permission");
}
/* Just go with signed 16-bit audio as it's the most compatible */
this->spec.format = AUDIO_S16SYS;
this->spec.channels = 1;
/*this->spec.freq = SL_SAMPLINGRATE_16 / 1000;*/
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(&this->spec);
LOGI("Try to open %u hz %u bit chan %u %s samples %u",
this->spec.freq, SDL_AUDIO_BITSIZE(this->spec.format),
this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples);
/* configure audio source */
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
SLDataSource audioSrc = {&loc_dev, NULL};
/* configure audio sink */
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, NUM_BUFFERS };
format_pcm.formatType = SL_DATAFORMAT_PCM;
format_pcm.numChannels = this->spec.channels;
format_pcm.samplesPerSec = this->spec.freq * 1000; /* / kilo Hz to milli Hz */
format_pcm.bitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
format_pcm.containerSize = SDL_AUDIO_BITSIZE(this->spec.format);
format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
format_pcm.channelMask = SL_SPEAKER_FRONT_CENTER;
SLDataSink audioSnk = { &loc_bufq, &format_pcm };
/* create audio recorder */
/* (requires the RECORD_AUDIO permission) */
const SLInterfaceID ids[1] = {
SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
};
const SLboolean req[1] = {
SL_BOOLEAN_TRUE,
};
result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audioSrc, &audioSnk, 1, ids, req);
if (SL_RESULT_SUCCESS != result) {
LOGE("CreateAudioRecorder failed: %d", result);
goto failed;
}
/* realize the recorder */
result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
if (SL_RESULT_SUCCESS != result) {
LOGE("RealizeAudioPlayer failed: %d", result);
goto failed;
}
/* get the record interface */
result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord);
if (SL_RESULT_SUCCESS != result) {
LOGE("SL_IID_RECORD interface get failed: %d", result);
goto failed;
}
/* get the buffer queue interface */
result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recorderBufferQueue);
if (SL_RESULT_SUCCESS != result) {
LOGE("SL_IID_BUFFERQUEUE interface get failed: %d", result);
goto failed;
}
/* register callback on the buffer queue */
/* context is '(SDL_PrivateAudioData *)this->hidden' */
result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback, this->hidden);
if (SL_RESULT_SUCCESS != result) {
LOGE("RegisterCallback failed: %d", result);
goto failed;
}
/* Create the audio buffer semaphore */
audiodata->playsem = SDL_CreateSemaphore(0);
if (!audiodata->playsem) {
LOGE("cannot create Semaphore!");
goto failed;
}
/* Create the sound buffers */
audiodata->mixbuff = (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
if (audiodata->mixbuff == NULL) {
LOGE("mixbuffer allocate - out of memory");
goto failed;
}
for (i = 0; i < NUM_BUFFERS; i++) {
audiodata->pmixbuff[i] = audiodata->mixbuff + i * this->spec.size;
}
/* in case already recording, stop recording and clear buffer queue */
result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
if (SL_RESULT_SUCCESS != result) {
LOGE("Record set state failed: %d", result);
goto failed;
}
/* enqueue empty buffers to be filled by the recorder */
for (i = 0; i < NUM_BUFFERS; i++) {
result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[i], this->spec.size);
if (SL_RESULT_SUCCESS != result) {
LOGE("Record enqueue buffers failed: %d", result);
goto failed;
}
}
/* start recording */
result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
if (SL_RESULT_SUCCESS != result) {
LOGE("Record set state failed: %d", result);
goto failed;
}
return 0;
failed:
return SDL_SetError("Open device failed!");
}
/* this callback handler is called every time a buffer finishes playing */
static void
bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) context;
LOGV("SLES: Playback Callback");
SDL_SemPost(audiodata->playsem);
}
static void
openslES_DestroyPCMPlayer(_THIS)
{
struct SDL_PrivateAudioData *audiodata = this->hidden;
SLresult result;
/* set the player's state to 'stopped' */
if (bqPlayerPlay != NULL) {
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED);
if (SL_RESULT_SUCCESS != result) {
LOGE("SetPlayState stopped failed: %d", result);
}
}
/* destroy buffer queue audio player object, and invalidate all associated interfaces */
if (bqPlayerObject != NULL) {
(*bqPlayerObject)->Destroy(bqPlayerObject);
bqPlayerObject = NULL;
bqPlayerPlay = NULL;
bqPlayerBufferQueue = NULL;
}
if (audiodata->playsem) {
SDL_DestroySemaphore(audiodata->playsem);
audiodata->playsem = NULL;
}
if (audiodata->mixbuff) {
SDL_free(audiodata->mixbuff);
}
}
static int
openslES_CreatePCMPlayer(_THIS)
{
struct SDL_PrivateAudioData *audiodata = this->hidden;
SLDataFormat_PCM format_pcm;
SLAndroidDataFormat_PCM_EX format_pcm_ex;
SLresult result;
int i;
/* If we want to add floating point audio support (requires API level 21)
it can be done as described here:
https://developer.android.com/ndk/guides/audio/opensl/android-extensions.html#floating-point
*/
if(SDL_GetAndroidSDKVersion() >= 21) {
SDL_AudioFormat test_format;
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
if (SDL_AUDIO_ISSIGNED(test_format)) {
break;
}
}
if (!test_format) {
/* Didn't find a compatible format : */
LOGI( "No compatible audio format, using signed 16-bit audio" );
test_format = AUDIO_S16SYS;
}
this->spec.format = test_format;
} else {
/* Just go with signed 16-bit audio as it's the most compatible */
this->spec.format = AUDIO_S16SYS;
}
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(&this->spec);
LOGI("Try to open %u hz %s %u bit chan %u %s samples %u",
this->spec.freq, SDL_AUDIO_ISFLOAT(this->spec.format) ? "float" : "pcm", SDL_AUDIO_BITSIZE(this->spec.format),
this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples);
/* configure audio source */
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, NUM_BUFFERS };
format_pcm.formatType = SL_DATAFORMAT_PCM;
format_pcm.numChannels = this->spec.channels;
format_pcm.samplesPerSec = this->spec.freq * 1000; /* / kilo Hz to milli Hz */
format_pcm.bitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
format_pcm.containerSize = SDL_AUDIO_BITSIZE(this->spec.format);
if (SDL_AUDIO_ISBIGENDIAN(this->spec.format)) {
format_pcm.endianness = SL_BYTEORDER_BIGENDIAN;
} else {
format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
}
switch (this->spec.channels)
{
case 1:
format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT;
break;
case 2:
format_pcm.channelMask = SL_ANDROID_SPEAKER_STEREO;
break;
case 3:
format_pcm.channelMask = SL_ANDROID_SPEAKER_STEREO | SL_SPEAKER_FRONT_CENTER;
break;
case 4:
format_pcm.channelMask = SL_ANDROID_SPEAKER_QUAD;
break;
case 5:
format_pcm.channelMask = SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER;
break;
case 6:
format_pcm.channelMask = SL_ANDROID_SPEAKER_5DOT1;
break;
case 7:
format_pcm.channelMask = SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_BACK_CENTER;
break;
case 8:
format_pcm.channelMask = SL_ANDROID_SPEAKER_7DOT1;
break;
default:
/* Unknown number of channels, fall back to stereo */
this->spec.channels = 2;
format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
break;
}
if(SDL_AUDIO_ISFLOAT(this->spec.format)) {
/* Copy all setup into PCM EX structure */
format_pcm_ex.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
format_pcm_ex.endianness = format_pcm.endianness;
format_pcm_ex.channelMask = format_pcm.channelMask;
format_pcm_ex.numChannels = format_pcm.numChannels;
format_pcm_ex.sampleRate = format_pcm.samplesPerSec;
format_pcm_ex.bitsPerSample = format_pcm.bitsPerSample;
format_pcm_ex.containerSize = format_pcm.containerSize;
format_pcm_ex.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
}
SLDataSource audioSrc = { &loc_bufq, SDL_AUDIO_ISFLOAT(this->spec.format) ? (void*)&format_pcm_ex : (void*)&format_pcm };
/* configure audio sink */
SLDataLocator_OutputMix loc_outmix = { SL_DATALOCATOR_OUTPUTMIX, outputMixObject };
SLDataSink audioSnk = { &loc_outmix, NULL };
/* create audio player */
const SLInterfaceID ids[2] = {
SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
SL_IID_VOLUME
};
const SLboolean req[2] = {
SL_BOOLEAN_TRUE,
SL_BOOLEAN_FALSE,
};
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req);
if (SL_RESULT_SUCCESS != result) {
LOGE("CreateAudioPlayer failed: %d", result);
goto failed;
}
/* realize the player */
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
if (SL_RESULT_SUCCESS != result) {
LOGE("RealizeAudioPlayer failed: %d", result);
goto failed;
}
/* get the play interface */
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
if (SL_RESULT_SUCCESS != result) {
LOGE("SL_IID_PLAY interface get failed: %d", result);
goto failed;
}
/* get the buffer queue interface */
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bqPlayerBufferQueue);
if (SL_RESULT_SUCCESS != result) {
LOGE("SL_IID_BUFFERQUEUE interface get failed: %d", result);
goto failed;
}
/* register callback on the buffer queue */
/* context is '(SDL_PrivateAudioData *)this->hidden' */
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, this->hidden);
if (SL_RESULT_SUCCESS != result) {
LOGE("RegisterCallback failed: %d", result);
goto failed;
}
#if 0
/* get the volume interface */
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
if (SL_RESULT_SUCCESS != result) {
LOGE("SL_IID_VOLUME interface get failed: %d", result);
/* goto failed; */
}
#endif
/* Create the audio buffer semaphore */
audiodata->playsem = SDL_CreateSemaphore(NUM_BUFFERS - 1);
if (!audiodata->playsem) {
LOGE("cannot create Semaphore!");
goto failed;
}
/* Create the sound buffers */
audiodata->mixbuff = (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
if (audiodata->mixbuff == NULL) {
LOGE("mixbuffer allocate - out of memory");
goto failed;
}
for (i = 0; i < NUM_BUFFERS; i++) {
audiodata->pmixbuff[i] = audiodata->mixbuff + i * this->spec.size;
}
/* set the player's state to playing */
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
if (SL_RESULT_SUCCESS != result) {
LOGE("Play set state failed: %d", result);
goto failed;
}
return 0;
failed:
return -1;
}
static int
openslES_OpenDevice(_THIS, const char *devname)
{
this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *this->hidden));
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
if (this->iscapture) {
LOGI("openslES_OpenDevice() %s for capture", devname);
return openslES_CreatePCMRecorder(this);
} else {
int ret;
LOGI("openslES_OpenDevice() %s for playing", devname);
ret = openslES_CreatePCMPlayer(this);
if (ret < 0) {
/* Another attempt to open the device with a lower frequency */
if (this->spec.freq > 48000) {
openslES_DestroyPCMPlayer(this);
this->spec.freq = 48000;
ret = openslES_CreatePCMPlayer(this);
}
}
if (ret == 0) {
return 0;
} else {
return SDL_SetError("Open device failed!");
}
}
}
static void
openslES_WaitDevice(_THIS)
{
struct SDL_PrivateAudioData *audiodata = this->hidden;
LOGV("openslES_WaitDevice()");
/* Wait for an audio chunk to finish */
SDL_SemWait(audiodata->playsem);
}
static void
openslES_PlayDevice(_THIS)
{
struct SDL_PrivateAudioData *audiodata = this->hidden;
SLresult result;
LOGV("======openslES_PlayDevice()======");
/* Queue it up */
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
audiodata->next_buffer++;
if (audiodata->next_buffer >= NUM_BUFFERS) {
audiodata->next_buffer = 0;
}
/* If Enqueue fails, callback won't be called.
* Post the semphore, not to run out of buffer */
if (SL_RESULT_SUCCESS != result) {
SDL_SemPost(audiodata->playsem);
}
}
/*/ n playn sem */
/* getbuf 0 - 1 */
/* fill buff 0 - 1 */
/* play 0 - 0 1 */
/* wait 1 0 0 */
/* getbuf 1 0 0 */
/* fill buff 1 0 0 */
/* play 0 0 0 */
/* wait */
/* */
/* okay.. */
static Uint8 *
openslES_GetDeviceBuf(_THIS)
{
struct SDL_PrivateAudioData *audiodata = this->hidden;
LOGV("openslES_GetDeviceBuf()");
return audiodata->pmixbuff[audiodata->next_buffer];
}
static int
openslES_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
struct SDL_PrivateAudioData *audiodata = this->hidden;
SLresult result;
/* Wait for new recorded data */
SDL_SemWait(audiodata->playsem);
/* Copy it to the output buffer */
SDL_assert(buflen == this->spec.size);
SDL_memcpy(buffer, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
/* Re-enqueue the buffer */
result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
if (SL_RESULT_SUCCESS != result) {
LOGE("Record enqueue buffers failed: %d", result);
return -1;
}
audiodata->next_buffer++;
if (audiodata->next_buffer >= NUM_BUFFERS) {
audiodata->next_buffer = 0;
}
return this->spec.size;
}
static void
openslES_CloseDevice(_THIS)
{
/* struct SDL_PrivateAudioData *audiodata = this->hidden; */
if (this->iscapture) {
LOGI("openslES_CloseDevice() for capture");
openslES_DestroyPCMRecorder(this);
} else {
LOGI("openslES_CloseDevice() for playing");
openslES_DestroyPCMPlayer(this);
}
SDL_free(this->hidden);
}
static SDL_bool
openslES_Init(SDL_AudioDriverImpl * impl)
{
LOGI("openslES_Init() called");
if (!openslES_CreateEngine()) {
return SDL_FALSE;
}
LOGI("openslES_Init() - set pointers");
/* Set the function pointers */
/* impl->DetectDevices = openslES_DetectDevices; */
impl->OpenDevice = openslES_OpenDevice;
impl->WaitDevice = openslES_WaitDevice;
impl->PlayDevice = openslES_PlayDevice;
impl->GetDeviceBuf = openslES_GetDeviceBuf;
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");
/* this audio target is available. */
return SDL_TRUE;
}
AudioBootStrap openslES_bootstrap = {
"openslES", "opensl ES audio driver", openslES_Init, SDL_FALSE
};
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);
}
}
}
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);
}
}
}
#endif /* SDL_AUDIO_DRIVER_OPENSLES */
/* vi: set ts=4 sw=4 expandtab: */
+46
View File
@@ -0,0 +1,46 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
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_openslesaudio_h
#define _SDL_openslesaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
#define NUM_BUFFERS 2 /* -- Don't lower this! */
struct SDL_PrivateAudioData
{
Uint8 *mixbuff;
int next_buffer;
Uint8 *pmixbuff[NUM_BUFFERS];
SDL_sem *playsem;
};
void openslES_ResumeDevices(void);
void openslES_PauseDevices(void);
#endif /* _SDL_openslesaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
+450
View File
@@ -0,0 +1,450 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
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"
#if SDL_AUDIO_DRIVER_OS2
/* Allow access to a raw mixing buffer */
#include "../../core/os2/SDL_os2.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "SDL_os2audio.h"
/*
void lockIncr(volatile int *piVal);
#pragma aux lockIncr = \
"lock add [eax], 1 "\
parm [eax];
void lockDecr(volatile int *piVal);
#pragma aux lockDecr = \
"lock sub [eax], 1 "\
parm [eax];
*/
static ULONG _getEnvULong(const char *name, ULONG ulMax, ULONG ulDefault)
{
ULONG ulValue;
char* end;
char* envval = SDL_getenv(name);
if (envval == NULL)
return ulDefault;
ulValue = SDL_strtoul(envval, &end, 10);
return (end == envval) || (ulValue > ulMax)? ulDefault : ulMax;
}
static int _MCIError(const char *func, ULONG ulResult)
{
CHAR acBuf[128];
mciGetErrorString(ulResult, acBuf, sizeof(acBuf));
return SDL_SetError("[%s] %s", func, acBuf);
}
static void _mixIOError(const char *function, ULONG ulRC)
{
debug_os2("%s() - failed, rc = 0x%X (%s)",
function, ulRC,
(ulRC == MCIERR_INVALID_MODE) ? "Mixer mode does not match request" :
(ulRC == MCIERR_INVALID_BUFFER) ? "Caller sent an invalid buffer" : "unknown");
}
static LONG APIENTRY cbAudioWriteEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer,
ULONG ulFlags)
{
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)pBuffer->ulUserParm;
ULONG ulRC;
if (ulFlags != MIX_WRITE_COMPLETE) {
debug_os2("flags = 0x%X", ulFlags);
return 0;
}
/*lockDecr((int *)&pAData->ulQueuedBuf);*/
ulRC = DosPostEventSem(pAData->hevBuf);
if (ulRC != NO_ERROR && ulRC != ERROR_ALREADY_POSTED) {
debug_os2("DosPostEventSem(), rc = %u", ulRC);
}
return 1; /* return value doesn't seem to matter. */
}
static LONG APIENTRY cbAudioReadEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer,
ULONG ulFlags)
{
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)pBuffer->ulUserParm;
ULONG ulRC;
if (ulFlags != MIX_READ_COMPLETE) {
debug_os2("flags = 0x%X", ulFlags);
return 0;
}
pAData->stMCIMixSetup.pmixRead(pAData->stMCIMixSetup.ulMixHandle, pBuffer, 1);
ulRC = DosPostEventSem(pAData->hevBuf);
if (ulRC != NO_ERROR && ulRC != ERROR_ALREADY_POSTED) {
debug_os2("DosPostEventSem(), rc = %u", ulRC);
}
return 1;
}
static void OS2_DetectDevices(void)
{
MCI_SYSINFO_PARMS stMCISysInfo;
CHAR acBuf[256];
ULONG ulDevicesNum;
MCI_SYSINFO_LOGDEVICE stLogDevice;
MCI_SYSINFO_PARMS stSysInfoParams;
ULONG ulRC;
ULONG ulHandle = 0;
acBuf[0] = '\0';
stMCISysInfo.pszReturn = acBuf;
stMCISysInfo.ulRetSize = sizeof(acBuf);
stMCISysInfo.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX;
ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_QUANTITY,
&stMCISysInfo, 0);
if (ulRC != NO_ERROR) {
debug_os2("MCI_SYSINFO, MCI_SYSINFO_QUANTITY - failed, rc = 0x%X", ulRC);
return;
}
ulDevicesNum = SDL_strtoul(stMCISysInfo.pszReturn, NULL, 10);
for (stSysInfoParams.ulNumber = 0; stSysInfoParams.ulNumber < ulDevicesNum;
stSysInfoParams.ulNumber++) {
/* Get device install name. */
stSysInfoParams.pszReturn = acBuf;
stSysInfoParams.ulRetSize = sizeof(acBuf);
stSysInfoParams.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX;
ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_INSTALLNAME,
&stSysInfoParams, 0);
if (ulRC != NO_ERROR) {
debug_os2("MCI_SYSINFO, MCI_SYSINFO_INSTALLNAME - failed, rc = 0x%X", ulRC);
continue;
}
/* Get textual product description. */
stSysInfoParams.ulItem = MCI_SYSINFO_QUERY_DRIVER;
stSysInfoParams.pSysInfoParm = &stLogDevice;
SDL_strlcpy(stLogDevice.szInstallName, stSysInfoParams.pszReturn, MAX_DEVICE_NAME);
ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_ITEM,
&stSysInfoParams, 0);
if (ulRC != NO_ERROR) {
debug_os2("MCI_SYSINFO, MCI_SYSINFO_ITEM - failed, rc = 0x%X", ulRC);
continue;
}
ulHandle++;
SDL_AddAudioDevice(0, stLogDevice.szProductInfo, NULL, (void *)(ulHandle));
ulHandle++;
SDL_AddAudioDevice(1, stLogDevice.szProductInfo, NULL, (void *)(ulHandle));
}
}
static void OS2_WaitDevice(_THIS)
{
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
ULONG ulRC;
/* Wait for an audio chunk to finish */
ulRC = DosWaitEventSem(pAData->hevBuf, 5000);
if (ulRC != NO_ERROR) {
debug_os2("DosWaitEventSem(), rc = %u", ulRC);
}
}
static Uint8 *OS2_GetDeviceBuf(_THIS)
{
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
return (Uint8 *) pAData->aMixBuffers[pAData->ulNextBuf].pBuffer;
}
static void OS2_PlayDevice(_THIS)
{
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
ULONG ulRC;
PMCI_MIX_BUFFER pMixBuffer = &pAData->aMixBuffers[pAData->ulNextBuf];
/* Queue it up */
/*lockIncr((int *)&pAData->ulQueuedBuf);*/
ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle,
pMixBuffer, 1);
if (ulRC != MCIERR_SUCCESS) {
_mixIOError("pmixWrite", ulRC);
} else {
pAData->ulNextBuf = (pAData->ulNextBuf + 1) % pAData->cMixBuffers;
}
}
static void OS2_CloseDevice(_THIS)
{
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
MCI_GENERIC_PARMS sMCIGenericParms;
ULONG ulRC;
if (pAData == NULL)
return;
/* Close up audio */
if (pAData->usDeviceId != (USHORT)~0) { /* Device is open. */
if (pAData->stMCIMixSetup.ulBitsPerSample != 0) { /* Mixer was initialized. */
ulRC = mciSendCommand(pAData->usDeviceId, MCI_MIXSETUP,
MCI_WAIT | MCI_MIXSETUP_DEINIT,
&pAData->stMCIMixSetup, 0);
if (ulRC != MCIERR_SUCCESS) {
debug_os2("MCI_MIXSETUP, MCI_MIXSETUP_DEINIT - failed");
}
}
if (pAData->cMixBuffers != 0) { /* Buffers was allocated. */
MCI_BUFFER_PARMS stMCIBuffer;
stMCIBuffer.ulBufferSize = pAData->aMixBuffers[0].ulBufferLength;
stMCIBuffer.ulNumBuffers = pAData->cMixBuffers;
stMCIBuffer.pBufList = pAData->aMixBuffers;
ulRC = mciSendCommand(pAData->usDeviceId, MCI_BUFFER,
MCI_WAIT | MCI_DEALLOCATE_MEMORY, &stMCIBuffer, 0);
if (ulRC != MCIERR_SUCCESS) {
debug_os2("MCI_BUFFER, MCI_DEALLOCATE_MEMORY - failed");
}
}
ulRC = mciSendCommand(pAData->usDeviceId, MCI_CLOSE, MCI_WAIT,
&sMCIGenericParms, 0);
if (ulRC != MCIERR_SUCCESS) {
debug_os2("MCI_CLOSE - failed");
}
}
if (pAData->hevBuf != NULLHANDLE)
DosCloseEventSem(pAData->hevBuf);
SDL_free(pAData);
}
static int OS2_OpenDevice(_THIS, const char *devname)
{
SDL_PrivateAudioData *pAData;
SDL_AudioFormat test_format;
MCI_AMP_OPEN_PARMS stMCIAmpOpen;
MCI_BUFFER_PARMS stMCIBuffer;
ULONG ulRC;
ULONG ulIdx;
BOOL new_freq;
SDL_bool iscapture = _this->iscapture;
new_freq = FALSE;
SDL_zero(stMCIAmpOpen);
SDL_zero(stMCIBuffer);
for (test_format = SDL_FirstAudioFormat(_this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
if (test_format == AUDIO_U8 || test_format == AUDIO_S16)
break;
}
if (!test_format) {
debug_os2("Unsupported audio format, AUDIO_S16 used");
test_format = AUDIO_S16;
}
pAData = (SDL_PrivateAudioData *) SDL_calloc(1, sizeof(struct SDL_PrivateAudioData));
if (pAData == NULL)
return SDL_OutOfMemory();
_this->hidden = pAData;
ulRC = DosCreateEventSem(NULL, &pAData->hevBuf, DCE_AUTORESET, TRUE);
if (ulRC != NO_ERROR) {
debug_os2("DosCreateEventSem() failed, rc = %u", ulRC);
return -1;
}
/* Open audio device */
stMCIAmpOpen.usDeviceID = (_this->handle != NULL) ? ((ULONG)_this->handle - 1) : 0;
stMCIAmpOpen.pszDeviceType = (PSZ)MCI_DEVTYPE_AUDIO_AMPMIX;
ulRC = mciSendCommand(0, MCI_OPEN,
(_getEnvULong("SDL_AUDIO_SHARE", 1, 0) != 0)?
MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE :
MCI_WAIT | MCI_OPEN_TYPE_ID,
&stMCIAmpOpen, 0);
if (ulRC != MCIERR_SUCCESS) {
stMCIAmpOpen.usDeviceID = (USHORT)~0;
return _MCIError("MCI_OPEN", ulRC);
}
pAData->usDeviceId = stMCIAmpOpen.usDeviceID;
if (iscapture) {
MCI_CONNECTOR_PARMS stMCIConnector;
MCI_AMP_SET_PARMS stMCIAmpSet;
BOOL fLineIn = _getEnvULong("SDL_AUDIO_LINEIN", 1, 0);
/* Set particular connector. */
SDL_zero(stMCIConnector);
stMCIConnector.ulConnectorType = (fLineIn)? MCI_LINE_IN_CONNECTOR :
MCI_MICROPHONE_CONNECTOR;
mciSendCommand(stMCIAmpOpen.usDeviceID, MCI_CONNECTOR,
MCI_WAIT | MCI_ENABLE_CONNECTOR |
MCI_CONNECTOR_TYPE, &stMCIConnector, 0);
/* Disable monitor. */
SDL_zero(stMCIAmpSet);
stMCIAmpSet.ulItem = MCI_AMP_SET_MONITOR;
mciSendCommand(stMCIAmpOpen.usDeviceID, MCI_SET,
MCI_WAIT | MCI_SET_OFF | MCI_SET_ITEM,
&stMCIAmpSet, 0);
/* Set record volume. */
stMCIAmpSet.ulLevel = _getEnvULong("SDL_AUDIO_RECVOL", 100, 90);
stMCIAmpSet.ulItem = MCI_AMP_SET_AUDIO;
stMCIAmpSet.ulAudio = MCI_SET_AUDIO_ALL; /* Both cnannels. */
stMCIAmpSet.ulValue = (fLineIn) ? MCI_LINE_IN_CONNECTOR :
MCI_MICROPHONE_CONNECTOR ;
mciSendCommand(stMCIAmpOpen.usDeviceID, MCI_SET,
MCI_WAIT | MCI_SET_AUDIO | MCI_AMP_SET_GAIN,
&stMCIAmpSet, 0);
}
_this->spec.format = test_format;
_this->spec.channels = _this->spec.channels > 1 ? 2 : 1;
if (_this->spec.freq < 8000) {
_this->spec.freq = 8000;
new_freq = TRUE;
} else if (_this->spec.freq > 48000) {
_this->spec.freq = 48000;
new_freq = TRUE;
}
/* Setup mixer. */
pAData->stMCIMixSetup.ulFormatTag = MCI_WAVE_FORMAT_PCM;
pAData->stMCIMixSetup.ulBitsPerSample = SDL_AUDIO_BITSIZE(test_format);
pAData->stMCIMixSetup.ulSamplesPerSec = _this->spec.freq;
pAData->stMCIMixSetup.ulChannels = _this->spec.channels;
pAData->stMCIMixSetup.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
if (!iscapture) {
pAData->stMCIMixSetup.ulFormatMode= MCI_PLAY;
pAData->stMCIMixSetup.pmixEvent = cbAudioWriteEvent;
} else {
pAData->stMCIMixSetup.ulFormatMode= MCI_RECORD;
pAData->stMCIMixSetup.pmixEvent = cbAudioReadEvent;
}
ulRC = mciSendCommand(pAData->usDeviceId, MCI_MIXSETUP,
MCI_WAIT | MCI_MIXSETUP_INIT, &pAData->stMCIMixSetup, 0);
if (ulRC != MCIERR_SUCCESS && _this->spec.freq > 44100) {
new_freq = TRUE;
pAData->stMCIMixSetup.ulSamplesPerSec = 44100;
_this->spec.freq = 44100;
ulRC = mciSendCommand(pAData->usDeviceId, MCI_MIXSETUP,
MCI_WAIT | MCI_MIXSETUP_INIT, &pAData->stMCIMixSetup, 0);
}
debug_os2("Setup mixer [BPS: %u, Freq.: %u, Channels: %u]: %s",
pAData->stMCIMixSetup.ulBitsPerSample,
pAData->stMCIMixSetup.ulSamplesPerSec,
pAData->stMCIMixSetup.ulChannels,
(ulRC == MCIERR_SUCCESS)? "SUCCESS" : "FAIL");
if (ulRC != MCIERR_SUCCESS) {
pAData->stMCIMixSetup.ulBitsPerSample = 0;
return _MCIError("MCI_MIXSETUP", ulRC);
}
if (_this->spec.samples == 0 || new_freq == TRUE) {
/* also see SDL_audio.c:prepare_audiospec() */
/* Pick a default of ~46 ms at desired frequency */
Uint32 samples = (_this->spec.freq / 1000) * 46;
Uint32 power2 = 1;
while (power2 < samples) {
power2 <<= 1;
}
_this->spec.samples = power2;
}
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(&_this->spec);
/* Allocate memory buffers */
stMCIBuffer.ulBufferSize = _this->spec.size;/* (_this->spec.freq / 1000) * 100 */
stMCIBuffer.ulNumBuffers = NUM_BUFFERS;
stMCIBuffer.pBufList = pAData->aMixBuffers;
ulRC = mciSendCommand(pAData->usDeviceId, MCI_BUFFER,
MCI_WAIT | MCI_ALLOCATE_MEMORY, &stMCIBuffer, 0);
if (ulRC != MCIERR_SUCCESS) {
return _MCIError("MCI_BUFFER", ulRC);
}
pAData->cMixBuffers = stMCIBuffer.ulNumBuffers;
_this->spec.size = stMCIBuffer.ulBufferSize;
/* Fill all device buffers with data */
for (ulIdx = 0; ulIdx < stMCIBuffer.ulNumBuffers; ulIdx++) {
pAData->aMixBuffers[ulIdx].ulFlags = 0;
pAData->aMixBuffers[ulIdx].ulBufferLength = stMCIBuffer.ulBufferSize;
pAData->aMixBuffers[ulIdx].ulUserParm = (ULONG)pAData;
SDL_memset(((PMCI_MIX_BUFFER)stMCIBuffer.pBufList)[ulIdx].pBuffer,
_this->spec.silence, stMCIBuffer.ulBufferSize);
}
/* Write buffers to kick off the amp mixer */
ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle,
pAData->aMixBuffers, 1);
if (ulRC != MCIERR_SUCCESS) {
_mixIOError("pmixWrite", ulRC);
return -1;
}
return 0;
}
static SDL_bool OS2_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->DetectDevices = OS2_DetectDevices;
impl->OpenDevice = OS2_OpenDevice;
impl->PlayDevice = OS2_PlayDevice;
impl->WaitDevice = OS2_WaitDevice;
impl->GetDeviceBuf = OS2_GetDeviceBuf;
impl->CloseDevice = OS2_CloseDevice;
/* TODO: IMPLEMENT CAPTURE SUPPORT:
impl->CaptureFromDevice = ;
impl->FlushCapture = ;
impl->HasCaptureSupport = SDL_TRUE;
*/
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap OS2AUDIO_bootstrap = {
"DART", "OS/2 DART", OS2_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_OS2 */
/* vi: set ts=4 sw=4 expandtab: */
+54
View File
@@ -0,0 +1,54 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
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_os2mm_h_
#define SDL_os2mm_h_
#include "../SDL_sysaudio.h"
#define INCL_OS2MM
#define INCL_PM
#define INCL_DOS
#define INCL_DOSERRORS
#include <os2.h>
#include <os2me.h>
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *_this
#define NUM_BUFFERS 3
typedef struct SDL_PrivateAudioData
{
USHORT usDeviceId;
BYTE _pad[2];
MCI_MIXSETUP_PARMS stMCIMixSetup;
HEV hevBuf;
ULONG ulNextBuf;
ULONG cMixBuffers;
MCI_MIX_BUFFER aMixBuffers[NUM_BUFFERS];
/* ULONG ulQueuedBuf;*/
} SDL_PrivateAudioData;
#endif /* SDL_os2mm_h_ */
/* vi: set ts=4 sw=4 expandtab: */
+30 -52
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -156,7 +156,7 @@ PAUDIO_WaitDevice(_THIS)
#ifdef DEBUG_AUDIO
fprintf(stderr, "Waiting for audio to get ready\n");
#endif
if (SDL_IOReady(this->hidden->audio_fd, SDL_TRUE, timeoutMS) <= 0) {
if (SDL_IOReady(this->hidden->audio_fd, SDL_IOR_WRITE, timeoutMS) <= 0) {
/*
* In general we should never print to the screen,
* but in this case we have no other way of letting
@@ -223,12 +223,12 @@ PAUDIO_CloseDevice(_THIS)
}
static int
PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
PAUDIO_OpenDevice(_THIS, const char *devname)
{
const char *workaround = SDL_getenv("SDL_DSP_NOSELECT");
char audiodev[1024];
const char *err = NULL;
int format;
int flags;
int bytes_per_sample;
SDL_AudioFormat test_format;
audio_init paud_init;
@@ -316,63 +316,44 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
paud_init.channels = this->spec.channels;
/* Try for a closest match on audio format */
format = 0;
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!format && test_format;) {
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
#endif
switch (test_format) {
case AUDIO_U8:
bytes_per_sample = 1;
paud_init.bits_per_sample = 8;
paud_init.flags = TWOS_COMPLEMENT | FIXED;
format = 1;
flags = TWOS_COMPLEMENT | FIXED;
break;
case AUDIO_S8:
bytes_per_sample = 1;
paud_init.bits_per_sample = 8;
paud_init.flags = SIGNED | TWOS_COMPLEMENT | FIXED;
format = 1;
flags = SIGNED | TWOS_COMPLEMENT | FIXED;
break;
case AUDIO_S16LSB:
bytes_per_sample = 2;
paud_init.bits_per_sample = 16;
paud_init.flags = SIGNED | TWOS_COMPLEMENT | FIXED;
format = 1;
flags = SIGNED | TWOS_COMPLEMENT | FIXED;
break;
case AUDIO_S16MSB:
bytes_per_sample = 2;
paud_init.bits_per_sample = 16;
paud_init.flags = BIG_ENDIAN | SIGNED | TWOS_COMPLEMENT | FIXED;
format = 1;
flags = BIG_ENDIAN | SIGNED | TWOS_COMPLEMENT | FIXED;
break;
case AUDIO_U16LSB:
bytes_per_sample = 2;
paud_init.bits_per_sample = 16;
paud_init.flags = TWOS_COMPLEMENT | FIXED;
format = 1;
flags = TWOS_COMPLEMENT | FIXED;
break;
case AUDIO_U16MSB:
bytes_per_sample = 2;
paud_init.bits_per_sample = 16;
paud_init.flags = BIG_ENDIAN | TWOS_COMPLEMENT | FIXED;
format = 1;
flags = BIG_ENDIAN | TWOS_COMPLEMENT | FIXED;
break;
default:
break;
}
if (!format) {
test_format = SDL_NextAudioFormat();
continue;
}
break;
}
if (format == 0) {
if (!test_format) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Couldn't find any hardware audio formats\n");
#endif
return SDL_SetError("Couldn't find any hardware audio formats");
return SDL_SetError("%s: Unsupported audio format", "paud");
}
this->spec.format = test_format;
paud_init.bits_per_sample = SDL_AUDIO_BITSIZE(test_format);
bytes_per_sample = SDL_AUDIO_BITSIZE(test_format) / 8;
paud_init.flags = flags;
/*
* We know the buffer size and the max number of subsequent writes
@@ -406,28 +387,25 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (ioctl(fd, AUDIO_INIT, &paud_init) < 0) {
switch (paud_init.rc) {
case 1:
err = "Couldn't set audio format: DSP can't do play requests";
err = "DSP can't do play requests";
break;
case 2:
err = "Couldn't set audio format: DSP can't do record requests";
err = "DSP can't do record requests";
break;
case 4:
err = "Couldn't set audio format: request was invalid";
err = "request was invalid";
break;
case 5:
err = "Couldn't set audio format: conflict with open's flags";
err = "conflict with open's flags";
break;
case 6:
err = "Couldn't set audio format: out of DSP MIPS or memory";
err = "out of DSP MIPS or memory";
break;
default:
err = "Couldn't set audio format: not documented in sys/audio.h";
err = "not documented in sys/audio.h";
break;
}
}
if (err != NULL) {
return SDL_SetError("Paudio: %s", err);
return SDL_SetError("paud: Couldn't set audio format (%s)", err);
}
/* Allocate mixing buffer */
@@ -485,14 +463,14 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
return 0;
}
static int
static SDL_bool
PAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* !!! FIXME: not right for device enum? */
int fd = OpenAudioPath(NULL, 0, OPEN_FLAGS, 0);
if (fd < 0) {
SDL_SetError("PAUDIO: Couldn't open audio device");
return 0;
return SDL_FALSE;
}
close(fd);
@@ -502,13 +480,13 @@ PAUDIO_Init(SDL_AudioDriverImpl * impl)
impl->PlayDevice = PAUDIO_WaitDevice;
impl->GetDeviceBuf = PAUDIO_GetDeviceBuf;
impl->CloseDevice = PAUDIO_CloseDevice;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: add device enum! */
impl->OnlyHasDefaultOutputDevice = SDL_TRUE; /* !!! FIXME: add device enum! */
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap PAUDIO_bootstrap = {
"paud", "AIX Paudio", PAUDIO_Init, 0
"paud", "AIX Paudio", PAUDIO_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_PAUDIO */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
File diff suppressed because it is too large Load Diff
+47
View File
@@ -0,0 +1,47 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
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_pipewire_h_
#define SDL_pipewire_h_
#include "../SDL_sysaudio.h"
#include <pipewire/pipewire.h>
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
struct pw_thread_loop *loop;
struct pw_stream *stream;
struct pw_context *context;
struct SDL_DataQueue *buffer;
size_t input_buffer_packet_size;
Sint32 stride; /* Bytes-per-frame */
int stream_init_status;
};
#endif /* SDL_pipewire_h_ */
/* vi: set ts=4 sw=4 expandtab: */
+55 -49
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -25,7 +25,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <malloc.h> /* memalign() */
#include "SDL_audio.h"
#include "SDL_error.h"
@@ -39,30 +39,48 @@
#include <pspthreadman.h>
/* The tag name used by PSP audio */
#define PSPAUDIO_DRIVER_NAME "psp"
#define PSPAUDIO_DRIVER_NAME "psp"
static int
PSPAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
PSPAUDIO_OpenDevice(_THIS, const char *devname)
{
int format, mixlen, i;
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc(sizeof(*this->hidden));
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_zerop(this->hidden);
switch (this->spec.format & 0xff) {
case 8:
case 16:
this->spec.format = AUDIO_S16LSB;
break;
default:
return SDL_SetError("Unsupported audio format");
}
/* device only natively supports S16LSB */
this->spec.format = AUDIO_S16LSB;
/* The sample count must be a multiple of 64. */
this->spec.samples = PSP_AUDIO_SAMPLE_ALIGN(this->spec.samples);
this->spec.freq = 44100;
/* Setup the hardware channel. */
if (this->spec.channels == 1) {
format = PSP_AUDIO_FORMAT_MONO;
} else {
format = PSP_AUDIO_FORMAT_STEREO;
this->spec.channels = 2; /* we're forcing the hardware to stereo. */
}
/* PSP has some limitations with the Audio. It fully supports 44.1KHz (Mono & Stereo),
however with frequencies differents than 44.1KHz, it just supports Stereo,
so a resampler must be done for these scenarios */
if (this->spec.freq == 44100) {
this->hidden->channel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, this->spec.samples, format);
} else {
this->hidden->channel = sceAudioSRCChReserve(this->spec.samples, this->spec.freq, 2);
}
if (this->hidden->channel < 0) {
free(this->hidden->rawbuf);
this->hidden->rawbuf = NULL;
return SDL_SetError("Couldn't reserve hardware channel");
}
/* Update the fragment size as size in bytes. */
SDL_CalculateAudioSpec(&this->spec);
@@ -76,21 +94,7 @@ PSPAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
return SDL_SetError("Couldn't allocate mixing buffer");
}
/* Setup the hardware channel. */
if (this->spec.channels == 1) {
format = PSP_AUDIO_FORMAT_MONO;
} else {
this->spec.channels = 2;
format = PSP_AUDIO_FORMAT_STEREO;
}
this->hidden->channel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, this->spec.samples, format);
if (this->hidden->channel < 0) {
free(this->hidden->rawbuf);
this->hidden->rawbuf = NULL;
return SDL_SetError("Couldn't reserve hardware channel");
}
memset(this->hidden->rawbuf, 0, mixlen);
SDL_memset(this->hidden->rawbuf, 0, mixlen);
for (i = 0; i < NUM_BUFFERS; i++) {
this->hidden->mixbufs[i] = &this->hidden->rawbuf[i * this->spec.size];
}
@@ -101,11 +105,12 @@ PSPAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
static void PSPAUDIO_PlayDevice(_THIS)
{
Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer];
if (this->spec.channels == 1) {
sceAudioOutputBlocking(this->hidden->channel, PSP_AUDIO_VOLUME_MAX, mixbuf);
if (this->spec.freq != 44100){
Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer];
SDL_assert(this->spec.channels == 2);
sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, mixbuf);
} else {
Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer];
sceAudioOutputPannedBlocking(this->hidden->channel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, mixbuf);
}
@@ -117,6 +122,7 @@ static void PSPAUDIO_WaitDevice(_THIS)
{
/* Because we block when sending audio, there's no need for this function to do anything. */
}
static Uint8 *PSPAUDIO_GetDeviceBuf(_THIS)
{
return this->hidden->mixbufs[this->hidden->next_buffer];
@@ -125,10 +131,18 @@ static Uint8 *PSPAUDIO_GetDeviceBuf(_THIS)
static void PSPAUDIO_CloseDevice(_THIS)
{
if (this->hidden->channel >= 0) {
sceAudioChRelease(this->hidden->channel);
if (this->spec.freq != 44100){
sceAudioSRCChRelease();
} else {
sceAudioChRelease(this->hidden->channel);
}
this->hidden->channel = -1;
}
if (this->hidden->rawbuf != NULL) {
free(this->hidden->rawbuf);
this->hidden->rawbuf = NULL;
}
free(this->hidden->rawbuf); /* this uses memalign(), not SDL_malloc(). */
SDL_free(this->hidden);
}
static void PSPAUDIO_ThreadInit(_THIS)
@@ -144,8 +158,7 @@ static void PSPAUDIO_ThreadInit(_THIS)
}
}
static int
static SDL_bool
PSPAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
@@ -157,25 +170,18 @@ PSPAUDIO_Init(SDL_AudioDriverImpl * impl)
impl->ThreadInit = PSPAUDIO_ThreadInit;
/* PSP audio device */
impl->OnlyHasDefaultOutputDevice = 1;
/*
impl->HasCaptureSupport = 1;
impl->OnlyHasDefaultCaptureDevice = 1;
*/
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
/*
impl->DetectDevices = DSOUND_DetectDevices;
impl->Deinitialize = DSOUND_Deinitialize;
impl->HasCaptureSupport = SDL_TRUE;
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
*/
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap PSPAUDIO_bootstrap = {
"psp", "PSP audio driver", PSPAUDIO_Init, 0
"psp", "PSP audio driver", PSPAUDIO_Init, SDL_FALSE
};
/* SDL_AUDI */
#endif /* SDL_AUDIO_DRIVER_PSP */
/* vi: set ts=4 sw=4 expandtab: */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+140 -55
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -26,7 +26,7 @@
Stéphan Kochen: stephan .a.t. kochen.nl
*/
#include "../../SDL_internal.h"
#include "SDL_assert.h"
#include "SDL_hints.h"
#if SDL_AUDIO_DRIVER_PULSEAUDIO
@@ -46,6 +46,10 @@
#include "SDL_loadso.h"
#include "../../thread/SDL_systhread.h"
/* should we include monitors in the device list? Set at SDL_Init time */
static SDL_bool include_monitors = SDL_FALSE;
#if (PA_API_VERSION < 12)
/** Return non-zero if the passed state is one of the connected states */
static SDL_INLINE int PA_CONTEXT_IS_GOOD(pa_context_state_t x) {
@@ -76,7 +80,7 @@ static void (*PULSEAUDIO_pa_mainloop_quit) (pa_mainloop *, int);
static void (*PULSEAUDIO_pa_mainloop_free) (pa_mainloop *);
static pa_operation_state_t (*PULSEAUDIO_pa_operation_get_state) (
pa_operation *);
const pa_operation *);
static void (*PULSEAUDIO_pa_operation_cancel) (pa_operation *);
static void (*PULSEAUDIO_pa_operation_unref) (pa_operation *);
@@ -88,7 +92,7 @@ static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_list) (pa_context *,
static pa_operation * (*PULSEAUDIO_pa_context_get_source_info_list) (pa_context *, pa_source_info_cb_t, void *);
static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_by_index) (pa_context *, uint32_t, pa_sink_info_cb_t, void *);
static pa_operation * (*PULSEAUDIO_pa_context_get_source_info_by_index) (pa_context *, uint32_t, pa_source_info_cb_t, void *);
static pa_context_state_t (*PULSEAUDIO_pa_context_get_state) (pa_context *);
static pa_context_state_t (*PULSEAUDIO_pa_context_get_state) (const pa_context *);
static pa_operation * (*PULSEAUDIO_pa_context_subscribe) (pa_context *, pa_subscription_mask_t, pa_context_success_cb_t, void *);
static void (*PULSEAUDIO_pa_context_set_subscribe_callback) (pa_context *, pa_context_subscribe_cb_t, void *);
static void (*PULSEAUDIO_pa_context_disconnect) (pa_context *);
@@ -97,12 +101,14 @@ static void (*PULSEAUDIO_pa_context_unref) (pa_context *);
static pa_stream * (*PULSEAUDIO_pa_stream_new) (pa_context *, const char *,
const pa_sample_spec *, const pa_channel_map *);
static int (*PULSEAUDIO_pa_stream_connect_playback) (pa_stream *, const char *,
const pa_buffer_attr *, pa_stream_flags_t, pa_cvolume *, pa_stream *);
const pa_buffer_attr *, pa_stream_flags_t, const pa_cvolume *, pa_stream *);
static int (*PULSEAUDIO_pa_stream_connect_record) (pa_stream *, const char *,
const pa_buffer_attr *, pa_stream_flags_t);
static pa_stream_state_t (*PULSEAUDIO_pa_stream_get_state) (pa_stream *);
static size_t (*PULSEAUDIO_pa_stream_writable_size) (pa_stream *);
static size_t (*PULSEAUDIO_pa_stream_readable_size) (pa_stream *);
static pa_stream_state_t (*PULSEAUDIO_pa_stream_get_state) (const pa_stream *);
static size_t (*PULSEAUDIO_pa_stream_writable_size) (const pa_stream *);
static size_t (*PULSEAUDIO_pa_stream_readable_size) (const pa_stream *);
static int (*PULSEAUDIO_pa_stream_begin_write) (pa_stream *, void **, size_t*);
static int (*PULSEAUDIO_pa_stream_cancel_write) (pa_stream *);
static int (*PULSEAUDIO_pa_stream_write) (pa_stream *, const void *, size_t,
pa_free_cb_t, int64_t, pa_seek_mode_t);
static pa_operation * (*PULSEAUDIO_pa_stream_drain) (pa_stream *,
@@ -216,6 +222,8 @@ load_pulseaudio_syms(void)
SDL_PULSEAUDIO_SYM(pa_stream_writable_size);
SDL_PULSEAUDIO_SYM(pa_stream_readable_size);
SDL_PULSEAUDIO_SYM(pa_stream_write);
SDL_PULSEAUDIO_SYM(pa_stream_begin_write);
SDL_PULSEAUDIO_SYM(pa_stream_cancel_write);
SDL_PULSEAUDIO_SYM(pa_stream_drain);
SDL_PULSEAUDIO_SYM(pa_stream_disconnect);
SDL_PULSEAUDIO_SYM(pa_stream_peek);
@@ -237,16 +245,26 @@ squashVersion(const int major, const int minor, const int patch)
static const char *
getAppName(void)
{
const char *verstr = PULSEAUDIO_pa_get_library_version();
if (verstr != NULL) {
int maj, min, patch;
if (SDL_sscanf(verstr, "%d.%d.%d", &maj, &min, &patch) == 3) {
if (squashVersion(maj, min, patch) >= squashVersion(0, 9, 15)) {
return NULL; /* 0.9.15+ handles NULL correctly. */
const char *retval = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME);
if (retval && *retval) {
return retval;
}
retval = SDL_GetHint(SDL_HINT_APP_NAME);
if (retval && *retval) {
return retval;
} else {
const char *verstr = PULSEAUDIO_pa_get_library_version();
retval = "SDL Application"; /* the "oh well" default. */
if (verstr != NULL) {
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. */
}
}
}
}
return "SDL Application"; /* oh well. */
return retval;
}
static void
@@ -290,32 +308,39 @@ ConnectToPulseServer_Internal(pa_mainloop **_mainloop, pa_context **_context)
return SDL_SetError("pa_mainloop_new() failed");
}
*_mainloop = mainloop;
mainloop_api = PULSEAUDIO_pa_mainloop_get_api(mainloop);
SDL_assert(mainloop_api); /* this never fails, right? */
context = PULSEAUDIO_pa_context_new(mainloop_api, getAppName());
if (!context) {
PULSEAUDIO_pa_mainloop_free(mainloop);
return SDL_SetError("pa_context_new() failed");
}
*_context = context;
/* Connect to the PulseAudio server */
if (PULSEAUDIO_pa_context_connect(context, NULL, 0, NULL) < 0) {
PULSEAUDIO_pa_context_unref(context);
PULSEAUDIO_pa_mainloop_free(mainloop);
return SDL_SetError("Could not setup connection to PulseAudio");
}
do {
if (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1, NULL) < 0) {
PULSEAUDIO_pa_context_unref(context);
PULSEAUDIO_pa_mainloop_free(mainloop);
return SDL_SetError("pa_mainloop_iterate() failed");
}
state = PULSEAUDIO_pa_context_get_state(context);
if (!PA_CONTEXT_IS_GOOD(state)) {
PULSEAUDIO_pa_context_unref(context);
PULSEAUDIO_pa_mainloop_free(mainloop);
return SDL_SetError("Could not connect to PulseAudio");
}
} while (state != PA_CONTEXT_READY);
*_context = context;
*_mainloop = mainloop;
return 0; /* connected and ready! */
}
@@ -343,7 +368,7 @@ PULSEAUDIO_WaitDevice(_THIS)
SDL_OpenedAudioDeviceDisconnected(this);
return;
}
if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= h->mixlen) {
if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= (h->mixlen/8)) {
return;
}
}
@@ -355,7 +380,7 @@ PULSEAUDIO_PlayDevice(_THIS)
/* Write the audio data */
struct SDL_PrivateAudioData *h = this->hidden;
if (SDL_AtomicGet(&this->enabled)) {
if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0) {
if (PULSEAUDIO_pa_stream_write(h->stream, h->pabuf, h->mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0) {
SDL_OpenedAudioDeviceDisconnected(this);
}
}
@@ -364,7 +389,21 @@ PULSEAUDIO_PlayDevice(_THIS)
static Uint8 *
PULSEAUDIO_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
struct SDL_PrivateAudioData *h = this->hidden;
size_t nbytes = h->mixlen;
int ret;
ret = PULSEAUDIO_pa_stream_begin_write(h->stream, &h->pabuf, &nbytes);
if (ret != 0) {
/* fall back it intermediate buffer */
h->pabuf = h->mixbuf;
} else if (nbytes < h->mixlen) {
PULSEAUDIO_pa_stream_cancel_write(h->stream);
h->pabuf = h->mixbuf;
}
return (Uint8 *)h->pabuf;
}
@@ -429,7 +468,7 @@ PULSEAUDIO_FlushCapture(_THIS)
h->capturelen = 0;
}
while (SDL_TRUE) {
while (SDL_AtomicGet(&this->enabled)) {
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
@@ -483,7 +522,7 @@ SourceDeviceNameCallback(pa_context *c, const pa_source_info *i, int is_last, vo
}
static SDL_bool
FindDeviceName(struct SDL_PrivateAudioData *h, const int iscapture, void *handle)
FindDeviceName(struct SDL_PrivateAudioData *h, const SDL_bool iscapture, void *handle)
{
const uint32_t idx = ((uint32_t) ((size_t) handle)) - 1;
@@ -505,15 +544,17 @@ FindDeviceName(struct SDL_PrivateAudioData *h, const int iscapture, void *handle
}
static int
PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
PULSEAUDIO_OpenDevice(_THIS, const char *devname)
{
struct SDL_PrivateAudioData *h = NULL;
Uint16 test_format = 0;
SDL_AudioFormat test_format;
pa_sample_spec paspec;
pa_buffer_attr paattr;
pa_channel_map pacmap;
pa_stream_flags_t flags = 0;
int state = 0;
const char *name = NULL;
SDL_bool iscapture = this->iscapture;
int state = 0, format = PA_SAMPLE_INVALID;
int rc = 0;
/* Initialize all variables that we clean on shutdown */
@@ -524,48 +565,43 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
SDL_zerop(this->hidden);
paspec.format = PA_SAMPLE_INVALID;
/* Try for a closest match on audio format */
for (test_format = SDL_FirstAudioFormat(this->spec.format);
(paspec.format == PA_SAMPLE_INVALID) && test_format;) {
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
#endif
switch (test_format) {
case AUDIO_U8:
paspec.format = PA_SAMPLE_U8;
format = PA_SAMPLE_U8;
break;
case AUDIO_S16LSB:
paspec.format = PA_SAMPLE_S16LE;
format = PA_SAMPLE_S16LE;
break;
case AUDIO_S16MSB:
paspec.format = PA_SAMPLE_S16BE;
format = PA_SAMPLE_S16BE;
break;
case AUDIO_S32LSB:
paspec.format = PA_SAMPLE_S32LE;
format = PA_SAMPLE_S32LE;
break;
case AUDIO_S32MSB:
paspec.format = PA_SAMPLE_S32BE;
format = PA_SAMPLE_S32BE;
break;
case AUDIO_F32LSB:
paspec.format = PA_SAMPLE_FLOAT32LE;
format = PA_SAMPLE_FLOAT32LE;
break;
case AUDIO_F32MSB:
paspec.format = PA_SAMPLE_FLOAT32BE;
format = PA_SAMPLE_FLOAT32BE;
break;
default:
paspec.format = PA_SAMPLE_INVALID;
break;
}
if (paspec.format == PA_SAMPLE_INVALID) {
test_format = SDL_NextAudioFormat();
continue;
}
break;
}
if (paspec.format == PA_SAMPLE_INVALID) {
return SDL_SetError("Couldn't find any hardware audio formats");
if (!test_format) {
return SDL_SetError("%s: Unsupported audio format", "pulseaudio");
}
this->spec.format = test_format;
paspec.format = format;
/* Calculate the final parameters for this audio specification */
#ifdef PA_STREAM_ADJUST_LATENCY
@@ -588,6 +624,7 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Reduced prebuffering compared to the defaults. */
#ifdef PA_STREAM_ADJUST_LATENCY
paattr.fragsize = this->spec.size;
/* 2x original requested bufsize */
paattr.tlength = h->mixlen * 4;
paattr.prebuf = -1;
@@ -596,6 +633,7 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
paattr.minreq = h->mixlen;
flags = PA_STREAM_ADJUST_LATENCY;
#else
paattr.fragsize = this->spec.size;
paattr.tlength = h->mixlen*2;
paattr.prebuf = h->mixlen*2;
paattr.maxlength = h->mixlen*2;
@@ -606,7 +644,7 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
return SDL_SetError("Could not connect to PulseAudio server");
}
if (!FindDeviceName(h, iscapture, handle)) {
if (!FindDeviceName(h, iscapture, this->handle)) {
return SDL_SetError("Requested PulseAudio sink/source missing?");
}
@@ -615,9 +653,11 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
PULSEAUDIO_pa_channel_map_init_auto(&pacmap, this->spec.channels,
PA_CHANNEL_MAP_WAVEEX);
name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME);
h->stream = PULSEAUDIO_pa_stream_new(
h->context,
"Simple DirectMedia Layer", /* stream description */
(name && *name) ? name : "Audio Stream", /* stream description */
&paspec, /* sample format spec */
&pacmap /* channel map */
);
@@ -662,12 +702,45 @@ static SDL_Thread *hotplug_thread = 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)
{
switch (format) {
case PA_SAMPLE_U8:
return AUDIO_U8;
case PA_SAMPLE_S16LE:
return AUDIO_S16LSB;
case PA_SAMPLE_S16BE:
return AUDIO_S16MSB;
case PA_SAMPLE_S32LE:
return AUDIO_S32LSB;
case PA_SAMPLE_S32BE:
return AUDIO_S32MSB;
case PA_SAMPLE_FLOAT32LE:
return AUDIO_F32LSB;
case PA_SAMPLE_FLOAT32BE:
return AUDIO_F32MSB;
default:
return 0;
}
}
/* This is called when PulseAudio adds an output ("sink") device. */
static void
SinkInfoCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
{
SDL_AudioSpec spec;
if (i) {
SDL_AddAudioDevice(SDL_FALSE, i->description, (void *) ((size_t) i->index+1));
spec.freq = i->sample_spec.rate;
spec.channels = i->sample_spec.channels;
spec.format = PulseFormatToSDLFormat(i->sample_spec.format);
spec.silence = 0;
spec.samples = 0;
spec.size = 0;
spec.callback = NULL;
spec.userdata = NULL;
SDL_AddAudioDevice(SDL_FALSE, i->description, &spec, (void *) ((size_t) i->index+1));
}
}
@@ -675,10 +748,20 @@ SinkInfoCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
static void
SourceInfoCallback(pa_context *c, const pa_source_info *i, int is_last, void *data)
{
SDL_AudioSpec spec;
if (i) {
/* Skip "monitor" sources. These are just output from other sinks. */
if (i->monitor_of_sink == PA_INVALID_INDEX) {
SDL_AddAudioDevice(SDL_TRUE, i->description, (void *) ((size_t) i->index+1));
/* Maybe skip "monitor" sources. These are just output from other sinks. */
if (include_monitors || (i->monitor_of_sink == PA_INVALID_INDEX)) {
spec.freq = i->sample_spec.rate;
spec.channels = i->sample_spec.channels;
spec.format = PulseFormatToSDLFormat(i->sample_spec.format);
spec.silence = 0;
spec.samples = 0;
spec.size = 0;
spec.callback = NULL;
spec.userdata = NULL;
SDL_AddAudioDevice(SDL_TRUE, i->description, &spec, (void *) ((size_t) i->index+1));
}
}
}
@@ -745,18 +828,20 @@ PULSEAUDIO_Deinitialize(void)
UnloadPulseAudioLibrary();
}
static int
static SDL_bool
PULSEAUDIO_Init(SDL_AudioDriverImpl * impl)
{
if (LoadPulseAudioLibrary() < 0) {
return 0;
return SDL_FALSE;
}
if (ConnectToPulseServer(&hotplug_mainloop, &hotplug_context) < 0) {
UnloadPulseAudioLibrary();
return 0;
return SDL_FALSE;
}
include_monitors = SDL_GetHintBoolean(SDL_HINT_AUDIO_INCLUDE_MONITORS, SDL_FALSE);
/* Set the function pointers */
impl->DetectDevices = PULSEAUDIO_DetectDevices;
impl->OpenDevice = PULSEAUDIO_OpenDevice;
@@ -770,11 +855,11 @@ PULSEAUDIO_Init(SDL_AudioDriverImpl * impl)
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap PULSEAUDIO_bootstrap = {
"pulseaudio", "PulseAudio", PULSEAUDIO_Init, 0
"pulseaudio", "PulseAudio", PULSEAUDIO_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_PULSEAUDIO */
+7 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -43,6 +43,12 @@ struct SDL_PrivateAudioData
Uint8 *mixbuf;
int mixlen;
/* Pointer to the actual buffer in use in the current
GetDeviceBuf() -> PlayDevice() iteration.
Can be either the pointer returned by pa_stream_begin_write()
or mixbuf */
void *pabuf;
const Uint8 *capturebuf;
int capturelen;
};
+48 -87
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -120,7 +120,9 @@ QSA_WaitDevice(_THIS)
/* If timeout occured than something wrong with hardware or driver */
/* For example, Vortex 8820 audio driver stucks on second DAC because */
/* it doesn't exist ! */
result = SDL_IOReady(this->hidden->audio_fd, !this->hidden->iscapture, 2 * 1000);
result = SDL_IOReady(this->hidden->audio_fd,
this->iscapture ? SDL_IOR_READ : SDL_IOR_WRITE,
2 * 1000);
switch (result) {
case -1:
SDL_SetError("QSA: SDL_IOReady() failed: %s", strerror(errno));
@@ -178,7 +180,7 @@ QSA_PlayDevice(_THIS)
} else {
if ((errno == EINVAL) || (errno == EIO)) {
SDL_zero(cstatus);
if (!this->hidden->iscapture) {
if (!this->iscapture) {
cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
} else {
cstatus.channel = SND_PCM_CHANNEL_CAPTURE;
@@ -194,7 +196,7 @@ QSA_PlayDevice(_THIS)
if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) ||
(cstatus.status == SND_PCM_STATUS_READY)) {
if (!this->hidden->iscapture) {
if (!this->iscapture) {
status =
snd_pcm_plugin_prepare(this->hidden->
audio_handle,
@@ -238,7 +240,7 @@ static void
QSA_CloseDevice(_THIS)
{
if (this->hidden->audio_handle != NULL) {
if (!this->hidden->iscapture) {
if (!this->iscapture) {
/* Finish playing available samples */
snd_pcm_plugin_flush(this->hidden->audio_handle,
SND_PCM_CHANNEL_PLAYBACK);
@@ -255,13 +257,13 @@ QSA_CloseDevice(_THIS)
}
static int
QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
QSA_OpenDevice(_THIS, const char *devname)
{
const QSA_Device *device = (const QSA_Device *) handle;
const QSA_Device *device = (const QSA_Device *) this->handle;
SDL_Bool iscapture = this->iscapture;
int status = 0;
int format = 0;
SDL_AudioFormat test_format = 0;
int found = 0;
SDL_AudioFormat test_format;
snd_pcm_channel_setup_t csetup;
snd_pcm_channel_params_t cparams;
@@ -278,9 +280,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Initialize channel transfer parameters to default */
QSA_InitAudioParams(&cparams);
/* Initialize channel direction: capture or playback */
this->hidden->iscapture = iscapture ? SDL_TRUE : SDL_FALSE;
if (device != NULL) {
/* Open requested audio device */
this->hidden->deviceno = device->deviceno;
@@ -303,89 +302,49 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
/* Try for a closest match on audio format */
format = 0;
/* can't use format as SND_PCM_SFMT_U8 = 0 in qsa */
found = 0;
for (test_format = SDL_FirstAudioFormat(this->spec.format); !found;) {
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
/* if match found set format to equivalent QSA format */
switch (test_format) {
case AUDIO_U8:
{
format = SND_PCM_SFMT_U8;
found = 1;
}
format = SND_PCM_SFMT_U8;
break;
case AUDIO_S8:
{
format = SND_PCM_SFMT_S8;
found = 1;
}
format = SND_PCM_SFMT_S8;
break;
case AUDIO_S16LSB:
{
format = SND_PCM_SFMT_S16_LE;
found = 1;
}
format = SND_PCM_SFMT_S16_LE;
break;
case AUDIO_S16MSB:
{
format = SND_PCM_SFMT_S16_BE;
found = 1;
}
format = SND_PCM_SFMT_S16_BE;
break;
case AUDIO_U16LSB:
{
format = SND_PCM_SFMT_U16_LE;
found = 1;
}
format = SND_PCM_SFMT_U16_LE;
break;
case AUDIO_U16MSB:
{
format = SND_PCM_SFMT_U16_BE;
found = 1;
}
format = SND_PCM_SFMT_U16_BE;
break;
case AUDIO_S32LSB:
{
format = SND_PCM_SFMT_S32_LE;
found = 1;
}
format = SND_PCM_SFMT_S32_LE;
break;
case AUDIO_S32MSB:
{
format = SND_PCM_SFMT_S32_BE;
found = 1;
}
format = SND_PCM_SFMT_S32_BE;
break;
case AUDIO_F32LSB:
{
format = SND_PCM_SFMT_FLOAT_LE;
found = 1;
}
format = SND_PCM_SFMT_FLOAT_LE;
break;
case AUDIO_F32MSB:
{
format = SND_PCM_SFMT_FLOAT_BE;
found = 1;
}
format = SND_PCM_SFMT_FLOAT_BE;
break;
default:
{
break;
}
}
if (!found) {
test_format = SDL_NextAudioFormat();
continue;
}
break;
}
/* assumes test_format not 0 on success */
if (test_format == 0) {
return SDL_SetError("QSA: Couldn't find any hardware audio formats");
/* can't use format as SND_PCM_SFMT_U8 = 0 in qsa */
if (!test_format) {
return SDL_SetError("%s: Unsupported audio format", "qsa");
}
this->spec.format = test_format;
/* Set the audio format */
@@ -405,7 +364,7 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Make sure channel is setup right one last time */
SDL_zero(csetup);
if (!this->hidden->iscapture) {
if (!this->iscapture) {
csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
} else {
csetup.channel = SND_PCM_CHANNEL_CAPTURE;
@@ -441,7 +400,7 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
this->hidden->pcm_len);
/* get the file descriptor */
if (!this->hidden->iscapture) {
if (!this->iscapture) {
this->hidden->audio_fd =
snd_pcm_file_descriptor(this->hidden->audio_handle,
SND_PCM_CHANNEL_PLAYBACK);
@@ -456,7 +415,7 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
/* Prepare an audio channel */
if (!this->hidden->iscapture) {
if (!this->iscapture) {
/* Prepare audio playback */
status =
snd_pcm_plugin_prepare(this->hidden->audio_handle,
@@ -528,7 +487,11 @@ QSA_DetectDevices(void)
devices;
status = snd_pcm_close(handle);
if (status == EOK) {
SDL_AddAudioDevice(SDL_FALSE, qsa_playback_device[qsa_playback_devices].name, &qsa_playback_device[qsa_playback_devices]);
/* 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(SDL_FALSE, qsa_playback_device[qsa_playback_devices].name, NULL, &qsa_playback_device[qsa_playback_devices]);
qsa_playback_devices++;
}
} else {
@@ -586,7 +549,11 @@ QSA_DetectDevices(void)
devices;
status = snd_pcm_close(handle);
if (status == EOK) {
SDL_AddAudioDevice(SDL_TRUE, qsa_capture_device[qsa_capture_devices].name, &qsa_capture_device[qsa_capture_devices]);
/* 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(SDL_TRUE, qsa_capture_device[qsa_capture_devices].name, NULL, &qsa_capture_device[qsa_capture_devices]);
qsa_capture_devices++;
}
} else {
@@ -619,18 +586,18 @@ QSA_Deinitialize(void)
{
/* Clear devices array on shutdown */
/* !!! FIXME: we zero these on init...any reason to do it here? */
SDL_zero(qsa_playback_device);
SDL_zero(qsa_capture_device);
SDL_zeroa(qsa_playback_device);
SDL_zeroa(qsa_capture_device);
qsa_playback_devices = 0;
qsa_capture_devices = 0;
}
static int
static SDL_bool
QSA_Init(SDL_AudioDriverImpl * impl)
{
/* Clear devices array */
SDL_zero(qsa_playback_device);
SDL_zero(qsa_capture_device);
SDL_zeroa(qsa_playback_device);
SDL_zeroa(qsa_capture_device);
qsa_playback_devices = 0;
qsa_capture_devices = 0;
@@ -645,20 +612,14 @@ QSA_Init(SDL_AudioDriverImpl * impl)
impl->GetDeviceBuf = QSA_GetDeviceBuf;
impl->CloseDevice = QSA_CloseDevice;
impl->Deinitialize = QSA_Deinitialize;
impl->LockDevice = NULL;
impl->UnlockDevice = NULL;
impl->ProvidesOwnCallbackThread = 0;
impl->SkipMixerLock = 0;
impl->HasCaptureSupport = 1;
impl->OnlyHasDefaultOutputDevice = 0;
impl->OnlyHasDefaultCaptureDevice = 0;
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap QSAAUDIO_bootstrap = {
"qsa", "QNX QSA Audio", QSA_Init, 0
"qsa", "QNX QSA Audio", QSA_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_QSA */
+1 -4
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -33,9 +33,6 @@
struct SDL_PrivateAudioData
{
/* SDL capture state */
SDL_bool iscapture;
/* The audio device handle */
int cardno;
int deviceno;
+20 -15
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -237,11 +237,11 @@ SNDIO_CloseDevice(_THIS)
}
static int
SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SNDIO_OpenDevice(_THIS, const char *devname)
{
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
SDL_AudioFormat test_format;
struct sio_par par;
int status;
SDL_bool iscapture = this->iscapture;
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc(sizeof(*this->hidden));
@@ -273,8 +273,7 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
par.appbufsz = par.round * 2;
/* Try for a closest match on audio format */
status = -1;
while (test_format && (status < 0)) {
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
if (!SDL_AUDIO_ISFLOAT(test_format)) {
par.le = SDL_AUDIO_ISLITTLEENDIAN(test_format) ? 1 : 0;
par.sig = SDL_AUDIO_ISSIGNED(test_format) ? 1 : 0;
@@ -290,15 +289,13 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
continue;
}
if ((par.bits == 8 * par.bps) || (par.msb)) {
status = 0;
break;
}
}
test_format = SDL_NextAudioFormat();
}
if (status < 0) {
return SDL_SetError("sndio: Couldn't find any hardware audio formats");
if (!test_format) {
return SDL_SetError("%s: Unsupported audio format", "sndio");
}
if ((par.bps == 4) && (par.sig) && (par.le))
@@ -350,11 +347,18 @@ SNDIO_Deinitialize(void)
UnloadSNDIOLibrary();
}
static int
static void
SNDIO_DetectDevices(void)
{
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, NULL, (void *) 0x1);
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, NULL, (void *) 0x2);
}
static SDL_bool
SNDIO_Init(SDL_AudioDriverImpl * impl)
{
if (LoadSNDIOLibrary() < 0) {
return 0;
return SDL_FALSE;
}
/* Set the function pointers */
@@ -366,15 +370,16 @@ SNDIO_Init(SDL_AudioDriverImpl * impl)
impl->CaptureFromDevice = SNDIO_CaptureFromDevice;
impl->FlushCapture = SNDIO_FlushCapture;
impl->Deinitialize = SNDIO_Deinitialize;
impl->DetectDevices = SNDIO_DetectDevices;
impl->AllowsArbitraryDeviceNames = 1;
impl->AllowsArbitraryDeviceNames = SDL_TRUE;
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap SNDIO_bootstrap = {
"sndio", "OpenBSD sndio", SNDIO_Init, 0
"sndio", "OpenBSD sndio", SNDIO_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_SNDIO */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+8 -7
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -98,7 +98,7 @@ SUNAUDIO_WaitDevice(_THIS)
}
}
#else
SDL_IOReady(this->hidden->audio_fd, SDL_TRUE, -1);
SDL_IOReady(this->hidden->audio_fd, SDL_IOR_WRITE, -1);
#endif
}
@@ -188,11 +188,12 @@ SUNAUDIO_CloseDevice(_THIS)
}
static int
SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SUNAUDIO_OpenDevice(_THIS, const char *devname)
{
#ifdef AUDIO_SETINFO
int enc;
#endif
SDL_bool iscapture = this->iscapture;
int desired_freq = 0;
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
SDL_AudioFormat format = 0;
@@ -394,7 +395,7 @@ snd2au(int sample)
return (mask & sample);
}
static int
static SDL_bool
SUNAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
@@ -405,13 +406,13 @@ SUNAUDIO_Init(SDL_AudioDriverImpl * impl)
impl->GetDeviceBuf = SUNAUDIO_GetDeviceBuf;
impl->CloseDevice = SUNAUDIO_CloseDevice;
impl->AllowsArbitraryDeviceNames = 1;
impl->AllowsArbitraryDeviceNames = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap SUNAUDIO_bootstrap = {
"audio", "UNIX /dev/audio interface", SUNAUDIO_Init, 0
"audio", "UNIX /dev/audio interface", SUNAUDIO_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_SUNAUDIO */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
+224
View File
@@ -0,0 +1,224 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
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"
#if SDL_AUDIO_DRIVER_VITA
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h> /* memalign() */
#include "SDL_audio.h"
#include "SDL_error.h"
#include "SDL_timer.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_vitaaudio.h"
#include <psp2/kernel/threadmgr.h>
#include <psp2/audioout.h>
#include <psp2/audioin.h>
#define SCE_AUDIO_SAMPLE_ALIGN(s) (((s) + 63) & ~63)
#define SCE_AUDIO_MAX_VOLUME 0x8000
static int
VITAAUD_OpenCaptureDevice(_THIS)
{
this->spec.freq = 16000;
this->spec.samples = 512;
this->spec.channels = 1;
SDL_CalculateAudioSpec(&this->spec);
this->hidden->port = sceAudioInOpenPort(SCE_AUDIO_IN_PORT_TYPE_VOICE , 512, 16000, SCE_AUDIO_IN_PARAM_FORMAT_S16_MONO);
if (this->hidden->port < 0) {
return SDL_SetError("Couldn't open audio in port: %x", this->hidden->port);
}
return 0;
}
static int
VITAAUD_OpenDevice(_THIS, const char *devname)
{
int format, mixlen, i, port = SCE_AUDIO_OUT_PORT_TYPE_MAIN;
int vols[2] = {SCE_AUDIO_MAX_VOLUME, SCE_AUDIO_MAX_VOLUME};
SDL_AudioFormat test_format;
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc(sizeof(*this->hidden));
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, sizeof(*this->hidden));
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
if (test_format == AUDIO_S16LSB) {
this->spec.format = test_format;
break;
}
}
if(!test_format) {
return SDL_SetError("Unsupported audio format");
}
if (this->iscapture) {
return VITAAUD_OpenCaptureDevice(this);
}
/* The sample count must be a multiple of 64. */
this->spec.samples = SCE_AUDIO_SAMPLE_ALIGN(this->spec.samples);
/* Update the fragment size as size in bytes. */
SDL_CalculateAudioSpec(&this->spec);
/* Allocate the mixing buffer. Its size and starting address must
be a multiple of 64 bytes. Our sample count is already a multiple of
64, so spec->size should be a multiple of 64 as well. */
mixlen = this->spec.size * NUM_BUFFERS;
this->hidden->rawbuf = (Uint8 *) memalign(64, mixlen);
if (this->hidden->rawbuf == NULL) {
return SDL_SetError("Couldn't allocate mixing buffer");
}
/* Setup the hardware channel. */
if (this->spec.channels == 1) {
format = SCE_AUDIO_OUT_MODE_MONO;
} else {
format = SCE_AUDIO_OUT_MODE_STEREO;
}
if(this->spec.freq < 48000) {
port = SCE_AUDIO_OUT_PORT_TYPE_BGM;
}
this->hidden->port = sceAudioOutOpenPort(port, this->spec.samples, this->spec.freq, format);
if (this->hidden->port < 0) {
free(this->hidden->rawbuf);
this->hidden->rawbuf = NULL;
return SDL_SetError("Couldn't open audio out port: %x", this->hidden->port);
}
sceAudioOutSetVolume(this->hidden->port, SCE_AUDIO_VOLUME_FLAG_L_CH|SCE_AUDIO_VOLUME_FLAG_R_CH, vols);
SDL_memset(this->hidden->rawbuf, 0, mixlen);
for (i = 0; i < NUM_BUFFERS; i++) {
this->hidden->mixbufs[i] = &this->hidden->rawbuf[i * this->spec.size];
}
this->hidden->next_buffer = 0;
return 0;
}
static void VITAAUD_PlayDevice(_THIS)
{
Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer];
sceAudioOutOutput(this->hidden->port, mixbuf);
this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
}
/* This function waits until it is possible to write a full sound buffer */
static void VITAAUD_WaitDevice(_THIS)
{
/* Because we block when sending audio, there's no need for this function to do anything. */
}
static Uint8 *VITAAUD_GetDeviceBuf(_THIS)
{
return this->hidden->mixbufs[this->hidden->next_buffer];
}
static void VITAAUD_CloseDevice(_THIS)
{
if (this->hidden->port >= 0) {
if (this->iscapture) {
sceAudioInReleasePort(this->hidden->port);
} else {
sceAudioOutReleasePort(this->hidden->port);
}
this->hidden->port = -1;
}
if (!this->iscapture && this->hidden->rawbuf != NULL) {
free(this->hidden->rawbuf); /* this uses memalign(), not SDL_malloc(). */
this->hidden->rawbuf = NULL;
}
}
static int VITAAUD_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
int ret;
SDL_assert(buflen == this->spec.size);
ret = sceAudioInInput(this->hidden->port, buffer);
if (ret < 0) {
return SDL_SetError("Failed to capture from device: %x", ret);
}
return this->spec.size;
}
static void VITAAUD_ThreadInit(_THIS)
{
/* Increase the priority of this audio thread by 1 to put it
ahead of other SDL threads. */
SceUID thid;
SceKernelThreadInfo info;
thid = sceKernelGetThreadId();
info.size = sizeof(SceKernelThreadInfo);
if (sceKernelGetThreadInfo(thid, &info) == 0) {
sceKernelChangeThreadPriority(thid, info.currentPriority - 1);
}
}
static SDL_bool
VITAAUD_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->OpenDevice = VITAAUD_OpenDevice;
impl->PlayDevice = VITAAUD_PlayDevice;
impl->WaitDevice = VITAAUD_WaitDevice;
impl->GetDeviceBuf = VITAAUD_GetDeviceBuf;
impl->CloseDevice = VITAAUD_CloseDevice;
impl->ThreadInit = VITAAUD_ThreadInit;
impl->CaptureFromDevice = VITAAUD_CaptureFromDevice;
/* and the capabilities */
impl->HasCaptureSupport = SDL_TRUE;
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap VITAAUD_bootstrap = {
"vita", "VITA audio driver", VITAAUD_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_VITA */
/* vi: set ts=4 sw=4 expandtab: */
+45
View File
@@ -0,0 +1,45 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
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_vitaaudio_h
#define _SDL_vitaaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
#define NUM_BUFFERS 2
struct SDL_PrivateAudioData {
/* The hardware input/output port. */
int port;
/* The raw allocated mixing buffer. */
Uint8 *rawbuf;
/* Individual mixing buffers. */
Uint8 *mixbufs[NUM_BUFFERS];
/* Index of the next available mixing buffer. */
int next_buffer;
};
#endif /* _SDL_vitaaudio_h */
/* vi: set ts=4 sw=4 expandtab: */
+84 -127
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -18,7 +18,6 @@
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#if SDL_AUDIO_DRIVER_WASAPI
@@ -28,8 +27,6 @@
#include "SDL_timer.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_assert.h"
#include "SDL_log.h"
#define COBJMACROS
#include <mmdeviceapi.h>
@@ -37,10 +34,16 @@
#include "SDL_wasapi.h"
/* This constant isn't available on MinGW-w64 */
/* These constants aren't available in older SDKs */
#ifndef AUDCLNT_STREAMFLAGS_RATEADJUST
#define AUDCLNT_STREAMFLAGS_RATEADJUST 0x00100000
#endif
#ifndef AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
#define AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY 0x08000000
#endif
#ifndef AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
#define AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000
#endif
/* these increment as default devices change. Opened default devices pick up changes in their threads. */
SDL_atomic_t WASAPI_DefaultPlaybackGeneration;
@@ -61,42 +64,6 @@ static const IID SDL_IID_IAudioCaptureClient = { 0xc8adbd64, 0xe71e, 0x48a0,{ 0x
static const GUID SDL_KSDATAFORMAT_SUBTYPE_PCM = { 0x00000001, 0x0000, 0x0010,{ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
static const GUID SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { 0x00000003, 0x0000, 0x0010,{ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
static SDL_bool
WStrEqual(const WCHAR *a, const WCHAR *b)
{
while (*a) {
if (*a != *b) {
return SDL_FALSE;
}
a++;
b++;
}
return *b == 0;
}
static size_t
WStrLen(const WCHAR *wstr)
{
size_t retval = 0;
if (wstr) {
while (*(wstr++)) {
retval++;
}
}
return retval;
}
static WCHAR *
WStrDupe(const WCHAR *wstr)
{
const size_t len = (WStrLen(wstr) + 1) * sizeof (WCHAR);
WCHAR *retval = (WCHAR *) SDL_malloc(len);
if (retval) {
SDL_memcpy(retval, wstr, len);
}
return retval;
}
void
WASAPI_RemoveDevice(const SDL_bool iscapture, LPCWSTR devid)
@@ -106,7 +73,7 @@ WASAPI_RemoveDevice(const SDL_bool iscapture, LPCWSTR devid)
DevIdList *prev = NULL;
for (i = deviceid_list; i; i = next) {
next = i->next;
if (WStrEqual(i->str, devid)) {
if (SDL_wcscmp(i->str, devid) == 0) {
if (prev) {
prev->next = next;
} else {
@@ -120,10 +87,33 @@ WASAPI_RemoveDevice(const SDL_bool iscapture, LPCWSTR devid)
}
}
static SDL_AudioFormat
WaveFormatToSDLFormat(WAVEFORMATEX *waveformat)
{
if ((waveformat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) && (waveformat->wBitsPerSample == 32)) {
return AUDIO_F32SYS;
} else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 16)) {
return AUDIO_S16SYS;
} else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 32)) {
return AUDIO_S32SYS;
} else if (waveformat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
const WAVEFORMATEXTENSIBLE *ext = (const WAVEFORMATEXTENSIBLE *) waveformat;
if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
return AUDIO_F32SYS;
} else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 16)) {
return AUDIO_S16SYS;
} else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
return AUDIO_S32SYS;
}
}
return 0;
}
void
WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, LPCWSTR devid)
WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid)
{
DevIdList *devidlist;
SDL_AudioSpec spec;
/* You can have multiple endpoints on a device that are mutually exclusive ("Speakers" vs "Line Out" or whatever).
In a perfect world, things that are unplugged won't be in this collection. The only gotcha is probably for
@@ -132,7 +122,7 @@ WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, LPCWSTR devid)
/* see if we already have this one. */
for (devidlist = deviceid_list; devidlist; devidlist = devidlist->next) {
if (WStrEqual(devidlist->str, devid)) {
if (SDL_wcscmp(devidlist->str, devid) == 0) {
return; /* we already have this. */
}
}
@@ -142,7 +132,7 @@ WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, LPCWSTR devid)
return; /* oh well. */
}
devid = WStrDupe(devid);
devid = SDL_wcsdup(devid);
if (!devid) {
SDL_free(devidlist);
return; /* oh well. */
@@ -152,7 +142,11 @@ WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, LPCWSTR devid)
devidlist->next = deviceid_list;
deviceid_list = devidlist;
SDL_AddAudioDevice(iscapture, devname, (void *) devid);
SDL_zero(spec);
spec.channels = (Uint8)fmt->Format.nChannels;
spec.freq = fmt->Format.nSamplesPerSec;
spec.format = WaveFormatToSDLFormat((WAVEFORMATEX *) fmt);
SDL_AddAudioDevice(iscapture, devname, &spec, (void *) devid);
}
static void
@@ -161,21 +155,6 @@ WASAPI_DetectDevices(void)
WASAPI_EnumerateEndpoints();
}
static int
WASAPI_GetPendingBytes(_THIS)
{
UINT32 frames = 0;
/* it's okay to fail here; we'll deal with failures in the audio thread. */
/* FIXME: need a lock around checking this->hidden->client */
if (this->hidden->client != NULL) { /* definitely activated? */
if (FAILED(IAudioClient_GetCurrentPadding(this->hidden->client, &frames))) {
return 0; /* oh well. */
}
}
return ((int) frames) * this->hidden->framesize;
}
static SDL_INLINE SDL_bool
WasapiFailed(_THIS, const HRESULT err)
{
@@ -230,7 +209,7 @@ UpdateAudioStream(_THIS, const SDL_AudioSpec *oldspec)
}
if (!this->stream) {
return -1;
return -1; /* SDL_NewAudioStream should have called SDL_SetError. */
}
}
@@ -327,17 +306,23 @@ static void
WASAPI_WaitDevice(_THIS)
{
while (RecoverWasapiIfLost(this) && this->hidden->client && this->hidden->event) {
/*SDL_Log("WAITDEVICE");*/
if (WaitForSingleObjectEx(this->hidden->event, INFINITE, FALSE) == WAIT_OBJECT_0) {
DWORD waitResult = WaitForSingleObjectEx(this->hidden->event, 200, FALSE);
if (waitResult == WAIT_OBJECT_0) {
const UINT32 maxpadding = this->spec.samples;
UINT32 padding = 0;
if (!WasapiFailed(this, IAudioClient_GetCurrentPadding(this->hidden->client, &padding))) {
/*SDL_Log("WASAPI EVENT! padding=%u maxpadding=%u", (unsigned int)padding, (unsigned int)maxpadding);*/
if (padding <= maxpadding) {
break;
if (this->iscapture) {
if (padding > 0) {
break;
}
} else {
if (padding <= maxpadding) {
break;
}
}
}
} else {
} else if (waitResult != WAIT_TIMEOUT) {
/*SDL_Log("WASAPI FAILED EVENT!");*/
IAudioClient_Stop(this->hidden->client);
SDL_OpenedAudioDeviceDisconnected(this);
@@ -440,7 +425,6 @@ ReleaseWasapiDevice(_THIS)
{
if (this->hidden->client) {
IAudioClient_Stop(this->hidden->client);
IAudioClient_SetEventHandle(this->hidden->client, NULL);
IAudioClient_Release(this->hidden->client);
this->hidden->client = NULL;
}
@@ -523,14 +507,13 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
const SDL_AudioSpec oldspec = this->spec;
const AUDCLNT_SHAREMODE sharemode = AUDCLNT_SHAREMODE_SHARED;
UINT32 bufsize = 0; /* this is in sample frames, not samples, not bytes. */
REFERENCE_TIME duration = 0;
REFERENCE_TIME default_period = 0;
IAudioClient *client = this->hidden->client;
IAudioRenderClient *render = NULL;
IAudioCaptureClient *capture = NULL;
WAVEFORMATEX *waveformat = NULL;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
SDL_AudioFormat test_format;
SDL_AudioFormat wasapi_format = 0;
SDL_bool valid_format = SDL_FALSE;
HRESULT ret = S_OK;
DWORD streamflags = 0;
@@ -557,56 +540,37 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
this->spec.channels = (Uint8) waveformat->nChannels;
/* Make sure we have a valid format that we can convert to whatever WASAPI wants. */
if ((waveformat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) && (waveformat->wBitsPerSample == 32)) {
wasapi_format = AUDIO_F32SYS;
} else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 16)) {
wasapi_format = AUDIO_S16SYS;
} else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 32)) {
wasapi_format = AUDIO_S32SYS;
} else if (waveformat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
const WAVEFORMATEXTENSIBLE *ext = (const WAVEFORMATEXTENSIBLE *) waveformat;
if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
wasapi_format = AUDIO_F32SYS;
} else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 16)) {
wasapi_format = AUDIO_S16SYS;
} else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
wasapi_format = AUDIO_S32SYS;
}
}
wasapi_format = WaveFormatToSDLFormat(waveformat);
while ((!valid_format) && (test_format)) {
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
if (test_format == wasapi_format) {
this->spec.format = test_format;
valid_format = SDL_TRUE;
break;
}
test_format = SDL_NextAudioFormat();
}
if (!valid_format) {
return SDL_SetError("WASAPI: Unsupported audio format");
if (!test_format) {
return SDL_SetError("%s: Unsupported audio format", "wasapi");
}
ret = IAudioClient_GetDevicePeriod(client, NULL, &duration);
ret = IAudioClient_GetDevicePeriod(client, &default_period, NULL);
if (FAILED(ret)) {
return WIN_SetErrorFromHRESULT("WASAPI can't determine minimum device period", ret);
}
/* favor WASAPI's resampler over our own, in Win7+. */
#if 1 /* we're getting reports that WASAPI's resampler introduces distortions, so it's disabled for now. --ryan. */
this->spec.freq = waveformat->nSamplesPerSec; /* force sampling rate so our resampler kicks in, if necessary. */
#else
/* favor WASAPI's resampler over our own */
if (this->spec.freq != waveformat->nSamplesPerSec) {
/* RATEADJUST only works with output devices in share mode, and is available in Win7 and later.*/
if (WIN_IsWindows7OrGreater() && !this->iscapture && (sharemode == AUDCLNT_SHAREMODE_SHARED)) {
streamflags |= AUDCLNT_STREAMFLAGS_RATEADJUST;
waveformat->nSamplesPerSec = this->spec.freq;
waveformat->nAvgBytesPerSec = waveformat->nSamplesPerSec * waveformat->nChannels * (waveformat->wBitsPerSample / 8);
}
else {
this->spec.freq = waveformat->nSamplesPerSec; /* force sampling rate so our resampler kicks in. */
}
streamflags |= (AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY);
waveformat->nSamplesPerSec = this->spec.freq;
waveformat->nAvgBytesPerSec = waveformat->nSamplesPerSec * waveformat->nChannels * (waveformat->wBitsPerSample / 8);
}
#endif
streamflags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
ret = IAudioClient_Initialize(client, sharemode, streamflags, duration, sharemode == AUDCLNT_SHAREMODE_SHARED ? 0 : duration, waveformat, NULL);
ret = IAudioClient_Initialize(client, sharemode, streamflags, 0, 0, waveformat, NULL);
if (FAILED(ret)) {
return WIN_SetErrorFromHRESULT("WASAPI can't initialize audio client", ret);
}
@@ -621,9 +585,12 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
return WIN_SetErrorFromHRESULT("WASAPI can't determine buffer size", ret);
}
this->spec.samples = (Uint16) bufsize;
if (!this->iscapture) {
this->spec.samples /= 2; /* fill half of the DMA buffer on each run. */
/* Match the callback size to the period size to cut down on the number of
interrupts waited for in each call to WaitDevice */
{
const float period_millis = default_period / 10000.0f;
const float period_frames = period_millis * this->spec.freq / 1000.0f;
this->spec.samples = (Uint16)SDL_ceilf(period_frames);
}
/* Update the fragment size as size in bytes */
@@ -665,9 +632,7 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
}
if (updatestream) {
if (UpdateAudioStream(this, &oldspec) == -1) {
return -1;
}
return UpdateAudioStream(this, &oldspec);
}
return 0; /* good to go. */
@@ -675,9 +640,9 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
static int
WASAPI_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
WASAPI_OpenDevice(_THIS, const char *devname)
{
LPCWSTR devid = (LPCWSTR) handle;
LPCWSTR devid = (LPCWSTR) this->handle;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
@@ -690,9 +655,9 @@ WASAPI_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
WASAPI_RefDevice(this); /* so CloseDevice() will unref to zero. */
if (!devid) { /* is default device? */
this->hidden->default_device_generation = SDL_AtomicGet(iscapture ? &WASAPI_DefaultCaptureGeneration : &WASAPI_DefaultPlaybackGeneration);
this->hidden->default_device_generation = SDL_AtomicGet(this->iscapture ? &WASAPI_DefaultCaptureGeneration : &WASAPI_DefaultPlaybackGeneration);
} else {
this->hidden->devid = WStrDupe(devid);
this->hidden->devid = SDL_wcsdup(devid);
if (!this->hidden->devid) {
return SDL_OutOfMemory();
}
@@ -725,12 +690,6 @@ WASAPI_ThreadDeinit(_THIS)
WASAPI_PlatformThreadDeinit(this);
}
void
WASAPI_BeginLoopIteration(_THIS)
{
/* no-op. */
}
static void
WASAPI_Deinitialize(void)
{
@@ -747,37 +706,35 @@ WASAPI_Deinitialize(void)
deviceid_list = NULL;
}
static int
static SDL_bool
WASAPI_Init(SDL_AudioDriverImpl * impl)
{
SDL_AtomicSet(&WASAPI_DefaultPlaybackGeneration, 1);
SDL_AtomicSet(&WASAPI_DefaultCaptureGeneration, 1);
if (WASAPI_PlatformInit() == -1) {
return 0;
return SDL_FALSE;
}
/* Set the function pointers */
impl->DetectDevices = WASAPI_DetectDevices;
impl->ThreadInit = WASAPI_ThreadInit;
impl->ThreadDeinit = WASAPI_ThreadDeinit;
impl->BeginLoopIteration = WASAPI_BeginLoopIteration;
impl->OpenDevice = WASAPI_OpenDevice;
impl->PlayDevice = WASAPI_PlayDevice;
impl->WaitDevice = WASAPI_WaitDevice;
impl->GetPendingBytes = WASAPI_GetPendingBytes;
impl->GetDeviceBuf = WASAPI_GetDeviceBuf;
impl->CaptureFromDevice = WASAPI_CaptureFromDevice;
impl->FlushCapture = WASAPI_FlushCapture;
impl->CloseDevice = WASAPI_CloseDevice;
impl->Deinitialize = WASAPI_Deinitialize;
impl->HasCaptureSupport = 1;
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap WASAPI_bootstrap = {
"wasapi", "WASAPI", WASAPI_Init, 0
"wasapi", "WASAPI", WASAPI_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_WASAPI */
+2 -3
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -63,7 +63,7 @@ extern SDL_atomic_t WASAPI_DefaultCaptureGeneration;
int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream);
void WASAPI_RefDevice(_THIS);
void WASAPI_UnrefDevice(_THIS);
void WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, LPCWSTR devid);
void WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid);
void WASAPI_RemoveDevice(const SDL_bool iscapture, LPCWSTR devid);
/* These are functions that are implemented differently for Windows vs WinRT. */
@@ -74,7 +74,6 @@ int WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery);
void WASAPI_PlatformThreadInit(_THIS);
void WASAPI_PlatformThreadDeinit(_THIS);
void WASAPI_PlatformDeleteActivationHandler(void *handler);
void WASAPI_BeginLoopIteration(_THIS);
#ifdef __cplusplus
}
+22 -17
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -18,7 +18,6 @@
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
/* This is code that Windows uses to talk to WASAPI-related system APIs.
@@ -34,8 +33,6 @@
#include "SDL_timer.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_assert.h"
#include "SDL_log.h"
#define COBJMACROS
#include <mmdeviceapi.h>
@@ -56,7 +53,7 @@ static IMMDeviceEnumerator *enumerator = NULL;
/* handle to Avrt.dll--Vista and later!--for flagging the callback thread as "Pro Audio" (low latency). */
static HMODULE libavrt = NULL;
typedef HANDLE(WINAPI *pfnAvSetMmThreadCharacteristicsW)(LPWSTR, LPDWORD);
typedef HANDLE(WINAPI *pfnAvSetMmThreadCharacteristicsW)(LPCWSTR, LPDWORD);
typedef BOOL(WINAPI *pfnAvRevertMmThreadCharacteristics)(HANDLE);
static pfnAvSetMmThreadCharacteristicsW pAvSetMmThreadCharacteristicsW = NULL;
static pfnAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL;
@@ -68,26 +65,31 @@ static const IID SDL_IID_IMMNotificationClient = { 0x7991eec9, 0x7e89, 0x4d85,{
static const IID SDL_IID_IMMEndpoint = { 0x1be09788, 0x6894, 0x4089,{ 0x85, 0x86, 0x9a, 0x2a, 0x6c, 0x26, 0x5a, 0xc5 } };
static const IID SDL_IID_IAudioClient = { 0x1cb9ad4c, 0xdbfa, 0x4c32,{ 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2 } };
static const PROPERTYKEY SDL_PKEY_Device_FriendlyName = { { 0xa45c254e, 0xdf1c, 0x4efd,{ 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, } }, 14 };
static const PROPERTYKEY SDL_PKEY_AudioEngine_DeviceFormat = { { 0xf19f064d, 0x82c, 0x4e27,{ 0xbc, 0x73, 0x68, 0x82, 0xa1, 0xbb, 0x8e, 0x4c, } }, 0 };
static char *
GetWasapiDeviceName(IMMDevice *device)
static void
GetWasapiDeviceInfo(IMMDevice *device, char **utf8dev, WAVEFORMATEXTENSIBLE *fmt)
{
/* PKEY_Device_FriendlyName gives you "Speakers (SoundBlaster Pro)" which drives me nuts. I'd rather it be
"SoundBlaster Pro (Speakers)" but I guess that's developers vs users. Windows uses the FriendlyName in
its own UIs, like Volume Control, etc. */
char *utf8dev = NULL;
IPropertyStore *props = NULL;
*utf8dev = NULL;
SDL_zerop(fmt);
if (SUCCEEDED(IMMDevice_OpenPropertyStore(device, STGM_READ, &props))) {
PROPVARIANT var;
PropVariantInit(&var);
if (SUCCEEDED(IPropertyStore_GetValue(props, &SDL_PKEY_Device_FriendlyName, &var))) {
utf8dev = WIN_StringToUTF8(var.pwszVal);
*utf8dev = WIN_StringToUTF8W(var.pwszVal);
}
PropVariantClear(&var);
if (SUCCEEDED(IPropertyStore_GetValue(props, &SDL_PKEY_AudioEngine_DeviceFormat, &var))) {
SDL_memcpy(fmt, var.blob.pBlobData, SDL_min(var.blob.cbSize, sizeof(WAVEFORMATEXTENSIBLE)));
}
PropVariantClear(&var);
IPropertyStore_Release(props);
}
return utf8dev;
}
@@ -197,9 +199,11 @@ SDLMMNotificationClient_OnDeviceStateChanged(IMMNotificationClient *ithis, LPCWS
if (SUCCEEDED(IMMEndpoint_GetDataFlow(endpoint, &flow))) {
const SDL_bool iscapture = (flow == eCapture);
if (dwNewState == DEVICE_STATE_ACTIVE) {
char *utf8dev = GetWasapiDeviceName(device);
char *utf8dev;
WAVEFORMATEXTENSIBLE fmt;
GetWasapiDeviceInfo(device, &utf8dev, &fmt);
if (utf8dev) {
WASAPI_AddDevice(iscapture, utf8dev, pwstrDeviceId);
WASAPI_AddDevice(iscapture, utf8dev, &fmt, pwstrDeviceId);
SDL_free(utf8dev);
}
} else {
@@ -248,13 +252,13 @@ WASAPI_PlatformInit(void)
return SDL_SetError("WASAPI: CoInitialize() failed");
}
ret = CoCreateInstance(&SDL_CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &SDL_IID_IMMDeviceEnumerator, (LPVOID) &enumerator);
ret = CoCreateInstance(&SDL_CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &SDL_IID_IMMDeviceEnumerator, (LPVOID *) &enumerator);
if (FAILED(ret)) {
WIN_CoUninitialize();
return WIN_SetErrorFromHRESULT("WASAPI CoCreateInstance(MMDeviceEnumerator)", ret);
}
libavrt = LoadLibraryW(L"avrt.dll"); /* this library is available in Vista and later. No WinXP, so have to LoadLibrary to use it for now! */
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");
@@ -294,7 +298,7 @@ WASAPI_PlatformThreadInit(_THIS)
/* Set this thread to very high "Pro Audio" priority. */
if (pAvSetMmThreadCharacteristicsW) {
DWORD idx = 0;
this->hidden->task = pAvSetMmThreadCharacteristicsW(TEXT("Pro Audio"), &idx);
this->hidden->task = pAvSetMmThreadCharacteristicsW(L"Pro Audio", &idx);
}
}
@@ -355,6 +359,7 @@ typedef struct
{
LPWSTR devid;
char *devname;
WAVEFORMATEXTENSIBLE fmt;
} EndpointItem;
static int sort_endpoints(const void *_a, const void *_b)
@@ -411,7 +416,7 @@ WASAPI_EnumerateEndpointsForFlow(const SDL_bool iscapture)
IMMDevice *device = NULL;
if (SUCCEEDED(IMMDeviceCollection_Item(collection, i, &device))) {
if (SUCCEEDED(IMMDevice_GetId(device, &item->devid))) {
item->devname = GetWasapiDeviceName(device);
GetWasapiDeviceInfo(device, &item->devname, &item->fmt);
}
IMMDevice_Release(device);
}
@@ -424,7 +429,7 @@ WASAPI_EnumerateEndpointsForFlow(const SDL_bool iscapture)
for (i = 0; i < total; i++) {
EndpointItem *item = items + i;
if ((item->devid) && (item->devname)) {
WASAPI_AddDevice(iscapture, item->devname, item->devid);
WASAPI_AddDevice(iscapture, item->devname, &item->fmt, item->devid);
}
SDL_free(item->devname);
CoTaskMemFree(item->devid);
+43 -6
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -18,7 +18,6 @@
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
// This is C++/CX code that the WinRT port uses to talk to WASAPI-related
@@ -33,6 +32,7 @@
#include <windows.devices.enumeration.h>
#include <windows.media.devices.h>
#include <wrl/implements.h>
#include <collection.h>
extern "C" {
#include "../../core/windows/SDL_windows.h"
@@ -40,8 +40,6 @@ extern "C" {
#include "SDL_timer.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_assert.h"
#include "SDL_log.h"
}
#define COBJMACROS
@@ -55,6 +53,8 @@ using namespace Windows::Media::Devices;
using namespace Windows::Foundation;
using namespace Microsoft::WRL;
static Platform::String^ SDL_PKEY_AudioEngine_DeviceFormat = L"{f19f064d-082c-4e27-bc73-6882a1bb8e4c} 0";
class SDL_WasapiDeviceEventHandler
{
public:
@@ -63,8 +63,10 @@ public:
void OnDeviceAdded(DeviceWatcher^ sender, DeviceInformation^ args);
void OnDeviceRemoved(DeviceWatcher^ sender, DeviceInformationUpdate^ args);
void OnDeviceUpdated(DeviceWatcher^ sender, DeviceInformationUpdate^ args);
void OnEnumerationCompleted(DeviceWatcher^ sender, Platform::Object^ args);
void OnDefaultRenderDeviceChanged(Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args);
void OnDefaultCaptureDeviceChanged(Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args);
SDL_semaphore* completed;
private:
const SDL_bool iscapture;
@@ -72,13 +74,22 @@ private:
Windows::Foundation::EventRegistrationToken added_handler;
Windows::Foundation::EventRegistrationToken removed_handler;
Windows::Foundation::EventRegistrationToken updated_handler;
Windows::Foundation::EventRegistrationToken completed_handler;
Windows::Foundation::EventRegistrationToken default_changed_handler;
};
SDL_WasapiDeviceEventHandler::SDL_WasapiDeviceEventHandler(const SDL_bool _iscapture)
: iscapture(_iscapture)
, watcher(DeviceInformation::CreateWatcher(_iscapture ? DeviceClass::AudioCapture : DeviceClass::AudioRender))
, completed(SDL_CreateSemaphore(0))
{
if (!completed)
return; // uhoh.
Platform::String^ selector = _iscapture ? MediaDevice::GetAudioCaptureSelector() :
MediaDevice::GetAudioRenderSelector();
Platform::Collections::Vector<Platform::String^> properties;
properties.Append(SDL_PKEY_AudioEngine_DeviceFormat);
watcher = DeviceInformation::CreateWatcher(selector, properties.GetView());
if (!watcher)
return; // uhoh.
@@ -86,6 +97,7 @@ SDL_WasapiDeviceEventHandler::SDL_WasapiDeviceEventHandler(const SDL_bool _iscap
added_handler = watcher->Added += ref new TypedEventHandler<DeviceWatcher^, DeviceInformation^>([this](DeviceWatcher^ sender, DeviceInformation^ args) { OnDeviceAdded(sender, args); } );
removed_handler = watcher->Removed += ref new TypedEventHandler<DeviceWatcher^, DeviceInformationUpdate^>([this](DeviceWatcher^ sender, DeviceInformationUpdate^ args) { OnDeviceRemoved(sender, args); } );
updated_handler = watcher->Updated += ref new TypedEventHandler<DeviceWatcher^, DeviceInformationUpdate^>([this](DeviceWatcher^ sender, DeviceInformationUpdate^ args) { OnDeviceUpdated(sender, args); } );
completed_handler = watcher->EnumerationCompleted += ref new TypedEventHandler<DeviceWatcher^, Platform::Object^>([this](DeviceWatcher^ sender, Platform::Object^ args) { OnEnumerationCompleted(sender, args); } );
if (iscapture) {
default_changed_handler = MediaDevice::DefaultAudioCaptureDeviceChanged += ref new TypedEventHandler<Platform::Object^, DefaultAudioCaptureDeviceChangedEventArgs^>([this](Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args) { OnDefaultCaptureDeviceChanged(sender, args); } );
} else {
@@ -100,9 +112,14 @@ SDL_WasapiDeviceEventHandler::~SDL_WasapiDeviceEventHandler()
watcher->Added -= added_handler;
watcher->Removed -= removed_handler;
watcher->Updated -= updated_handler;
watcher->EnumerationCompleted -= completed_handler;
watcher->Stop();
watcher = nullptr;
}
if (completed) {
SDL_DestroySemaphore(completed);
completed = nullptr;
}
if (iscapture) {
MediaDevice::DefaultAudioCaptureDeviceChanged -= default_changed_handler;
@@ -117,7 +134,18 @@ SDL_WasapiDeviceEventHandler::OnDeviceAdded(DeviceWatcher^ sender, DeviceInforma
SDL_assert(sender == this->watcher);
char *utf8dev = WIN_StringToUTF8(info->Name->Data());
if (utf8dev) {
WASAPI_AddDevice(this->iscapture, utf8dev, info->Id->Data());
WAVEFORMATEXTENSIBLE fmt;
Platform::Object^ obj = info->Properties->Lookup(SDL_PKEY_AudioEngine_DeviceFormat);
if (obj) {
IPropertyValue^ property = (IPropertyValue^) obj;
Platform::Array<unsigned char>^ data;
property->GetUInt8Array(&data);
SDL_memcpy(&fmt, data->Data, SDL_min(data->Length, sizeof(WAVEFORMATEXTENSIBLE)));
} else {
SDL_zero(fmt);
}
WASAPI_AddDevice(this->iscapture, utf8dev, &fmt, info->Id->Data());
SDL_free(utf8dev);
}
}
@@ -135,6 +163,13 @@ SDL_WasapiDeviceEventHandler::OnDeviceUpdated(DeviceWatcher^ sender, DeviceInfor
SDL_assert(sender == this->watcher);
}
void
SDL_WasapiDeviceEventHandler::OnEnumerationCompleted(DeviceWatcher^ sender, Platform::Object^ args)
{
SDL_assert(sender == this->watcher);
SDL_SemPost(this->completed);
}
void
SDL_WasapiDeviceEventHandler::OnDefaultRenderDeviceChanged(Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args)
{
@@ -173,6 +208,8 @@ void WASAPI_EnumerateEndpoints(void)
// listening for updates.
playback_device_event_handler = new SDL_WasapiDeviceEventHandler(SDL_FALSE);
capture_device_event_handler = new SDL_WasapiDeviceEventHandler(SDL_TRUE);
SDL_SemWait(playback_device_event_handler->completed);
SDL_SemWait(capture_device_event_handler->completed);
}
struct SDL_WasapiActivationHandler : public RuntimeClass< RuntimeClassFlags< ClassicCom >, FtmBase, IActivateAudioInterfaceCompletionHandler >
+25 -22
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -27,7 +27,6 @@
#include "../../core/windows/SDL_windows.h"
#include <mmsystem.h>
#include "SDL_assert.h"
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
@@ -76,12 +75,19 @@ static void DetectWave##typ##Devs(void) { \
const UINT iscapture = iscap ? 1 : 0; \
const UINT devcount = wave##typ##GetNumDevs(); \
capstyp##2W caps; \
SDL_AudioSpec spec; \
UINT i; \
SDL_zero(spec); \
for (i = 0; i < devcount; i++) { \
if (wave##typ##GetDevCaps(i,(LP##capstyp##W)&caps,sizeof(caps))==MMSYSERR_NOERROR) { \
char *name = WIN_LookupAudioDeviceName(caps.szPname,&caps.NameGuid); \
if (name != NULL) { \
SDL_AddAudioDevice((int) iscapture, name, (void *) ((size_t) i+1)); \
/* Note that freq/format are not filled in, as this information \
* is not provided by the caps struct! At best, we get possible \
* sample formats, but not an _active_ format. \
*/ \
spec.channels = (Uint8)caps.wChannels; \
SDL_AddAudioDevice((int) iscapture, name, &spec, (void *) ((size_t) i+1)); \
SDL_free(name); \
} \
} \
@@ -129,7 +135,7 @@ FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
}
static int
SetMMerror(char *function, MMRESULT code)
SetMMerror(const char *function, MMRESULT code)
{
int len;
char errbuf[MAXERRORLENGTH];
@@ -277,10 +283,11 @@ PrepWaveFormat(_THIS, UINT devId, WAVEFORMATEX *pfmt, const int iscapture)
}
static int
WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
WINMM_OpenDevice(_THIS, const char *devname)
{
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
int valid_datatype = 0;
SDL_AudioFormat test_format;
SDL_bool iscapture = this->iscapture;
void *handle = this->handle;
MMRESULT result;
WAVEFORMATEX waveformat;
UINT devId = WAVE_MAPPER; /* WAVE_MAPPER == choose system's default */
@@ -307,7 +314,7 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (this->spec.channels > 2)
this->spec.channels = 2; /* !!! FIXME: is this right? */
while ((!valid_datatype) && (test_format)) {
for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
switch (test_format) {
case AUDIO_U8:
case AUDIO_S16:
@@ -315,20 +322,17 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
case AUDIO_F32:
this->spec.format = test_format;
if (PrepWaveFormat(this, devId, &waveformat, iscapture)) {
valid_datatype = 1;
} else {
test_format = SDL_NextAudioFormat();
break;
}
break;
continue;
default:
test_format = SDL_NextAudioFormat();
break;
continue;
}
break;
}
if (!valid_datatype) {
return SDL_SetError("Unsupported audio format");
if (!test_format) {
return SDL_SetError("%s: Unsupported audio format", "winmm");
}
/* Update the fragment size as size in bytes */
@@ -387,7 +391,7 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
return SDL_OutOfMemory();
}
SDL_zero(this->hidden->wavebuf);
SDL_zeroa(this->hidden->wavebuf);
for (i = 0; i < NUM_BUFFERS; ++i) {
this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
@@ -428,8 +432,7 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
return 0; /* Ready to go! */
}
static int
static SDL_bool
WINMM_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
@@ -444,11 +447,11 @@ WINMM_Init(SDL_AudioDriverImpl * impl)
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
return SDL_TRUE; /* this audio target is available. */
}
AudioBootStrap WINMM_bootstrap = {
"winmm", "Windows Waveform Audio", WINMM_Init, 0
"winmm", "Windows Waveform Audio", WINMM_Init, SDL_FALSE
};
#endif /* SDL_AUDIO_DRIVER_WINMM */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
File diff suppressed because it is too large Load Diff
+26 -6
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -33,11 +33,14 @@ extern "C" {
#include "SDL_audio.h"
#include "SDL_rect.h"
#include "SDL_video.h"
/* 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);
extern void Android_JNI_SetOrientation(int w, int h, int resizable, const char *hint);
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);
@@ -45,6 +48,7 @@ extern void Android_JNI_HideTextInput(void);
extern SDL_bool Android_JNI_IsScreenKeyboardShown(void);
extern ANativeWindow* Android_JNI_GetNativeWindow(void);
extern SDL_DisplayOrientation Android_JNI_GetDisplayOrientation(void);
extern int Android_JNI_GetDisplayDPI(float *ddpi, float *xdpi, float *ydpi);
/* Audio support */
@@ -54,10 +58,11 @@ extern void Android_JNI_WriteAudioBuffer(void);
extern int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen);
extern void Android_JNI_FlushCapturedAudio(void);
extern void Android_JNI_CloseAudioDevice(const int iscapture);
extern void Android_JNI_AudioSetThreadPriority(int iscapture, int device_id);
/* Detecting device type */
extern SDL_bool Android_IsDeXMode();
extern SDL_bool Android_IsChromebook();
extern SDL_bool Android_IsDeXMode(void);
extern SDL_bool Android_IsChromebook(void);
#include "SDL_rwops.h"
@@ -91,15 +96,16 @@ void Android_JNI_HapticStop(int device_id);
void Android_JNI_SuspendScreenSaver(SDL_bool suspend);
/* Touch support */
int Android_JNI_InitTouch(void);
void Android_JNI_SetSeparateMouseAndTouch(SDL_bool new_value);
int Android_JNI_GetTouchDeviceIds(int **ids);
void Android_JNI_InitTouch(void);
/* Threads */
#include <jni.h>
JNIEnv *Android_JNI_GetEnv(void);
int Android_JNI_SetupThread(void);
/* Locale */
int Android_JNI_GetLocale(char *buf, size_t buflen);
/* Generic messages */
int Android_JNI_SendMessage(int command, int param);
@@ -112,6 +118,7 @@ int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *bu
/* Cursor support */
int Android_JNI_CreateCustomCursor(SDL_Surface *surface, int hot_x, int hot_y);
void Android_JNI_DestroyCustomCursor(int cursorID);
SDL_bool Android_JNI_SetCustomCursor(int cursorID);
SDL_bool Android_JNI_SetSystemCursor(int cursorID);
@@ -119,12 +126,25 @@ SDL_bool Android_JNI_SetSystemCursor(int cursorID);
SDL_bool Android_JNI_SupportsRelativeMouse(void);
SDL_bool Android_JNI_SetRelativeMouseEnabled(SDL_bool enabled);
/* Request permission */
SDL_bool Android_JNI_RequestPermission(const char *permission);
/* Show toast notification */
int Android_JNI_ShowToast(const char* message, int duration, int gravity, int xOffset, int yOffset);
int Android_JNI_OpenURL(const char *url);
int SDL_GetAndroidSDKVersion(void);
SDL_bool SDL_IsAndroidTablet(void);
SDL_bool SDL_IsAndroidTV(void);
SDL_bool SDL_IsChromebook(void);
SDL_bool SDL_IsDeXMode(void);
void Android_ActivityMutex_Lock(void);
void Android_ActivityMutex_Unlock(void);
void Android_ActivityMutex_Lock_Running(void);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
/* *INDENT-OFF* */
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -0,0 +1,165 @@
#include <sys/kbio.h>
/*
* Automatically generated from /usr/share/vt/keymaps/us.acc.kbd.
* DO NOT EDIT!
*/
static keymap_t keymap_default_us_acc = { 0x6d, {
/* alt
* scan cntrl alt alt cntrl
* code base shift cntrl shift alt shift cntrl shift spcl flgs
* ---------------------------------------------------------------------------
*/
/*00*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 },
/*01*/{{ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, DBG, }, 0x03,0x00 },
/*02*/{{ '1', '!', NOP, NOP, '1', '!', NOP, NOP, }, 0x33,0x00 },
/*03*/{{ '2', '@', 0x00, 0x00, '2', '@', 0x00, 0x00, }, 0x00,0x00 },
/*04*/{{ '3', '#', NOP, NOP, '3', '#', NOP, NOP, }, 0x33,0x00 },
/*05*/{{ '4', '$', NOP, NOP, '4', '$', NOP, NOP, }, 0x33,0x00 },
/*06*/{{ '5', '%', NOP, NOP, '5', '%', NOP, NOP, }, 0x33,0x00 },
/*07*/{{ '6', '^', 0x1E, 0x1E, '6', DCIR, 0x1E, 0x1E, }, 0x04,0x00 },
/*08*/{{ '7', '&', NOP, NOP, '7', '&', NOP, NOP, }, 0x33,0x00 },
/*09*/{{ '8', '*', NOP, NOP, '8', DRIN, NOP, NOP, }, 0x37,0x00 },
/*0a*/{{ '9', '(', NOP, NOP, '9', '(', NOP, NOP, }, 0x33,0x00 },
/*0b*/{{ '0', ')', NOP, NOP, '0', ')', NOP, NOP, }, 0x33,0x00 },
/*0c*/{{ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, }, 0x00,0x00 },
/*0d*/{{ '=', '+', NOP, NOP, '=', '+', NOP, NOP, }, 0x33,0x00 },
/*0e*/{{ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, }, 0x00,0x00 },
/*0f*/{{ 0x09, BTAB, NEXT, NEXT, 0x09, BTAB, NOP, NOP, }, 0x77,0x00 },
/*10*/{{ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, }, 0x00,0x01 },
/*11*/{{ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, }, 0x00,0x01 },
/*12*/{{ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, }, 0x00,0x01 },
/*13*/{{ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, }, 0x00,0x01 },
/*14*/{{ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, }, 0x00,0x01 },
/*15*/{{ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, }, 0x00,0x01 },
/*16*/{{ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, }, 0x00,0x01 },
/*17*/{{ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, }, 0x00,0x01 },
/*18*/{{ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, }, 0x00,0x01 },
/*19*/{{ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, }, 0x00,0x01 },
/*1a*/{{ '[', '{', 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, }, 0x00,0x00 },
/*1b*/{{ ']', '}', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, }, 0x00,0x00 },
/*1c*/{{ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, }, 0x00,0x00 },
/*1d*/{{ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, }, 0xFF,0x00 },
/*1e*/{{ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, }, 0x00,0x01 },
/*1f*/{{ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, }, 0x00,0x01 },
/*20*/{{ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, }, 0x00,0x01 },
/*21*/{{ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, }, 0x00,0x01 },
/*22*/{{ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, }, 0x00,0x01 },
/*23*/{{ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, }, 0x00,0x01 },
/*24*/{{ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, }, 0x00,0x01 },
/*25*/{{ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, }, 0x00,0x01 },
/*26*/{{ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, }, 0x00,0x01 },
/*27*/{{ ';', ':', NOP, NOP, ';', ':', NOP, NOP, }, 0x33,0x00 },
/*28*/{{ '\'', '"', NOP, NOP, DACU, DUML, NOP, NOP, }, 0x3F,0x00 },
/*29*/{{ '`', '~', NOP, NOP, DGRA, DTIL, NOP, NOP, }, 0x3F,0x00 },
/*2a*/{{ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, }, 0xFF,0x00 },
/*2b*/{{ '\\', '|', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, }, 0x00,0x00 },
/*2c*/{{ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, }, 0x00,0x01 },
/*2d*/{{ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, }, 0x00,0x01 },
/*2e*/{{ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, }, 0x00,0x01 },
/*2f*/{{ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, }, 0x00,0x01 },
/*30*/{{ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, }, 0x00,0x01 },
/*31*/{{ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, }, 0x00,0x01 },
/*32*/{{ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, }, 0x00,0x01 },
/*33*/{{ ',', '<', NOP, NOP, DCED, '<', NOP, NOP, }, 0x3B,0x00 },
/*34*/{{ '.', '>', NOP, NOP, '.', '>', NOP, NOP, }, 0x33,0x00 },
/*35*/{{ '/', '?', NOP, NOP, '/', '?', NOP, NOP, }, 0x33,0x00 },
/*36*/{{ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, }, 0xFF,0x00 },
/*37*/{{ '*', '*', '*', '*', '*', '*', '*', '*', }, 0x00,0x00 },
/*38*/{{ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, }, 0xFF,0x00 },
/*39*/{{ ' ', ' ', 0x00, 0x00, ' ', ' ', SUSP, SUSP, }, 0x03,0x00 },
/*3a*/{{ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, }, 0xFF,0x00 },
/*3b*/{{ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11),}, 0xFF,0x00 },
/*3c*/{{ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12),}, 0xFF,0x00 },
/*3d*/{{ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13),}, 0xFF,0x00 },
/*3e*/{{ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14),}, 0xFF,0x00 },
/*3f*/{{ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15),}, 0xFF,0x00 },
/*40*/{{ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16),}, 0xFF,0x00 },
/*41*/{{ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7),}, 0xFF,0x00 },
/*42*/{{ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8),}, 0xFF,0x00 },
/*43*/{{ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9),}, 0xFF,0x00 },
/*44*/{{ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10),}, 0xFF,0x00 },
/*45*/{{ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, }, 0xFF,0x00 },
/*46*/{{ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, }, 0xFF,0x00 },
/*47*/{{ F(49), '7', '7', '7', '7', '7', '7', '7', }, 0x80,0x02 },
/*48*/{{ F(50), '8', '8', '8', '8', '8', '8', '8', }, 0x80,0x02 },
/*49*/{{ F(51), '9', '9', '9', '9', '9', '9', '9', }, 0x80,0x02 },
/*4a*/{{ F(52), '-', '-', '-', '-', '-', '-', '-', }, 0x80,0x02 },
/*4b*/{{ F(53), '4', '4', '4', '4', '4', '4', '4', }, 0x80,0x02 },
/*4c*/{{ F(54), '5', '5', '5', '5', '5', '5', '5', }, 0x80,0x02 },
/*4d*/{{ F(55), '6', '6', '6', '6', '6', '6', '6', }, 0x80,0x02 },
/*4e*/{{ F(56), '+', '+', '+', '+', '+', '+', '+', }, 0x80,0x02 },
/*4f*/{{ F(57), '1', '1', '1', '1', '1', '1', '1', }, 0x80,0x02 },
/*50*/{{ F(58), '2', '2', '2', '2', '2', '2', '2', }, 0x80,0x02 },
/*51*/{{ F(59), '3', '3', '3', '3', '3', '3', '3', }, 0x80,0x02 },
/*52*/{{ F(60), '0', '0', '0', '0', '0', '0', '0', }, 0x80,0x02 },
/*53*/{{ 0x7F, '.', '.', '.', '.', '.', RBT, RBT, }, 0x03,0x02 },
/*54*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 },
/*55*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 },
/*56*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 },
/*57*/{{ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11),}, 0xFF,0x00 },
/*58*/{{ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12),}, 0xFF,0x00 },
/*59*/{{ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, }, 0x00,0x00 },
/*5a*/{{ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, }, 0xFF,0x00 },
/*5b*/{{ '/', '/', '/', '/', '/', '/', '/', '/', }, 0x00,0x02 },
/*5c*/{{ NEXT, NEXT, NOP, NOP, DBG, DBG, DBG, DBG, }, 0xFF,0x00 },
/*5d*/{{ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, }, 0xFF,0x00 },
/*5e*/{{ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49),}, 0xFF,0x00 },
/*5f*/{{ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50),}, 0xFF,0x00 },
/*60*/{{ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51),}, 0xFF,0x00 },
/*61*/{{ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53),}, 0xFF,0x00 },
/*62*/{{ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55),}, 0xFF,0x00 },
/*63*/{{ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57),}, 0xFF,0x00 },
/*64*/{{ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58),}, 0xFF,0x00 },
/*65*/{{ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59),}, 0xFF,0x00 },
/*66*/{{ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60),}, 0xFF,0x00 },
/*67*/{{ F(61), F(61), F(61), F(61), F(61), F(61), RBT, F(61),}, 0xFF,0x00 },
/*68*/{{ SPSC, SPSC, SUSP, SUSP, NOP, NOP, SUSP, SUSP, }, 0xFF,0x00 },
/*69*/{{ F(62), F(62), F(62), F(62), F(62), F(62), F(62), F(62),}, 0xFF,0x00 },
/*6a*/{{ F(63), F(63), F(63), F(63), F(63), F(63), F(63), F(63),}, 0xFF,0x00 },
/*6b*/{{ F(64), F(64), F(64), F(64), F(64), F(64), F(64), F(64),}, 0xFF,0x00 },
/*6c*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 },
} };
static accentmap_t accentmap_default_us_acc = { 11, {
/* dgra=0 */
{ '`', { { 'a',0xe0 }, { 'A',0xc0 }, { 'e',0xe8 }, { 'E',0xc8 },
{ 'i',0xec }, { 'I',0xcc }, { 'o',0xf2 }, { 'O',0xd2 },
{ 'u',0xf9 }, { 'U',0xd9 }, }, },
/* dacu=1 */
{ 0xb4, { { 'a',0xe1 }, { 'A',0xc1 }, { 'e',0xe9 }, { 'E',0xc9 },
{ 'i',0xed }, { 'I',0xcd }, { 'o',0xf3 }, { 'O',0xd3 },
{ 'u',0xfa }, { 'U',0xda }, { 'y',0xfd }, { 'Y',0xdd }, }, },
/* dcir=2 */
{ '^', { { 'a',0xe2 }, { 'A',0xc2 }, { 'e',0xea }, { 'E',0xca },
{ 'i',0xee }, { 'I',0xce }, { 'o',0xf4 }, { 'O',0xd4 },
{ 'u',0xfb }, { 'U',0xdb }, }, },
/* dtil=3 */
{ '~', { { 'a',0xe3 }, { 'A',0xc3 }, { 'n',0xf1 }, { 'N',0xd1 },
{ 'o',0xf5 }, { 'O',0xd5 }, }, },
/* dmac=4 */
{ 0x00 },
/* dbre=5 */
{ 0x00 },
/* ddot=6 */
{ 0x00 },
/* duml=7 */
{ 0xa8, { { 'a',0xe4 }, { 'A',0xc4 }, { 'e',0xeb }, { 'E',0xcb },
{ 'i',0xef }, { 'I',0xcf }, { 'o',0xf6 }, { 'O',0xd6 },
{ 'u',0xfc }, { 'U',0xdc }, { 'y',0xff }, }, },
/* dsla=8 */
{ 0x00 },
/* drin=9 */
{ 0xb0, { { 'a',0xe5 }, { 'A',0xc5 }, }, },
/* dced=10 */
{ 0xb8, { { 'c',0xe7 }, { 'C',0xc7 }, }, },
/* dapo=11 */
{ 0x00 },
/* ddac=12 */
{ 0x00 },
/* dogo=13 */
{ 0x00 },
/* dcar=14 */
{ 0x00 },
} };
@@ -0,0 +1,584 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
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 "../linux/SDL_evdev_kbd.h"
#include "SDL_hints.h"
#ifdef SDL_INPUT_FBSDKBIO
/* This logic is adapted from drivers/tty/vt/keyboard.c in the Linux kernel source, slightly modified to work with FreeBSD */
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/kbio.h>
#include <sys/consio.h>
#include <signal.h>
#include "../../events/SDL_events_c.h"
#include "SDL_evdev_kbd_default_keyaccmap.h"
typedef void (fn_handler_fn)(SDL_EVDEV_keyboard_state *kbd);
/*
* Keyboard State
*/
struct SDL_EVDEV_keyboard_state
{
int console_fd;
int keyboard_fd;
unsigned long old_kbd_mode;
unsigned short **key_maps;
keymap_t* key_map;
keyboard_info_t* kbInfo;
unsigned char shift_down[4]; /* shift state counters.. */
SDL_bool dead_key_next;
int npadch; /* -1 or number assembled on pad */
accentmap_t *accents;
unsigned int diacr;
SDL_bool rep; /* flag telling character repeat */
unsigned char lockstate;
unsigned char ledflagstate;
char shift_state;
char text[128];
unsigned int text_len;
};
static int SDL_EVDEV_kbd_load_keymaps(SDL_EVDEV_keyboard_state *kbd)
{
return (ioctl(kbd->keyboard_fd, GIO_KEYMAP, kbd->key_map) >= 0);
}
static SDL_EVDEV_keyboard_state * kbd_cleanup_state = NULL;
static int kbd_cleanup_sigactions_installed = 0;
static int kbd_cleanup_atexit_installed = 0;
static struct sigaction old_sigaction[NSIG];
static int fatal_signals[] =
{
/* Handlers for SIGTERM and SIGINT are installed in SDL_QuitInit. */
SIGHUP, SIGQUIT, SIGILL, SIGABRT,
SIGFPE, SIGSEGV, SIGPIPE, SIGBUS,
SIGSYS
};
static void kbd_cleanup(void)
{
struct mouse_info mData;
SDL_EVDEV_keyboard_state* kbd = kbd_cleanup_state;
if (kbd == NULL) {
return;
}
kbd_cleanup_state = NULL;
SDL_zero(mData);
mData.operation = MOUSE_SHOW;
ioctl(kbd->keyboard_fd, KDSKBMODE, kbd->old_kbd_mode);
if (kbd->keyboard_fd != kbd->console_fd) close(kbd->keyboard_fd);
ioctl(kbd->console_fd, CONS_SETKBD, (unsigned long)(kbd->kbInfo->kb_index));
ioctl(kbd->console_fd, CONS_MOUSECTL, &mData);
}
void
SDL_EVDEV_kbd_reraise_signal(int sig)
{
raise(sig);
}
siginfo_t* SDL_EVDEV_kdb_cleanup_siginfo = NULL;
void* SDL_EVDEV_kdb_cleanup_ucontext = NULL;
static void kbd_cleanup_signal_action(int signum, siginfo_t* info, void* ucontext)
{
struct sigaction* old_action_p = &(old_sigaction[signum]);
sigset_t sigset;
/* Restore original signal handler before going any further. */
sigaction(signum, old_action_p, NULL);
/* Unmask current signal. */
sigemptyset(&sigset);
sigaddset(&sigset, signum);
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
/* Save original signal info and context for archeologists. */
SDL_EVDEV_kdb_cleanup_siginfo = info;
SDL_EVDEV_kdb_cleanup_ucontext = ucontext;
/* Restore keyboard. */
kbd_cleanup();
/* Reraise signal. */
SDL_EVDEV_kbd_reraise_signal(signum);
}
static void kbd_unregister_emerg_cleanup()
{
int tabidx, signum;
kbd_cleanup_state = NULL;
if (!kbd_cleanup_sigactions_installed) {
return;
}
kbd_cleanup_sigactions_installed = 0;
for (tabidx = 0; tabidx < sizeof(fatal_signals) / sizeof(fatal_signals[0]); ++tabidx) {
struct sigaction* old_action_p;
struct sigaction cur_action;
signum = fatal_signals[tabidx];
old_action_p = &(old_sigaction[signum]);
/* Examine current signal action */
if (sigaction(signum, NULL, &cur_action))
continue;
/* Check if action installed and not modifed */
if (!(cur_action.sa_flags & SA_SIGINFO)
|| cur_action.sa_sigaction != &kbd_cleanup_signal_action)
continue;
/* Restore original action */
sigaction(signum, old_action_p, NULL);
}
}
static void kbd_cleanup_atexit(void)
{
/* Restore keyboard. */
kbd_cleanup();
/* Try to restore signal handlers in case shared library is being unloaded */
kbd_unregister_emerg_cleanup();
}
static void kbd_register_emerg_cleanup(SDL_EVDEV_keyboard_state * kbd)
{
int tabidx, signum;
if (kbd_cleanup_state != NULL) {
return;
}
kbd_cleanup_state = kbd;
if (!kbd_cleanup_atexit_installed) {
/* Since glibc 2.2.3, atexit() (and on_exit(3)) can be used within a shared library to establish
* functions that are called when the shared library is unloaded.
* -- man atexit(3)
*/
atexit(kbd_cleanup_atexit);
kbd_cleanup_atexit_installed = 1;
}
if (kbd_cleanup_sigactions_installed) {
return;
}
kbd_cleanup_sigactions_installed = 1;
for (tabidx = 0; tabidx < sizeof(fatal_signals) / sizeof(fatal_signals[0]); ++tabidx) {
struct sigaction* old_action_p;
struct sigaction new_action;
signum = fatal_signals[tabidx];
old_action_p = &(old_sigaction[signum]);
if (sigaction(signum, NULL, old_action_p))
continue;
/* Skip SIGHUP and SIGPIPE if handler is already installed
* - assume the handler will do the cleanup
*/
if ((signum == SIGHUP || signum == SIGPIPE)
&& (old_action_p->sa_handler != SIG_DFL
|| (void (*)(int))old_action_p->sa_sigaction != SIG_DFL))
continue;
new_action = *old_action_p;
new_action.sa_flags |= SA_SIGINFO;
new_action.sa_sigaction = &kbd_cleanup_signal_action;
sigaction(signum, &new_action, NULL);
}
}
SDL_EVDEV_keyboard_state *
SDL_EVDEV_kbd_init(void)
{
SDL_EVDEV_keyboard_state *kbd;
struct mouse_info mData;
char flag_state;
char* devicePath;
SDL_zero(mData);
mData.operation = MOUSE_HIDE;
kbd = (SDL_EVDEV_keyboard_state *)SDL_calloc(1, sizeof(SDL_EVDEV_keyboard_state));
if (!kbd) {
return NULL;
}
kbd->npadch = -1;
/* This might fail if we're not connected to a tty (e.g. on the Steam Link) */
kbd->keyboard_fd = kbd->console_fd = open("/dev/tty", O_RDONLY | O_CLOEXEC);
kbd->shift_state = 0;
kbd->accents = SDL_calloc(sizeof(accentmap_t), 1);
kbd->key_map = SDL_calloc(sizeof(keymap_t), 1);
kbd->kbInfo = SDL_calloc(sizeof(keyboard_info_t), 1);
ioctl(kbd->console_fd, KDGKBINFO, kbd->kbInfo);
ioctl(kbd->console_fd, CONS_MOUSECTL, &mData);
if (ioctl(kbd->console_fd, KDGKBSTATE, &flag_state) == 0) {
kbd->ledflagstate = flag_state;
}
if (ioctl(kbd->console_fd, GIO_DEADKEYMAP, kbd->accents) < 0)
{
SDL_free(kbd->accents);
kbd->accents = &accentmap_default_us_acc;
}
if (ioctl(kbd->console_fd, KDGKBMODE, &kbd->old_kbd_mode) == 0) {
/* Set the keyboard in XLATE mode and load the keymaps */
ioctl(kbd->console_fd, KDSKBMODE, (unsigned long)(K_XLATE));
if(!SDL_EVDEV_kbd_load_keymaps(kbd))
{
SDL_free(kbd->key_map);
kbd->key_map = &keymap_default_us_acc;
}
/* Allow inhibiting keyboard mute with env. variable for debugging etc. */
if (SDL_getenv("SDL_INPUT_FREEBSD_KEEP_KBD") == NULL) {
/* Take keyboard from console and open the actual keyboard device.
* Ensures that the keystrokes do not leak through to the console.
*/
ioctl(kbd->console_fd, CONS_RELKBD, 1ul);
SDL_asprintf(&devicePath, "/dev/kbd%d", kbd->kbInfo->kb_index);
kbd->keyboard_fd = open(devicePath, O_WRONLY | O_CLOEXEC);
if (kbd->keyboard_fd == -1)
{
// Give keyboard back.
ioctl(kbd->console_fd, CONS_SETKBD, (unsigned long)(kbd->kbInfo->kb_index));
kbd->keyboard_fd = kbd->console_fd;
}
/* Make sure to restore keyboard if application fails to call
* SDL_Quit before exit or fatal signal is raised.
*/
if (!SDL_GetHintBoolean(SDL_HINT_NO_SIGNAL_HANDLERS, SDL_FALSE)) {
kbd_register_emerg_cleanup(kbd);
}
SDL_free(devicePath);
}
else kbd->keyboard_fd = kbd->console_fd;
}
return kbd;
}
void
SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *kbd)
{
struct mouse_info mData;
if (!kbd) {
return;
}
SDL_zero(mData);
mData.operation = MOUSE_SHOW;
ioctl(kbd->console_fd, CONS_MOUSECTL, &mData);
kbd_unregister_emerg_cleanup();
if (kbd->keyboard_fd >= 0) {
/* Restore the original keyboard mode */
ioctl(kbd->keyboard_fd, KDSKBMODE, kbd->old_kbd_mode);
close(kbd->keyboard_fd);
if (kbd->console_fd != kbd->keyboard_fd && kbd->console_fd >= 0)
{
// Give back keyboard.
ioctl(kbd->console_fd, CONS_SETKBD, (unsigned long)(kbd->kbInfo->kb_index));
}
kbd->console_fd = kbd->keyboard_fd = -1;
}
SDL_free(kbd);
}
/*
* Helper Functions.
*/
static void put_queue(SDL_EVDEV_keyboard_state *kbd, uint c)
{
/* c is already part of a UTF-8 sequence and safe to add as a character */
if (kbd->text_len < (sizeof(kbd->text)-1)) {
kbd->text[kbd->text_len++] = (char)c;
}
}
static void put_utf8(SDL_EVDEV_keyboard_state *kbd, uint c)
{
if (c < 0x80)
/* 0******* */
put_queue(kbd, c);
else if (c < 0x800) {
/* 110***** 10****** */
put_queue(kbd, 0xc0 | (c >> 6));
put_queue(kbd, 0x80 | (c & 0x3f));
} else if (c < 0x10000) {
if (c >= 0xD800 && c < 0xE000)
return;
if (c == 0xFFFF)
return;
/* 1110**** 10****** 10****** */
put_queue(kbd, 0xe0 | (c >> 12));
put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
put_queue(kbd, 0x80 | (c & 0x3f));
} else if (c < 0x110000) {
/* 11110*** 10****** 10****** 10****** */
put_queue(kbd, 0xf0 | (c >> 18));
put_queue(kbd, 0x80 | ((c >> 12) & 0x3f));
put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
put_queue(kbd, 0x80 | (c & 0x3f));
}
}
/*
* We have a combining character DIACR here, followed by the character CH.
* If the combination occurs in the table, return the corresponding value.
* Otherwise, if CH is a space or equals DIACR, return DIACR.
* Otherwise, conclude that DIACR was not combining after all,
* queue it and return CH.
*/
static unsigned int handle_diacr(SDL_EVDEV_keyboard_state *kbd, unsigned int ch)
{
unsigned int d = kbd->diacr;
unsigned int i, j;
kbd->diacr = 0;
for (i = 0; i < kbd->accents->n_accs; i++) {
if (kbd->accents->acc[i].accchar == d)
{
for (j = 0; j < NUM_ACCENTCHARS; ++j) {
if (kbd->accents->acc[i].map[j][0] == 0) /* end of table */
break;
if (kbd->accents->acc[i].map[j][0] == ch)
return kbd->accents->acc[i].map[j][1];
}
}
}
if (ch == ' ' || ch == d) {
put_utf8(kbd, d);
return 0;
}
put_utf8(kbd, d);
return ch;
}
static int vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
return (kbd->ledflagstate & flag) != 0;
}
static void chg_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
kbd->ledflagstate ^= flag;
ioctl(kbd->keyboard_fd, KDSKBSTATE, (unsigned long)(kbd->ledflagstate));
}
/*
* Special function handlers
*/
static void k_self(SDL_EVDEV_keyboard_state *kbd, unsigned int value, char up_flag)
{
if (up_flag)
return; /* no action, if this is a key release */
if (kbd->diacr)
value = handle_diacr(kbd, value);
if (kbd->dead_key_next) {
kbd->dead_key_next = SDL_FALSE;
kbd->diacr = value;
return;
}
put_utf8(kbd, value);
}
static void k_deadunicode(SDL_EVDEV_keyboard_state *kbd, unsigned int value, char up_flag)
{
if (up_flag)
return;
kbd->diacr = (kbd->diacr ? handle_diacr(kbd, value) : value);
}
static void k_shift(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
int old_state = kbd->shift_state;
if (kbd->rep)
return;
if (up_flag) {
/*
* handle the case that two shift or control
* keys are depressed simultaneously
*/
if (kbd->shift_down[value])
kbd->shift_down[value]--;
} else
kbd->shift_down[value]++;
if (kbd->shift_down[value])
kbd->shift_state |= (1 << value);
else
kbd->shift_state &= ~(1 << value);
/* kludge */
if (up_flag && kbd->shift_state != old_state && kbd->npadch != -1) {
put_utf8(kbd, kbd->npadch);
kbd->npadch = -1;
}
}
void
SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode, int down)
{
keymap_t key_map;
struct keyent_t keysym;
unsigned int final_key_state;
unsigned int map_from_key_sym;
key_map = *kbd->key_map;
if (!kbd) {
return;
}
kbd->rep = (down == 2);
if (keycode < NUM_KEYS) {
if (keycode >= 89 && keycode <= 95) {
/* These constitute unprintable language-related keys, so ignore them. */
return;
}
if (keycode > 95)
keycode -= 7;
if (vc_kbd_led(kbd, ALKED) || (kbd->shift_state & 0x8))
{
keycode += ALTGR_OFFSET;
}
keysym = key_map.key[keycode];
} else {
return;
}
final_key_state = kbd->shift_state & 0x7;
if ((keysym.flgs & FLAG_LOCK_C) && vc_kbd_led(kbd, LED_CAP))
final_key_state ^= 0x1;
if ((keysym.flgs & FLAG_LOCK_N) && vc_kbd_led(kbd, LED_NUM))
final_key_state ^= 0x1;
map_from_key_sym = keysym.map[final_key_state];
if ((keysym.spcl & (0x80 >> final_key_state)) || (map_from_key_sym & SPCLKEY)) {
/* Special function.*/
if (map_from_key_sym == 0)
return; /* Nothing to do. */
if (map_from_key_sym & SPCLKEY)
map_from_key_sym &= ~SPCLKEY;
if (map_from_key_sym >= F_ACC && map_from_key_sym <= L_ACC) {
/* Accent function.*/
unsigned int accent_index = map_from_key_sym - F_ACC;
if (kbd->accents->acc[accent_index].accchar != 0) {
k_deadunicode(kbd, kbd->accents->acc[accent_index].accchar, !down);
}
} else {
switch(map_from_key_sym) {
case ASH: /* alt/meta shift */
k_shift(kbd, 3, down == 0);
break;
case LSHA: /* left shift + alt lock */
case RSHA: /* right shift + alt lock */
if (down == 0) chg_vc_kbd_led(kbd, ALKED);
case LSH: /* left shift */
case RSH: /* right shift */
k_shift(kbd, 0, down == 0);
break;
case LCTRA: /* left ctrl + alt lock */
case RCTRA: /* right ctrl + alt lock */
if (down == 0) chg_vc_kbd_led(kbd, ALKED);
case LCTR: /* left ctrl */
case RCTR: /* right ctrl */
k_shift(kbd, 1, down == 0);
break;
case LALTA: /* left alt + alt lock */
case RALTA: /* right alt + alt lock */
if (down == 0) chg_vc_kbd_led(kbd, ALKED);
case LALT: /* left alt */
case RALT: /* right alt */
k_shift(kbd, 2, down == 0);
break;
case ALK: /* alt lock */
if (down == 1) chg_vc_kbd_led(kbd, ALKED);
break;
case CLK: /* caps lock*/
if (down == 1) chg_vc_kbd_led(kbd, CLKED);
break;
case NLK: /* num lock */
if (down == 1) chg_vc_kbd_led(kbd, NLKED);
break;
case SLK: /* scroll lock */
if (down == 1) chg_vc_kbd_led(kbd, SLKED);
break;
default:
return;
}
}
} else {
if (map_from_key_sym == '\n' || map_from_key_sym == '\r') {
if (kbd->diacr) {
kbd->diacr = 0;
return;
}
}
if (map_from_key_sym >= ' ' && map_from_key_sym != 127) {
k_self(kbd, map_from_key_sym, !down);
}
}
if (kbd->text_len > 0) {
kbd->text[kbd->text_len] = '\0';
SDL_SendKeyboardText(kbd->text);
kbd->text_len = 0;
}
}
#endif /* SDL_INPUT_FBSDKBIO */
/* vi: set ts=4 sw=4 expandtab: */
+67 -18
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -19,7 +19,9 @@
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#include "SDL_hints.h"
#include "SDL_dbus.h"
#include "SDL_atomic.h"
#if SDL_USE_LIBDBUS
/* we never link directly to libdbus. */
@@ -57,6 +59,10 @@ LoadDBUSSyms(void)
SDL_DBUS_SYM(message_new_method_call);
SDL_DBUS_SYM(message_append_args);
SDL_DBUS_SYM(message_append_args_valist);
SDL_DBUS_SYM(message_iter_init_append);
SDL_DBUS_SYM(message_iter_open_container);
SDL_DBUS_SYM(message_iter_append_basic);
SDL_DBUS_SYM(message_iter_close_container);
SDL_DBUS_SYM(message_get_args);
SDL_DBUS_SYM(message_get_args_valist);
SDL_DBUS_SYM(message_iter_init);
@@ -65,6 +71,7 @@ LoadDBUSSyms(void)
SDL_DBUS_SYM(message_iter_get_arg_type);
SDL_DBUS_SYM(message_iter_recurse);
SDL_DBUS_SYM(message_unref);
SDL_DBUS_SYM(threads_init_default);
SDL_DBUS_SYM(error_init);
SDL_DBUS_SYM(error_is_set);
SDL_DBUS_SYM(error_free);
@@ -108,26 +115,61 @@ LoadDBUSLibrary(void)
return retval;
}
void
SDL_DBus_Init(void)
static SDL_SpinLock spinlock_dbus_init = 0;
/* you must hold spinlock_dbus_init before calling this! */
static void
SDL_DBus_Init_Spinlocked(void)
{
if (!dbus.session_conn && LoadDBUSLibrary() != -1) {
static SDL_bool is_dbus_available = SDL_TRUE;
if (!is_dbus_available) {
return; /* don't keep trying if this fails. */
}
if (!dbus.session_conn) {
DBusError err;
dbus.error_init(&err);
dbus.session_conn = dbus.bus_get_private(DBUS_BUS_SESSION, &err);
if (!dbus.error_is_set(&err)) {
dbus.system_conn = dbus.bus_get_private(DBUS_BUS_SYSTEM, &err);
if (LoadDBUSLibrary() == -1) {
is_dbus_available = SDL_FALSE; /* can't load at all? Don't keep trying. */
return; /* oh well */
}
if (!dbus.threads_init_default()) {
is_dbus_available = SDL_FALSE;
return;
}
dbus.error_init(&err);
/* session bus is required */
dbus.session_conn = dbus.bus_get_private(DBUS_BUS_SESSION, &err);
if (dbus.error_is_set(&err)) {
dbus.error_free(&err);
SDL_DBus_Quit();
is_dbus_available = SDL_FALSE;
return; /* oh well */
}
dbus.connection_set_exit_on_disconnect(dbus.system_conn, 0);
dbus.connection_set_exit_on_disconnect(dbus.session_conn, 0);
/* system bus is optional */
dbus.system_conn = dbus.bus_get_private(DBUS_BUS_SYSTEM, &err);
if (!dbus.error_is_set(&err)) {
dbus.connection_set_exit_on_disconnect(dbus.system_conn, 0);
}
dbus.error_free(&err);
}
}
void
SDL_DBus_Init(void)
{
SDL_AtomicLock(&spinlock_dbus_init); /* make sure two threads can't init at same time, since this can happen before SDL_Init. */
SDL_DBus_Init_Spinlocked();
SDL_AtomicUnlock(&spinlock_dbus_init);
}
void
SDL_DBus_Quit(void)
{
@@ -154,15 +196,11 @@ SDL_DBus_Quit(void)
SDL_DBusContext *
SDL_DBus_GetContext(void)
{
if(!dbus_handle || !dbus.session_conn){
if (!dbus_handle || !dbus.session_conn) {
SDL_DBus_Init();
}
if(dbus_handle && dbus.session_conn){
return &dbus;
} else {
return NULL;
}
return (dbus_handle && dbus.session_conn) ? &dbus : NULL;
}
static SDL_bool
@@ -310,7 +348,11 @@ SDL_DBus_QueryProperty(const char *node, const char *path, const char *interface
void
SDL_DBus_ScreensaverTickle(void)
{
SDL_DBus_CallVoidMethod("org.gnome.ScreenSaver", "/org/gnome/ScreenSaver", "org.gnome.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
if (screensaver_cookie == 0) { /* 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);
}
}
SDL_bool
@@ -324,8 +366,15 @@ SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
const char *interface = "org.freedesktop.ScreenSaver";
if (inhibit) {
const char *app = "My SDL application";
const char *reason = "Playing a game";
const char *app = SDL_GetHint(SDL_HINT_APP_NAME);
const char *reason = SDL_GetHint(SDL_HINT_SCREENSAVER_INHIBIT_ACTIVITY_NAME);
if (!app || !app[0]) {
app = "My SDL application";
}
if (!reason || !reason[0]) {
reason = "Playing a game";
}
if (!SDL_DBus_CallMethod(node, path, interface, "Inhibit",
DBUS_TYPE_STRING, &app, DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID,
DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
+6 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -54,6 +54,10 @@ typedef struct SDL_DBusContext {
DBusMessage *(*message_new_method_call)(const char *, const char *, const char *, const char *);
dbus_bool_t (*message_append_args)(DBusMessage *, int, ...);
dbus_bool_t (*message_append_args_valist)(DBusMessage *, int, va_list);
void (*message_iter_init_append)(DBusMessage *, DBusMessageIter *);
dbus_bool_t (*message_iter_open_container)(DBusMessageIter *, int, const char *, DBusMessageIter *);
dbus_bool_t (*message_iter_append_basic)(DBusMessageIter *, int, const void *);
dbus_bool_t (*message_iter_close_container)(DBusMessageIter *, DBusMessageIter *);
dbus_bool_t (*message_get_args)(DBusMessage *, DBusError *, int, ...);
dbus_bool_t (*message_get_args_valist)(DBusMessage *, DBusError *, int, va_list);
dbus_bool_t (*message_iter_init)(DBusMessage *, DBusMessageIter *);
@@ -62,6 +66,7 @@ typedef struct SDL_DBusContext {
int (*message_iter_get_arg_type)(DBusMessageIter *);
void (*message_iter_recurse)(DBusMessageIter *, DBusMessageIter *);
void (*message_unref)(DBusMessage *);
dbus_bool_t (*threads_init_default)(void);
void (*error_init)(DBusError *);
dbus_bool_t (*error_is_set)(const DBusError *);
void (*error_free)(DBusError *);
+158 -30
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -39,11 +39,11 @@
#include <linux/input.h>
#include "SDL.h"
#include "SDL_assert.h"
#include "SDL_endian.h"
#include "SDL_scancode.h"
#include "../../events/SDL_events_c.h"
#include "../../events/scancodes_linux.h" /* adds linux_scancode_table */
#include "../../core/linux/SDL_evdev_capabilities.h"
#include "../../core/linux/SDL_udev.h"
/* These are not defined in older Linux kernel headers */
@@ -55,6 +55,11 @@
#define ABS_MT_POSITION_X 0x35
#define ABS_MT_POSITION_Y 0x36
#define ABS_MT_TRACKING_ID 0x39
#define ABS_MT_PRESSURE 0x3a
#endif
#ifndef REL_WHEEL_HI_RES
#define REL_WHEEL_HI_RES 0x0b
#define REL_HWHEEL_HI_RES 0x0c
#endif
typedef struct SDL_evdevlist_item
@@ -74,6 +79,7 @@ typedef struct SDL_evdevlist_item
int min_x, max_x, range_x;
int min_y, max_y, range_y;
int min_pressure, max_pressure, range_pressure;
int max_slots;
int current_slot;
@@ -85,10 +91,14 @@ typedef struct SDL_evdevlist_item
EVDEV_TOUCH_SLOTDELTA_MOVE
} delta;
int tracking_id;
int x, y;
int x, y, pressure;
} * slots;
} * touchscreen_data;
SDL_bool high_res_wheel;
SDL_bool high_res_hwheel;
struct SDL_evdevlist_item *next;
} SDL_evdevlist_item;
@@ -126,6 +136,14 @@ static Uint8 EVDEV_MouseButtons[] = {
SDL_BUTTON_X2 + 3 /* BTN_TASK 0x117 */
};
static int
SDL_EVDEV_SetRelativeMouseMode(SDL_bool enabled)
{
/* Mice already send relative events through this interface */
return 0;
}
int
SDL_EVDEV_Init(void)
{
@@ -159,6 +177,8 @@ SDL_EVDEV_Init(void)
_this->kbd = SDL_EVDEV_kbd_init();
}
SDL_GetMouse()->SetRelativeMouseMode = SDL_EVDEV_SetRelativeMouseMode;
_this->ref_count += 1;
return 0;
@@ -205,8 +225,14 @@ static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_cl
switch(udev_event) {
case SDL_UDEV_DEVICEADDED:
if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD |
SDL_UDEV_DEVICE_TOUCHSCREEN)))
if (udev_class & SDL_UDEV_DEVICE_TOUCHPAD) {
udev_class |= SDL_UDEV_DEVICE_TOUCHSCREEN;
}
if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD | SDL_UDEV_DEVICE_TOUCHSCREEN)))
return;
if ((udev_class & SDL_UDEV_DEVICE_JOYSTICK))
return;
SDL_EVDEV_device_added(dev_path, udev_class);
@@ -229,7 +255,7 @@ SDL_EVDEV_Poll(void)
SDL_Scancode scan_code;
int mouse_button;
SDL_Mouse *mouse;
float norm_x, norm_y;
float norm_x, norm_y, norm_pressure;
if (!_this) {
return;
@@ -264,6 +290,20 @@ SDL_EVDEV_Poll(void)
break;
}
/* BTH_TOUCH event value 1 indicates there is contact with
a touchscreen or trackpad (earlist finger's current
position is sent in EV_ABS ABS_X/ABS_Y, switching to
next finger after earlist is released) */
if (item->is_touchscreen && events[i].code == BTN_TOUCH) {
if (item->touchscreen_data->max_slots == 1) {
if (events[i].value)
item->touchscreen_data->slots[0].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
else
item->touchscreen_data->slots[0].delta = EVDEV_TOUCH_SLOTDELTA_UP;
}
break;
}
/* Probably keyboard */
scan_code = SDL_EVDEV_translate_keycode(events[i].code);
if (scan_code != SDL_SCANCODE_UNKNOWN) {
@@ -308,15 +348,29 @@ SDL_EVDEV_Poll(void)
item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
}
break;
case ABS_X:
if (item->is_touchscreen) /* FIXME: temp hack */
case ABS_MT_PRESSURE:
if (!item->is_touchscreen) /* FIXME: temp hack */
break;
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
item->touchscreen_data->slots[item->touchscreen_data->current_slot].pressure = events[i].value;
if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
}
break;
case ABS_X:
if (item->is_touchscreen) {
if (item->touchscreen_data->max_slots != 1)
break;
item->touchscreen_data->slots[0].x = events[i].value;
} else
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
break;
case ABS_Y:
if (item->is_touchscreen) /* FIXME: temp hack */
break;
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value);
if (item->is_touchscreen) {
if (item->touchscreen_data->max_slots != 1)
break;
item->touchscreen_data->slots[0].y = events[i].value;
} else
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value);
break;
default:
break;
@@ -331,10 +385,20 @@ SDL_EVDEV_Poll(void)
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value);
break;
case REL_WHEEL:
SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value, SDL_MOUSEWHEEL_NORMAL);
if (!item->high_res_wheel)
SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value, SDL_MOUSEWHEEL_NORMAL);
break;
case REL_WHEEL_HI_RES:
SDL_assert(item->high_res_wheel);
SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value / 120.0f, SDL_MOUSEWHEEL_NORMAL);
break;
case REL_HWHEEL:
SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0, SDL_MOUSEWHEEL_NORMAL);
if (!item->high_res_hwheel)
SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0, SDL_MOUSEWHEEL_NORMAL);
break;
case REL_HWHEEL_HI_RES:
SDL_assert(item->high_res_hwheel);
SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value / 120.0f, 0, SDL_MOUSEWHEEL_NORMAL);
break;
default:
break;
@@ -352,18 +416,29 @@ SDL_EVDEV_Poll(void)
norm_y = (float)(item->touchscreen_data->slots[j].y - item->touchscreen_data->min_y) /
(float)item->touchscreen_data->range_y;
if (item->touchscreen_data->range_pressure > 0) {
norm_pressure = (float)(item->touchscreen_data->slots[j].pressure - item->touchscreen_data->min_pressure) /
(float)item->touchscreen_data->range_pressure;
} else {
/* This touchscreen does not support pressure */
norm_pressure = 1.0f;
}
/* FIXME: the touch's window shouldn't be null, but
* the coordinate space of touch positions needs to
* be window-relative in that case. */
switch(item->touchscreen_data->slots[j].delta) {
case EVDEV_TOUCH_SLOTDELTA_DOWN:
SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_TRUE, norm_x, norm_y, 1.0f);
SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, SDL_TRUE, norm_x, norm_y, norm_pressure);
item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
break;
case EVDEV_TOUCH_SLOTDELTA_UP:
SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_FALSE, norm_x, norm_y, 1.0f);
SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, SDL_FALSE, norm_x, norm_y, norm_pressure);
item->touchscreen_data->slots[j].tracking_id = -1;
item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
break;
case EVDEV_TOUCH_SLOTDELTA_MOVE:
SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, norm_x, norm_y, 1.0f);
SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, norm_x, norm_y, norm_pressure);
item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
break;
default:
@@ -394,13 +469,20 @@ SDL_EVDEV_translate_keycode(int keycode)
{
SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
if (keycode < SDL_arraysize(linux_scancode_table))
if (keycode < SDL_arraysize(linux_scancode_table)) {
scancode = linux_scancode_table[keycode];
if (scancode == SDL_SCANCODE_UNKNOWN) {
SDL_Log("The key you just pressed is not recognized by SDL. To help "
"get this fixed, please report this to the SDL forums/mailing list "
"<https://discourse.libsdl.org/> EVDEV KeyCode %d", keycode);
if (scancode == SDL_SCANCODE_UNKNOWN) {
/* BTN_TOUCH is handled elsewhere, but we might still end up here if
you get an unexpected BTN_TOUCH from something SDL believes is not
a touch device. In this case, we'd rather not get a misleading
SDL_Log message about an unknown key. */
if (keycode != BTN_TOUCH) {
SDL_Log("The key you just pressed is not recognized by SDL. To help "
"get this fixed, please report this to the SDL forums/mailing list "
"<https://discourse.libsdl.org/> EVDEV KeyCode %d", keycode);
}
}
}
return scancode;
@@ -411,6 +493,7 @@ static int
SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
{
int ret, i;
unsigned long xreq, yreq;
char name[64];
struct input_absinfo abs_info;
@@ -433,7 +516,24 @@ SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
return SDL_OutOfMemory();
}
ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_X), &abs_info);
ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
if (ret < 0) {
SDL_free(item->touchscreen_data->name);
SDL_free(item->touchscreen_data);
return SDL_SetError("Failed to get evdev touchscreen limits");
}
if (abs_info.maximum == 0) {
item->touchscreen_data->max_slots = 1;
xreq = EVIOCGABS(ABS_X);
yreq = EVIOCGABS(ABS_Y);
} else {
item->touchscreen_data->max_slots = abs_info.maximum + 1;
xreq = EVIOCGABS(ABS_MT_POSITION_X);
yreq = EVIOCGABS(ABS_MT_POSITION_Y);
}
ret = ioctl(item->fd, xreq, &abs_info);
if (ret < 0) {
SDL_free(item->touchscreen_data->name);
SDL_free(item->touchscreen_data);
@@ -443,7 +543,7 @@ SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
item->touchscreen_data->max_x = abs_info.maximum;
item->touchscreen_data->range_x = abs_info.maximum - abs_info.minimum;
ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_Y), &abs_info);
ret = ioctl(item->fd, yreq, &abs_info);
if (ret < 0) {
SDL_free(item->touchscreen_data->name);
SDL_free(item->touchscreen_data);
@@ -453,13 +553,15 @@ SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
item->touchscreen_data->max_y = abs_info.maximum;
item->touchscreen_data->range_y = abs_info.maximum - abs_info.minimum;
ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
ret = ioctl(item->fd, EVIOCGABS(ABS_MT_PRESSURE), &abs_info);
if (ret < 0) {
SDL_free(item->touchscreen_data->name);
SDL_free(item->touchscreen_data);
return SDL_SetError("Failed to get evdev touchscreen limits");
}
item->touchscreen_data->max_slots = abs_info.maximum + 1;
item->touchscreen_data->min_pressure = abs_info.minimum;
item->touchscreen_data->max_pressure = abs_info.maximum;
item->touchscreen_data->range_pressure = abs_info.maximum - abs_info.minimum;
item->touchscreen_data->slots = SDL_calloc(
item->touchscreen_data->max_slots,
@@ -475,6 +577,7 @@ SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
}
ret = SDL_AddTouch(item->fd, /* I guess our fd is unique enough */
SDL_TOUCH_DEVICE_DIRECT,
item->touchscreen_data->name);
if (ret < 0) {
SDL_free(item->touchscreen_data->slots);
@@ -512,8 +615,8 @@ SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
*
* this is the structure we're trying to emulate
*/
__u32* mt_req_code;
__s32* mt_req_values;
Uint32* mt_req_code;
Sint32* mt_req_values;
size_t mt_req_size;
/* TODO: sync devices other than touchscreen */
@@ -528,7 +631,7 @@ SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
return;
}
mt_req_values = (__s32*)mt_req_code + 1;
mt_req_values = (Sint32*)mt_req_code + 1;
*mt_req_code = ABS_MT_TRACKING_ID;
ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
@@ -593,6 +696,24 @@ SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
}
}
*mt_req_code = ABS_MT_PRESSURE;
ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
if (ret < 0) {
SDL_free(mt_req_code);
return;
}
for(i = 0; i < item->touchscreen_data->max_slots; i++) {
if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
item->touchscreen_data->slots[i].pressure != mt_req_values[i]) {
item->touchscreen_data->slots[i].pressure = mt_req_values[i];
if (item->touchscreen_data->slots[i].delta ==
EVDEV_TOUCH_SLOTDELTA_NONE) {
item->touchscreen_data->slots[i].delta =
EVDEV_TOUCH_SLOTDELTA_MOVE;
}
}
}
ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
if (ret < 0) {
SDL_free(mt_req_code);
@@ -611,6 +732,7 @@ SDL_EVDEV_device_added(const char *dev_path, int udev_class)
{
int ret;
SDL_evdevlist_item *item;
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) {
@@ -624,7 +746,7 @@ SDL_EVDEV_device_added(const char *dev_path, int udev_class)
return SDL_OutOfMemory();
}
item->fd = open(dev_path, O_RDONLY | O_NONBLOCK);
item->fd = open(dev_path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
if (item->fd < 0) {
SDL_free(item);
return SDL_SetError("Unable to open %s", dev_path);
@@ -637,11 +759,17 @@ SDL_EVDEV_device_added(const char *dev_path, int udev_class)
return SDL_OutOfMemory();
}
if (ioctl(item->fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0) {
item->high_res_wheel = test_bit(REL_WHEEL_HI_RES, relbit);
item->high_res_hwheel = test_bit(REL_HWHEEL_HI_RES, relbit);
}
if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) {
item->is_touchscreen = 1;
if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) {
close(item->fd);
SDL_free(item->path);
SDL_free(item);
return ret;
}
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -0,0 +1,145 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 2020 Collabora Ltd.
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_evdev_capabilities.h"
#if HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX)
/* missing defines in older Linux kernel headers */
#ifndef BTN_TRIGGER_HAPPY
#define BTN_TRIGGER_HAPPY 0x2c0
#endif
#ifndef BTN_DPAD_UP
#define BTN_DPAD_UP 0x220
#endif
#ifndef KEY_ALS_TOGGLE
#define KEY_ALS_TOGGLE 0x230
#endif
extern int
SDL_EVDEV_GuessDeviceClass(unsigned long bitmask_ev[NBITS(EV_MAX)],
unsigned long bitmask_abs[NBITS(ABS_MAX)],
unsigned long bitmask_key[NBITS(KEY_MAX)],
unsigned long bitmask_rel[NBITS(REL_MAX)])
{
struct range {
unsigned start;
unsigned end;
};
/* key code ranges above BTN_MISC (start is inclusive, stop is exclusive)*/
static const struct range high_key_blocks[] = {
{ KEY_OK, BTN_DPAD_UP },
{ KEY_ALS_TOGGLE, BTN_TRIGGER_HAPPY }
};
int devclass = 0;
unsigned long keyboard_mask;
/* X, Y, Z axes but no buttons probably means an accelerometer */
if (test_bit(EV_ABS, bitmask_ev) &&
test_bit(ABS_X, bitmask_abs) &&
test_bit(ABS_Y, bitmask_abs) &&
test_bit(ABS_Z, bitmask_abs) &&
!test_bit(EV_KEY, bitmask_ev)) {
return SDL_UDEV_DEVICE_ACCELEROMETER;
}
/* RX, RY, RZ axes but no buttons also probably means an accelerometer */
if (test_bit(EV_ABS, bitmask_ev) &&
test_bit(ABS_RX, bitmask_abs) &&
test_bit(ABS_RY, bitmask_abs) &&
test_bit(ABS_RZ, bitmask_abs) &&
!test_bit(EV_KEY, bitmask_ev)) {
return SDL_UDEV_DEVICE_ACCELEROMETER;
}
if (test_bit(EV_ABS, bitmask_ev) &&
test_bit(ABS_X, bitmask_abs) && test_bit(ABS_Y, bitmask_abs)) {
if (test_bit(BTN_STYLUS, bitmask_key) || test_bit(BTN_TOOL_PEN, bitmask_key)) {
; /* ID_INPUT_TABLET */
} else if (test_bit(BTN_TOOL_FINGER, bitmask_key) && !test_bit(BTN_TOOL_PEN, bitmask_key)) {
devclass |= SDL_UDEV_DEVICE_TOUCHPAD; /* ID_INPUT_TOUCHPAD */
} else if (test_bit(BTN_MOUSE, bitmask_key)) {
devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */
} else if (test_bit(BTN_TOUCH, bitmask_key)) {
/* TODO: better determining between touchscreen and multitouch touchpad,
see https://github.com/systemd/systemd/blob/master/src/udev/udev-builtin-input_id.c */
devclass |= SDL_UDEV_DEVICE_TOUCHSCREEN; /* ID_INPUT_TOUCHSCREEN */
}
if (test_bit(BTN_TRIGGER, bitmask_key) ||
test_bit(BTN_A, bitmask_key) ||
test_bit(BTN_1, bitmask_key) ||
test_bit(ABS_RX, bitmask_abs) ||
test_bit(ABS_RY, bitmask_abs) ||
test_bit(ABS_RZ, bitmask_abs) ||
test_bit(ABS_THROTTLE, bitmask_abs) ||
test_bit(ABS_RUDDER, bitmask_abs) ||
test_bit(ABS_WHEEL, bitmask_abs) ||
test_bit(ABS_GAS, bitmask_abs) ||
test_bit(ABS_BRAKE, bitmask_abs)) {
devclass |= SDL_UDEV_DEVICE_JOYSTICK; /* ID_INPUT_JOYSTICK */
}
}
if (test_bit(EV_REL, bitmask_ev) &&
test_bit(REL_X, bitmask_rel) && test_bit(REL_Y, bitmask_rel) &&
test_bit(BTN_MOUSE, bitmask_key)) {
devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */
}
if (test_bit(EV_KEY, bitmask_ev)) {
unsigned i;
unsigned long found = 0;
for (i = 0; i < BTN_MISC/BITS_PER_LONG; ++i) {
found |= bitmask_key[i];
}
/* If there are no keys in the lower block, check the higher blocks */
if (!found) {
unsigned block;
for (block = 0; block < (sizeof(high_key_blocks) / sizeof(struct range)); ++block) {
for (i = high_key_blocks[block].start; i < high_key_blocks[block].end; ++i) {
if (test_bit(i, bitmask_key)) {
found = 1;
break;
}
}
}
}
if (found > 0) {
devclass |= SDL_UDEV_DEVICE_KEYBOARD; /* ID_INPUT_KEY */
}
}
/* the first 32 bits are ESC, numbers, and Q to D; if we have any of
* those, consider it a keyboard device; do not test KEY_RESERVED, though */
keyboard_mask = 0xFFFFFFFE;
if ((bitmask_key[0] & keyboard_mask) != 0)
devclass |= SDL_UDEV_DEVICE_KEYBOARD; /* ID_INPUT_KEYBOARD */
return devclass;
}
#endif
@@ -0,0 +1,60 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 2020 Collabora Ltd.
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_evdev_capabilities_h_
#define SDL_evdev_capabilities_h_
#if HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX)
#include <linux/input.h>
/* A device can be any combination of these classes */
typedef enum
{
SDL_UDEV_DEVICE_UNKNOWN = 0x0000,
SDL_UDEV_DEVICE_MOUSE = 0x0001,
SDL_UDEV_DEVICE_KEYBOARD = 0x0002,
SDL_UDEV_DEVICE_JOYSTICK = 0x0004,
SDL_UDEV_DEVICE_SOUND = 0x0008,
SDL_UDEV_DEVICE_TOUCHSCREEN = 0x0010,
SDL_UDEV_DEVICE_ACCELEROMETER = 0x0020,
SDL_UDEV_DEVICE_TOUCHPAD = 0x0040
} SDL_UDEV_deviceclass;
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
#define EVDEV_OFF(x) ((x)%BITS_PER_LONG)
#define EVDEV_LONG(x) ((x)/BITS_PER_LONG)
#define test_bit(bit, array) ((array[EVDEV_LONG(bit)] >> EVDEV_OFF(bit)) & 1)
extern int SDL_EVDEV_GuessDeviceClass(unsigned long bitmask_ev[NBITS(EV_MAX)],
unsigned long bitmask_abs[NBITS(ABS_MAX)],
unsigned long bitmask_key[NBITS(KEY_MAX)],
unsigned long bitmask_rel[NBITS(REL_MAX)]);
#endif /* HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX) */
#endif /* SDL_evdev_capabilities_h_ */
/* vi: set ts=4 sw=4 expandtab: */
+13 -11
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -216,11 +216,10 @@ static void kbd_cleanup(void)
}
kbd_cleanup_state = NULL;
fprintf(stderr, "(SDL restoring keyboard) ");
ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
}
void
static void
SDL_EVDEV_kbd_reraise_signal(int sig)
{
raise(sig);
@@ -345,7 +344,7 @@ SDL_EVDEV_kbd_init(void)
SDL_EVDEV_keyboard_state *kbd;
int i;
char flag_state;
char shift_state[2] = {TIOCL_GETSHIFTSTATE, 0};
char shift_state[ sizeof (long) ] = {TIOCL_GETSHIFTSTATE, 0};
kbd = (SDL_EVDEV_keyboard_state *)SDL_calloc(1, sizeof(*kbd));
if (!kbd) {
@@ -355,7 +354,7 @@ SDL_EVDEV_kbd_init(void)
kbd->npadch = -1;
/* This might fail if we're not connected to a tty (e.g. on the Steam Link) */
kbd->console_fd = open("/dev/tty", O_RDONLY);
kbd->console_fd = open("/dev/tty", O_RDONLY | O_CLOEXEC);
if (ioctl(kbd->console_fd, TIOCLINUX, shift_state) == 0) {
kbd->shift_state = *shift_state;
@@ -387,7 +386,7 @@ SDL_EVDEV_kbd_init(void)
}
/* Allow inhibiting keyboard mute with env. variable for debugging etc. */
if (getenv("SDL_INPUT_LINUX_KEEP_KBD") == NULL) {
if (SDL_getenv("SDL_INPUT_LINUX_KEEP_KBD") == NULL) {
/* Mute the keyboard so keystrokes only generate evdev events
* and do not leak through to the console
*/
@@ -510,17 +509,19 @@ static unsigned int handle_diacr(SDL_EVDEV_keyboard_state *kbd, unsigned int ch)
static int vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
return ((kbd->ledflagstate >> flag) & 1);
return (kbd->ledflagstate & flag) != 0;
}
static void set_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
kbd->ledflagstate |= 1 << flag;
kbd->ledflagstate |= flag;
ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate));
}
static void clr_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
kbd->ledflagstate &= ~(1 << flag);
kbd->ledflagstate &= ~flag;
ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate));
}
static void chg_vc_kbd_lock(SDL_EVDEV_keyboard_state *kbd, int flag)
@@ -535,7 +536,8 @@ static void chg_vc_kbd_slock(SDL_EVDEV_keyboard_state *kbd, int flag)
static void chg_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
kbd->ledflagstate ^= 1 << flag;
kbd->ledflagstate ^= flag;
ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate));
}
/*
@@ -817,7 +819,7 @@ SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode, int d
}
}
#else /* !SDL_INPUT_LINUXKD */
#elif !defined(SDL_INPUT_FBSDKBIO) /* !SDL_INPUT_LINUXKD */
SDL_EVDEV_keyboard_state *
SDL_EVDEV_kbd_init(void)
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

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