Fixed an iOS view orientation issue when SDL_GL_CreateContext or SDL_CreateRenderer is called.

This commit is contained in:
Alex Szpakowski
2015-04-10 23:30:31 -03:00
commit fe6c797cad
1638 changed files with 474295 additions and 0 deletions

477
src/SDL.c Normal file
View File

@@ -0,0 +1,477 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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 defined(__WIN32__)
#include "core/windows/SDL_windows.h"
#endif
/* Initialization code for SDL */
#include "SDL.h"
#include "SDL_bits.h"
#include "SDL_revision.h"
#include "SDL_assert_c.h"
#include "events/SDL_events_c.h"
#include "haptic/SDL_haptic_c.h"
#include "joystick/SDL_joystick_c.h"
/* Initialization/Cleanup routines */
#if !SDL_TIMERS_DISABLED
extern int SDL_TimerInit(void);
extern void SDL_TimerQuit(void);
extern void SDL_TicksInit(void);
extern void SDL_TicksQuit(void);
#endif
#if SDL_VIDEO_DRIVER_WINDOWS
extern int SDL_HelperWindowCreate(void);
extern int SDL_HelperWindowDestroy(void);
#endif
/* The initialized subsystems */
#ifdef SDL_MAIN_NEEDED
static SDL_bool SDL_MainIsReady = SDL_FALSE;
#else
static SDL_bool SDL_MainIsReady = SDL_TRUE;
#endif
static SDL_bool SDL_bInMainQuit = SDL_FALSE;
static Uint8 SDL_SubsystemRefCount[ 32 ];
/* Private helper to increment a subsystem's ref counter. */
static void
SDL_PrivateSubsystemRefCountIncr(Uint32 subsystem)
{
int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
SDL_assert(SDL_SubsystemRefCount[subsystem_index] < 255);
++SDL_SubsystemRefCount[subsystem_index];
}
/* Private helper to decrement a subsystem's ref counter. */
static void
SDL_PrivateSubsystemRefCountDecr(Uint32 subsystem)
{
int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
if (SDL_SubsystemRefCount[subsystem_index] > 0) {
--SDL_SubsystemRefCount[subsystem_index];
}
}
/* Private helper to check if a system needs init. */
static SDL_bool
SDL_PrivateShouldInitSubsystem(Uint32 subsystem)
{
int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
SDL_assert(SDL_SubsystemRefCount[subsystem_index] < 255);
return (SDL_SubsystemRefCount[subsystem_index] == 0);
}
/* Private helper to check if a system needs to be quit. */
static SDL_bool
SDL_PrivateShouldQuitSubsystem(Uint32 subsystem) {
int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
if (SDL_SubsystemRefCount[subsystem_index] == 0) {
return SDL_FALSE;
}
/* If we're in SDL_Quit, we shut down every subsystem, even if refcount
* isn't zero.
*/
return SDL_SubsystemRefCount[subsystem_index] == 1 || SDL_bInMainQuit;
}
void
SDL_SetMainReady(void)
{
SDL_MainIsReady = SDL_TRUE;
}
int
SDL_InitSubSystem(Uint32 flags)
{
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;
}
/* Clear the error message */
SDL_ClearError();
#if SDL_VIDEO_DRIVER_WINDOWS
if ((flags & (SDL_INIT_HAPTIC|SDL_INIT_JOYSTICK))) {
if (SDL_HelperWindowCreate() < 0) {
return -1;
}
}
#endif
#if !SDL_TIMERS_DISABLED
SDL_TicksInit();
#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 */
flags |= SDL_INIT_EVENTS;
}
/* Initialize the event subsystem */
if ((flags & SDL_INIT_EVENTS)) {
#if !SDL_EVENTS_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_EVENTS)) {
if (SDL_StartEventLoop() < 0) {
return (-1);
}
SDL_QuitInit();
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_EVENTS);
#else
return SDL_SetError("SDL not built with events support");
#endif
}
/* Initialize the timer subsystem */
if ((flags & SDL_INIT_TIMER)){
#if !SDL_TIMERS_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_TIMER)) {
if (SDL_TimerInit() < 0) {
return (-1);
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_TIMER);
#else
return SDL_SetError("SDL not built with timer support");
#endif
}
/* Initialize the video subsystem */
if ((flags & SDL_INIT_VIDEO)){
#if !SDL_VIDEO_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_VIDEO)) {
if (SDL_VideoInit(NULL) < 0) {
return (-1);
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_VIDEO);
#else
return SDL_SetError("SDL not built with video support");
#endif
}
/* Initialize the audio subsystem */
if ((flags & SDL_INIT_AUDIO)){
#if !SDL_AUDIO_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_AUDIO)) {
if (SDL_AudioInit(NULL) < 0) {
return (-1);
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_AUDIO);
#else
return SDL_SetError("SDL not built with audio support");
#endif
}
/* Initialize the joystick subsystem */
if ((flags & SDL_INIT_JOYSTICK)){
#if !SDL_JOYSTICK_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_JOYSTICK)) {
if (SDL_JoystickInit() < 0) {
return (-1);
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_JOYSTICK);
#else
return SDL_SetError("SDL not built with joystick support");
#endif
}
if ((flags & SDL_INIT_GAMECONTROLLER)){
#if !SDL_JOYSTICK_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_GAMECONTROLLER)) {
if (SDL_GameControllerInit() < 0) {
return (-1);
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_GAMECONTROLLER);
#else
return SDL_SetError("SDL not built with joystick support");
#endif
}
/* Initialize the haptic subsystem */
if ((flags & SDL_INIT_HAPTIC)){
#if !SDL_HAPTIC_DISABLED
if (SDL_PrivateShouldInitSubsystem(SDL_INIT_HAPTIC)) {
if (SDL_HapticInit() < 0) {
return (-1);
}
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_HAPTIC);
#else
return SDL_SetError("SDL not built with haptic (force feedback) support");
#endif
}
return (0);
}
int
SDL_Init(Uint32 flags)
{
return SDL_InitSubSystem(flags);
}
void
SDL_QuitSubSystem(Uint32 flags)
{
/* Shut down requested initialized subsystems */
#if !SDL_JOYSTICK_DISABLED
if ((flags & SDL_INIT_GAMECONTROLLER)) {
/* game controller implies joystick */
flags |= SDL_INIT_JOYSTICK;
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_GAMECONTROLLER)) {
SDL_GameControllerQuit();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_GAMECONTROLLER);
}
if ((flags & SDL_INIT_JOYSTICK)) {
/* joystick implies events */
flags |= SDL_INIT_EVENTS;
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_JOYSTICK)) {
SDL_JoystickQuit();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_JOYSTICK);
}
#endif
#if !SDL_HAPTIC_DISABLED
if ((flags & SDL_INIT_HAPTIC)) {
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_HAPTIC)) {
SDL_HapticQuit();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_HAPTIC);
}
#endif
#if !SDL_AUDIO_DISABLED
if ((flags & SDL_INIT_AUDIO)) {
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_AUDIO)) {
SDL_AudioQuit();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_AUDIO);
}
#endif
#if !SDL_VIDEO_DISABLED
if ((flags & SDL_INIT_VIDEO)) {
/* video implies events */
flags |= SDL_INIT_EVENTS;
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_VIDEO)) {
SDL_VideoQuit();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_VIDEO);
}
#endif
#if !SDL_TIMERS_DISABLED
if ((flags & SDL_INIT_TIMER)) {
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_TIMER)) {
SDL_TimerQuit();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_TIMER);
}
#endif
#if !SDL_EVENTS_DISABLED
if ((flags & SDL_INIT_EVENTS)) {
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_EVENTS)) {
SDL_QuitQuit();
SDL_StopEventLoop();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_EVENTS);
}
#endif
}
Uint32
SDL_WasInit(Uint32 flags)
{
int i;
int num_subsystems = SDL_arraysize(SDL_SubsystemRefCount);
Uint32 initialized = 0;
if (!flags) {
flags = SDL_INIT_EVERYTHING;
}
num_subsystems = SDL_min(num_subsystems, SDL_MostSignificantBitIndex32(flags) + 1);
/* Iterate over each bit in flags, and check the matching subsystem. */
for (i = 0; i < num_subsystems; ++i) {
if ((flags & 1) && SDL_SubsystemRefCount[i] > 0) {
initialized |= (1 << i);
}
flags >>= 1;
}
return initialized;
}
void
SDL_Quit(void)
{
SDL_bInMainQuit = SDL_TRUE;
/* Quit all subsystems */
#if SDL_VIDEO_DRIVER_WINDOWS
SDL_HelperWindowDestroy();
#endif
SDL_QuitSubSystem(SDL_INIT_EVERYTHING);
#if !SDL_TIMERS_DISABLED
SDL_TicksQuit();
#endif
SDL_ClearHints();
SDL_AssertionsQuit();
SDL_LogResetPriorities();
/* Now that every subsystem has been quit, we reset the subsystem refcount
* and the list of initialized subsystems.
*/
SDL_memset( SDL_SubsystemRefCount, 0x0, sizeof(SDL_SubsystemRefCount) );
SDL_bInMainQuit = SDL_FALSE;
}
/* Get the library version number */
void
SDL_GetVersion(SDL_version * ver)
{
SDL_VERSION(ver);
}
/* Get the library source revision */
const char *
SDL_GetRevision(void)
{
return SDL_REVISION;
}
/* Get the library source revision number */
int
SDL_GetRevisionNumber(void)
{
return SDL_REVISION_NUMBER;
}
/* Get the name of the platform */
const char *
SDL_GetPlatform()
{
#if __AIX__
return "AIX";
#elif __ANDROID__
return "Android";
#elif __BSDI__
return "BSDI";
#elif __DREAMCAST__
return "Dreamcast";
#elif __EMSCRIPTEN__
return "Emscripten";
#elif __FREEBSD__
return "FreeBSD";
#elif __HAIKU__
return "Haiku";
#elif __HPUX__
return "HP-UX";
#elif __IRIX__
return "Irix";
#elif __LINUX__
return "Linux";
#elif __MINT__
return "Atari MiNT";
#elif __MACOS__
return "MacOS Classic";
#elif __MACOSX__
return "Mac OS X";
#elif __NACL__
return "NaCl";
#elif __NETBSD__
return "NetBSD";
#elif __OPENBSD__
return "OpenBSD";
#elif __OS2__
return "OS/2";
#elif __OSF__
return "OSF/1";
#elif __QNXNTO__
return "QNX Neutrino";
#elif __RISCOS__
return "RISC OS";
#elif __SOLARIS__
return "Solaris";
#elif __WIN32__
return "Windows";
#elif __WINRT__
return "WinRT";
#elif __IPHONEOS__
return "iOS";
#elif __PSP__
return "PlayStation Portable";
#else
return "Unknown (see SDL_platform.h)";
#endif
}
#if defined(__WIN32__)
#if !defined(HAVE_LIBC) || (defined(__WATCOMC__) && defined(BUILD_DLL))
/* Need to include DllMain() on Watcom C for some reason.. */
BOOL APIENTRY
_DllMainCRTStartup(HANDLE hModule,
DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
#endif /* building DLL with Watcom C */
#endif /* __WIN32__ */
/* vi: set sts=4 ts=4 sw=4 expandtab: */

384
src/SDL_assert.c Normal file
View File

@@ -0,0 +1,384 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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 defined(__WIN32__)
#include "core/windows/SDL_windows.h"
#endif
#include "SDL.h"
#include "SDL_atomic.h"
#include "SDL_messagebox.h"
#include "SDL_video.h"
#include "SDL_assert.h"
#include "SDL_assert_c.h"
#include "video/SDL_sysvideo.h"
#ifdef __WIN32__
#ifndef WS_OVERLAPPEDWINDOW
#define WS_OVERLAPPEDWINDOW 0
#endif
#else /* fprintf, _exit(), etc. */
#include <stdio.h>
#include <stdlib.h>
#if ! defined(__WINRT__)
#include <unistd.h>
#endif
#endif
static SDL_assert_state
SDL_PromptAssertion(const SDL_assert_data *data, void *userdata);
/*
* We keep all triggered assertions in a singly-linked list so we can
* generate a report later.
*/
static SDL_assert_data *triggered_assertions = NULL;
static SDL_mutex *assertion_mutex = NULL;
static SDL_AssertionHandler assertion_handler = SDL_PromptAssertion;
static void *assertion_userdata = NULL;
#ifdef __GNUC__
static void
debug_print(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
#endif
static void
debug_print(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
SDL_LogMessageV(SDL_LOG_CATEGORY_ASSERT, SDL_LOG_PRIORITY_WARN, fmt, ap);
va_end(ap);
}
static void SDL_AddAssertionToReport(SDL_assert_data *data)
{
/* (data) is always a static struct defined with the assert macros, so
we don't have to worry about copying or allocating them. */
data->trigger_count++;
if (data->trigger_count == 1) { /* not yet added? */
data->next = triggered_assertions;
triggered_assertions = data;
}
}
static void SDL_GenerateAssertionReport(void)
{
const SDL_assert_data *item = triggered_assertions;
/* only do this if the app hasn't assigned an assertion handler. */
if ((item != NULL) && (assertion_handler != SDL_PromptAssertion)) {
debug_print("\n\nSDL assertion report.\n");
debug_print("All SDL assertions between last init/quit:\n\n");
while (item != NULL) {
debug_print(
"'%s'\n"
" * %s (%s:%d)\n"
" * triggered %u time%s.\n"
" * always ignore: %s.\n",
item->condition, item->function, item->filename,
item->linenum, item->trigger_count,
(item->trigger_count == 1) ? "" : "s",
item->always_ignore ? "yes" : "no");
item = item->next;
}
debug_print("\n");
SDL_ResetAssertionReport();
}
}
static void SDL_ExitProcess(int exitcode)
{
#ifdef __WIN32__
ExitProcess(exitcode);
#else
_exit(exitcode);
#endif
}
static void SDL_AbortAssertion(void)
{
SDL_Quit();
SDL_ExitProcess(42);
}
static SDL_assert_state
SDL_PromptAssertion(const SDL_assert_data *data, void *userdata)
{
#ifdef __WIN32__
#define ENDLINE "\r\n"
#else
#define ENDLINE "\n"
#endif
const char *envr;
SDL_assert_state state = SDL_ASSERTION_ABORT;
SDL_Window *window;
SDL_MessageBoxData messagebox;
SDL_MessageBoxButtonData buttons[] = {
{ 0, SDL_ASSERTION_RETRY, "Retry" },
{ 0, SDL_ASSERTION_BREAK, "Break" },
{ 0, SDL_ASSERTION_ABORT, "Abort" },
{ SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
SDL_ASSERTION_IGNORE, "Ignore" },
{ SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
SDL_ASSERTION_ALWAYS_IGNORE, "Always Ignore" }
};
char *message;
int selected;
(void) userdata; /* unused in default handler. */
message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
if (!message) {
/* Uh oh, we're in real trouble now... */
return SDL_ASSERTION_ABORT;
}
SDL_snprintf(message, SDL_MAX_LOG_MESSAGE,
"Assertion failure at %s (%s:%d), triggered %u %s:" ENDLINE
" '%s'",
data->function, data->filename, data->linenum,
data->trigger_count, (data->trigger_count == 1) ? "time" : "times",
data->condition);
debug_print("\n\n%s\n\n", message);
/* let env. variable override, so unit tests won't block in a GUI. */
envr = SDL_getenv("SDL_ASSERT");
if (envr != NULL) {
SDL_stack_free(message);
if (SDL_strcmp(envr, "abort") == 0) {
return SDL_ASSERTION_ABORT;
} else if (SDL_strcmp(envr, "break") == 0) {
return SDL_ASSERTION_BREAK;
} else if (SDL_strcmp(envr, "retry") == 0) {
return SDL_ASSERTION_RETRY;
} else if (SDL_strcmp(envr, "ignore") == 0) {
return SDL_ASSERTION_IGNORE;
} else if (SDL_strcmp(envr, "always_ignore") == 0) {
return SDL_ASSERTION_ALWAYS_IGNORE;
} else {
return SDL_ASSERTION_ABORT; /* oh well. */
}
}
/* Leave fullscreen mode, if possible (scary!) */
window = SDL_GetFocusWindow();
if (window) {
if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) {
SDL_MinimizeWindow(window);
} else {
/* !!! FIXME: ungrab the input if we're not fullscreen? */
/* No need to mess with the window */
window = NULL;
}
}
/* Show a messagebox if we can, otherwise fall back to stdio */
SDL_zero(messagebox);
messagebox.flags = SDL_MESSAGEBOX_WARNING;
messagebox.window = window;
messagebox.title = "Assertion Failed";
messagebox.message = message;
messagebox.numbuttons = SDL_arraysize(buttons);
messagebox.buttons = buttons;
if (SDL_ShowMessageBox(&messagebox, &selected) == 0) {
if (selected == -1) {
state = SDL_ASSERTION_IGNORE;
} else {
state = (SDL_assert_state)selected;
}
}
#ifdef HAVE_STDIO_H
else
{
/* this is a little hacky. */
for ( ; ; ) {
char buf[32];
fprintf(stderr, "Abort/Break/Retry/Ignore/AlwaysIgnore? [abriA] : ");
fflush(stderr);
if (fgets(buf, sizeof (buf), stdin) == NULL) {
break;
}
if (SDL_strcmp(buf, "a") == 0) {
state = SDL_ASSERTION_ABORT;
break;
} else if (SDL_strcmp(buf, "b") == 0) {
state = SDL_ASSERTION_BREAK;
break;
} else if (SDL_strcmp(buf, "r") == 0) {
state = SDL_ASSERTION_RETRY;
break;
} else if (SDL_strcmp(buf, "i") == 0) {
state = SDL_ASSERTION_IGNORE;
break;
} else if (SDL_strcmp(buf, "A") == 0) {
state = SDL_ASSERTION_ALWAYS_IGNORE;
break;
}
}
}
#endif /* HAVE_STDIO_H */
/* Re-enter fullscreen mode */
if (window) {
SDL_RestoreWindow(window);
}
SDL_stack_free(message);
return state;
}
SDL_assert_state
SDL_ReportAssertion(SDL_assert_data *data, const char *func, const char *file,
int line)
{
static int assertion_running = 0;
static SDL_SpinLock spinlock = 0;
SDL_assert_state state = SDL_ASSERTION_IGNORE;
SDL_AtomicLock(&spinlock);
if (assertion_mutex == NULL) { /* never called SDL_Init()? */
assertion_mutex = SDL_CreateMutex();
if (assertion_mutex == NULL) {
SDL_AtomicUnlock(&spinlock);
return SDL_ASSERTION_IGNORE; /* oh well, I guess. */
}
}
SDL_AtomicUnlock(&spinlock);
if (SDL_LockMutex(assertion_mutex) < 0) {
return SDL_ASSERTION_IGNORE; /* oh well, I guess. */
}
/* doing this because Visual C is upset over assigning in the macro. */
if (data->trigger_count == 0) {
data->function = func;
data->filename = file;
data->linenum = line;
}
SDL_AddAssertionToReport(data);
assertion_running++;
if (assertion_running > 1) { /* assert during assert! Abort. */
if (assertion_running == 2) {
SDL_AbortAssertion();
} else if (assertion_running == 3) { /* Abort asserted! */
SDL_ExitProcess(42);
} else {
while (1) { /* do nothing but spin; what else can you do?! */ }
}
}
if (!data->always_ignore) {
state = assertion_handler(data, assertion_userdata);
}
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;
break;
case SDL_ASSERTION_IGNORE:
case SDL_ASSERTION_RETRY:
case SDL_ASSERTION_BREAK:
break; /* macro handles these. */
}
assertion_running--;
SDL_UnlockMutex(assertion_mutex);
return state;
}
void SDL_AssertionsQuit(void)
{
SDL_GenerateAssertionReport();
if (assertion_mutex != NULL) {
SDL_DestroyMutex(assertion_mutex);
assertion_mutex = NULL;
}
}
void SDL_SetAssertionHandler(SDL_AssertionHandler handler, void *userdata)
{
if (handler != NULL) {
assertion_handler = handler;
assertion_userdata = userdata;
} else {
assertion_handler = SDL_PromptAssertion;
assertion_userdata = NULL;
}
}
const SDL_assert_data *SDL_GetAssertionReport(void)
{
return triggered_assertions;
}
void SDL_ResetAssertionReport(void)
{
SDL_assert_data *next = NULL;
SDL_assert_data *item;
for (item = triggered_assertions; item != NULL; item = next) {
next = (SDL_assert_data *) item->next;
item->always_ignore = SDL_FALSE;
item->trigger_count = 0;
item->next = NULL;
}
triggered_assertions = NULL;
}
SDL_AssertionHandler SDL_GetDefaultAssertionHandler(void)
{
return SDL_PromptAssertion;
}
SDL_AssertionHandler SDL_GetAssertionHandler(void **userdata)
{
if (userdata != NULL) {
*userdata = assertion_userdata;
}
return assertion_handler;
}
/* vi: set ts=4 sw=4 expandtab: */

24
src/SDL_assert_c.h Normal file
View File

@@ -0,0 +1,24 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
extern void SDL_AssertionsQuit(void);
/* vi: set ts=4 sw=4 expandtab: */

275
src/SDL_error.c Normal file
View File

@@ -0,0 +1,275 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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"
/* 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 */
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;
/* Copy in the key, mark error as valid */
error = SDL_GetErrBuf();
error->error = 1;
SDL_strlcpy((char *) error->key, fmt, sizeof(error->key));
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 '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_end(ap);
/* If we are in debug mode, print out an error message */
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "%s", SDL_GetError());
return -1;
}
/* This function has a bit more overhead than most error functions
so that it supports internationalization and thread-safe errors.
*/
static char *
SDL_GetErrorMsg(char *errstr, int maxlen)
{
SDL_error *error;
/* 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++;
}
*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 */
}
return (errstr);
}
/* Available for backwards compatibility */
const char *
SDL_GetError(void)
{
static char errmsg[SDL_ERRBUFIZE];
return SDL_GetErrorMsg(errmsg, SDL_ERRBUFIZE);
}
void
SDL_ClearError(void)
{
SDL_error *error;
error = SDL_GetErrBuf();
error->error = 0;
}
/* Very common errors go here */
int
SDL_Error(SDL_errorcode code)
{
switch (code) {
case SDL_ENOMEM:
return SDL_SetError("Out of memory");
case SDL_EFREAD:
return SDL_SetError("Error reading from datastream");
case SDL_EFWRITE:
return SDL_SetError("Error writing to datastream");
case SDL_EFSEEK:
return SDL_SetError("Error seeking in datastream");
case SDL_UNSUPPORTED:
return SDL_SetError("That operation is not supported");
default:
return SDL_SetError("Unknown SDL error");
}
}
#ifdef TEST_ERROR
int
main(int argc, char *argv[])
{
char buffer[BUFSIZ + 1];
SDL_SetError("Hi there!");
printf("Error 1: %s\n", SDL_GetError());
SDL_ClearError();
SDL_memset(buffer, '1', BUFSIZ);
buffer[BUFSIZ] = 0;
SDL_SetError("This is the error: %s (%f)", buffer, 1.0);
printf("Error 2: %s\n", SDL_GetError());
exit(0);
}
#endif
/* vi: set ts=4 sw=4 expandtab: */

64
src/SDL_error_c.h Normal file
View File

@@ -0,0 +1,64 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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"
/* This file defines a structure that carries language-independent
error messages
*/
#ifndef _SDL_error_c_h
#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;
double value_f;
char buf[ERR_MAX_STRLEN];
} args[ERR_MAX_ARGS];
} SDL_error;
/* Defined in SDL_thread.c */
extern SDL_error *SDL_GetErrBuf(void);
#endif /* _SDL_error_c_h */
/* vi: set ts=4 sw=4 expandtab: */

223
src/SDL_hints.c Normal file
View File

@@ -0,0 +1,223 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_hints.h"
#include "SDL_error.h"
/* Assuming there aren't many hints set and they aren't being queried in
critical performance paths, we'll just use linked lists here.
*/
typedef struct SDL_HintWatch {
SDL_HintCallback callback;
void *userdata;
struct SDL_HintWatch *next;
} SDL_HintWatch;
typedef struct SDL_Hint {
char *name;
char *value;
SDL_HintPriority priority;
SDL_HintWatch *callbacks;
struct SDL_Hint *next;
} SDL_Hint;
static SDL_Hint *SDL_hints;
SDL_bool
SDL_SetHintWithPriority(const char *name, const char *value,
SDL_HintPriority priority)
{
const char *env;
SDL_Hint *hint;
SDL_HintWatch *entry;
if (!name || !value) {
return SDL_FALSE;
}
env = SDL_getenv(name);
if (env && priority < SDL_HINT_OVERRIDE) {
return SDL_FALSE;
}
for (hint = SDL_hints; hint; hint = hint->next) {
if (SDL_strcmp(name, hint->name) == 0) {
if (priority < hint->priority) {
return SDL_FALSE;
}
if (!hint->value || !value || SDL_strcmp(hint->value, value) != 0) {
for (entry = hint->callbacks; entry; ) {
/* Save the next entry in case this one is deleted */
SDL_HintWatch *next = entry->next;
entry->callback(entry->userdata, name, hint->value, value);
entry = next;
}
SDL_free(hint->value);
hint->value = value ? SDL_strdup(value) : NULL;
}
hint->priority = priority;
return SDL_TRUE;
}
}
/* Couldn't find the hint, add a new one */
hint = (SDL_Hint *)SDL_malloc(sizeof(*hint));
if (!hint) {
return SDL_FALSE;
}
hint->name = SDL_strdup(name);
hint->value = value ? SDL_strdup(value) : NULL;
hint->priority = priority;
hint->callbacks = NULL;
hint->next = SDL_hints;
SDL_hints = hint;
return SDL_TRUE;
}
SDL_bool
SDL_SetHint(const char *name, const char *value)
{
return SDL_SetHintWithPriority(name, value, SDL_HINT_NORMAL);
}
const char *
SDL_GetHint(const char *name)
{
const char *env;
SDL_Hint *hint;
env = SDL_getenv(name);
for (hint = SDL_hints; hint; hint = hint->next) {
if (SDL_strcmp(name, hint->name) == 0) {
if (!env || hint->priority == SDL_HINT_OVERRIDE) {
return hint->value;
}
break;
}
}
return env;
}
void
SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata)
{
SDL_Hint *hint;
SDL_HintWatch *entry;
const char *value;
if (!name || !*name) {
SDL_InvalidParamError("name");
return;
}
if (!callback) {
SDL_InvalidParamError("callback");
return;
}
SDL_DelHintCallback(name, callback, userdata);
entry = (SDL_HintWatch *)SDL_malloc(sizeof(*entry));
if (!entry) {
SDL_OutOfMemory();
return;
}
entry->callback = callback;
entry->userdata = userdata;
for (hint = SDL_hints; hint; hint = hint->next) {
if (SDL_strcmp(name, hint->name) == 0) {
break;
}
}
if (!hint) {
/* Need to add a hint entry for this watcher */
hint = (SDL_Hint *)SDL_malloc(sizeof(*hint));
if (!hint) {
SDL_OutOfMemory();
SDL_free(entry);
return;
}
hint->name = SDL_strdup(name);
hint->value = NULL;
hint->priority = SDL_HINT_DEFAULT;
hint->callbacks = NULL;
hint->next = SDL_hints;
SDL_hints = hint;
}
/* Add it to the callbacks for this hint */
entry->next = hint->callbacks;
hint->callbacks = entry;
/* Now call it with the current value */
value = SDL_GetHint(name);
callback(userdata, name, value, value);
}
void
SDL_DelHintCallback(const char *name, SDL_HintCallback callback, void *userdata)
{
SDL_Hint *hint;
SDL_HintWatch *entry, *prev;
for (hint = SDL_hints; hint; hint = hint->next) {
if (SDL_strcmp(name, hint->name) == 0) {
prev = NULL;
for (entry = hint->callbacks; entry; entry = entry->next) {
if (callback == entry->callback && userdata == entry->userdata) {
if (prev) {
prev->next = entry->next;
} else {
hint->callbacks = entry->next;
}
SDL_free(entry);
break;
}
prev = entry;
}
return;
}
}
}
void SDL_ClearHints(void)
{
SDL_Hint *hint;
SDL_HintWatch *entry;
while (SDL_hints) {
hint = SDL_hints;
SDL_hints = hint->next;
SDL_free(hint->name);
SDL_free(hint->value);
for (entry = hint->callbacks; entry; ) {
SDL_HintWatch *freeable = entry;
entry = entry->next;
SDL_free(freeable);
}
SDL_free(hint);
}
}
/* vi: set ts=4 sw=4 expandtab: */

38
src/SDL_internal.h Normal file
View File

@@ -0,0 +1,38 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_internal_h
#define _SDL_internal_h
#include "dynapi/SDL_dynapi.h"
#if SDL_DYNAMIC_API
#include "dynapi/SDL_dynapi_overrides.h"
/* force DECLSPEC and SDLCALL off...it's all internal symbols now.
These will have actual #defines during SDL_dynapi.c only */
#define DECLSPEC
#define SDLCALL
#endif
#include "SDL_config.h"
#endif
/* vi: set ts=4 sw=4 expandtab: */

440
src/SDL_log.c Normal file
View File

@@ -0,0 +1,440 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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 defined(__WIN32__) || defined(__WINRT__)
#include "core/windows/SDL_windows.h"
#endif
/* Simple log messages in SDL */
#include "SDL_error.h"
#include "SDL_log.h"
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#if defined(__ANDROID__)
#include <android/log.h>
#endif
#define DEFAULT_PRIORITY SDL_LOG_PRIORITY_CRITICAL
#define DEFAULT_ASSERT_PRIORITY SDL_LOG_PRIORITY_WARN
#define DEFAULT_APPLICATION_PRIORITY SDL_LOG_PRIORITY_INFO
#define DEFAULT_TEST_PRIORITY SDL_LOG_PRIORITY_VERBOSE
typedef struct SDL_LogLevel
{
int category;
SDL_LogPriority priority;
struct SDL_LogLevel *next;
} SDL_LogLevel;
/* The default log output function */
static void SDL_LogOutput(void *userdata,
int category, SDL_LogPriority priority,
const char *message);
static SDL_LogLevel *SDL_loglevels;
static SDL_LogPriority SDL_default_priority = DEFAULT_PRIORITY;
static SDL_LogPriority SDL_assert_priority = DEFAULT_ASSERT_PRIORITY;
static SDL_LogPriority SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
static SDL_LogPriority SDL_test_priority = DEFAULT_TEST_PRIORITY;
static SDL_LogOutputFunction SDL_log_function = SDL_LogOutput;
static void *SDL_log_userdata = NULL;
static const char *SDL_priority_prefixes[SDL_NUM_LOG_PRIORITIES] = {
NULL,
"VERBOSE",
"DEBUG",
"INFO",
"WARN",
"ERROR",
"CRITICAL"
};
#ifdef __ANDROID__
static const char *SDL_category_prefixes[SDL_LOG_CATEGORY_RESERVED1] = {
"APP",
"ERROR",
"SYSTEM",
"AUDIO",
"VIDEO",
"RENDER",
"INPUT"
};
static int SDL_android_priority[SDL_NUM_LOG_PRIORITIES] = {
ANDROID_LOG_UNKNOWN,
ANDROID_LOG_VERBOSE,
ANDROID_LOG_DEBUG,
ANDROID_LOG_INFO,
ANDROID_LOG_WARN,
ANDROID_LOG_ERROR,
ANDROID_LOG_FATAL
};
#endif /* __ANDROID__ */
void
SDL_LogSetAllPriority(SDL_LogPriority priority)
{
SDL_LogLevel *entry;
for (entry = SDL_loglevels; entry; entry = entry->next) {
entry->priority = priority;
}
SDL_default_priority = priority;
SDL_assert_priority = priority;
SDL_application_priority = priority;
}
void
SDL_LogSetPriority(int category, SDL_LogPriority priority)
{
SDL_LogLevel *entry;
for (entry = SDL_loglevels; entry; entry = entry->next) {
if (entry->category == category) {
entry->priority = priority;
return;
}
}
/* Create a new entry */
entry = (SDL_LogLevel *)SDL_malloc(sizeof(*entry));
if (entry) {
entry->category = category;
entry->priority = priority;
entry->next = SDL_loglevels;
SDL_loglevels = entry;
}
}
SDL_LogPriority
SDL_LogGetPriority(int category)
{
SDL_LogLevel *entry;
for (entry = SDL_loglevels; entry; entry = entry->next) {
if (entry->category == category) {
return entry->priority;
}
}
if (category == SDL_LOG_CATEGORY_TEST) {
return SDL_test_priority;
} else if (category == SDL_LOG_CATEGORY_APPLICATION) {
return SDL_application_priority;
} else if (category == SDL_LOG_CATEGORY_ASSERT) {
return SDL_assert_priority;
} else {
return SDL_default_priority;
}
}
void
SDL_LogResetPriorities(void)
{
SDL_LogLevel *entry;
while (SDL_loglevels) {
entry = SDL_loglevels;
SDL_loglevels = entry->next;
SDL_free(entry);
}
SDL_default_priority = DEFAULT_PRIORITY;
SDL_assert_priority = DEFAULT_ASSERT_PRIORITY;
SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
SDL_test_priority = DEFAULT_TEST_PRIORITY;
}
void
SDL_Log(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap);
va_end(ap);
}
void
SDL_LogVerbose(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
SDL_LogMessageV(category, SDL_LOG_PRIORITY_VERBOSE, fmt, ap);
va_end(ap);
}
void
SDL_LogDebug(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
SDL_LogMessageV(category, SDL_LOG_PRIORITY_DEBUG, fmt, ap);
va_end(ap);
}
void
SDL_LogInfo(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
SDL_LogMessageV(category, SDL_LOG_PRIORITY_INFO, fmt, ap);
va_end(ap);
}
void
SDL_LogWarn(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
SDL_LogMessageV(category, SDL_LOG_PRIORITY_WARN, fmt, ap);
va_end(ap);
}
void
SDL_LogError(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
SDL_LogMessageV(category, SDL_LOG_PRIORITY_ERROR, fmt, ap);
va_end(ap);
}
void
SDL_LogCritical(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
SDL_LogMessageV(category, SDL_LOG_PRIORITY_CRITICAL, fmt, ap);
va_end(ap);
}
void
SDL_LogMessage(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
SDL_LogMessageV(category, priority, fmt, ap);
va_end(ap);
}
#ifdef __ANDROID__
static const char *
GetCategoryPrefix(int category)
{
if (category < SDL_LOG_CATEGORY_RESERVED1) {
return SDL_category_prefixes[category];
}
if (category < SDL_LOG_CATEGORY_CUSTOM) {
return "RESERVED";
}
return "CUSTOM";
}
#endif /* __ANDROID__ */
void
SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list ap)
{
char *message;
size_t len;
/* Nothing to do if we don't have an output function */
if (!SDL_log_function) {
return;
}
/* Make sure we don't exceed array bounds */
if ((int)priority < 0 || priority >= SDL_NUM_LOG_PRIORITIES) {
return;
}
/* See if we want to do anything with this message */
if (priority < SDL_LogGetPriority(category)) {
return;
}
message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
if (!message) {
return;
}
SDL_vsnprintf(message, SDL_MAX_LOG_MESSAGE, fmt, ap);
/* Chop off final endline. */
len = SDL_strlen(message);
if ((len > 0) && (message[len-1] == '\n')) {
message[--len] = '\0';
if ((len > 0) && (message[len-1] == '\r')) { /* catch "\r\n", too. */
message[--len] = '\0';
}
}
SDL_log_function(SDL_log_userdata, category, priority, message);
SDL_stack_free(message);
}
#if defined(__WIN32__)
/* Flag tracking the attachment of the console: 0=unattached, 1=attached, -1=error */
static int consoleAttached = 0;
/* Handle to stderr output of console. */
static HANDLE stderrHandle = NULL;
#endif
static void
SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
const char *message)
{
#if defined(__WIN32__) || defined(__WINRT__)
/* Way too many allocations here, urgh */
/* Note: One can't call SDL_SetError here, since that function itself logs. */
{
char *output;
size_t length;
LPTSTR tstr;
#ifndef __WINRT__
BOOL attachResult;
DWORD attachError;
unsigned long charsWritten;
/* Maybe attach console and get stderr handle */
if (consoleAttached == 0) {
attachResult = AttachConsole(ATTACH_PARENT_PROCESS);
if (!attachResult) {
attachError = GetLastError();
if (attachError == ERROR_INVALID_HANDLE) {
OutputDebugString(TEXT("Parent process has no console\r\n"));
consoleAttached = -1;
} else if (attachError == ERROR_GEN_FAILURE) {
OutputDebugString(TEXT("Could not attach to console of parent process\r\n"));
consoleAttached = -1;
} else if (attachError == ERROR_ACCESS_DENIED) {
/* Already attached */
consoleAttached = 1;
} else {
OutputDebugString(TEXT("Error attaching console\r\n"));
consoleAttached = -1;
}
} else {
/* Newly attached */
consoleAttached = 1;
}
if (consoleAttached == 1) {
stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
}
}
#endif /* ifndef __WINRT__ */
length = SDL_strlen(SDL_priority_prefixes[priority]) + 2 + SDL_strlen(message) + 1 + 1 + 1;
output = SDL_stack_alloc(char, length);
SDL_snprintf(output, length, "%s: %s\r\n", SDL_priority_prefixes[priority], message);
tstr = WIN_UTF8ToString(output);
/* Output to debugger */
OutputDebugString(tstr);
#ifndef __WINRT__
/* Screen output to stderr, if console was attached. */
if (consoleAttached == 1) {
if (!WriteConsole(stderrHandle, tstr, lstrlen(tstr), &charsWritten, NULL)) {
OutputDebugString(TEXT("Error calling WriteConsole\r\n"));
}
if (charsWritten == ERROR_NOT_ENOUGH_MEMORY) {
OutputDebugString(TEXT("Insufficient heap memory to write message\r\n"));
}
}
#endif /* ifndef __WINRT__ */
SDL_free(tstr);
SDL_stack_free(output);
}
#elif defined(__ANDROID__)
{
char tag[32];
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.
*/
extern void SDL_NSLog(const char *text);
{
char *text;
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);
SDL_NSLog(text);
SDL_stack_free(text);
return;
}
}
#elif defined(__PSP__)
{
FILE* pFile;
pFile = fopen ("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);
#if __NACL__
fflush(stderr);
#endif
#endif
}
void
SDL_LogGetOutputFunction(SDL_LogOutputFunction *callback, void **userdata)
{
if (callback) {
*callback = SDL_log_function;
}
if (userdata) {
*userdata = SDL_log_userdata;
}
}
void
SDL_LogSetOutputFunction(SDL_LogOutputFunction callback, void *userdata)
{
SDL_log_function = callback;
SDL_log_userdata = userdata;
}
/* vi: set ts=4 sw=4 expandtab: */

246
src/atomic/SDL_atomic.c Normal file
View File

@@ -0,0 +1,246 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_atomic.h"
#if defined(_MSC_VER) && (_MSC_VER >= 1500)
#include <intrin.h>
#define HAVE_MSC_ATOMICS 1
#endif
#if defined(__MACOSX__) /* !!! FIXME: should we favor gcc atomics? */
#include <libkern/OSAtomic.h>
#endif
#if !defined(HAVE_GCC_ATOMICS) && defined(__SOLARIS__)
#include <atomic.h>
#endif
/*
If any of the operations are not provided then we must emulate some
of them. That means we need a nice implementation of spin locks
that avoids the "one big lock" problem. We use a vector of spin
locks and pick which one to use based on the address of the operand
of the function.
To generate the index of the lock we first shift by 3 bits to get
rid on the zero bits that result from 32 and 64 bit allignment of
data. We then mask off all but 5 bits and use those 5 bits as an
index into the table.
Picking the lock this way insures that accesses to the same data at
the same time will go to the same lock. OTOH, accesses to different
data have only a 1/32 chance of hitting the same lock. That should
pretty much eliminate the chances of several atomic operations on
different data from waiting on the same "big lock". If it isn't
then the table of locks can be expanded to a new size so long as
the new size is a power of two.
Contributed by Bob Pendleton, bob@pendleton.com
*/
#if !defined(HAVE_MSC_ATOMICS) && !defined(HAVE_GCC_ATOMICS) && !defined(__MACOSX__) && !defined(__SOLARIS__)
#define EMULATE_CAS 1
#endif
#if EMULATE_CAS
static SDL_SpinLock locks[32];
static SDL_INLINE void
enterLock(void *a)
{
uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
SDL_AtomicLock(&locks[index]);
}
static SDL_INLINE void
leaveLock(void *a)
{
uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
SDL_AtomicUnlock(&locks[index]);
}
#endif
SDL_bool
SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval)
{
#ifdef HAVE_MSC_ATOMICS
return (_InterlockedCompareExchange((long*)&a->value, (long)newval, (long)oldval) == (long)oldval);
#elif defined(__MACOSX__) /* !!! FIXME: should we favor gcc atomics? */
return (SDL_bool) OSAtomicCompareAndSwap32Barrier(oldval, newval, &a->value);
#elif defined(HAVE_GCC_ATOMICS)
return (SDL_bool) __sync_bool_compare_and_swap(&a->value, oldval, newval);
#elif defined(__SOLARIS__) && defined(_LP64)
return (SDL_bool) ((int) atomic_cas_64((volatile uint64_t*)&a->value, (uint64_t)oldval, (uint64_t)newval) == oldval);
#elif defined(__SOLARIS__) && !defined(_LP64)
return (SDL_bool) ((int) atomic_cas_32((volatile uint32_t*)&a->value, (uint32_t)oldval, (uint32_t)newval) == oldval);
#elif EMULATE_CAS
SDL_bool retval = SDL_FALSE;
enterLock(a);
if (a->value == oldval) {
a->value = newval;
retval = SDL_TRUE;
}
leaveLock(a);
return retval;
#else
#error Please define your platform.
#endif
}
SDL_bool
SDL_AtomicCASPtr(void **a, void *oldval, void *newval)
{
#if defined(HAVE_MSC_ATOMICS) && (_M_IX86)
return (_InterlockedCompareExchange((long*)a, (long)newval, (long)oldval) == (long)oldval);
#elif defined(HAVE_MSC_ATOMICS) && (!_M_IX86)
return (_InterlockedCompareExchangePointer(a, newval, oldval) == oldval);
#elif defined(__MACOSX__) && defined(__LP64__) /* !!! FIXME: should we favor gcc atomics? */
return (SDL_bool) OSAtomicCompareAndSwap64Barrier((int64_t)oldval, (int64_t)newval, (int64_t*) a);
#elif defined(__MACOSX__) && !defined(__LP64__) /* !!! FIXME: should we favor gcc atomics? */
return (SDL_bool) OSAtomicCompareAndSwap32Barrier((int32_t)oldval, (int32_t)newval, (int32_t*) a);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_bool_compare_and_swap(a, oldval, newval);
#elif defined(__SOLARIS__)
return (SDL_bool) (atomic_cas_ptr(a, oldval, newval) == oldval);
#elif EMULATE_CAS
SDL_bool retval = SDL_FALSE;
enterLock(a);
if (*a == oldval) {
*a = newval;
retval = SDL_TRUE;
}
leaveLock(a);
return retval;
#else
#error Please define your platform.
#endif
}
int
SDL_AtomicSet(SDL_atomic_t *a, int v)
{
#ifdef HAVE_MSC_ATOMICS
return _InterlockedExchange((long*)&a->value, v);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_lock_test_and_set(&a->value, v);
#elif defined(__SOLARIS__) && defined(_LP64)
return (int) atomic_swap_64((volatile uint64_t*)&a->value, (uint64_t)v);
#elif defined(__SOLARIS__) && !defined(_LP64)
return (int) atomic_swap_32((volatile uint32_t*)&a->value, (uint32_t)v);
#else
int value;
do {
value = a->value;
} while (!SDL_AtomicCAS(a, value, v));
return value;
#endif
}
void*
SDL_AtomicSetPtr(void **a, void *v)
{
#if defined(HAVE_MSC_ATOMICS) && (_M_IX86)
return (void *) _InterlockedExchange((long *)a, (long) v);
#elif defined(HAVE_MSC_ATOMICS) && (!_M_IX86)
return _InterlockedExchangePointer(a, v);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_lock_test_and_set(a, v);
#elif defined(__SOLARIS__)
return atomic_swap_ptr(a, v);
#else
void *value;
do {
value = *a;
} while (!SDL_AtomicCASPtr(a, value, v));
return value;
#endif
}
int
SDL_AtomicAdd(SDL_atomic_t *a, int v)
{
#ifdef HAVE_MSC_ATOMICS
return _InterlockedExchangeAdd((long*)&a->value, v);
#elif defined(HAVE_GCC_ATOMICS)
return __sync_fetch_and_add(&a->value, v);
#elif defined(__SOLARIS__)
int pv = a->value;
membar_consumer();
#if defined(_LP64)
atomic_add_64((volatile uint64_t*)&a->value, v);
#elif !defined(_LP64)
atomic_add_32((volatile uint32_t*)&a->value, v);
#endif
return pv;
#else
int value;
do {
value = a->value;
} while (!SDL_AtomicCAS(a, value, (value + v)));
return value;
#endif
}
int
SDL_AtomicGet(SDL_atomic_t *a)
{
int value;
do {
value = a->value;
} while (!SDL_AtomicCAS(a, value, value));
return value;
}
void *
SDL_AtomicGetPtr(void **a)
{
void *value;
do {
value = *a;
} while (!SDL_AtomicCASPtr(a, value, value));
return value;
}
#ifdef __thumb__
#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
__asm__(
" .align 2\n"
" .globl _SDL_MemoryBarrierRelease\n"
" .globl _SDL_MemoryBarrierAcquire\n"
"_SDL_MemoryBarrierRelease:\n"
"_SDL_MemoryBarrierAcquire:\n"
" mov r0, #0\n"
" mcr p15, 0, r0, c7, c10, 5\n"
" bx lr\n"
);
#endif
#endif
/* vi: set ts=4 sw=4 expandtab: */

135
src/atomic/SDL_spinlock.c Normal file
View File

@@ -0,0 +1,135 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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 defined(__WIN32__) || defined(__WINRT__)
#include "../core/windows/SDL_windows.h"
#endif
#include "SDL_atomic.h"
#include "SDL_mutex.h"
#include "SDL_timer.h"
#if !defined(HAVE_GCC_ATOMICS) && defined(__SOLARIS__)
#include <atomic.h>
#endif
/* This function is where all the magic happens... */
SDL_bool
SDL_AtomicTryLock(SDL_SpinLock *lock)
{
#if SDL_ATOMIC_DISABLED
/* Terrible terrible damage */
static SDL_mutex *_spinlock_mutex;
if (!_spinlock_mutex) {
/* Race condition on first lock... */
_spinlock_mutex = SDL_CreateMutex();
}
SDL_LockMutex(_spinlock_mutex);
if (*lock == 0) {
*lock = 1;
SDL_UnlockMutex(_spinlock_mutex);
return SDL_TRUE;
} else {
SDL_UnlockMutex(_spinlock_mutex);
return SDL_FALSE;
}
#elif defined(_MSC_VER)
SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long));
return (InterlockedExchange((long*)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_5__) || defined(__ARM_ARCH_5TE__) || \
defined(__ARM_ARCH_5TEJ__))
int result;
__asm__ __volatile__ (
"swp %0, %1, [%2]\n"
: "=&r,&r" (result) : "r,0" (1), "r,r" (lock) : "memory");
return (result == 0);
#elif defined(__GNUC__) && defined(__arm__)
int result;
__asm__ __volatile__ (
"ldrex %0, [%2]\nteq %0, #0\nstrexeq %0, %1, [%2]"
: "=&r" (result) : "r" (1), "r" (lock) : "cc", "memory");
return (result == 0);
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
int result;
__asm__ __volatile__(
"lock ; xchgl %0, (%1)\n"
: "=r" (result) : "r" (lock), "0" (1) : "cc", "memory");
return (result == 0);
#elif defined(__MACOSX__) || defined(__IPHONEOS__)
/* Maybe used for PowerPC, but the Intel asm or gcc atomics are favored. */
return OSAtomicCompareAndSwap32Barrier(0, 1, lock);
#elif defined(__SOLARIS__) && defined(_LP64)
/* Used for Solaris with non-gcc compilers. */
return (SDL_bool) ((int) atomic_cas_64((volatile uint64_t*)lock, 0, 1) == 0);
#elif defined(__SOLARIS__) && !defined(_LP64)
/* Used for Solaris with non-gcc compilers. */
return (SDL_bool) ((int) atomic_cas_32((volatile uint32_t*)lock, 0, 1) == 0);
#else
#error Please implement for your platform.
return SDL_FALSE;
#endif
}
void
SDL_AtomicLock(SDL_SpinLock *lock)
{
/* FIXME: Should we have an eventual timeout? */
while (!SDL_AtomicTryLock(lock)) {
SDL_Delay(0);
}
}
void
SDL_AtomicUnlock(SDL_SpinLock *lock)
{
#if defined(_MSC_VER)
_ReadWriteBarrier();
*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;
membar_producer();
#else
*lock = 0;
#endif
}
/* vi: set ts=4 sw=4 expandtab: */

1455
src/audio/SDL_audio.c Normal file

File diff suppressed because it is too large Load Diff

55
src/audio/SDL_audio_c.h Normal file
View File

@@ -0,0 +1,55 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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"
/* Functions and variables exported from SDL_audio.c for SDL_sysaudio.c */
/* Functions to get a list of "close" audio formats */
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 void SDL_CalculateAudioSpec(SDL_AudioSpec * spec);
/* The actual mixing thread function */
extern int SDLCALL SDL_RunAudio(void *audiop);
/* this is used internally to access some autogenerated code. */
typedef struct
{
SDL_AudioFormat src_fmt;
SDL_AudioFormat dst_fmt;
SDL_AudioFilter filter;
} SDL_AudioTypeFilters;
extern const SDL_AudioTypeFilters sdl_audio_type_filters[];
/* this is used internally to access some autogenerated code. */
typedef struct
{
SDL_AudioFormat fmt;
int channels;
int upsample;
int multiple;
SDL_AudioFilter filter;
} SDL_AudioRateFilters;
extern const SDL_AudioRateFilters sdl_audio_rate_filters[];
/* vi: set ts=4 sw=4 expandtab: */

1121
src/audio/SDL_audiocvt.c Normal file

File diff suppressed because it is too large Load Diff

123
src/audio/SDL_audiodev.c Normal file
View File

@@ -0,0 +1,123 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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"
/* Get the name of the audio device we use for output */
#if SDL_AUDIO_DRIVER_BSD || SDL_AUDIO_DRIVER_OSS || SDL_AUDIO_DRIVER_SUNAUDIO
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h> /* For close() */
#include "SDL_stdinc.h"
#include "SDL_audiodev_c.h"
#ifndef _PATH_DEV_DSP
#if defined(__NETBSD__) || defined(__OPENBSD__)
#define _PATH_DEV_DSP "/dev/audio"
#else
#define _PATH_DEV_DSP "/dev/dsp"
#endif
#endif
#ifndef _PATH_DEV_DSP24
#define _PATH_DEV_DSP24 "/dev/sound/dsp"
#endif
#ifndef _PATH_DEV_AUDIO
#define _PATH_DEV_AUDIO "/dev/audio"
#endif
static void
test_device(const int iscapture, const char *fname, int flags, int (*test) (int fd))
{
struct stat sb;
if ((stat(fname, &sb) == 0) && (S_ISCHR(sb.st_mode))) {
const int audio_fd = open(fname, flags, 0);
if (audio_fd >= 0) {
const int okay = test(audio_fd);
close(audio_fd);
if (okay) {
static size_t dummyhandle = 0;
dummyhandle++;
SDL_assert(dummyhandle != 0);
SDL_AddAudioDevice(iscapture, fname, (void *) dummyhandle);
}
}
}
}
static int
test_stub(int fd)
{
return 1;
}
static void
SDL_EnumUnixAudioDevices_Internal(const int iscapture, const int classic, int (*test)(int))
{
const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT;
const char *audiodev;
char audiopath[1024];
if (test == NULL)
test = test_stub;
/* Figure out what our audio device is */
if (((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) &&
((audiodev = SDL_getenv("AUDIODEV")) == NULL)) {
if (classic) {
audiodev = _PATH_DEV_AUDIO;
} else {
struct stat sb;
/* Added support for /dev/sound/\* in Linux 2.4 */
if (((stat("/dev/sound", &sb) == 0) && S_ISDIR(sb.st_mode))
&& ((stat(_PATH_DEV_DSP24, &sb) == 0)
&& S_ISCHR(sb.st_mode))) {
audiodev = _PATH_DEV_DSP24;
} else {
audiodev = _PATH_DEV_DSP;
}
}
}
test_device(iscapture, audiodev, flags, test);
if (SDL_strlen(audiodev) < (sizeof(audiopath) - 3)) {
int instance = 0;
while (instance++ <= 64) {
SDL_snprintf(audiopath, SDL_arraysize(audiopath),
"%s%d", audiodev, instance);
test_device(iscapture, audiopath, flags, test);
}
}
}
void
SDL_EnumUnixAudioDevices(const int classic, int (*test)(int))
{
SDL_EnumUnixAudioDevices_Internal(SDL_TRUE, classic, test);
SDL_EnumUnixAudioDevices_Internal(SDL_FALSE, classic, test);
}
#endif /* Audio driver selection */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,38 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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.h"
#include "../SDL_internal.h"
#include "SDL_sysaudio.h"
/* Open the audio device for playback, and don't block if busy */
/* #define USE_BLOCKING_WRITES */
#ifdef USE_BLOCKING_WRITES
#define OPEN_FLAGS_OUTPUT O_WRONLY
#define OPEN_FLAGS_INPUT O_RDONLY
#else
#define OPEN_FLAGS_OUTPUT (O_WRONLY|O_NONBLOCK)
#define OPEN_FLAGS_INPUT (O_RDONLY|O_NONBLOCK)
#endif
extern void SDL_EnumUnixAudioDevices(const int classic, int (*test)(int));
/* vi: set ts=4 sw=4 expandtab: */

25
src/audio/SDL_audiomem.h Normal file
View File

@@ -0,0 +1,25 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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"
#define SDL_AllocAudioMem SDL_malloc
#define SDL_FreeAudioMem SDL_free
/* vi: set ts=4 sw=4 expandtab: */

16015
src/audio/SDL_audiotypecvt.c Normal file

File diff suppressed because it is too large Load Diff

321
src/audio/SDL_mixer.c Normal file
View File

@@ -0,0 +1,321 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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"
/* This provides the default mixing callback for the SDL audio routines */
#include "SDL_cpuinfo.h"
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "SDL_sysaudio.h"
/* 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,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D,
0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4,
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
};
/* 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)
void
SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
Uint32 len, int volume)
{
if (volume == 0) {
return;
}
switch (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--) {
src_sample = *src;
ADJUST_VOLUME_U8(src_sample, volume);
*dst = mix8[*dst + src_sample];
++dst;
++src;
}
#endif
}
break;
case AUDIO_S8:
{
Sint8 *dst8, *src8;
Sint8 src_sample;
int dst_sample;
const int max_audioval = ((1 << (8 - 1)) - 1);
const int min_audioval = -(1 << (8 - 1));
src8 = (Sint8 *) src;
dst8 = (Sint8 *) dst;
while (len--) {
src_sample = *src8;
ADJUST_VOLUME(src_sample, volume);
dst_sample = *dst8 + src_sample;
if (dst_sample > max_audioval) {
*dst8 = max_audioval;
} else if (dst_sample < min_audioval) {
*dst8 = min_audioval;
} else {
*dst8 = dst_sample;
}
++dst8;
++src8;
}
}
break;
case AUDIO_S16LSB:
{
Sint16 src1, src2;
int dst_sample;
const int max_audioval = ((1 << (16 - 1)) - 1);
const int min_audioval = -(1 << (16 - 1));
len /= 2;
while (len--) {
src1 = ((src[1]) << 8 | src[0]);
ADJUST_VOLUME(src1, volume);
src2 = ((dst[1]) << 8 | dst[0]);
src += 2;
dst_sample = src1 + src2;
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 += 2;
}
}
break;
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));
len /= 2;
while (len--) {
src1 = ((src[0]) << 8 | src[1]);
ADJUST_VOLUME(src1, volume);
src2 = ((dst[0]) << 8 | dst[1]);
src += 2;
dst_sample = src1 + src2;
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 += 2;
}
#endif
}
break;
case AUDIO_S32LSB:
{
const Uint32 *src32 = (Uint32 *) src;
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));
len /= 4;
while (len--) {
src1 = (Sint64) ((Sint32) SDL_SwapLE32(*src32));
src32++;
ADJUST_VOLUME(src1, volume);
src2 = (Sint64) ((Sint32) SDL_SwapLE32(*dst32));
dst_sample = src1 + src2;
if (dst_sample > max_audioval) {
dst_sample = max_audioval;
} else if (dst_sample < min_audioval) {
dst_sample = min_audioval;
}
*(dst32++) = SDL_SwapLE32((Uint32) ((Sint32) dst_sample));
}
}
break;
case AUDIO_S32MSB:
{
const Uint32 *src32 = (Uint32 *) src;
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));
len /= 4;
while (len--) {
src1 = (Sint64) ((Sint32) SDL_SwapBE32(*src32));
src32++;
ADJUST_VOLUME(src1, volume);
src2 = (Sint64) ((Sint32) SDL_SwapBE32(*dst32));
dst_sample = src1 + src2;
if (dst_sample > max_audioval) {
dst_sample = max_audioval;
} else if (dst_sample < min_audioval) {
dst_sample = min_audioval;
}
*(dst32++) = SDL_SwapBE32((Uint32) ((Sint32) dst_sample));
}
}
break;
case AUDIO_F32LSB:
{
const float fmaxvolume = 1.0f / ((float) SDL_MIX_MAXVOLUME);
const float fvolume = (float) volume;
const float *src32 = (float *) src;
float *dst32 = (float *) dst;
float src1, src2;
double dst_sample;
/* !!! FIXME: are these right? */
const double max_audioval = 3.402823466e+38F;
const double min_audioval = -3.402823466e+38F;
len /= 4;
while (len--) {
src1 = ((SDL_SwapFloatLE(*src32) * fvolume) * fmaxvolume);
src2 = SDL_SwapFloatLE(*dst32);
src32++;
dst_sample = ((double) src1) + ((double) src2);
if (dst_sample > max_audioval) {
dst_sample = max_audioval;
} else if (dst_sample < min_audioval) {
dst_sample = min_audioval;
}
*(dst32++) = SDL_SwapFloatLE((float) dst_sample);
}
}
break;
case AUDIO_F32MSB:
{
const float fmaxvolume = 1.0f / ((float) SDL_MIX_MAXVOLUME);
const float fvolume = (float) volume;
const float *src32 = (float *) src;
float *dst32 = (float *) dst;
float src1, src2;
double dst_sample;
/* !!! FIXME: are these right? */
const double max_audioval = 3.402823466e+38F;
const double min_audioval = -3.402823466e+38F;
len /= 4;
while (len--) {
src1 = ((SDL_SwapFloatBE(*src32) * fvolume) * fmaxvolume);
src2 = SDL_SwapFloatBE(*dst32);
src32++;
dst_sample = ((double) src1) + ((double) src2);
if (dst_sample > max_audioval) {
dst_sample = max_audioval;
} else if (dst_sample < min_audioval) {
dst_sample = min_audioval;
}
*(dst32++) = SDL_SwapFloatBE((float) dst_sample);
}
}
break;
default: /* If this happens... FIXME! */
SDL_SetError("SDL_MixAudio(): unknown audio format");
return;
}
}
/* vi: set ts=4 sw=4 expandtab: */

199
src/audio/SDL_sysaudio.h Normal file
View File

@@ -0,0 +1,199 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_sysaudio_h
#define _SDL_sysaudio_h
#include "SDL_mutex.h"
#include "SDL_thread.h"
/* The SDL audio driver */
typedef struct SDL_AudioDevice SDL_AudioDevice;
#define _THIS SDL_AudioDevice *_this
/* 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);
/* 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);
/* 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,
etc. If the device is totally gone, please also call SDL_RemoveAudioDevice()
as appropriate so SDL's list of devices is accurate. */
extern void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device);
/* This is the size of a packet when using SDL_QueueAudio(). We allocate
these as necessary and pool them, under the assumption that we'll
eventually end up with a handful that keep recycling, meeting whatever
the app needs. We keep packing data tightly as more arrives to avoid
wasting space, and if we get a giant block of data, we'll split them
into multiple packets behind the scenes. My expectation is that most
apps will have 2-3 of these in the pool. 8k should cover most needs, but
if this is crippling for some embedded system, we can #ifdef this.
The system preallocates enough packets for 2 callbacks' worth of data. */
#define SDL_AUDIOBUFFERQUEUE_PACKETLEN (8 * 1024)
/* Used by apps that queue audio instead of using the callback. */
typedef struct SDL_AudioBufferQueue
{
Uint8 data[SDL_AUDIOBUFFERQUEUE_PACKETLEN]; /* packet data. */
Uint32 datalen; /* bytes currently in use in this packet. */
Uint32 startpos; /* bytes currently consumed in this packet. */
struct SDL_AudioBufferQueue *next; /* next item in linked list. */
} SDL_AudioBufferQueue;
typedef struct SDL_AudioDriverImpl
{
void (*DetectDevices) (void);
int (*OpenDevice) (_THIS, void *handle, const char *devname, int iscapture);
void (*ThreadInit) (_THIS); /* Called by audio thread at start */
void (*WaitDevice) (_THIS);
void (*PlayDevice) (_THIS);
int (*GetPendingBytes) (_THIS);
Uint8 *(*GetDeviceBuf) (_THIS);
void (*WaitDone) (_THIS);
void (*CloseDevice) (_THIS);
void (*LockDevice) (_THIS);
void (*UnlockDevice) (_THIS);
void (*FreeDeviceHandle) (void *handle); /**< SDL is done with handle from SDL_AddAudioDevice() */
void (*Deinitialize) (void);
/* !!! 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; /* !!! FIXME: do we need this anymore? */
int HasCaptureSupport;
int OnlyHasDefaultOutputDevice;
int OnlyHasDefaultInputDevice;
int AllowsArbitraryDeviceNames;
} SDL_AudioDriverImpl;
typedef struct SDL_AudioDeviceItem
{
void *handle;
struct SDL_AudioDeviceItem *next;
#if (defined(__GNUC__) && (__GNUC__ <= 2))
char name[1]; /* actually variable length. */
#else
char name[];
#endif
} SDL_AudioDeviceItem;
typedef struct SDL_AudioDriver
{
/* * * */
/* The name of this audio driver */
const char *name;
/* * * */
/* The description of this audio driver */
const char *desc;
SDL_AudioDriverImpl impl;
/* A mutex for device detection */
SDL_mutex *detectionLock;
SDL_bool captureDevicesRemoved;
SDL_bool outputDevicesRemoved;
int outputDeviceCount;
int inputDeviceCount;
SDL_AudioDeviceItem *outputDevices;
SDL_AudioDeviceItem *inputDevices;
} SDL_AudioDriver;
/* Streamer */
typedef struct
{
Uint8 *buffer;
int max_len; /* the maximum length in bytes */
int read_pos, write_pos; /* the position of the write and read heads in bytes */
} SDL_AudioStreamer;
/* Define the SDL audio driver structure */
struct SDL_AudioDevice
{
/* * * */
/* Data common to all devices */
SDL_AudioDeviceID id;
/* The current audio specification (shared with audio thread) */
SDL_AudioSpec spec;
/* An audio conversion block for audio format emulation */
SDL_AudioCVT convert;
/* The streamer, if sample rate conversion necessitates it */
int use_streamer;
SDL_AudioStreamer streamer;
/* Current state flags */
/* !!! FIXME: should be SDL_bool */
int iscapture;
int enabled; /* true if device is functioning and connected. */
int shutdown; /* true if we are signaling the play thread to end. */
int paused;
int opened;
/* Fake audio buffer for when the audio hardware is busy */
Uint8 *fake_stream;
/* A mutex for locking the mixing buffers */
SDL_mutex *mixer_lock;
/* A thread to feed the audio device */
SDL_Thread *thread;
SDL_threadID threadid;
/* Queued buffers (if app not using callback). */
SDL_AudioBufferQueue *buffer_queue_head; /* device fed from here. */
SDL_AudioBufferQueue *buffer_queue_tail; /* queue fills to here. */
SDL_AudioBufferQueue *buffer_queue_pool; /* these are unused packets. */
Uint32 queued_bytes; /* number of bytes of audio data in the queue. */
/* * * */
/* Data private to this driver */
struct SDL_PrivateAudioData *hidden;
};
#undef _THIS
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. */
} AudioBootStrap;
#endif /* _SDL_sysaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

624
src/audio/SDL_wave.c Normal file
View File

@@ -0,0 +1,624 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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"
/* Microsoft WAVE file loading routines */
#include "SDL_audio.h"
#include "SDL_wave.h"
static int ReadChunk(SDL_RWops * src, Chunk * chunk);
struct MS_ADPCM_decodestate
{
Uint8 hPredictor;
Uint16 iDelta;
Sint16 iSamp1;
Sint16 iSamp2;
};
static struct MS_ADPCM_decoder
{
WaveFMT wavefmt;
Uint16 wSamplesPerBlock;
Uint16 wNumCoef;
Sint16 aCoeff[7][2];
/* * * */
struct MS_ADPCM_decodestate state[2];
} MS_ADPCM_state;
static int
InitMS_ADPCM(WaveFMT * format)
{
Uint8 *rogue_feel;
int i;
/* Set the rogue pointer to the MS_ADPCM specific data */
MS_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding);
MS_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels);
MS_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency);
MS_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate);
MS_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign);
MS_ADPCM_state.wavefmt.bitspersample =
SDL_SwapLE16(format->bitspersample);
rogue_feel = (Uint8 *) format + sizeof(*format);
if (sizeof(*format) == 16) {
/* const Uint16 extra_info = ((rogue_feel[1] << 8) | rogue_feel[0]); */
rogue_feel += sizeof(Uint16);
}
MS_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1] << 8) | rogue_feel[0]);
rogue_feel += sizeof(Uint16);
MS_ADPCM_state.wNumCoef = ((rogue_feel[1] << 8) | rogue_feel[0]);
rogue_feel += sizeof(Uint16);
if (MS_ADPCM_state.wNumCoef != 7) {
SDL_SetError("Unknown set of MS_ADPCM coefficients");
return (-1);
}
for (i = 0; i < MS_ADPCM_state.wNumCoef; ++i) {
MS_ADPCM_state.aCoeff[i][0] = ((rogue_feel[1] << 8) | rogue_feel[0]);
rogue_feel += sizeof(Uint16);
MS_ADPCM_state.aCoeff[i][1] = ((rogue_feel[1] << 8) | rogue_feel[0]);
rogue_feel += sizeof(Uint16);
}
return (0);
}
static Sint32
MS_ADPCM_nibble(struct MS_ADPCM_decodestate *state,
Uint8 nybble, Sint16 * coeff)
{
const Sint32 max_audioval = ((1 << (16 - 1)) - 1);
const Sint32 min_audioval = -(1 << (16 - 1));
const Sint32 adaptive[] = {
230, 230, 230, 230, 307, 409, 512, 614,
768, 614, 512, 409, 307, 230, 230, 230
};
Sint32 new_sample, delta;
new_sample = ((state->iSamp1 * coeff[0]) +
(state->iSamp2 * coeff[1])) / 256;
if (nybble & 0x08) {
new_sample += state->iDelta * (nybble - 0x10);
} else {
new_sample += state->iDelta * nybble;
}
if (new_sample < min_audioval) {
new_sample = min_audioval;
} else if (new_sample > max_audioval) {
new_sample = max_audioval;
}
delta = ((Sint32) state->iDelta * adaptive[nybble]) / 256;
if (delta < 16) {
delta = 16;
}
state->iDelta = (Uint16) delta;
state->iSamp2 = state->iSamp1;
state->iSamp1 = (Sint16) new_sample;
return (new_sample);
}
static int
MS_ADPCM_decode(Uint8 ** audio_buf, Uint32 * audio_len)
{
struct MS_ADPCM_decodestate *state[2];
Uint8 *freeable, *encoded, *decoded;
Sint32 encoded_len, samplesleft;
Sint8 nybble;
Uint8 stereo;
Sint16 *coeff[2];
Sint32 new_sample;
/* Allocate the proper sized output buffer */
encoded_len = *audio_len;
encoded = *audio_buf;
freeable = *audio_buf;
*audio_len = (encoded_len / MS_ADPCM_state.wavefmt.blockalign) *
MS_ADPCM_state.wSamplesPerBlock *
MS_ADPCM_state.wavefmt.channels * sizeof(Sint16);
*audio_buf = (Uint8 *) SDL_malloc(*audio_len);
if (*audio_buf == NULL) {
return SDL_OutOfMemory();
}
decoded = *audio_buf;
/* Get ready... Go! */
stereo = (MS_ADPCM_state.wavefmt.channels == 2);
state[0] = &MS_ADPCM_state.state[0];
state[1] = &MS_ADPCM_state.state[stereo];
while (encoded_len >= MS_ADPCM_state.wavefmt.blockalign) {
/* Grab the initial information for this block */
state[0]->hPredictor = *encoded++;
if (stereo) {
state[1]->hPredictor = *encoded++;
}
state[0]->iDelta = ((encoded[1] << 8) | encoded[0]);
encoded += sizeof(Sint16);
if (stereo) {
state[1]->iDelta = ((encoded[1] << 8) | encoded[0]);
encoded += sizeof(Sint16);
}
state[0]->iSamp1 = ((encoded[1] << 8) | encoded[0]);
encoded += sizeof(Sint16);
if (stereo) {
state[1]->iSamp1 = ((encoded[1] << 8) | encoded[0]);
encoded += sizeof(Sint16);
}
state[0]->iSamp2 = ((encoded[1] << 8) | encoded[0]);
encoded += sizeof(Sint16);
if (stereo) {
state[1]->iSamp2 = ((encoded[1] << 8) | encoded[0]);
encoded += sizeof(Sint16);
}
coeff[0] = MS_ADPCM_state.aCoeff[state[0]->hPredictor];
coeff[1] = MS_ADPCM_state.aCoeff[state[1]->hPredictor];
/* Store the two initial samples we start with */
decoded[0] = state[0]->iSamp2 & 0xFF;
decoded[1] = state[0]->iSamp2 >> 8;
decoded += 2;
if (stereo) {
decoded[0] = state[1]->iSamp2 & 0xFF;
decoded[1] = state[1]->iSamp2 >> 8;
decoded += 2;
}
decoded[0] = state[0]->iSamp1 & 0xFF;
decoded[1] = state[0]->iSamp1 >> 8;
decoded += 2;
if (stereo) {
decoded[0] = state[1]->iSamp1 & 0xFF;
decoded[1] = state[1]->iSamp1 >> 8;
decoded += 2;
}
/* Decode and store the other samples in this block */
samplesleft = (MS_ADPCM_state.wSamplesPerBlock - 2) *
MS_ADPCM_state.wavefmt.channels;
while (samplesleft > 0) {
nybble = (*encoded) >> 4;
new_sample = MS_ADPCM_nibble(state[0], nybble, coeff[0]);
decoded[0] = new_sample & 0xFF;
new_sample >>= 8;
decoded[1] = new_sample & 0xFF;
decoded += 2;
nybble = (*encoded) & 0x0F;
new_sample = MS_ADPCM_nibble(state[1], nybble, coeff[1]);
decoded[0] = new_sample & 0xFF;
new_sample >>= 8;
decoded[1] = new_sample & 0xFF;
decoded += 2;
++encoded;
samplesleft -= 2;
}
encoded_len -= MS_ADPCM_state.wavefmt.blockalign;
}
SDL_free(freeable);
return (0);
}
struct IMA_ADPCM_decodestate
{
Sint32 sample;
Sint8 index;
};
static struct IMA_ADPCM_decoder
{
WaveFMT wavefmt;
Uint16 wSamplesPerBlock;
/* * * */
struct IMA_ADPCM_decodestate state[2];
} IMA_ADPCM_state;
static int
InitIMA_ADPCM(WaveFMT * format)
{
Uint8 *rogue_feel;
/* Set the rogue pointer to the IMA_ADPCM specific data */
IMA_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding);
IMA_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels);
IMA_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency);
IMA_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate);
IMA_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign);
IMA_ADPCM_state.wavefmt.bitspersample =
SDL_SwapLE16(format->bitspersample);
rogue_feel = (Uint8 *) format + sizeof(*format);
if (sizeof(*format) == 16) {
/* const Uint16 extra_info = ((rogue_feel[1] << 8) | rogue_feel[0]); */
rogue_feel += sizeof(Uint16);
}
IMA_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1] << 8) | rogue_feel[0]);
return (0);
}
static Sint32
IMA_ADPCM_nibble(struct IMA_ADPCM_decodestate *state, Uint8 nybble)
{
const Sint32 max_audioval = ((1 << (16 - 1)) - 1);
const Sint32 min_audioval = -(1 << (16 - 1));
const int index_table[16] = {
-1, -1, -1, -1,
2, 4, 6, 8,
-1, -1, -1, -1,
2, 4, 6, 8
};
const Sint32 step_table[89] = {
7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31,
34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130,
143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408,
449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282,
1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327,
3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630,
9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350,
22385, 24623, 27086, 29794, 32767
};
Sint32 delta, step;
/* Compute difference and new sample value */
if (state->index > 88) {
state->index = 88;
} else if (state->index < 0) {
state->index = 0;
}
/* explicit cast to avoid gcc warning about using 'char' as array index */
step = step_table[(int)state->index];
delta = step >> 3;
if (nybble & 0x04)
delta += step;
if (nybble & 0x02)
delta += (step >> 1);
if (nybble & 0x01)
delta += (step >> 2);
if (nybble & 0x08)
delta = -delta;
state->sample += delta;
/* Update index value */
state->index += index_table[nybble];
/* Clamp output sample */
if (state->sample > max_audioval) {
state->sample = max_audioval;
} else if (state->sample < min_audioval) {
state->sample = min_audioval;
}
return (state->sample);
}
/* Fill the decode buffer with a channel block of data (8 samples) */
static void
Fill_IMA_ADPCM_block(Uint8 * decoded, Uint8 * encoded,
int channel, int numchannels,
struct IMA_ADPCM_decodestate *state)
{
int i;
Sint8 nybble;
Sint32 new_sample;
decoded += (channel * 2);
for (i = 0; i < 4; ++i) {
nybble = (*encoded) & 0x0F;
new_sample = IMA_ADPCM_nibble(state, nybble);
decoded[0] = new_sample & 0xFF;
new_sample >>= 8;
decoded[1] = new_sample & 0xFF;
decoded += 2 * numchannels;
nybble = (*encoded) >> 4;
new_sample = IMA_ADPCM_nibble(state, nybble);
decoded[0] = new_sample & 0xFF;
new_sample >>= 8;
decoded[1] = new_sample & 0xFF;
decoded += 2 * numchannels;
++encoded;
}
}
static int
IMA_ADPCM_decode(Uint8 ** audio_buf, Uint32 * audio_len)
{
struct IMA_ADPCM_decodestate *state;
Uint8 *freeable, *encoded, *decoded;
Sint32 encoded_len, samplesleft;
unsigned int c, channels;
/* Check to make sure we have enough variables in the state array */
channels = IMA_ADPCM_state.wavefmt.channels;
if (channels > SDL_arraysize(IMA_ADPCM_state.state)) {
SDL_SetError("IMA ADPCM decoder can only handle %u channels",
(unsigned int)SDL_arraysize(IMA_ADPCM_state.state));
return (-1);
}
state = IMA_ADPCM_state.state;
/* Allocate the proper sized output buffer */
encoded_len = *audio_len;
encoded = *audio_buf;
freeable = *audio_buf;
*audio_len = (encoded_len / IMA_ADPCM_state.wavefmt.blockalign) *
IMA_ADPCM_state.wSamplesPerBlock *
IMA_ADPCM_state.wavefmt.channels * sizeof(Sint16);
*audio_buf = (Uint8 *) SDL_malloc(*audio_len);
if (*audio_buf == NULL) {
return SDL_OutOfMemory();
}
decoded = *audio_buf;
/* Get ready... Go! */
while (encoded_len >= IMA_ADPCM_state.wavefmt.blockalign) {
/* Grab the initial information for this block */
for (c = 0; c < channels; ++c) {
/* Fill the state information for this block */
state[c].sample = ((encoded[1] << 8) | encoded[0]);
encoded += 2;
if (state[c].sample & 0x8000) {
state[c].sample -= 0x10000;
}
state[c].index = *encoded++;
/* Reserved byte in buffer header, should be 0 */
if (*encoded++ != 0) {
/* Uh oh, corrupt data? Buggy code? */ ;
}
/* Store the initial sample we start with */
decoded[0] = (Uint8) (state[c].sample & 0xFF);
decoded[1] = (Uint8) (state[c].sample >> 8);
decoded += 2;
}
/* Decode and store the other samples in this block */
samplesleft = (IMA_ADPCM_state.wSamplesPerBlock - 1) * channels;
while (samplesleft > 0) {
for (c = 0; c < channels; ++c) {
Fill_IMA_ADPCM_block(decoded, encoded,
c, channels, &state[c]);
encoded += 4;
samplesleft -= 8;
}
decoded += (channels * 8 * 2);
}
encoded_len -= IMA_ADPCM_state.wavefmt.blockalign;
}
SDL_free(freeable);
return (0);
}
SDL_AudioSpec *
SDL_LoadWAV_RW(SDL_RWops * src, int freesrc,
SDL_AudioSpec * spec, Uint8 ** audio_buf, Uint32 * audio_len)
{
int was_error;
Chunk chunk;
int lenread;
int IEEE_float_encoded, MS_ADPCM_encoded, IMA_ADPCM_encoded;
int samplesize;
/* WAV magic header */
Uint32 RIFFchunk;
Uint32 wavelen = 0;
Uint32 WAVEmagic;
Uint32 headerDiff = 0;
/* FMT chunk */
WaveFMT *format = NULL;
SDL_zero(chunk);
/* Make sure we are passed a valid data source */
was_error = 0;
if (src == NULL) {
was_error = 1;
goto done;
}
/* Check the magic header */
RIFFchunk = SDL_ReadLE32(src);
wavelen = SDL_ReadLE32(src);
if (wavelen == WAVE) { /* The RIFFchunk has already been read */
WAVEmagic = wavelen;
wavelen = RIFFchunk;
RIFFchunk = RIFF;
} else {
WAVEmagic = SDL_ReadLE32(src);
}
if ((RIFFchunk != RIFF) || (WAVEmagic != WAVE)) {
SDL_SetError("Unrecognized file type (not WAVE)");
was_error = 1;
goto done;
}
headerDiff += sizeof(Uint32); /* for WAVE */
/* Read the audio data format chunk */
chunk.data = NULL;
do {
SDL_free(chunk.data);
chunk.data = NULL;
lenread = ReadChunk(src, &chunk);
if (lenread < 0) {
was_error = 1;
goto done;
}
/* 2 Uint32's for chunk header+len, plus the lenread */
headerDiff += lenread + 2 * sizeof(Uint32);
} while ((chunk.magic == FACT) || (chunk.magic == LIST) || (chunk.magic == BEXT) || (chunk.magic == JUNK));
/* Decode the audio data format */
format = (WaveFMT *) chunk.data;
if (chunk.magic != FMT) {
SDL_SetError("Complex WAVE files not supported");
was_error = 1;
goto done;
}
IEEE_float_encoded = MS_ADPCM_encoded = IMA_ADPCM_encoded = 0;
switch (SDL_SwapLE16(format->encoding)) {
case PCM_CODE:
/* We can understand this */
break;
case IEEE_FLOAT_CODE:
IEEE_float_encoded = 1;
/* We can understand this */
break;
case MS_ADPCM_CODE:
/* Try to understand this */
if (InitMS_ADPCM(format) < 0) {
was_error = 1;
goto done;
}
MS_ADPCM_encoded = 1;
break;
case IMA_ADPCM_CODE:
/* Try to understand this */
if (InitIMA_ADPCM(format) < 0) {
was_error = 1;
goto done;
}
IMA_ADPCM_encoded = 1;
break;
case MP3_CODE:
SDL_SetError("MPEG Layer 3 data not supported");
was_error = 1;
goto done;
default:
SDL_SetError("Unknown WAVE data format: 0x%.4x",
SDL_SwapLE16(format->encoding));
was_error = 1;
goto done;
}
SDL_memset(spec, 0, (sizeof *spec));
spec->freq = SDL_SwapLE32(format->frequency);
if (IEEE_float_encoded) {
if ((SDL_SwapLE16(format->bitspersample)) != 32) {
was_error = 1;
} else {
spec->format = AUDIO_F32;
}
} else {
switch (SDL_SwapLE16(format->bitspersample)) {
case 4:
if (MS_ADPCM_encoded || IMA_ADPCM_encoded) {
spec->format = AUDIO_S16;
} else {
was_error = 1;
}
break;
case 8:
spec->format = AUDIO_U8;
break;
case 16:
spec->format = AUDIO_S16;
break;
case 32:
spec->format = AUDIO_S32;
break;
default:
was_error = 1;
break;
}
}
if (was_error) {
SDL_SetError("Unknown %d-bit PCM data format",
SDL_SwapLE16(format->bitspersample));
goto done;
}
spec->channels = (Uint8) SDL_SwapLE16(format->channels);
spec->samples = 4096; /* Good default buffer size */
/* Read the audio data chunk */
*audio_buf = NULL;
do {
SDL_free(*audio_buf);
*audio_buf = NULL;
lenread = ReadChunk(src, &chunk);
if (lenread < 0) {
was_error = 1;
goto done;
}
*audio_len = lenread;
*audio_buf = chunk.data;
if (chunk.magic != DATA)
headerDiff += lenread + 2 * sizeof(Uint32);
} while (chunk.magic != DATA);
headerDiff += 2 * sizeof(Uint32); /* for the data chunk and len */
if (MS_ADPCM_encoded) {
if (MS_ADPCM_decode(audio_buf, audio_len) < 0) {
was_error = 1;
goto done;
}
}
if (IMA_ADPCM_encoded) {
if (IMA_ADPCM_decode(audio_buf, audio_len) < 0) {
was_error = 1;
goto done;
}
}
/* Don't return a buffer that isn't a multiple of samplesize */
samplesize = ((SDL_AUDIO_BITSIZE(spec->format)) / 8) * spec->channels;
*audio_len &= ~(samplesize - 1);
done:
SDL_free(format);
if (src) {
if (freesrc) {
SDL_RWclose(src);
} else {
/* seek to the end of the file (given by the RIFF chunk) */
SDL_RWseek(src, wavelen - chunk.length - headerDiff, RW_SEEK_CUR);
}
}
if (was_error) {
spec = NULL;
}
return (spec);
}
/* Since the WAV memory is allocated in the shared library, it must also
be freed here. (Necessary under Win32, VC++)
*/
void
SDL_FreeWAV(Uint8 * audio_buf)
{
SDL_free(audio_buf);
}
static int
ReadChunk(SDL_RWops * src, Chunk * chunk)
{
chunk->magic = SDL_ReadLE32(src);
chunk->length = SDL_ReadLE32(src);
chunk->data = (Uint8 *) SDL_malloc(chunk->length);
if (chunk->data == NULL) {
return SDL_OutOfMemory();
}
if (SDL_RWread(src, chunk->data, chunk->length, 1) != 1) {
SDL_free(chunk->data);
chunk->data = NULL;
return SDL_Error(SDL_EFREAD);
}
return (chunk->length);
}
/* vi: set ts=4 sw=4 expandtab: */

67
src/audio/SDL_wave.h Normal file
View File

@@ -0,0 +1,67 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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"
/* WAVE files are little-endian */
/*******************************************/
/* Define values for Microsoft WAVE format */
/*******************************************/
#define RIFF 0x46464952 /* "RIFF" */
#define WAVE 0x45564157 /* "WAVE" */
#define FACT 0x74636166 /* "fact" */
#define LIST 0x5453494c /* "LIST" */
#define BEXT 0x74786562 /* "bext" */
#define JUNK 0x4B4E554A /* "JUNK" */
#define FMT 0x20746D66 /* "fmt " */
#define DATA 0x61746164 /* "data" */
#define PCM_CODE 0x0001
#define MS_ADPCM_CODE 0x0002
#define IEEE_FLOAT_CODE 0x0003
#define IMA_ADPCM_CODE 0x0011
#define MP3_CODE 0x0055
#define WAVE_MONO 1
#define WAVE_STEREO 2
/* Normally, these three chunks come consecutively in a WAVE file */
typedef struct WaveFMT
{
/* 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;
/* The general chunk found in the WAVE file */
typedef struct Chunk
{
Uint32 magic;
Uint32 length;
Uint8 *data;
} Chunk;
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,685 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_ALSA
/* Allow access to a raw mixing buffer */
#include <sys/types.h>
#include <signal.h> /* For kill() */
#include <errno.h>
#include <string.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_alsa_audio.h"
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
#include "SDL_loadso.h"
#endif
static int (*ALSA_snd_pcm_open)
(snd_pcm_t **, const char *, snd_pcm_stream_t, int);
static int (*ALSA_snd_pcm_close) (snd_pcm_t * pcm);
static snd_pcm_sframes_t(*ALSA_snd_pcm_writei)
(snd_pcm_t *, const void *, snd_pcm_uframes_t);
static int (*ALSA_snd_pcm_recover) (snd_pcm_t *, int, int);
static int (*ALSA_snd_pcm_prepare) (snd_pcm_t *);
static int (*ALSA_snd_pcm_drain) (snd_pcm_t *);
static const char *(*ALSA_snd_strerror) (int);
static size_t(*ALSA_snd_pcm_hw_params_sizeof) (void);
static size_t(*ALSA_snd_pcm_sw_params_sizeof) (void);
static void (*ALSA_snd_pcm_hw_params_copy)
(snd_pcm_hw_params_t *, const snd_pcm_hw_params_t *);
static int (*ALSA_snd_pcm_hw_params_any) (snd_pcm_t *, snd_pcm_hw_params_t *);
static int (*ALSA_snd_pcm_hw_params_set_access)
(snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_access_t);
static int (*ALSA_snd_pcm_hw_params_set_format)
(snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_format_t);
static int (*ALSA_snd_pcm_hw_params_set_channels)
(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int);
static int (*ALSA_snd_pcm_hw_params_get_channels)
(const snd_pcm_hw_params_t *, unsigned int *);
static int (*ALSA_snd_pcm_hw_params_set_rate_near)
(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *);
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)
(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 *);
static int (*ALSA_snd_pcm_hw_params_set_buffer_size_near)
(snd_pcm_t *pcm, snd_pcm_hw_params_t *, snd_pcm_uframes_t *);
static int (*ALSA_snd_pcm_hw_params_get_buffer_size)
(const snd_pcm_hw_params_t *, snd_pcm_uframes_t *);
static int (*ALSA_snd_pcm_hw_params) (snd_pcm_t *, snd_pcm_hw_params_t *);
static int (*ALSA_snd_pcm_sw_params_current) (snd_pcm_t *,
snd_pcm_sw_params_t *);
static int (*ALSA_snd_pcm_sw_params_set_start_threshold)
(snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
static int (*ALSA_snd_pcm_sw_params) (snd_pcm_t *, snd_pcm_sw_params_t *);
static int (*ALSA_snd_pcm_nonblock) (snd_pcm_t *, int);
static int (*ALSA_snd_pcm_wait)(snd_pcm_t *, int);
static int (*ALSA_snd_pcm_sw_params_set_avail_min)
(snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
#define snd_pcm_hw_params_sizeof ALSA_snd_pcm_hw_params_sizeof
#define snd_pcm_sw_params_sizeof ALSA_snd_pcm_sw_params_sizeof
static const char *alsa_library = SDL_AUDIO_DRIVER_ALSA_DYNAMIC;
static void *alsa_handle = NULL;
static int
load_alsa_sym(const char *fn, void **addr)
{
*addr = SDL_LoadFunction(alsa_handle, fn);
if (*addr == NULL) {
/* Don't call SDL_SetError(): SDL_LoadFunction already did. */
return 0;
}
return 1;
}
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
#define SDL_ALSA_SYM(x) \
if (!load_alsa_sym(#x, (void **) (char *) &ALSA_##x)) return -1
#else
#define SDL_ALSA_SYM(x) ALSA_##x = x
#endif
static int
load_alsa_syms(void)
{
SDL_ALSA_SYM(snd_pcm_open);
SDL_ALSA_SYM(snd_pcm_close);
SDL_ALSA_SYM(snd_pcm_writei);
SDL_ALSA_SYM(snd_pcm_recover);
SDL_ALSA_SYM(snd_pcm_prepare);
SDL_ALSA_SYM(snd_pcm_drain);
SDL_ALSA_SYM(snd_strerror);
SDL_ALSA_SYM(snd_pcm_hw_params_sizeof);
SDL_ALSA_SYM(snd_pcm_sw_params_sizeof);
SDL_ALSA_SYM(snd_pcm_hw_params_copy);
SDL_ALSA_SYM(snd_pcm_hw_params_any);
SDL_ALSA_SYM(snd_pcm_hw_params_set_access);
SDL_ALSA_SYM(snd_pcm_hw_params_set_format);
SDL_ALSA_SYM(snd_pcm_hw_params_set_channels);
SDL_ALSA_SYM(snd_pcm_hw_params_get_channels);
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_get_periods);
SDL_ALSA_SYM(snd_pcm_hw_params_set_buffer_size_near);
SDL_ALSA_SYM(snd_pcm_hw_params_get_buffer_size);
SDL_ALSA_SYM(snd_pcm_hw_params);
SDL_ALSA_SYM(snd_pcm_sw_params_current);
SDL_ALSA_SYM(snd_pcm_sw_params_set_start_threshold);
SDL_ALSA_SYM(snd_pcm_sw_params);
SDL_ALSA_SYM(snd_pcm_nonblock);
SDL_ALSA_SYM(snd_pcm_wait);
SDL_ALSA_SYM(snd_pcm_sw_params_set_avail_min);
return 0;
}
#undef SDL_ALSA_SYM
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
static void
UnloadALSALibrary(void)
{
if (alsa_handle != NULL) {
SDL_UnloadObject(alsa_handle);
alsa_handle = NULL;
}
}
static int
LoadALSALibrary(void)
{
int retval = 0;
if (alsa_handle == NULL) {
alsa_handle = SDL_LoadObject(alsa_library);
if (alsa_handle == NULL) {
retval = -1;
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
} else {
retval = load_alsa_syms();
if (retval < 0) {
UnloadALSALibrary();
}
}
}
return retval;
}
#else
static void
UnloadALSALibrary(void)
{
}
static int
LoadALSALibrary(void)
{
load_alsa_syms();
return 0;
}
#endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */
static const char *
get_audio_device(int channels)
{
const char *device;
device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */
if (device == NULL) {
switch (channels) {
case 6:
device = "plug:surround51";
break;
case 4:
device = "plug:surround40";
break;
default:
device = "default";
break;
}
}
return device;
}
/* This function waits until it is possible to write a full sound buffer */
static void
ALSA_WaitDevice(_THIS)
{
/* We're in blocking mode, so there's nothing to do here */
}
/* !!! FIXME: is there a channel swizzler in alsalib instead? */
/*
* http://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) \
T *ptr = (T *) this->hidden->mixbuf; \
Uint32 i; \
for (i = 0; i < this->spec.samples; 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 SDL_INLINE void
swizzle_alsa_channels_6_64bit(_THIS)
{
SWIZ6(Uint64);
}
static SDL_INLINE void
swizzle_alsa_channels_6_32bit(_THIS)
{
SWIZ6(Uint32);
}
static SDL_INLINE void
swizzle_alsa_channels_6_16bit(_THIS)
{
SWIZ6(Uint16);
}
static SDL_INLINE void
swizzle_alsa_channels_6_8bit(_THIS)
{
SWIZ6(Uint8);
}
#undef SWIZ6
/*
* Called right before feeding this->hidden->mixbuf to the hardware. Swizzle
* channels from Windows/Mac order to the format alsalib will want.
*/
static SDL_INLINE void
swizzle_alsa_channels(_THIS)
{
if (this->spec.channels == 6) {
const Uint16 fmtsize = (this->spec.format & 0xFF); /* bits/channel. */
if (fmtsize == 16)
swizzle_alsa_channels_6_16bit(this);
else if (fmtsize == 8)
swizzle_alsa_channels_6_8bit(this);
else if (fmtsize == 32)
swizzle_alsa_channels_6_32bit(this);
else if (fmtsize == 64)
swizzle_alsa_channels_6_64bit(this);
}
/* !!! FIXME: update this for 7.1 if needed, later. */
}
static void
ALSA_PlayDevice(_THIS)
{
int status;
const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf;
const int frame_size = (((int) (this->spec.format & 0xFF)) / 8) *
this->spec.channels;
snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples);
swizzle_alsa_channels(this);
while ( frames_left > 0 && this->enabled ) {
/* !!! FIXME: This works, but needs more testing before going live */
/* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */
status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
sample_buf, frames_left);
if (status < 0) {
if (status == -EAGAIN) {
/* Apparently snd_pcm_recover() doesn't handle this case -
does it assume snd_pcm_wait() above? */
SDL_Delay(1);
continue;
}
status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
if (status < 0) {
/* Hmm, not much we can do - abort */
fprintf(stderr, "ALSA write failed (unrecoverable): %s\n",
ALSA_snd_strerror(status));
SDL_OpenedAudioDeviceDisconnected(this);
return;
}
continue;
}
sample_buf += status * frame_size;
frames_left -= status;
}
}
static Uint8 *
ALSA_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static void
ALSA_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->pcm_handle) {
ALSA_snd_pcm_drain(this->hidden->pcm_handle);
ALSA_snd_pcm_close(this->hidden->pcm_handle);
this->hidden->pcm_handle = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
ALSA_finalize_hardware(_THIS, snd_pcm_hw_params_t *hwparams, int override)
{
int status;
snd_pcm_uframes_t bufsize;
/* "set" the hardware with the desired parameters */
status = ALSA_snd_pcm_hw_params(this->hidden->pcm_handle, hwparams);
if ( status < 0 ) {
return(-1);
}
/* Get samples for the actual buffer size */
status = ALSA_snd_pcm_hw_params_get_buffer_size(hwparams, &bufsize);
if ( status < 0 ) {
return(-1);
}
if ( !override && bufsize != this->spec.samples * 2 ) {
return(-1);
}
/* !!! FIXME: Is this safe to do? */
this->spec.samples = bufsize / 2;
/* This is useful for debugging */
if ( SDL_getenv("SDL_AUDIO_ALSA_DEBUG") ) {
snd_pcm_uframes_t persize = 0;
unsigned int periods = 0;
ALSA_snd_pcm_hw_params_get_period_size(hwparams, &persize, NULL);
ALSA_snd_pcm_hw_params_get_periods(hwparams, &periods, NULL);
fprintf(stderr,
"ALSA: period size = %ld, periods = %u, buffer size = %lu\n",
persize, periods, bufsize);
}
return(0);
}
static int
ALSA_set_period_size(_THIS, snd_pcm_hw_params_t *params, int override)
{
const char *env;
int status;
snd_pcm_hw_params_t *hwparams;
snd_pcm_uframes_t frames;
unsigned int periods;
/* Copy the hardware parameters for this setup */
snd_pcm_hw_params_alloca(&hwparams);
ALSA_snd_pcm_hw_params_copy(hwparams, params);
if ( !override ) {
env = SDL_getenv("SDL_AUDIO_ALSA_SET_PERIOD_SIZE");
if ( env ) {
override = SDL_atoi(env);
if ( override == 0 ) {
return(-1);
}
}
}
frames = this->spec.samples;
status = ALSA_snd_pcm_hw_params_set_period_size_near(
this->hidden->pcm_handle, hwparams, &frames, NULL);
if ( status < 0 ) {
return(-1);
}
periods = 2;
status = ALSA_snd_pcm_hw_params_set_periods_near(
this->hidden->pcm_handle, hwparams, &periods, NULL);
if ( status < 0 ) {
return(-1);
}
return ALSA_finalize_hardware(this, hwparams, override);
}
static int
ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params, int override)
{
const char *env;
int status;
snd_pcm_hw_params_t *hwparams;
snd_pcm_uframes_t frames;
/* Copy the hardware parameters for this setup */
snd_pcm_hw_params_alloca(&hwparams);
ALSA_snd_pcm_hw_params_copy(hwparams, params);
if ( !override ) {
env = SDL_getenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE");
if ( env ) {
override = SDL_atoi(env);
if ( override == 0 ) {
return(-1);
}
}
}
frames = this->spec.samples * 2;
status = ALSA_snd_pcm_hw_params_set_buffer_size_near(
this->hidden->pcm_handle, hwparams, &frames);
if ( status < 0 ) {
return(-1);
}
return ALSA_finalize_hardware(this, hwparams, override);
}
static int
ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
int status = 0;
snd_pcm_t *pcm_handle = NULL;
snd_pcm_hw_params_t *hwparams = NULL;
snd_pcm_sw_params_t *swparams = NULL;
snd_pcm_format_t format = 0;
SDL_AudioFormat test_format = 0;
unsigned int rate = 0;
unsigned int channels = 0;
/* Initialize all variables that we clean on shutdown */
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));
/* Open the audio device */
/* Name of device should depend on # channels in spec */
status = ALSA_snd_pcm_open(&pcm_handle,
get_audio_device(this->spec.channels),
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("ALSA: Couldn't open audio device: %s",
ALSA_snd_strerror(status));
}
this->hidden->pcm_handle = pcm_handle;
/* Figure out what the hardware is capable of */
snd_pcm_hw_params_alloca(&hwparams);
status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("ALSA: Couldn't get hardware config: %s",
ALSA_snd_strerror(status));
}
/* SDL only uses interleaved sample output */
status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
SND_PCM_ACCESS_RW_INTERLEAVED);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("ALSA: Couldn't set interleaved access: %s",
ALSA_snd_strerror(status));
}
/* 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. */
switch (test_format) {
case AUDIO_U8:
format = SND_PCM_FORMAT_U8;
break;
case AUDIO_S8:
format = SND_PCM_FORMAT_S8;
break;
case AUDIO_S16LSB:
format = SND_PCM_FORMAT_S16_LE;
break;
case AUDIO_S16MSB:
format = SND_PCM_FORMAT_S16_BE;
break;
case AUDIO_U16LSB:
format = SND_PCM_FORMAT_U16_LE;
break;
case AUDIO_U16MSB:
format = SND_PCM_FORMAT_U16_BE;
break;
case AUDIO_S32LSB:
format = SND_PCM_FORMAT_S32_LE;
break;
case AUDIO_S32MSB:
format = SND_PCM_FORMAT_S32_BE;
break;
case AUDIO_F32LSB:
format = SND_PCM_FORMAT_FLOAT_LE;
break;
case AUDIO_F32MSB:
format = SND_PCM_FORMAT_FLOAT_BE;
break;
default:
status = -1;
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) {
ALSA_CloseDevice(this);
return SDL_SetError("ALSA: Couldn't find any hardware audio formats");
}
this->spec.format = test_format;
/* Set the number of channels */
status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
this->spec.channels);
channels = this->spec.channels;
if (status < 0) {
status = ALSA_snd_pcm_hw_params_get_channels(hwparams, &channels);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("ALSA: Couldn't set audio channels");
}
this->spec.channels = channels;
}
/* Set the audio rate */
rate = this->spec.freq;
status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
&rate, NULL);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("ALSA: Couldn't set audio frequency: %s",
ALSA_snd_strerror(status));
}
this->spec.freq = rate;
/* Set the buffer size, in samples */
if ( ALSA_set_period_size(this, hwparams, 0) < 0 &&
ALSA_set_buffer_size(this, hwparams, 0) < 0 ) {
/* Failed to set desired buffer size, do the best you can... */
if ( ALSA_set_period_size(this, hwparams, 1) < 0 ) {
ALSA_CloseDevice(this);
return SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status));
}
}
/* Set the software parameters */
snd_pcm_sw_params_alloca(&swparams);
status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("ALSA: Couldn't get software config: %s",
ALSA_snd_strerror(status));
}
status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, this->spec.samples);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("Couldn't set minimum available samples: %s",
ALSA_snd_strerror(status));
}
status =
ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 1);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("ALSA: Couldn't set start threshold: %s",
ALSA_snd_strerror(status));
}
status = ALSA_snd_pcm_sw_params(pcm_handle, swparams);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("Couldn't set software audio parameters: %s",
ALSA_snd_strerror(status));
}
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&this->spec);
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
ALSA_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
/* Switch to blocking mode for playback */
ALSA_snd_pcm_nonblock(pcm_handle, 0);
/* We're ready to rock and roll. :-) */
return 0;
}
static void
ALSA_Deinitialize(void)
{
UnloadALSALibrary();
}
static int
ALSA_Init(SDL_AudioDriverImpl * impl)
{
if (LoadALSALibrary() < 0) {
return 0;
}
/* Set the function pointers */
impl->OpenDevice = ALSA_OpenDevice;
impl->WaitDevice = ALSA_WaitDevice;
impl->GetDeviceBuf = ALSA_GetDeviceBuf;
impl->PlayDevice = ALSA_PlayDevice;
impl->CloseDevice = ALSA_CloseDevice;
impl->Deinitialize = ALSA_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: Add device enum! */
return 1; /* this audio target is available. */
}
AudioBootStrap ALSA_bootstrap = {
"alsa", "ALSA PCM audio", ALSA_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_ALSA */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,45 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_ALSA_audio_h
#define _SDL_ALSA_audio_h
#include <alsa/asoundlib.h>
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* The audio device handle */
snd_pcm_t *pcm_handle;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
};
#endif /* _SDL_ALSA_audio_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,185 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_ANDROID
/* Output audio to Android */
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "SDL_androidaudio.h"
#include "../../core/android/SDL_android.h"
#include <android/log.h>
static SDL_AudioDevice* audioDevice = NULL;
static int
AndroidAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
SDL_AudioFormat test_format;
if (iscapture) {
/* TODO: implement capture */
return SDL_SetError("Capture not supported on Android");
}
if (audioDevice != NULL) {
return SDL_SetError("Only one audio device at a time please!");
}
audioDevice = this;
this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *this->hidden));
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
test_format = SDL_FirstAudioFormat(this->spec.format);
while (test_format != 0) { /* no "UNKNOWN" constant */
if ((test_format == AUDIO_U8) || (test_format == AUDIO_S16LSB)) {
this->spec.format = test_format;
break;
}
test_format = SDL_NextAudioFormat();
}
if (test_format == 0) {
/* Didn't find a compatible format :( */
return SDL_SetError("No compatible audio format!");
}
if (this->spec.channels > 1) {
this->spec.channels = 2;
} else {
this->spec.channels = 1;
}
if (this->spec.freq < 8000) {
this->spec.freq = 8000;
}
if (this->spec.freq > 48000) {
this->spec.freq = 48000;
}
/* TODO: pass in/return a (Java) device ID, also whether we're opening for input or output */
this->spec.samples = Android_JNI_OpenAudioDevice(this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
SDL_CalculateAudioSpec(&this->spec);
if (this->spec.samples == 0) {
/* Init failed? */
return SDL_SetError("Java-side initialization failed!");
}
return 0;
}
static void
AndroidAUD_PlayDevice(_THIS)
{
Android_JNI_WriteAudioBuffer();
}
static Uint8 *
AndroidAUD_GetDeviceBuf(_THIS)
{
return Android_JNI_GetAudioBuffer();
}
static void
AndroidAUD_CloseDevice(_THIS)
{
/* At this point SDL_CloseAudioDevice via close_audio_device took care of terminating the audio thread
so it's safe to terminate the Java side buffer and AudioTrack
*/
Android_JNI_CloseAudioDevice();
if (audioDevice == this) {
if (audioDevice->hidden != NULL) {
SDL_free(this->hidden);
this->hidden = NULL;
}
audioDevice = NULL;
}
}
static int
AndroidAUD_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->OpenDevice = AndroidAUD_OpenDevice;
impl->PlayDevice = AndroidAUD_PlayDevice;
impl->GetDeviceBuf = AndroidAUD_GetDeviceBuf;
impl->CloseDevice = AndroidAUD_CloseDevice;
/* and the capabilities */
impl->HasCaptureSupport = 0; /* TODO */
impl->OnlyHasDefaultOutputDevice = 1;
impl->OnlyHasDefaultInputDevice = 1;
return 1; /* this audio target is available. */
}
AudioBootStrap ANDROIDAUD_bootstrap = {
"android", "SDL Android audio driver", AndroidAUD_Init, 0
};
/* Pause (block) all non already paused audio devices by taking their mixer lock */
void AndroidAUD_PauseDevices(void)
{
/* TODO: Handle multiple devices? */
struct SDL_PrivateAudioData *private;
if(audioDevice != NULL && audioDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
if (audioDevice->paused) {
/* The device is already paused, leave it alone */
private->resume = SDL_FALSE;
}
else {
SDL_LockMutex(audioDevice->mixer_lock);
audioDevice->paused = SDL_TRUE;
private->resume = SDL_TRUE;
}
}
}
/* Resume (unblock) all non already paused audio devices by releasing their mixer lock */
void AndroidAUD_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) {
audioDevice->paused = SDL_FALSE;
private->resume = SDL_FALSE;
SDL_UnlockMutex(audioDevice->mixer_lock);
}
}
}
#endif /* SDL_AUDIO_DRIVER_ANDROID */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,41 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_androidaudio_h
#define _SDL_androidaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* Resume device if it was paused automatically */
int resume;
};
static void AndroidAUD_CloseDevice(_THIS);
#endif /* _SDL_androidaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,384 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_ARTS
/* Allow access to a raw mixing buffer */
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#include <unistd.h>
#include <errno.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_artsaudio.h"
#ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
#include "SDL_name.h"
#include "SDL_loadso.h"
#else
#define SDL_NAME(X) X
#endif
#ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
static const char *arts_library = SDL_AUDIO_DRIVER_ARTS_DYNAMIC;
static void *arts_handle = NULL;
/* !!! FIXME: I hate this SDL_NAME clutter...it makes everything so messy! */
static int (*SDL_NAME(arts_init)) (void);
static void (*SDL_NAME(arts_free)) (void);
static arts_stream_t(*SDL_NAME(arts_play_stream)) (int rate, int bits,
int channels,
const char *name);
static int (*SDL_NAME(arts_stream_set)) (arts_stream_t s,
arts_parameter_t param, int value);
static int (*SDL_NAME(arts_stream_get)) (arts_stream_t s,
arts_parameter_t param);
static int (*SDL_NAME(arts_write)) (arts_stream_t s, const void *buffer,
int count);
static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s);
static int (*SDL_NAME(arts_suspend))(void);
static int (*SDL_NAME(arts_suspended)) (void);
static const char *(*SDL_NAME(arts_error_text)) (int errorcode);
#define SDL_ARTS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
static struct
{
const char *name;
void **func;
} arts_functions[] = {
/* *INDENT-OFF* */
SDL_ARTS_SYM(arts_init),
SDL_ARTS_SYM(arts_free),
SDL_ARTS_SYM(arts_play_stream),
SDL_ARTS_SYM(arts_stream_set),
SDL_ARTS_SYM(arts_stream_get),
SDL_ARTS_SYM(arts_write),
SDL_ARTS_SYM(arts_close_stream),
SDL_ARTS_SYM(arts_suspend),
SDL_ARTS_SYM(arts_suspended),
SDL_ARTS_SYM(arts_error_text),
/* *INDENT-ON* */
};
#undef SDL_ARTS_SYM
static void
UnloadARTSLibrary()
{
if (arts_handle != NULL) {
SDL_UnloadObject(arts_handle);
arts_handle = NULL;
}
}
static int
LoadARTSLibrary(void)
{
int i, retval = -1;
if (arts_handle == NULL) {
arts_handle = SDL_LoadObject(arts_library);
if (arts_handle != NULL) {
retval = 0;
for (i = 0; i < SDL_arraysize(arts_functions); ++i) {
*arts_functions[i].func =
SDL_LoadFunction(arts_handle, arts_functions[i].name);
if (!*arts_functions[i].func) {
retval = -1;
UnloadARTSLibrary();
break;
}
}
}
}
return retval;
}
#else
static void
UnloadARTSLibrary()
{
return;
}
static int
LoadARTSLibrary(void)
{
return 0;
}
#endif /* SDL_AUDIO_DRIVER_ARTS_DYNAMIC */
/* This function waits until it is possible to write a full sound buffer */
static void
ARTS_WaitDevice(_THIS)
{
Sint32 ticks;
/* Check to see if the thread-parent process is still alive */
{
static int cnt = 0;
/* Note that this only works with thread implementations
that use a different process id for each thread.
*/
/* Check every 10 loops */
if (this->hidden->parent && (((++cnt) % 10) == 0)) {
if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) {
SDL_OpenedAudioDeviceDisconnected(this);
}
}
}
/* Use timer for general audio synchronization */
ticks =
((Sint32) (this->hidden->next_frame - SDL_GetTicks())) - FUDGE_TICKS;
if (ticks > 0) {
SDL_Delay(ticks);
}
}
static void
ARTS_PlayDevice(_THIS)
{
/* Write the audio data */
int written = SDL_NAME(arts_write) (this->hidden->stream,
this->hidden->mixbuf,
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);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
}
static void
ARTS_WaitDone(_THIS)
{
/* !!! FIXME: camp here until buffer drains... SDL_Delay(???); */
}
static Uint8 *
ARTS_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static void
ARTS_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->stream) {
SDL_NAME(arts_close_stream) (this->hidden->stream);
this->hidden->stream = 0;
}
SDL_NAME(arts_free) ();
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
ARTS_Suspend(void)
{
const Uint32 abortms = SDL_GetTicks() + 3000; /* give up after 3 secs */
while ( (!SDL_NAME(arts_suspended)()) && !SDL_TICKS_PASSED(SDL_GetTicks(), abortms) ) {
if ( SDL_NAME(arts_suspend)() ) {
break;
}
}
return SDL_NAME(arts_suspended)();
}
static int
ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
int rc = 0;
int bits = 0, frag_spec = 0;
SDL_AudioFormat test_format = 0, format = 0;
/* Initialize all variables that we clean on shutdown */
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));
/* Try for a closest match on audio format */
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!format && test_format;) {
#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();
}
}
if (format == 0) {
ARTS_CloseDevice(this);
return SDL_SetError("Couldn't find any hardware audio formats");
}
this->spec.format = test_format;
if ((rc = SDL_NAME(arts_init) ()) != 0) {
ARTS_CloseDevice(this);
return SDL_SetError("Unable to initialize ARTS: %s",
SDL_NAME(arts_error_text) (rc));
}
if (!ARTS_Suspend()) {
ARTS_CloseDevice(this);
return SDL_SetError("ARTS can not open audio device");
}
this->hidden->stream = SDL_NAME(arts_play_stream) (this->spec.freq,
bits,
this->spec.channels,
"SDL");
/* Play nothing so we have at least one write (server bug workaround). */
SDL_NAME(arts_write) (this->hidden->stream, "", 0);
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&this->spec);
/* Determine the power of two of the fragment size */
for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec);
if ((0x01 << frag_spec) != this->spec.size) {
ARTS_CloseDevice(this);
return SDL_SetError("Fragment size must be a power of two");
}
frag_spec |= 0x00020000; /* two fragments, for low latency */
#ifdef ARTS_P_PACKET_SETTINGS
SDL_NAME(arts_stream_set) (this->hidden->stream,
ARTS_P_PACKET_SETTINGS, frag_spec);
#else
SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_SIZE,
frag_spec & 0xffff);
SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_COUNT,
frag_spec >> 16);
#endif
this->spec.size = SDL_NAME(arts_stream_get) (this->hidden->stream,
ARTS_P_PACKET_SIZE);
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
ARTS_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/* Get the parent process id (we're the parent of the audio thread) */
this->hidden->parent = getpid();
/* We're ready to rock and roll. :-) */
return 0;
}
static void
ARTS_Deinitialize(void)
{
UnloadARTSLibrary();
}
static int
ARTS_Init(SDL_AudioDriverImpl * impl)
{
if (LoadARTSLibrary() < 0) {
return 0;
} else {
if (SDL_NAME(arts_init) () != 0) {
UnloadARTSLibrary();
SDL_SetError("ARTS: arts_init failed (no audio server?)");
return 0;
}
/* Play a stream so aRts doesn't crash */
if (ARTS_Suspend()) {
arts_stream_t stream;
stream = SDL_NAME(arts_play_stream) (44100, 16, 2, "SDL");
SDL_NAME(arts_write) (stream, "", 0);
SDL_NAME(arts_close_stream) (stream);
}
SDL_NAME(arts_free) ();
}
/* Set the function pointers */
impl->OpenDevice = ARTS_OpenDevice;
impl->PlayDevice = ARTS_PlayDevice;
impl->WaitDevice = ARTS_WaitDevice;
impl->GetDeviceBuf = ARTS_GetDeviceBuf;
impl->CloseDevice = ARTS_CloseDevice;
impl->WaitDone = ARTS_WaitDone;
impl->Deinitialize = ARTS_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1;
return 1; /* this audio target is available. */
}
AudioBootStrap ARTS_bootstrap = {
"arts", "Analog RealTime Synthesizer", ARTS_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_ARTS */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,52 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_artscaudio_h
#define _SDL_artscaudio_h
#include <artsc.h>
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* The stream descriptor for the audio device */
arts_stream_t stream;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
/* Support for audio timing using a timer, in addition to select() */
float frame_ticks;
float next_frame;
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
#endif /* _SDL_artscaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,363 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_BSD
/*
* Driver for native OpenBSD/NetBSD audio(4).
* vedge@vedge.com.ar.
*/
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/audioio.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_bsdaudio.h"
/* Use timer for synchronization */
/* #define USE_TIMER_SYNC */
/* #define DEBUG_AUDIO */
/* #define DEBUG_AUDIO_STREAM */
static void
BSDAUDIO_DetectDevices(void)
{
SDL_EnumUnixAudioDevices(0, NULL);
}
static void
BSDAUDIO_Status(_THIS)
{
#ifdef DEBUG_AUDIO
/* *INDENT-OFF* */
audio_info_t info;
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
fprintf(stderr, "AUDIO_GETINFO failed.\n");
return;
}
fprintf(stderr, "\n"
"[play/record info]\n"
"buffer size : %d bytes\n"
"sample rate : %i Hz\n"
"channels : %i\n"
"precision : %i-bit\n"
"encoding : 0x%x\n"
"seek : %i\n"
"sample count : %i\n"
"EOF count : %i\n"
"paused : %s\n"
"error occured : %s\n"
"waiting : %s\n"
"active : %s\n"
"",
info.play.buffer_size,
info.play.sample_rate,
info.play.channels,
info.play.precision,
info.play.encoding,
info.play.seek,
info.play.samples,
info.play.eof,
info.play.pause ? "yes" : "no",
info.play.error ? "yes" : "no",
info.play.waiting ? "yes" : "no",
info.play.active ? "yes" : "no");
fprintf(stderr, "\n"
"[audio info]\n"
"monitor_gain : %i\n"
"hw block size : %d bytes\n"
"hi watermark : %i\n"
"lo watermark : %i\n"
"audio mode : %s\n"
"",
info.monitor_gain,
info.blocksize,
info.hiwat, info.lowat,
(info.mode == AUMODE_PLAY) ? "PLAY"
: (info.mode = AUMODE_RECORD) ? "RECORD"
: (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL" : "?"));
/* *INDENT-ON* */
#endif /* DEBUG_AUDIO */
}
/* This function waits until it is possible to write a full sound buffer */
static void
BSDAUDIO_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 select() for audio synchronization */
fd_set fdset;
struct timeval timeout;
FD_ZERO(&fdset);
FD_SET(this->hidden->audio_fd, &fdset);
timeout.tv_sec = 10;
timeout.tv_usec = 0;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Waiting for audio to get ready\n");
#endif
if (select(this->hidden->audio_fd + 1, NULL, &fdset, NULL, &timeout)
<= 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
BSDAUDIO_PlayDevice(_THIS)
{
int written, p = 0;
/* 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;
}
if (p < written
|| ((written < 0) && ((errno == 0) || (errno == EAGAIN)))) {
SDL_Delay(1); /* Let a little CPU time go by */
}
} while (p < written);
/* 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);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
}
static Uint8 *
BSDAUDIO_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static void
BSDAUDIO_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
SDL_AudioFormat format = 0;
audio_info_t info;
/* We don't care what the devname is...we'll try to open anything. */
/* ...but default to first name in the list... */
if (devname == NULL) {
devname = SDL_GetAudioDeviceName(0, iscapture);
if (devname == NULL) {
return SDL_SetError("No such audio device");
}
}
/* Initialize all variables that we clean on shutdown */
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));
/* Open the audio device */
this->hidden->audio_fd = open(devname, flags, 0);
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 = AUMODE_PLAY;
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
BSDAUDIO_CloseDevice(this);
return SDL_SetError("Couldn't put device into play mode");
}
AUDIO_INITINFO(&info);
for (format = SDL_FirstAudioFormat(this->spec.format);
format; format = SDL_NextAudioFormat()) {
switch (format) {
case AUDIO_U8:
info.play.encoding = AUDIO_ENCODING_ULINEAR;
info.play.precision = 8;
break;
case AUDIO_S8:
info.play.encoding = AUDIO_ENCODING_SLINEAR;
info.play.precision = 8;
break;
case AUDIO_S16LSB:
info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
info.play.precision = 16;
break;
case AUDIO_S16MSB:
info.play.encoding = AUDIO_ENCODING_SLINEAR_BE;
info.play.precision = 16;
break;
case AUDIO_U16LSB:
info.play.encoding = AUDIO_ENCODING_ULINEAR_LE;
info.play.precision = 16;
break;
case AUDIO_U16MSB:
info.play.encoding = AUDIO_ENCODING_ULINEAR_BE;
info.play.precision = 16;
break;
default:
continue;
}
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == 0) {
break;
}
}
if (!format) {
BSDAUDIO_CloseDevice(this);
return SDL_SetError("No supported encoding for 0x%x", this->spec.format);
}
this->spec.format = format;
AUDIO_INITINFO(&info);
info.play.channels = this->spec.channels;
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) {
this->spec.channels = 1;
}
AUDIO_INITINFO(&info);
info.play.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);
this->spec.freq = info.play.sample_rate;
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
BSDAUDIO_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
BSDAUDIO_Status(this);
/* We're ready to rock and roll. :-) */
return 0;
}
static int
BSDAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->DetectDevices = BSDAUDIO_DetectDevices;
impl->OpenDevice = BSDAUDIO_OpenDevice;
impl->PlayDevice = BSDAUDIO_PlayDevice;
impl->WaitDevice = BSDAUDIO_WaitDevice;
impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf;
impl->CloseDevice = BSDAUDIO_CloseDevice;
impl->AllowsArbitraryDeviceNames = 1;
return 1; /* this audio target is available. */
}
AudioBootStrap BSD_AUDIO_bootstrap = {
"bsd", "BSD audio", BSDAUDIO_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_BSD */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,51 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_bsdaudio_h
#define _SDL_bsdaudio_h
#include "../SDL_sysaudio.h"
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* The file descriptor for the audio device */
int audio_fd;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
/* Support for audio timing using a timer, in addition to select() */
float frame_ticks;
float next_frame;
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
#endif /* _SDL_bsdaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,698 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_COREAUDIO
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_coreaudio.h"
#include "SDL_assert.h"
#define DEBUG_COREAUDIO 0
static void COREAUDIO_CloseDevice(_THIS);
#define CHECK_RESULT(msg) \
if (result != noErr) { \
COREAUDIO_CloseDevice(this); \
SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
return 0; \
}
#if MACOSX_COREAUDIO
static const AudioObjectPropertyAddress devlist_address = {
kAudioHardwarePropertyDevices,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
typedef void (*addDevFn)(const char *name, const int iscapture, AudioDeviceID devId, void *data);
typedef struct AudioDeviceList
{
AudioDeviceID devid;
SDL_bool alive;
struct AudioDeviceList *next;
} AudioDeviceList;
static AudioDeviceList *output_devs = NULL;
static AudioDeviceList *capture_devs = NULL;
static SDL_bool
add_to_internal_dev_list(const int iscapture, AudioDeviceID devId)
{
AudioDeviceList *item = (AudioDeviceList *) SDL_malloc(sizeof (AudioDeviceList));
if (item == NULL) {
return SDL_FALSE;
}
item->devid = devId;
item->alive = SDL_TRUE;
item->next = iscapture ? capture_devs : output_devs;
if (iscapture) {
capture_devs = item;
} else {
output_devs = item;
}
return SDL_TRUE;
}
static void
addToDevList(const char *name, const int iscapture, AudioDeviceID devId, void *data)
{
if (add_to_internal_dev_list(iscapture, devId)) {
SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
}
}
static void
build_device_list(int iscapture, addDevFn addfn, void *addfndata)
{
OSStatus result = noErr;
UInt32 size = 0;
AudioDeviceID *devs = NULL;
UInt32 i = 0;
UInt32 max = 0;
result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
&devlist_address, 0, NULL, &size);
if (result != kAudioHardwareNoError)
return;
devs = (AudioDeviceID *) alloca(size);
if (devs == NULL)
return;
result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
&devlist_address, 0, NULL, &size, devs);
if (result != kAudioHardwareNoError)
return;
max = size / sizeof (AudioDeviceID);
for (i = 0; i < max; i++) {
CFStringRef cfstr = NULL;
char *ptr = NULL;
AudioDeviceID dev = devs[i];
AudioBufferList *buflist = NULL;
int usable = 0;
CFIndex len = 0;
const AudioObjectPropertyAddress addr = {
kAudioDevicePropertyStreamConfiguration,
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster
};
const AudioObjectPropertyAddress nameaddr = {
kAudioObjectPropertyName,
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster
};
result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size);
if (result != noErr)
continue;
buflist = (AudioBufferList *) SDL_malloc(size);
if (buflist == NULL)
continue;
result = AudioObjectGetPropertyData(dev, &addr, 0, NULL,
&size, buflist);
if (result == noErr) {
UInt32 j;
for (j = 0; j < buflist->mNumberBuffers; j++) {
if (buflist->mBuffers[j].mNumberChannels > 0) {
usable = 1;
break;
}
}
}
SDL_free(buflist);
if (!usable)
continue;
size = sizeof (CFStringRef);
result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr);
if (result != kAudioHardwareNoError)
continue;
len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
kCFStringEncodingUTF8);
ptr = (char *) SDL_malloc(len + 1);
usable = ((ptr != NULL) &&
(CFStringGetCString
(cfstr, ptr, len + 1, kCFStringEncodingUTF8)));
CFRelease(cfstr);
if (usable) {
len = strlen(ptr);
/* Some devices have whitespace at the end...trim it. */
while ((len > 0) && (ptr[len - 1] == ' ')) {
len--;
}
usable = (len > 0);
}
if (usable) {
ptr[len] = '\0';
#if DEBUG_COREAUDIO
printf("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n",
((iscapture) ? "capture" : "output"),
(int) *devCount, ptr, (int) dev);
#endif
addfn(ptr, iscapture, dev, addfndata);
}
SDL_free(ptr); /* addfn() would have copied the string. */
}
}
static void
free_audio_device_list(AudioDeviceList **list)
{
AudioDeviceList *item = *list;
while (item) {
AudioDeviceList *next = item->next;
SDL_free(item);
item = next;
}
*list = NULL;
}
static void
COREAUDIO_DetectDevices(void)
{
build_device_list(SDL_TRUE, addToDevList, NULL);
build_device_list(SDL_FALSE, addToDevList, NULL);
}
static void
build_device_change_list(const char *name, const int iscapture, AudioDeviceID devId, void *data)
{
AudioDeviceList **list = (AudioDeviceList **) data;
AudioDeviceList *item;
for (item = *list; item != NULL; item = item->next) {
if (item->devid == devId) {
item->alive = SDL_TRUE;
return;
}
}
add_to_internal_dev_list(iscapture, devId); /* new device, add it. */
SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
}
static void
reprocess_device_list(const int iscapture, AudioDeviceList **list)
{
AudioDeviceList *item;
AudioDeviceList *prev = NULL;
for (item = *list; item != NULL; item = item->next) {
item->alive = SDL_FALSE;
}
build_device_list(iscapture, build_device_change_list, list);
/* free items in the list that aren't still alive. */
item = *list;
while (item != NULL) {
AudioDeviceList *next = item->next;
if (item->alive) {
prev = item;
} else {
SDL_RemoveAudioDevice(iscapture, (void *) ((size_t) item->devid));
if (prev) {
prev->next = item->next;
} else {
*list = item->next;
}
SDL_free(item);
}
item = next;
}
}
/* this is called when the system's list of available audio devices changes. */
static OSStatus
device_list_changed(AudioObjectID systemObj, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
{
reprocess_device_list(SDL_TRUE, &capture_devs);
reprocess_device_list(SDL_FALSE, &output_devs);
return 0;
}
#endif
/* The CoreAudio callback */
static OSStatus
outputCallback(void *inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber, UInt32 inNumberFrames,
AudioBufferList * ioData)
{
SDL_AudioDevice *this = (SDL_AudioDevice *) inRefCon;
AudioBuffer *abuf;
UInt32 remaining, len;
void *ptr;
UInt32 i;
/* Only do anything if audio is enabled and not paused */
if (!this->enabled || this->paused) {
for (i = 0; i < ioData->mNumberBuffers; i++) {
abuf = &ioData->mBuffers[i];
SDL_memset(abuf->mData, this->spec.silence, abuf->mDataByteSize);
}
return 0;
}
/* No SDL conversion should be needed here, ever, since we accept
any input format in OpenAudio, and leave the conversion to CoreAudio.
*/
/*
SDL_assert(!this->convert.needed);
SDL_assert(this->spec.channels == ioData->mNumberChannels);
*/
for (i = 0; i < ioData->mNumberBuffers; i++) {
abuf = &ioData->mBuffers[i];
remaining = abuf->mDataByteSize;
ptr = abuf->mData;
while (remaining > 0) {
if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
/* Generate the data */
SDL_LockMutex(this->mixer_lock);
(*this->spec.callback)(this->spec.userdata,
this->hidden->buffer, this->hidden->bufferSize);
SDL_UnlockMutex(this->mixer_lock);
this->hidden->bufferOffset = 0;
}
len = this->hidden->bufferSize - this->hidden->bufferOffset;
if (len > remaining)
len = remaining;
SDL_memcpy(ptr, (char *)this->hidden->buffer +
this->hidden->bufferOffset, len);
ptr = (char *)ptr + len;
remaining -= len;
this->hidden->bufferOffset += len;
}
}
return 0;
}
static OSStatus
inputCallback(void *inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber, UInt32 inNumberFrames,
AudioBufferList * ioData)
{
/* err = AudioUnitRender(afr->fAudioUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, afr->fAudioBuffer); */
/* !!! FIXME: write me! */
return noErr;
}
#if MACOSX_COREAUDIO
static const AudioObjectPropertyAddress alive_address =
{
kAudioDevicePropertyDeviceIsAlive,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
static OSStatus
device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
{
SDL_AudioDevice *this = (SDL_AudioDevice *) data;
SDL_bool dead = SDL_FALSE;
UInt32 isAlive = 1;
UInt32 size = sizeof (isAlive);
OSStatus error;
if (!this->enabled) {
return 0; /* already known to be dead. */
}
error = AudioObjectGetPropertyData(this->hidden->deviceID, &alive_address,
0, NULL, &size, &isAlive);
if (error == kAudioHardwareBadDeviceError) {
dead = SDL_TRUE; /* device was unplugged. */
} else if ((error == kAudioHardwareNoError) && (!isAlive)) {
dead = SDL_TRUE; /* device died in some other way. */
}
if (dead) {
SDL_OpenedAudioDeviceDisconnected(this);
}
return 0;
}
#endif
static void
COREAUDIO_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
if (this->hidden->audioUnitOpened) {
#if MACOSX_COREAUDIO
/* Unregister our disconnect callback. */
AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
#endif
AURenderCallbackStruct callback;
const AudioUnitElement output_bus = 0;
const AudioUnitElement input_bus = 1;
const int iscapture = this->iscapture;
const AudioUnitElement bus =
((iscapture) ? input_bus : output_bus);
const AudioUnitScope scope =
((iscapture) ? kAudioUnitScope_Output :
kAudioUnitScope_Input);
/* stop processing the audio unit */
AudioOutputUnitStop(this->hidden->audioUnit);
/* Remove the input callback */
SDL_memset(&callback, 0, sizeof(AURenderCallbackStruct));
AudioUnitSetProperty(this->hidden->audioUnit,
kAudioUnitProperty_SetRenderCallback,
scope, bus, &callback, sizeof(callback));
#if MACOSX_COREAUDIO
CloseComponent(this->hidden->audioUnit);
#else
AudioComponentInstanceDispose(this->hidden->audioUnit);
#endif
this->hidden->audioUnitOpened = 0;
}
SDL_free(this->hidden->buffer);
SDL_free(this->hidden);
this->hidden = NULL;
}
}
#if MACOSX_COREAUDIO
static int
prepare_device(_THIS, void *handle, int iscapture)
{
AudioDeviceID devid = (AudioDeviceID) ((size_t) handle);
OSStatus result = noErr;
UInt32 size = 0;
UInt32 alive = 0;
pid_t pid = 0;
AudioObjectPropertyAddress addr = {
0,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
if (handle == NULL) {
size = sizeof (AudioDeviceID);
addr.mSelector =
((iscapture) ? kAudioHardwarePropertyDefaultInputDevice :
kAudioHardwarePropertyDefaultOutputDevice);
result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr,
0, NULL, &size, &devid);
CHECK_RESULT("AudioHardwareGetProperty (default device)");
}
addr.mSelector = kAudioDevicePropertyDeviceIsAlive;
addr.mScope = iscapture ? kAudioDevicePropertyScopeInput :
kAudioDevicePropertyScopeOutput;
size = sizeof (alive);
result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &alive);
CHECK_RESULT
("AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)");
if (!alive) {
SDL_SetError("CoreAudio: requested device exists, but isn't alive.");
return 0;
}
addr.mSelector = kAudioDevicePropertyHogMode;
size = sizeof (pid);
result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &pid);
/* some devices don't support this property, so errors are fine here. */
if ((result == noErr) && (pid != -1)) {
SDL_SetError("CoreAudio: requested device is being hogged.");
return 0;
}
this->hidden->deviceID = devid;
return 1;
}
#endif
static int
prepare_audiounit(_THIS, void *handle, int iscapture,
const AudioStreamBasicDescription * strdesc)
{
OSStatus result = noErr;
AURenderCallbackStruct callback;
#if MACOSX_COREAUDIO
ComponentDescription desc;
Component comp = NULL;
#else
AudioComponentDescription desc;
AudioComponent comp = NULL;
#endif
const AudioUnitElement output_bus = 0;
const AudioUnitElement input_bus = 1;
const AudioUnitElement bus = ((iscapture) ? input_bus : output_bus);
const AudioUnitScope scope = ((iscapture) ? kAudioUnitScope_Output :
kAudioUnitScope_Input);
#if MACOSX_COREAUDIO
if (!prepare_device(this, handle, iscapture)) {
return 0;
}
#endif
SDL_zero(desc);
desc.componentType = kAudioUnitType_Output;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
#if MACOSX_COREAUDIO
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
comp = FindNextComponent(NULL, &desc);
#else
desc.componentSubType = kAudioUnitSubType_RemoteIO;
comp = AudioComponentFindNext(NULL, &desc);
#endif
if (comp == NULL) {
SDL_SetError("Couldn't find requested CoreAudio component");
return 0;
}
/* Open & initialize the audio unit */
#if MACOSX_COREAUDIO
result = OpenAComponent(comp, &this->hidden->audioUnit);
CHECK_RESULT("OpenAComponent");
#else
/*
AudioComponentInstanceNew only available on iPhone OS 2.0 and Mac OS X 10.6
We can't use OpenAComponent on iPhone because it is not present
*/
result = AudioComponentInstanceNew(comp, &this->hidden->audioUnit);
CHECK_RESULT("AudioComponentInstanceNew");
#endif
this->hidden->audioUnitOpened = 1;
#if MACOSX_COREAUDIO
result = AudioUnitSetProperty(this->hidden->audioUnit,
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global, 0,
&this->hidden->deviceID,
sizeof(AudioDeviceID));
CHECK_RESULT
("AudioUnitSetProperty (kAudioOutputUnitProperty_CurrentDevice)");
#endif
/* Set the data format of the audio unit. */
result = AudioUnitSetProperty(this->hidden->audioUnit,
kAudioUnitProperty_StreamFormat,
scope, bus, strdesc, sizeof(*strdesc));
CHECK_RESULT("AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)");
/* Set the audio callback */
SDL_memset(&callback, 0, sizeof(AURenderCallbackStruct));
callback.inputProc = ((iscapture) ? inputCallback : outputCallback);
callback.inputProcRefCon = this;
result = AudioUnitSetProperty(this->hidden->audioUnit,
kAudioUnitProperty_SetRenderCallback,
scope, bus, &callback, sizeof(callback));
CHECK_RESULT
("AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback)");
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&this->spec);
/* Allocate a sample buffer */
this->hidden->bufferOffset = this->hidden->bufferSize = this->spec.size;
this->hidden->buffer = SDL_malloc(this->hidden->bufferSize);
result = AudioUnitInitialize(this->hidden->audioUnit);
CHECK_RESULT("AudioUnitInitialize");
/* Finally, start processing of the audio unit */
result = AudioOutputUnitStart(this->hidden->audioUnit);
CHECK_RESULT("AudioOutputUnitStart");
#if MACOSX_COREAUDIO
/* Fire a callback if the device stops being "alive" (disconnected, etc). */
AudioObjectAddPropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
#endif
/* We're running! */
return 1;
}
static int
COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
AudioStreamBasicDescription strdesc;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
int valid_datatype = 0;
/* Initialize all variables that we clean on shutdown */
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));
/* Setup a AudioStreamBasicDescription with the requested format */
SDL_memset(&strdesc, '\0', sizeof(AudioStreamBasicDescription));
strdesc.mFormatID = kAudioFormatLinearPCM;
strdesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
strdesc.mChannelsPerFrame = this->spec.channels;
strdesc.mSampleRate = this->spec.freq;
strdesc.mFramesPerPacket = 1;
while ((!valid_datatype) && (test_format)) {
this->spec.format = test_format;
/* Just a list of valid SDL formats, so people don't pass junk here. */
switch (test_format) {
case AUDIO_U8:
case AUDIO_S8:
case AUDIO_U16LSB:
case AUDIO_S16LSB:
case AUDIO_U16MSB:
case AUDIO_S16MSB:
case AUDIO_S32LSB:
case AUDIO_S32MSB:
case AUDIO_F32LSB:
case AUDIO_F32MSB:
valid_datatype = 1;
strdesc.mBitsPerChannel = SDL_AUDIO_BITSIZE(this->spec.format);
if (SDL_AUDIO_ISBIGENDIAN(this->spec.format))
strdesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
if (SDL_AUDIO_ISFLOAT(this->spec.format))
strdesc.mFormatFlags |= kLinearPCMFormatFlagIsFloat;
else if (SDL_AUDIO_ISSIGNED(this->spec.format))
strdesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
break;
}
}
if (!valid_datatype) { /* shouldn't happen, but just in case... */
COREAUDIO_CloseDevice(this);
return SDL_SetError("Unsupported audio format");
}
strdesc.mBytesPerFrame =
strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8;
strdesc.mBytesPerPacket =
strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
if (!prepare_audiounit(this, handle, iscapture, &strdesc)) {
COREAUDIO_CloseDevice(this);
return -1; /* prepare_audiounit() will call SDL_SetError()... */
}
return 0; /* good to go. */
}
static void
COREAUDIO_Deinitialize(void)
{
#if MACOSX_COREAUDIO
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL);
free_audio_device_list(&capture_devs);
free_audio_device_list(&output_devs);
#endif
}
static int
COREAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->OpenDevice = COREAUDIO_OpenDevice;
impl->CloseDevice = COREAUDIO_CloseDevice;
impl->Deinitialize = COREAUDIO_Deinitialize;
#if MACOSX_COREAUDIO
impl->DetectDevices = COREAUDIO_DetectDevices;
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL);
#else
impl->OnlyHasDefaultOutputDevice = 1;
/* Set category to ambient sound so that other music continues playing.
You can change this at runtime in your own code if you need different
behavior. If this is common, we can add an SDL hint for this.
*/
AudioSessionInitialize(NULL, NULL, NULL, nil);
UInt32 category = kAudioSessionCategory_AmbientSound;
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(UInt32), &category);
#endif
impl->ProvidesOwnCallbackThread = 1;
return 1; /* this audio target is available. */
}
AudioBootStrap COREAUDIO_bootstrap = {
"coreaudio", "CoreAudio", COREAUDIO_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_COREAUDIO */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,57 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_coreaudio_h
#define _SDL_coreaudio_h
#include "../SDL_sysaudio.h"
#if !defined(__IPHONEOS__)
#define MACOSX_COREAUDIO 1
#endif
#if MACOSX_COREAUDIO
#include <CoreAudio/CoreAudio.h>
#include <CoreServices/CoreServices.h>
#else
#include <AudioToolbox/AudioToolbox.h>
#endif
#include <AudioUnit/AudioUnit.h>
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
AudioUnit audioUnit;
int audioUnitOpened;
void *buffer;
UInt32 bufferOffset;
UInt32 bufferSize;
#if MACOSX_COREAUDIO
AudioDeviceID deviceID;
#endif
};
#endif /* _SDL_coreaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,517 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_DSOUND
/* Allow access to a raw mixing buffer */
#include "SDL_timer.h"
#include "SDL_loadso.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "SDL_directsound.h"
#ifndef WAVE_FORMAT_IEEE_FLOAT
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
#endif
/* DirectX function pointers for audio */
static void* DSoundDLL = NULL;
typedef HRESULT(WINAPI*fnDirectSoundCreate8)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN);
typedef HRESULT(WINAPI*fnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
typedef HRESULT(WINAPI*fnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW,LPVOID);
static fnDirectSoundCreate8 pDirectSoundCreate8 = NULL;
static fnDirectSoundEnumerateW pDirectSoundEnumerateW = NULL;
static fnDirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW = NULL;
static void
DSOUND_Unload(void)
{
pDirectSoundCreate8 = NULL;
pDirectSoundEnumerateW = NULL;
pDirectSoundCaptureEnumerateW = NULL;
if (DSoundDLL != NULL) {
SDL_UnloadObject(DSoundDLL);
DSoundDLL = NULL;
}
}
static int
DSOUND_Load(void)
{
int loaded = 0;
DSOUND_Unload();
DSoundDLL = SDL_LoadObject("DSOUND.DLL");
if (DSoundDLL == NULL) {
SDL_SetError("DirectSound: failed to load DSOUND.DLL");
} else {
/* Now make sure we have DirectX 8 or better... */
#define DSOUNDLOAD(f) { \
p##f = (fn##f) SDL_LoadFunction(DSoundDLL, #f); \
if (!p##f) loaded = 0; \
}
loaded = 1; /* will reset if necessary. */
DSOUNDLOAD(DirectSoundCreate8);
DSOUNDLOAD(DirectSoundEnumerateW);
DSOUNDLOAD(DirectSoundCaptureEnumerateW);
#undef DSOUNDLOAD
if (!loaded) {
SDL_SetError("DirectSound: System doesn't appear to have DX8.");
}
}
if (!loaded) {
DSOUND_Unload();
}
return loaded;
}
static int
SetDSerror(const char *function, int code)
{
static const char *error;
static char errbuf[1024];
errbuf[0] = 0;
switch (code) {
case E_NOINTERFACE:
error = "Unsupported interface -- Is DirectX 8.0 or later installed?";
break;
case DSERR_ALLOCATED:
error = "Audio device in use";
break;
case DSERR_BADFORMAT:
error = "Unsupported audio format";
break;
case DSERR_BUFFERLOST:
error = "Mixing buffer was lost";
break;
case DSERR_CONTROLUNAVAIL:
error = "Control requested is not available";
break;
case DSERR_INVALIDCALL:
error = "Invalid call for the current state";
break;
case DSERR_INVALIDPARAM:
error = "Invalid parameter";
break;
case DSERR_NODRIVER:
error = "No audio device found";
break;
case DSERR_OUTOFMEMORY:
error = "Out of memory";
break;
case DSERR_PRIOLEVELNEEDED:
error = "Caller doesn't have priority";
break;
case DSERR_UNSUPPORTED:
error = "Function not supported";
break;
default:
SDL_snprintf(errbuf, SDL_arraysize(errbuf),
"%s: Unknown DirectSound error: 0x%x", function, code);
break;
}
if (!errbuf[0]) {
SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function,
error);
}
return SDL_SetError("%s", errbuf);
}
static void
DSOUND_FreeDeviceHandle(void *handle)
{
SDL_free(handle);
}
static BOOL CALLBACK
FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data)
{
const int iscapture = (int) ((size_t) data);
if (guid != NULL) { /* skip default device */
char *str = WIN_StringToUTF8(desc);
if (str != NULL) {
LPGUID cpyguid = (LPGUID) SDL_malloc(sizeof (GUID));
SDL_memcpy(cpyguid, guid, sizeof (GUID));
SDL_AddAudioDevice(iscapture, str, cpyguid);
SDL_free(str); /* addfn() makes a copy of this string. */
}
}
return TRUE; /* keep enumerating. */
}
static void
DSOUND_DetectDevices(void)
{
pDirectSoundCaptureEnumerateW(FindAllDevs, (void *) ((size_t) 1));
pDirectSoundEnumerateW(FindAllDevs, (void *) ((size_t) 0));
}
static void
DSOUND_WaitDevice(_THIS)
{
DWORD status = 0;
DWORD cursor = 0;
DWORD junk = 0;
HRESULT result = DS_OK;
/* Semi-busy wait, since we have no way of getting play notification
on a primary mixing buffer located in hardware (DirectX 5.0)
*/
result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
&junk, &cursor);
if (result != DS_OK) {
if (result == DSERR_BUFFERLOST) {
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
}
#ifdef DEBUG_SOUND
SetDSerror("DirectSound GetCurrentPosition", result);
#endif
return;
}
while ((cursor / this->hidden->mixlen) == this->hidden->lastchunk) {
/* FIXME: find out how much time is left and sleep that long */
SDL_Delay(1);
/* Try to restore a lost sound buffer */
IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
if ((status & DSBSTATUS_BUFFERLOST)) {
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
if ((status & DSBSTATUS_BUFFERLOST)) {
break;
}
}
if (!(status & DSBSTATUS_PLAYING)) {
result = IDirectSoundBuffer_Play(this->hidden->mixbuf, 0, 0,
DSBPLAY_LOOPING);
if (result == DS_OK) {
continue;
}
#ifdef DEBUG_SOUND
SetDSerror("DirectSound Play", result);
#endif
return;
}
/* Find out where we are playing */
result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
&junk, &cursor);
if (result != DS_OK) {
SetDSerror("DirectSound GetCurrentPosition", result);
return;
}
}
}
static void
DSOUND_PlayDevice(_THIS)
{
/* Unlock the buffer, allowing it to play */
if (this->hidden->locked_buf) {
IDirectSoundBuffer_Unlock(this->hidden->mixbuf,
this->hidden->locked_buf,
this->hidden->mixlen, NULL, 0);
}
}
static Uint8 *
DSOUND_GetDeviceBuf(_THIS)
{
DWORD cursor = 0;
DWORD junk = 0;
HRESULT result = DS_OK;
DWORD rawlen = 0;
/* Figure out which blocks to fill next */
this->hidden->locked_buf = NULL;
result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
&junk, &cursor);
if (result == DSERR_BUFFERLOST) {
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
&junk, &cursor);
}
if (result != DS_OK) {
SetDSerror("DirectSound GetCurrentPosition", result);
return (NULL);
}
cursor /= this->hidden->mixlen;
#ifdef DEBUG_SOUND
/* Detect audio dropouts */
{
DWORD spot = cursor;
if (spot < this->hidden->lastchunk) {
spot += this->hidden->num_buffers;
}
if (spot > this->hidden->lastchunk + 1) {
fprintf(stderr, "Audio dropout, missed %d fragments\n",
(spot - (this->hidden->lastchunk + 1)));
}
}
#endif
this->hidden->lastchunk = cursor;
cursor = (cursor + 1) % this->hidden->num_buffers;
cursor *= this->hidden->mixlen;
/* Lock the audio buffer */
result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
this->hidden->mixlen,
(LPVOID *) & this->hidden->locked_buf,
&rawlen, NULL, &junk, 0);
if (result == DSERR_BUFFERLOST) {
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
this->hidden->mixlen,
(LPVOID *) & this->
hidden->locked_buf, &rawlen, NULL,
&junk, 0);
}
if (result != DS_OK) {
SetDSerror("DirectSound Lock", result);
return (NULL);
}
return (this->hidden->locked_buf);
}
static void
DSOUND_WaitDone(_THIS)
{
Uint8 *stream = DSOUND_GetDeviceBuf(this);
/* Wait for the playing chunk to finish */
if (stream != NULL) {
SDL_memset(stream, this->spec.silence, this->hidden->mixlen);
DSOUND_PlayDevice(this);
}
DSOUND_WaitDevice(this);
/* Stop the looping sound buffer */
IDirectSoundBuffer_Stop(this->hidden->mixbuf);
}
static void
DSOUND_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
if (this->hidden->sound != NULL) {
if (this->hidden->mixbuf != NULL) {
/* Clean up the audio buffer */
IDirectSoundBuffer_Release(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
IDirectSound_Release(this->hidden->sound);
this->hidden->sound = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
/* This function tries to create a secondary audio buffer, and returns the
number of audio chunks available in the created buffer.
*/
static int
CreateSecondary(_THIS, HWND focus)
{
LPDIRECTSOUND sndObj = this->hidden->sound;
LPDIRECTSOUNDBUFFER *sndbuf = &this->hidden->mixbuf;
Uint32 chunksize = this->spec.size;
const int numchunks = 8;
HRESULT result = DS_OK;
DSBUFFERDESC format;
LPVOID pvAudioPtr1, pvAudioPtr2;
DWORD dwAudioBytes1, dwAudioBytes2;
WAVEFORMATEX wfmt;
SDL_zero(wfmt);
if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
} else {
wfmt.wFormatTag = WAVE_FORMAT_PCM;
}
wfmt.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
wfmt.nChannels = this->spec.channels;
wfmt.nSamplesPerSec = this->spec.freq;
wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8);
wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign;
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(&this->spec);
/* Try to set primary mixing privileges */
if (focus) {
result = IDirectSound_SetCooperativeLevel(sndObj,
focus, DSSCL_PRIORITY);
} else {
result = IDirectSound_SetCooperativeLevel(sndObj,
GetDesktopWindow(),
DSSCL_NORMAL);
}
if (result != DS_OK) {
return SetDSerror("DirectSound SetCooperativeLevel", result);
}
/* Try to create the secondary buffer */
SDL_zero(format);
format.dwSize = sizeof(format);
format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
if (!focus) {
format.dwFlags |= DSBCAPS_GLOBALFOCUS;
} else {
format.dwFlags |= DSBCAPS_STICKYFOCUS;
}
format.dwBufferBytes = numchunks * chunksize;
if ((format.dwBufferBytes < DSBSIZE_MIN) ||
(format.dwBufferBytes > DSBSIZE_MAX)) {
return SDL_SetError("Sound buffer size must be between %d and %d",
DSBSIZE_MIN / numchunks, DSBSIZE_MAX / numchunks);
}
format.dwReserved = 0;
format.lpwfxFormat = &wfmt;
result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
if (result != DS_OK) {
return SetDSerror("DirectSound CreateSoundBuffer", result);
}
IDirectSoundBuffer_SetFormat(*sndbuf, &wfmt);
/* Silence the initial audio buffer */
result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
(LPVOID *) & pvAudioPtr1, &dwAudioBytes1,
(LPVOID *) & pvAudioPtr2, &dwAudioBytes2,
DSBLOCK_ENTIREBUFFER);
if (result == DS_OK) {
SDL_memset(pvAudioPtr1, this->spec.silence, dwAudioBytes1);
IDirectSoundBuffer_Unlock(*sndbuf,
(LPVOID) pvAudioPtr1, dwAudioBytes1,
(LPVOID) pvAudioPtr2, dwAudioBytes2);
}
/* We're ready to go */
return (numchunks);
}
static int
DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
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;
/* Initialize all variables that we clean on shutdown */
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));
/* Open the audio device */
result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL);
if (result != DS_OK) {
DSOUND_CloseDevice(this);
return SetDSerror("DirectSoundCreate", result);
}
while ((!valid_format) && (test_format)) {
switch (test_format) {
case AUDIO_U8:
case AUDIO_S16:
case AUDIO_S32:
case AUDIO_F32:
tried_format = SDL_TRUE;
this->spec.format = test_format;
this->hidden->num_buffers = CreateSecondary(this, NULL);
if (this->hidden->num_buffers > 0) {
valid_format = SDL_TRUE;
}
break;
}
test_format = SDL_NextAudioFormat();
}
if (!valid_format) {
DSOUND_CloseDevice(this);
if (tried_format) {
return -1; /* CreateSecondary() should have called SDL_SetError(). */
}
return SDL_SetError("DirectSound: Unsupported audio format");
}
/* The buffer will auto-start playing in DSOUND_WaitDevice() */
this->hidden->mixlen = this->spec.size;
return 0; /* good to go. */
}
static void
DSOUND_Deinitialize(void)
{
DSOUND_Unload();
}
static int
DSOUND_Init(SDL_AudioDriverImpl * impl)
{
if (!DSOUND_Load()) {
return 0;
}
/* Set the function pointers */
impl->DetectDevices = DSOUND_DetectDevices;
impl->OpenDevice = DSOUND_OpenDevice;
impl->PlayDevice = DSOUND_PlayDevice;
impl->WaitDevice = DSOUND_WaitDevice;
impl->WaitDone = DSOUND_WaitDone;
impl->GetDeviceBuf = DSOUND_GetDeviceBuf;
impl->CloseDevice = DSOUND_CloseDevice;
impl->FreeDeviceHandle = DSOUND_FreeDeviceHandle;
impl->Deinitialize = DSOUND_Deinitialize;
return 1; /* this audio target is available. */
}
AudioBootStrap DSOUND_bootstrap = {
"directsound", "DirectSound", DSOUND_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_DSOUND */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,46 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_directsound_h
#define _SDL_directsound_h
#include "../../core/windows/SDL_directx.h"
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
/* The DirectSound objects */
struct SDL_PrivateAudioData
{
LPDIRECTSOUND sound;
LPDIRECTSOUNDBUFFER mixbuf;
int num_buffers;
int mixlen;
DWORD lastchunk;
Uint8 *locked_buf;
};
#endif /* _SDL_directsound_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,165 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_DISK
/* Output raw audio data to a file. */
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#include "SDL_rwops.h"
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_diskaudio.h"
/* environment variables and defaults. */
#define DISKENVR_OUTFILE "SDL_DISKAUDIOFILE"
#define DISKDEFAULT_OUTFILE "sdlaudio.raw"
#define DISKENVR_WRITEDELAY "SDL_DISKAUDIODELAY"
#define DISKDEFAULT_WRITEDELAY 150
static const char *
DISKAUD_GetOutputFilename(const char *devname)
{
if (devname == NULL) {
devname = SDL_getenv(DISKENVR_OUTFILE);
if (devname == NULL) {
devname = DISKDEFAULT_OUTFILE;
}
}
return devname;
}
/* This function waits until it is possible to write a full sound buffer */
static void
DISKAUD_WaitDevice(_THIS)
{
SDL_Delay(this->hidden->write_delay);
}
static void
DISKAUD_PlayDevice(_THIS)
{
size_t written;
/* Write the audio data */
written = SDL_RWwrite(this->hidden->output,
this->hidden->mixbuf, 1, this->hidden->mixlen);
/* If we couldn't write, assume fatal error for now */
if (written != this->hidden->mixlen) {
SDL_OpenedAudioDeviceDisconnected(this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
}
static Uint8 *
DISKAUD_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static void
DISKAUD_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->output != NULL) {
SDL_RWclose(this->hidden->output);
this->hidden->output = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
const char *envr = SDL_getenv(DISKENVR_WRITEDELAY);
const char *fname = DISKAUD_GetOutputFilename(devname);
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));
this->hidden->mixlen = this->spec.size;
this->hidden->write_delay =
(envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY;
/* Open the audio device */
this->hidden->output = SDL_RWFromFile(fname, "wb");
if (this->hidden->output == NULL) {
DISKAUD_CloseDevice(this);
return -1;
}
/* Allocate mixing buffer */
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
DISKAUD_CloseDevice(this);
return -1;
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
#if HAVE_STDIO_H
fprintf(stderr,
"WARNING: You are using the SDL disk writer audio driver!\n"
" Writing to file [%s].\n", fname);
#endif
/* We're ready to rock and roll. :-) */
return 0;
}
static int
DISKAUD_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->OpenDevice = DISKAUD_OpenDevice;
impl->WaitDevice = DISKAUD_WaitDevice;
impl->PlayDevice = DISKAUD_PlayDevice;
impl->GetDeviceBuf = DISKAUD_GetDeviceBuf;
impl->CloseDevice = DISKAUD_CloseDevice;
impl->AllowsArbitraryDeviceNames = 1;
return 1; /* this audio target is available. */
}
AudioBootStrap DISKAUD_bootstrap = {
"disk", "direct-to-disk audio", DISKAUD_Init, 1
};
#endif /* SDL_AUDIO_DRIVER_DISK */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,42 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_diskaudio_h
#define _SDL_diskaudio_h
#include "SDL_rwops.h"
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* The file descriptor for the audio device */
SDL_RWops *output;
Uint8 *mixbuf;
Uint32 mixlen;
Uint32 write_delay;
};
#endif /* _SDL_diskaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,308 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_OSS
/* Allow access to a raw mixing buffer */
#include <stdio.h> /* For perror() */
#include <string.h> /* For strerror() */
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#if SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H
/* This is installed on some systems */
#include <soundcard.h>
#else
/* This is recommended by OSS */
#include <sys/soundcard.h>
#endif
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_dspaudio.h"
static void
DSP_DetectDevices(void)
{
SDL_EnumUnixAudioDevices(0, NULL);
}
static void
DSP_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
int format;
int value;
int frag_spec;
SDL_AudioFormat test_format;
/* We don't care what the devname is...we'll try to open anything. */
/* ...but default to first name in the list... */
if (devname == NULL) {
devname = SDL_GetAudioDeviceName(0, iscapture);
if (devname == NULL) {
return SDL_SetError("No such audio device");
}
}
/* Make sure fragment size stays a power of 2, or OSS fails. */
/* I don't know which of these are actually legal values, though... */
if (this->spec.channels > 8)
this->spec.channels = 8;
else if (this->spec.channels > 4)
this->spec.channels = 4;
else if (this->spec.channels > 2)
this->spec.channels = 2;
/* Initialize all variables that we clean on shutdown */
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));
/* Open the audio device */
this->hidden->audio_fd = open(devname, flags, 0);
if (this->hidden->audio_fd < 0) {
DSP_CloseDevice(this);
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
}
this->hidden->mixbuf = NULL;
/* Make the file descriptor use blocking writes with fcntl() */
{
long ctlflags;
ctlflags = fcntl(this->hidden->audio_fd, F_GETFL);
ctlflags &= ~O_NONBLOCK;
if (fcntl(this->hidden->audio_fd, F_SETFL, ctlflags) < 0) {
DSP_CloseDevice(this);
return SDL_SetError("Couldn't set audio blocking mode");
}
}
/* Get a list of supported hardware formats */
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
perror("SNDCTL_DSP_GETFMTS");
DSP_CloseDevice(this);
return SDL_SetError("Couldn't get audio format list");
}
/* Try for a closest match on audio format */
format = 0;
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!format && test_format;) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
#endif
switch (test_format) {
case AUDIO_U8:
if (value & AFMT_U8) {
format = AFMT_U8;
}
break;
case AUDIO_S16LSB:
if (value & AFMT_S16_LE) {
format = AFMT_S16_LE;
}
break;
case AUDIO_S16MSB:
if (value & AFMT_S16_BE) {
format = AFMT_S16_BE;
}
break;
#if 0
/*
* These formats are not used by any real life systems so they are not
* needed here.
*/
case AUDIO_S8:
if (value & AFMT_S8) {
format = AFMT_S8;
}
break;
case AUDIO_U16LSB:
if (value & AFMT_U16_LE) {
format = AFMT_U16_LE;
}
break;
case AUDIO_U16MSB:
if (value & AFMT_U16_BE) {
format = AFMT_U16_BE;
}
break;
#endif
default:
format = 0;
break;
}
if (!format) {
test_format = SDL_NextAudioFormat();
}
}
if (format == 0) {
DSP_CloseDevice(this);
return SDL_SetError("Couldn't find any hardware audio formats");
}
this->spec.format = test_format;
/* Set the audio format */
value = format;
if ((ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
(value != format)) {
perror("SNDCTL_DSP_SETFMT");
DSP_CloseDevice(this);
return SDL_SetError("Couldn't set audio format");
}
/* Set the number of channels of output */
value = this->spec.channels;
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
perror("SNDCTL_DSP_CHANNELS");
DSP_CloseDevice(this);
return SDL_SetError("Cannot set the number of channels");
}
this->spec.channels = value;
/* Set the DSP frequency */
value = this->spec.freq;
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
perror("SNDCTL_DSP_SPEED");
DSP_CloseDevice(this);
return SDL_SetError("Couldn't set audio frequency");
}
this->spec.freq = value;
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&this->spec);
/* Determine the power of two of the fragment size */
for (frag_spec = 0; (0x01U << frag_spec) < this->spec.size; ++frag_spec);
if ((0x01U << frag_spec) != this->spec.size) {
DSP_CloseDevice(this);
return SDL_SetError("Fragment size must be a power of two");
}
frag_spec |= 0x00020000; /* two fragments, for low latency */
/* Set the audio buffering parameters */
#ifdef DEBUG_AUDIO
fprintf(stderr, "Requesting %d fragments of size %d\n",
(frag_spec >> 16), 1 << (frag_spec & 0xFFFF));
#endif
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
perror("SNDCTL_DSP_SETFRAGMENT");
}
#ifdef DEBUG_AUDIO
{
audio_buf_info info;
ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETOSPACE, &info);
fprintf(stderr, "fragments = %d\n", info.fragments);
fprintf(stderr, "fragstotal = %d\n", info.fragstotal);
fprintf(stderr, "fragsize = %d\n", info.fragsize);
fprintf(stderr, "bytes = %d\n", info.bytes);
}
#endif
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
DSP_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/* We're ready to rock and roll. :-) */
return 0;
}
static void
DSP_PlayDevice(_THIS)
{
const Uint8 *mixbuf = this->hidden->mixbuf;
const int mixlen = this->hidden->mixlen;
if (write(this->hidden->audio_fd, mixbuf, mixlen) == -1) {
perror("Audio write");
SDL_OpenedAudioDeviceDisconnected(this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen);
#endif
}
static Uint8 *
DSP_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static int
DSP_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->DetectDevices = DSP_DetectDevices;
impl->OpenDevice = DSP_OpenDevice;
impl->PlayDevice = DSP_PlayDevice;
impl->GetDeviceBuf = DSP_GetDeviceBuf;
impl->CloseDevice = DSP_CloseDevice;
impl->AllowsArbitraryDeviceNames = 1;
return 1; /* this audio target is available. */
}
AudioBootStrap DSP_bootstrap = {
"dsp", "OSS /dev/dsp standard audio", DSP_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_OSS */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,43 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_dspaudio_h
#define _SDL_dspaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* The file descriptor for the audio device */
int audio_fd;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
#endif /* _SDL_dspaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,48 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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"
/* Output audio to nowhere... */
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "SDL_dummyaudio.h"
static int
DUMMYAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
return 0; /* always succeeds. */
}
static int
DUMMYAUD_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->OpenDevice = DUMMYAUD_OpenDevice;
impl->OnlyHasDefaultOutputDevice = 1;
return 1; /* this audio target is available. */
}
AudioBootStrap DUMMYAUD_bootstrap = {
"dummy", "SDL dummy audio driver", DUMMYAUD_Init, 1
};
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,41 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_dummyaudio_h
#define _SDL_dummyaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* The file descriptor for the audio device */
Uint8 *mixbuf;
Uint32 mixlen;
Uint32 write_delay;
Uint32 initial_calls;
};
#endif /* _SDL_dummyaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,275 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_EMSCRIPTEN
#include "SDL_audio.h"
#include "SDL_log.h"
#include "../SDL_audio_c.h"
#include "SDL_emscriptenaudio.h"
#include <emscripten/emscripten.h>
static int
copyData(_THIS)
{
int byte_len;
if (this->hidden->write_off + this->convert.len_cvt > this->hidden->mixlen) {
if (this->hidden->write_off > this->hidden->read_off) {
SDL_memmove(this->hidden->mixbuf,
this->hidden->mixbuf + this->hidden->read_off,
this->hidden->mixlen - this->hidden->read_off);
this->hidden->write_off = this->hidden->write_off - this->hidden->read_off;
} else {
this->hidden->write_off = 0;
}
this->hidden->read_off = 0;
}
SDL_memcpy(this->hidden->mixbuf + this->hidden->write_off,
this->convert.buf,
this->convert.len_cvt);
this->hidden->write_off += this->convert.len_cvt;
byte_len = this->hidden->write_off - this->hidden->read_off;
return byte_len;
}
static void
HandleAudioProcess(_THIS)
{
Uint8 *buf = NULL;
int byte_len = 0;
int bytes = SDL_AUDIO_BITSIZE(this->spec.format) / 8;
int bytes_in = SDL_AUDIO_BITSIZE(this->convert.src_format) / 8;
/* Only do soemthing if audio is enabled */
if (!this->enabled)
return;
if (this->paused)
return;
if (this->convert.needed) {
if (this->hidden->conv_in_len != 0) {
this->convert.len = this->hidden->conv_in_len * bytes_in * this->spec.channels;
}
(*this->spec.callback) (this->spec.userdata,
this->convert.buf,
this->convert.len);
SDL_ConvertAudio(&this->convert);
buf = this->convert.buf;
byte_len = this->convert.len_cvt;
/* size mismatch*/
if (byte_len != this->spec.size) {
if (!this->hidden->mixbuf) {
this->hidden->mixlen = this->spec.size > byte_len ? this->spec.size * 2 : byte_len * 2;
this->hidden->mixbuf = SDL_malloc(this->hidden->mixlen);
}
/* copy existing data */
byte_len = copyData(this);
/* read more data*/
while (byte_len < this->spec.size) {
(*this->spec.callback) (this->spec.userdata,
this->convert.buf,
this->convert.len);
SDL_ConvertAudio(&this->convert);
byte_len = copyData(this);
}
byte_len = this->spec.size;
buf = this->hidden->mixbuf + this->hidden->read_off;
this->hidden->read_off += byte_len;
}
} else {
if (!this->hidden->mixbuf) {
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = SDL_malloc(this->hidden->mixlen);
}
(*this->spec.callback) (this->spec.userdata,
this->hidden->mixbuf,
this->hidden->mixlen);
buf = this->hidden->mixbuf;
byte_len = this->hidden->mixlen;
}
if (buf) {
EM_ASM_ARGS({
var numChannels = SDL2.audio.currentOutputBuffer['numberOfChannels'];
for (var c = 0; c < numChannels; ++c) {
var channelData = SDL2.audio.currentOutputBuffer['getChannelData'](c);
if (channelData.length != $1) {
throw 'Web Audio output buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!';
}
for (var j = 0; j < $1; ++j) {
channelData[j] = getValue($0 + (j*numChannels + c)*4, 'float');
}
}
}, buf, byte_len / bytes / this->spec.channels);
}
}
static void
Emscripten_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
/* Clean up the audio buffer */
SDL_free(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
SDL_bool valid_format = SDL_FALSE;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
int i;
float f;
int result;
while ((!valid_format) && (test_format)) {
switch (test_format) {
case AUDIO_F32: /* web audio only supports floats */
this->spec.format = test_format;
valid_format = SDL_TRUE;
break;
}
test_format = SDL_NextAudioFormat();
}
if (!valid_format) {
/* Didn't find a compatible format :( */
return SDL_SetError("No compatible audio format!");
}
/* Initialize all variables that we clean on shutdown */
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));
/* based on parts of library_sdl.js */
/* create context (TODO: this puts stuff in the global namespace...)*/
result = EM_ASM_INT_V({
if(typeof(SDL2) === 'undefined')
SDL2 = {};
if(typeof(SDL2.audio) === 'undefined')
SDL2.audio = {};
if (!SDL2.audioContext) {
if (typeof(AudioContext) !== 'undefined') {
SDL2.audioContext = new AudioContext();
} else if (typeof(webkitAudioContext) !== 'undefined') {
SDL2.audioContext = new webkitAudioContext();
} else {
return -1;
}
}
return 0;
});
if (result < 0) {
return SDL_SetError("Web Audio API is not available!");
}
/* limit to native freq */
int sampleRate = EM_ASM_INT_V({
return SDL2.audioContext['sampleRate'];
});
if(this->spec.freq != sampleRate) {
for (i = this->spec.samples; i > 0; i--) {
f = (float)i / (float)sampleRate * (float)this->spec.freq;
if (SDL_floor(f) == f) {
this->hidden->conv_in_len = SDL_floor(f);
break;
}
}
this->spec.freq = sampleRate;
}
SDL_CalculateAudioSpec(&this->spec);
/* setup a ScriptProcessorNode */
EM_ASM_ARGS({
SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0);
SDL2.audio.scriptProcessorNode['onaudioprocess'] = function (e) {
SDL2.audio.currentOutputBuffer = e['outputBuffer'];
Runtime.dynCall('vi', $2, [$3]);
};
SDL2.audio.scriptProcessorNode['connect'](SDL2.audioContext['destination']);
}, this->spec.channels, this->spec.samples, HandleAudioProcess, this);
return 0;
}
static int
Emscripten_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->OpenDevice = Emscripten_OpenDevice;
impl->CloseDevice = Emscripten_CloseDevice;
/* only one output */
impl->OnlyHasDefaultOutputDevice = 1;
/* no threads here */
impl->SkipMixerLock = 1;
impl->ProvidesOwnCallbackThread = 1;
/* check availability */
int available = EM_ASM_INT_V({
if (typeof(AudioContext) !== 'undefined') {
return 1;
} else if (typeof(webkitAudioContext) !== 'undefined') {
return 1;
}
return 0;
});
return available;
}
AudioBootStrap EmscriptenAudio_bootstrap = {
"emscripten", "SDL emscripten audio driver", Emscripten_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_EMSCRIPTEN */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,42 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_emscriptenaudio_h
#define _SDL_emscriptenaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
Uint8 *mixbuf;
Uint32 mixlen;
Uint32 conv_in_len;
Uint32 write_off, read_off;
};
#endif /* _SDL_emscriptenaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,345 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_ESD
/* Allow access to an ESD network stream mixing buffer */
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <esd.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_esdaudio.h"
#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
#include "SDL_name.h"
#include "SDL_loadso.h"
#else
#define SDL_NAME(X) X
#endif
#ifdef SDL_AUDIO_DRIVER_ESD_DYNAMIC
static const char *esd_library = SDL_AUDIO_DRIVER_ESD_DYNAMIC;
static void *esd_handle = NULL;
static int (*SDL_NAME(esd_open_sound)) (const char *host);
static int (*SDL_NAME(esd_close)) (int esd);
static int (*SDL_NAME(esd_play_stream)) (esd_format_t format, int rate,
const char *host, const char *name);
#define SDL_ESD_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
static struct
{
const char *name;
void **func;
} const esd_functions[] = {
SDL_ESD_SYM(esd_open_sound),
SDL_ESD_SYM(esd_close), SDL_ESD_SYM(esd_play_stream),
};
#undef SDL_ESD_SYM
static void
UnloadESDLibrary()
{
if (esd_handle != NULL) {
SDL_UnloadObject(esd_handle);
esd_handle = NULL;
}
}
static int
LoadESDLibrary(void)
{
int i, retval = -1;
if (esd_handle == NULL) {
esd_handle = SDL_LoadObject(esd_library);
if (esd_handle) {
retval = 0;
for (i = 0; i < SDL_arraysize(esd_functions); ++i) {
*esd_functions[i].func =
SDL_LoadFunction(esd_handle, esd_functions[i].name);
if (!*esd_functions[i].func) {
retval = -1;
UnloadESDLibrary();
break;
}
}
}
}
return retval;
}
#else
static void
UnloadESDLibrary()
{
return;
}
static int
LoadESDLibrary(void)
{
return 0;
}
#endif /* SDL_AUDIO_DRIVER_ESD_DYNAMIC */
/* This function waits until it is possible to write a full sound buffer */
static void
ESD_WaitDevice(_THIS)
{
Sint32 ticks;
/* Check to see if the thread-parent process is still alive */
{
static int cnt = 0;
/* Note that this only works with thread implementations
that use a different process id for each thread.
*/
/* Check every 10 loops */
if (this->hidden->parent && (((++cnt) % 10) == 0)) {
if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) {
SDL_OpenedAudioDeviceDisconnected(this);
}
}
}
/* Use timer for general audio synchronization */
ticks = ((Sint32) (this->hidden->next_frame - SDL_GetTicks())) - FUDGE_TICKS;
if (ticks > 0) {
SDL_Delay(ticks);
}
}
static void
ESD_PlayDevice(_THIS)
{
int written = 0;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
written = write(this->hidden->audio_fd,
this->hidden->mixbuf, this->hidden->mixlen);
if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
SDL_Delay(1); /* Let a little CPU time go by */
}
} while ((written < 0) &&
((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
/* Set the next write frame */
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 *
ESD_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static void
ESD_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->audio_fd >= 0) {
SDL_NAME(esd_close) (this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
/* Try to get the name of the program */
static char *
get_progname(void)
{
char *progname = NULL;
#ifdef __LINUX__
FILE *fp;
static char temp[BUFSIZ];
SDL_snprintf(temp, SDL_arraysize(temp), "/proc/%d/cmdline", getpid());
fp = fopen(temp, "r");
if (fp != NULL) {
if (fgets(temp, sizeof(temp) - 1, fp)) {
progname = SDL_strrchr(temp, '/');
if (progname == NULL) {
progname = temp;
} else {
progname = progname + 1;
}
}
fclose(fp);
}
#endif
return (progname);
}
static int
ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
esd_format_t format = (ESD_STREAM | ESD_PLAY);
SDL_AudioFormat test_format = 0;
int found = 0;
/* Initialize all variables that we clean on shutdown */
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));
this->hidden->audio_fd = -1;
/* Convert audio spec to the ESD audio format */
/* Try for a closest match on audio format */
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!found && test_format; test_format = SDL_NextAudioFormat()) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
#endif
found = 1;
switch (test_format) {
case AUDIO_U8:
format |= ESD_BITS8;
break;
case AUDIO_S16SYS:
format |= ESD_BITS16;
break;
default:
found = 0;
break;
}
}
if (!found) {
ESD_CloseDevice(this);
return SDL_SetError("Couldn't find any hardware audio formats");
}
if (this->spec.channels == 1) {
format |= ESD_MONO;
} else {
format |= ESD_STEREO;
}
#if 0
this->spec.samples = ESD_BUF_SIZE; /* Darn, no way to change this yet */
#endif
/* Open a connection to the ESD audio server */
this->hidden->audio_fd =
SDL_NAME(esd_play_stream) (format, this->spec.freq, NULL,
get_progname());
if (this->hidden->audio_fd < 0) {
ESD_CloseDevice(this);
return SDL_SetError("Couldn't open ESD connection");
}
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&this->spec);
this->hidden->frame_ticks =
(float) (this->spec.samples * 1000) / this->spec.freq;
this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
ESD_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/* Get the parent process id (we're the parent of the audio thread) */
this->hidden->parent = getpid();
/* We're ready to rock and roll. :-) */
return 0;
}
static void
ESD_Deinitialize(void)
{
UnloadESDLibrary();
}
static int
ESD_Init(SDL_AudioDriverImpl * impl)
{
if (LoadESDLibrary() < 0) {
return 0;
} else {
int connection = 0;
/* Don't start ESD if it's not running */
SDL_setenv("ESD_NO_SPAWN", "1", 0);
connection = SDL_NAME(esd_open_sound) (NULL);
if (connection < 0) {
UnloadESDLibrary();
SDL_SetError("ESD: esd_open_sound failed (no audio server?)");
return 0;
}
SDL_NAME(esd_close) (connection);
}
/* Set the function pointers */
impl->OpenDevice = ESD_OpenDevice;
impl->PlayDevice = ESD_PlayDevice;
impl->WaitDevice = ESD_WaitDevice;
impl->GetDeviceBuf = ESD_GetDeviceBuf;
impl->CloseDevice = ESD_CloseDevice;
impl->Deinitialize = ESD_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1;
return 1; /* this audio target is available. */
}
AudioBootStrap ESD_bootstrap = {
"esd", "Enlightened Sound Daemon", ESD_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_ESD */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,50 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_esdaudio_h
#define _SDL_esdaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* The file descriptor for the audio device */
int audio_fd;
/* The parent process id, to detect when application quits */
pid_t parent;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
/* Support for audio timing using a timer */
float frame_ticks;
float next_frame;
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
#endif /* _SDL_esdaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,345 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_FUSIONSOUND
/* Allow access to a raw mixing buffer */
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#include <unistd.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_fsaudio.h"
#include <fusionsound/fusionsound_version.h>
/* #define SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC "libfusionsound.so" */
#ifdef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC
#include "SDL_name.h"
#include "SDL_loadso.h"
#else
#define SDL_NAME(X) X
#endif
#if (FUSIONSOUND_MAJOR_VERSION == 1) && (FUSIONSOUND_MINOR_VERSION < 1)
typedef DFBResult DirectResult;
#endif
/* Buffers to use - more than 2 gives a lot of latency */
#define FUSION_BUFFERS (2)
#ifdef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC
static const char *fs_library = SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC;
static void *fs_handle = NULL;
static DirectResult (*SDL_NAME(FusionSoundInit)) (int *argc, char *(*argv[]));
static DirectResult (*SDL_NAME(FusionSoundCreate)) (IFusionSound **
ret_interface);
#define SDL_FS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
static struct
{
const char *name;
void **func;
} fs_functions[] = {
/* *INDENT-OFF* */
SDL_FS_SYM(FusionSoundInit),
SDL_FS_SYM(FusionSoundCreate),
/* *INDENT-ON* */
};
#undef SDL_FS_SYM
static void
UnloadFusionSoundLibrary()
{
if (fs_handle != NULL) {
SDL_UnloadObject(fs_handle);
fs_handle = NULL;
}
}
static int
LoadFusionSoundLibrary(void)
{
int i, retval = -1;
if (fs_handle == NULL) {
fs_handle = SDL_LoadObject(fs_library);
if (fs_handle != NULL) {
retval = 0;
for (i = 0; i < SDL_arraysize(fs_functions); ++i) {
*fs_functions[i].func =
SDL_LoadFunction(fs_handle, fs_functions[i].name);
if (!*fs_functions[i].func) {
retval = -1;
UnloadFusionSoundLibrary();
break;
}
}
}
}
return retval;
}
#else
static void
UnloadFusionSoundLibrary()
{
return;
}
static int
LoadFusionSoundLibrary(void)
{
return 0;
}
#endif /* SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC */
/* This function waits until it is possible to write a full sound buffer */
static void
SDL_FS_WaitDevice(_THIS)
{
this->hidden->stream->Wait(this->hidden->stream,
this->hidden->mixsamples);
}
static void
SDL_FS_PlayDevice(_THIS)
{
DirectResult ret;
ret = this->hidden->stream->Write(this->hidden->stream,
this->hidden->mixbuf,
this->hidden->mixsamples);
/* If we couldn't write, assume fatal error for now */
if (ret) {
SDL_OpenedAudioDeviceDisconnected(this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
#endif
}
static void
SDL_FS_WaitDone(_THIS)
{
this->hidden->stream->Wait(this->hidden->stream,
this->hidden->mixsamples * FUSION_BUFFERS);
}
static Uint8 *
SDL_FS_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static void
SDL_FS_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->stream) {
this->hidden->stream->Release(this->hidden->stream);
this->hidden->stream = NULL;
}
if (this->hidden->fs) {
this->hidden->fs->Release(this->hidden->fs);
this->hidden->fs = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
int bytes;
SDL_AudioFormat test_format = 0, format = 0;
FSSampleFormat fs_format;
FSStreamDescription desc;
DirectResult ret;
/* Initialize all variables that we clean on shutdown */
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));
/* Try for a closest match on audio format */
for (test_format = SDL_FirstAudioFormat(this->spec.format);
!format && test_format;) {
#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();
}
}
if (format == 0) {
SDL_FS_CloseDevice(this);
return SDL_SetError("Couldn't find any hardware audio formats");
}
this->spec.format = test_format;
/* Retrieve the main sound interface. */
ret = SDL_NAME(FusionSoundCreate) (&this->hidden->fs);
if (ret) {
SDL_FS_CloseDevice(this);
return SDL_SetError("Unable to initialize FusionSound: %d", ret);
}
this->hidden->mixsamples = this->spec.size / bytes / this->spec.channels;
/* Fill stream description. */
desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE |
FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT | FSSDF_PREBUFFER;
desc.samplerate = this->spec.freq;
desc.buffersize = this->spec.size * FUSION_BUFFERS;
desc.channels = this->spec.channels;
desc.prebuffer = 10;
desc.sampleformat = fs_format;
ret =
this->hidden->fs->CreateStream(this->hidden->fs, &desc,
&this->hidden->stream);
if (ret) {
SDL_FS_CloseDevice(this);
return SDL_SetError("Unable to create FusionSoundStream: %d", ret);
}
/* See what we got */
desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE |
FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT;
ret = this->hidden->stream->GetDescription(this->hidden->stream, &desc);
this->spec.freq = desc.samplerate;
this->spec.size =
desc.buffersize / FUSION_BUFFERS * bytes * desc.channels;
this->spec.channels = desc.channels;
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&this->spec);
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
SDL_FS_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/* We're ready to rock and roll. :-) */
return 0;
}
static void
SDL_FS_Deinitialize(void)
{
UnloadFusionSoundLibrary();
}
static int
SDL_FS_Init(SDL_AudioDriverImpl * impl)
{
if (LoadFusionSoundLibrary() < 0) {
return 0;
} else {
DirectResult ret;
ret = SDL_NAME(FusionSoundInit) (NULL, NULL);
if (ret) {
UnloadFusionSoundLibrary();
SDL_SetError
("FusionSound: SDL_FS_init failed (FusionSoundInit: %d)",
ret);
return 0;
}
}
/* Set the function pointers */
impl->OpenDevice = SDL_FS_OpenDevice;
impl->PlayDevice = SDL_FS_PlayDevice;
impl->WaitDevice = SDL_FS_WaitDevice;
impl->GetDeviceBuf = SDL_FS_GetDeviceBuf;
impl->CloseDevice = SDL_FS_CloseDevice;
impl->WaitDone = SDL_FS_WaitDone;
impl->Deinitialize = SDL_FS_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1;
return 1; /* this audio target is available. */
}
AudioBootStrap FUSIONSOUND_bootstrap = {
"fusionsound", "FusionSound", SDL_FS_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_FUSIONSOUND */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,49 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_fsaudio_h
#define _SDL_fsaudio_h
#include <fusionsound/fusionsound.h>
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* Interface */
IFusionSound *fs;
/* The stream interface for the audio device */
IFusionSoundStream *stream;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
int mixsamples;
};
#endif /* _SDL_fsaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,240 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_HAIKU
/* Allow access to the audio stream on Haiku */
#include <SoundPlayer.h>
#include <signal.h>
#include "../../main/haiku/SDL_BeApp.h"
extern "C"
{
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_haikuaudio.h"
}
/* !!! FIXME: have the callback call the higher level to avoid code dupe. */
/* The Haiku callback for handling the audio buffer */
static void
FillSound(void *device, void *stream, size_t len,
const media_raw_audio_format & format)
{
SDL_AudioDevice *audio = (SDL_AudioDevice *) device;
/* Only do soemthing if audio is enabled */
if (!audio->enabled)
return;
if (!audio->paused) {
if (audio->convert.needed) {
SDL_LockMutex(audio->mixer_lock);
(*audio->spec.callback) (audio->spec.userdata,
(Uint8 *) audio->convert.buf,
audio->convert.len);
SDL_UnlockMutex(audio->mixer_lock);
SDL_ConvertAudio(&audio->convert);
SDL_memcpy(stream, audio->convert.buf, audio->convert.len_cvt);
} else {
SDL_LockMutex(audio->mixer_lock);
(*audio->spec.callback) (audio->spec.userdata,
(Uint8 *) stream, len);
SDL_UnlockMutex(audio->mixer_lock);
}
}
}
static void
HAIKUAUDIO_CloseDevice(_THIS)
{
if (_this->hidden != NULL) {
if (_this->hidden->audio_obj) {
_this->hidden->audio_obj->Stop();
delete _this->hidden->audio_obj;
_this->hidden->audio_obj = NULL;
}
delete _this->hidden;
_this->hidden = NULL;
}
}
static const int sig_list[] = {
SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGWINCH, 0
};
static inline void
MaskSignals(sigset_t * omask)
{
sigset_t mask;
int i;
sigemptyset(&mask);
for (i = 0; sig_list[i]; ++i) {
sigaddset(&mask, sig_list[i]);
}
sigprocmask(SIG_BLOCK, &mask, omask);
}
static inline void
UnmaskSignals(sigset_t * omask)
{
sigprocmask(SIG_SETMASK, omask, NULL);
}
static int
HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
int valid_datatype = 0;
media_raw_audio_format format;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(_this->spec.format);
/* Initialize all variables that we clean on shutdown */
_this->hidden = new SDL_PrivateAudioData;
if (_this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(_this->hidden, 0, (sizeof *_this->hidden));
/* Parse the audio format and fill the Be raw audio format */
SDL_memset(&format, '\0', sizeof(media_raw_audio_format));
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;
switch (test_format) {
case AUDIO_S8:
format.format = media_raw_audio_format::B_AUDIO_CHAR;
break;
case AUDIO_U8:
format.format = media_raw_audio_format::B_AUDIO_UCHAR;
break;
case AUDIO_S16LSB:
format.format = media_raw_audio_format::B_AUDIO_SHORT;
break;
case AUDIO_S16MSB:
format.format = media_raw_audio_format::B_AUDIO_SHORT;
format.byte_order = B_MEDIA_BIG_ENDIAN;
break;
case AUDIO_S32LSB:
format.format = media_raw_audio_format::B_AUDIO_INT;
break;
case AUDIO_S32MSB:
format.format = media_raw_audio_format::B_AUDIO_INT;
format.byte_order = B_MEDIA_BIG_ENDIAN;
break;
case AUDIO_F32LSB:
format.format = media_raw_audio_format::B_AUDIO_FLOAT;
break;
case AUDIO_F32MSB:
format.format = media_raw_audio_format::B_AUDIO_FLOAT;
format.byte_order = B_MEDIA_BIG_ENDIAN;
break;
default:
valid_datatype = 0;
test_format = SDL_NextAudioFormat();
break;
}
}
if (!valid_datatype) { /* shouldn't happen, but just in case... */
HAIKUAUDIO_CloseDevice(_this);
return SDL_SetError("Unsupported audio format");
}
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&_this->spec);
format.buffer_size = _this->spec.size;
/* Subscribe to the audio stream (creates a new thread) */
sigset_t omask;
MaskSignals(&omask);
_this->hidden->audio_obj = new BSoundPlayer(&format, "SDL Audio",
FillSound, NULL, _this);
UnmaskSignals(&omask);
if (_this->hidden->audio_obj->Start() == B_NO_ERROR) {
_this->hidden->audio_obj->SetHasData(true);
} else {
HAIKUAUDIO_CloseDevice(_this);
return SDL_SetError("Unable to start Be audio");
}
/* We're running! */
return 0;
}
static void
HAIKUAUDIO_Deinitialize(void)
{
SDL_QuitBeApp();
}
static int
HAIKUAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Initialize the Be Application, if it's not already started */
if (SDL_InitBeApp() < 0) {
return 0;
}
/* Set the function pointers */
impl->OpenDevice = HAIKUAUDIO_OpenDevice;
impl->CloseDevice = HAIKUAUDIO_CloseDevice;
impl->Deinitialize = HAIKUAUDIO_Deinitialize;
impl->ProvidesOwnCallbackThread = 1;
impl->OnlyHasDefaultOutputDevice = 1;
return 1; /* this audio target is available. */
}
extern "C"
{
extern AudioBootStrap HAIKUAUDIO_bootstrap;
}
AudioBootStrap HAIKUAUDIO_bootstrap = {
"haiku", "Haiku BSoundPlayer", HAIKUAUDIO_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_HAIKU */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,38 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_beaudio_h
#define _SDL_beaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *_this
struct SDL_PrivateAudioData
{
BSoundPlayer *audio_obj;
};
#endif /* _SDL_beaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,152 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_NACL
#include "SDL_naclaudio.h"
#include "SDL_audio.h"
#include "SDL_mutex.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi_simple/ps.h"
#include "ppapi_simple/ps_interface.h"
#include "ppapi_simple/ps_event.h"
/* The tag name used by NACL audio */
#define NACLAUD_DRIVER_NAME "nacl"
#define SAMPLE_FRAME_COUNT 4096
/* Audio driver functions */
static int NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture);
static void NACLAUD_CloseDevice(_THIS);
static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data);
/* FIXME: Make use of latency if needed */
static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data) {
SDL_AudioDevice* _this = (SDL_AudioDevice*) data;
SDL_LockMutex(private->mutex);
if (_this->enabled && !_this->paused) {
if (_this->convert.needed) {
SDL_LockMutex(_this->mixer_lock);
(*_this->spec.callback) (_this->spec.userdata,
(Uint8 *) _this->convert.buf,
_this->convert.len);
SDL_UnlockMutex(_this->mixer_lock);
SDL_ConvertAudio(&_this->convert);
SDL_memcpy(samples, _this->convert.buf, _this->convert.len_cvt);
} else {
SDL_LockMutex(_this->mixer_lock);
(*_this->spec.callback) (_this->spec.userdata, (Uint8 *) samples, buffer_size);
SDL_UnlockMutex(_this->mixer_lock);
}
} else {
SDL_memset(samples, 0, buffer_size);
}
return;
}
static void NACLAUD_CloseDevice(SDL_AudioDevice *device) {
const PPB_Core *core = PSInterfaceCore();
const PPB_Audio *ppb_audio = PSInterfaceAudio();
SDL_PrivateAudioData *hidden = (SDL_PrivateAudioData *) device->hidden;
ppb_audio->StopPlayback(hidden->audio);
SDL_DestroyMutex(hidden->mutex);
core->ReleaseResource(hidden->audio);
}
static int
NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) {
PP_Instance instance = PSGetInstanceId();
const PPB_Audio *ppb_audio = PSInterfaceAudio();
const PPB_AudioConfig *ppb_audiocfg = PSInterfaceAudioConfig();
private = (SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *private));
if (private == NULL) {
SDL_OutOfMemory();
return 0;
}
private->mutex = SDL_CreateMutex();
_this->spec.freq = 44100;
_this->spec.format = AUDIO_S16LSB;
_this->spec.channels = 2;
_this->spec.samples = ppb_audiocfg->RecommendSampleFrameCount(
instance,
PP_AUDIOSAMPLERATE_44100,
SAMPLE_FRAME_COUNT);
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&_this->spec);
private->audio = ppb_audio->Create(
instance,
ppb_audiocfg->CreateStereo16Bit(instance, PP_AUDIOSAMPLERATE_44100, _this->spec.samples),
nacl_audio_callback,
_this);
/* Start audio playback while we are still on the main thread. */
ppb_audio->StartPlayback(private->audio);
return 1;
}
static int
NACLAUD_Init(SDL_AudioDriverImpl * impl)
{
if (PSGetInstanceId() == 0) {
return 0;
}
/* Set the function pointers */
impl->OpenDevice = NACLAUD_OpenDevice;
impl->CloseDevice = NACLAUD_CloseDevice;
impl->OnlyHasDefaultOutputDevice = 1;
impl->ProvidesOwnCallbackThread = 1;
/*
* impl->WaitDevice = NACLAUD_WaitDevice;
* impl->GetDeviceBuf = NACLAUD_GetDeviceBuf;
* impl->PlayDevice = NACLAUD_PlayDevice;
* impl->Deinitialize = NACLAUD_Deinitialize;
*/
return 1;
}
AudioBootStrap NACLAUD_bootstrap = {
NACLAUD_DRIVER_NAME, "SDL NaCl Audio Driver",
NACLAUD_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_NACL */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,41 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_naclaudio_h
#define _SDL_naclaudio_h
#include "SDL_audio.h"
#include "../SDL_sysaudio.h"
#include "SDL_mutex.h"
#include "ppapi/c/ppb_audio.h"
#define _THIS SDL_AudioDevice *_this
#define private _this->hidden
typedef struct SDL_PrivateAudioData {
SDL_mutex* mutex;
PP_Resource audio;
} SDL_PrivateAudioData;
#endif /* _SDL_naclaudio_h */

View File

@@ -0,0 +1,397 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_NAS
/* Allow access to a raw mixing buffer */
#include <signal.h>
#include <unistd.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "SDL_loadso.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_nasaudio.h"
static struct SDL_PrivateAudioData *this2 = NULL;
static void (*NAS_AuCloseServer) (AuServer *);
static void (*NAS_AuNextEvent) (AuServer *, AuBool, AuEvent *);
static AuBool(*NAS_AuDispatchEvent) (AuServer *, AuEvent *);
static AuFlowID(*NAS_AuCreateFlow) (AuServer *, AuStatus *);
static void (*NAS_AuStartFlow) (AuServer *, AuFlowID, AuStatus *);
static void (*NAS_AuSetElements)
(AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *);
static void (*NAS_AuWriteElement)
(AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *);
static AuServer *(*NAS_AuOpenServer)
(_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **);
static AuEventHandlerRec *(*NAS_AuRegisterEventHandler)
(AuServer *, AuMask, int, AuID, AuEventHandlerCallback, AuPointer);
#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
static const char *nas_library = SDL_AUDIO_DRIVER_NAS_DYNAMIC;
static void *nas_handle = NULL;
static int
load_nas_sym(const char *fn, void **addr)
{
*addr = SDL_LoadFunction(nas_handle, fn);
if (*addr == NULL) {
return 0;
}
return 1;
}
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
#define SDL_NAS_SYM(x) \
if (!load_nas_sym(#x, (void **) (char *) &NAS_##x)) return -1
#else
#define SDL_NAS_SYM(x) NAS_##x = x
#endif
static int
load_nas_syms(void)
{
SDL_NAS_SYM(AuCloseServer);
SDL_NAS_SYM(AuNextEvent);
SDL_NAS_SYM(AuDispatchEvent);
SDL_NAS_SYM(AuCreateFlow);
SDL_NAS_SYM(AuStartFlow);
SDL_NAS_SYM(AuSetElements);
SDL_NAS_SYM(AuWriteElement);
SDL_NAS_SYM(AuOpenServer);
SDL_NAS_SYM(AuRegisterEventHandler);
return 0;
}
#undef SDL_NAS_SYM
#ifdef SDL_AUDIO_DRIVER_NAS_DYNAMIC
static void
UnloadNASLibrary(void)
{
if (nas_handle != NULL) {
SDL_UnloadObject(nas_handle);
nas_handle = NULL;
}
}
static int
LoadNASLibrary(void)
{
int retval = 0;
if (nas_handle == NULL) {
nas_handle = SDL_LoadObject(nas_library);
if (nas_handle == NULL) {
/* 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);
SDL_strlcpy(err, origerr, len);
retval = -1;
SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s\n",
nas_library, err);
} else {
retval = load_nas_syms();
if (retval < 0) {
UnloadNASLibrary();
}
}
}
return retval;
}
#else
static void
UnloadNASLibrary(void)
{
}
static int
LoadNASLibrary(void)
{
load_nas_syms();
return 0;
}
#endif /* SDL_AUDIO_DRIVER_NAS_DYNAMIC */
/* This function waits until it is possible to write a full sound buffer */
static void
NAS_WaitDevice(_THIS)
{
while (this->hidden->buf_free < this->hidden->mixlen) {
AuEvent ev;
NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
NAS_AuDispatchEvent(this->hidden->aud, &ev);
}
}
static void
NAS_PlayDevice(_THIS)
{
while (this->hidden->mixlen > this->hidden->buf_free) {
/*
* We think the buffer is full? Yikes! Ask the server for events,
* in the hope that some of them is LowWater events telling us more
* of the buffer is free now than what we think.
*/
AuEvent ev;
NAS_AuNextEvent(this->hidden->aud, AuTrue, &ev);
NAS_AuDispatchEvent(this->hidden->aud, &ev);
}
this->hidden->buf_free -= this->hidden->mixlen;
/* Write the audio data */
NAS_AuWriteElement(this->hidden->aud, this->hidden->flow, 0,
this->hidden->mixlen, this->hidden->mixbuf, AuFalse,
NULL);
this->hidden->written += this->hidden->mixlen;
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
#endif
}
static Uint8 *
NAS_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static void
NAS_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->aud) {
NAS_AuCloseServer(this->hidden->aud);
this->hidden->aud = 0;
}
SDL_free(this->hidden);
this2 = this->hidden = NULL;
}
}
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)
{
switch (ev->type) {
case AuEventTypeElementNotify:
{
AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev;
switch (event->kind) {
case AuElementNotifyKindLowWater:
if (this2->buf_free >= 0) {
this2->really += event->num_bytes;
gettimeofday(&this2->last_tv, 0);
this2->buf_free += event->num_bytes;
} else {
this2->buf_free = event->num_bytes;
}
break;
case AuElementNotifyKindState:
switch (event->cur_state) {
case AuStatePause:
if (event->reason != AuReasonUser) {
if (this2->buf_free >= 0) {
this2->really += event->num_bytes;
gettimeofday(&this2->last_tv, 0);
this2->buf_free += event->num_bytes;
} else {
this2->buf_free = event->num_bytes;
}
}
break;
}
}
}
}
return AuTrue;
}
static AuDeviceID
find_device(_THIS, int nch)
{
/* These "Au" things are all macros, not functions... */
int i;
for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
AuComponentKindPhysicalOutput) &&
AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) {
return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i));
}
}
return AuNone;
}
static int
NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
AuElement elms[3];
int buffer_size;
SDL_AudioFormat test_format, format;
/* Initialize all variables that we clean on shutdown */
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));
/* 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();
}
}
if (format == 0) {
NAS_CloseDevice(this);
return SDL_SetError("NAS: Couldn't find any hardware audio formats");
}
this->spec.format = test_format;
this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
if (this->hidden->aud == 0) {
NAS_CloseDevice(this);
return SDL_SetError("NAS: Couldn't open connection to NAS server");
}
this->hidden->dev = find_device(this, this->spec.channels);
if ((this->hidden->dev == AuNone)
|| (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) {
NAS_CloseDevice(this);
return SDL_SetError("NAS: Couldn't find a fitting device on NAS server");
}
buffer_size = this->spec.freq;
if (buffer_size < 4096)
buffer_size = 4096;
if (buffer_size > 32768)
buffer_size = 32768; /* So that the buffer won't get unmanageably big. */
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&this->spec);
this2 = this->hidden;
AuMakeElementImportClient(elms, this->spec.freq, format,
this->spec.channels, AuTrue, buffer_size,
buffer_size / 4, 0, NULL);
AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq,
AuUnlimitedSamples, 0, NULL);
NAS_AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms,
NULL);
NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
this->hidden->flow, event_handler,
(AuPointer) NULL);
NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
NAS_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/* We're ready to rock and roll. :-) */
return 0;
}
static void
NAS_Deinitialize(void)
{
UnloadNASLibrary();
}
static int
NAS_Init(SDL_AudioDriverImpl * impl)
{
if (LoadNASLibrary() < 0) {
return 0;
} else {
AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
if (aud == NULL) {
SDL_SetError("NAS: AuOpenServer() failed (no audio server?)");
return 0;
}
NAS_AuCloseServer(aud);
}
/* Set the function pointers */
impl->OpenDevice = NAS_OpenDevice;
impl->PlayDevice = NAS_PlayDevice;
impl->WaitDevice = NAS_WaitDevice;
impl->GetDeviceBuf = NAS_GetDeviceBuf;
impl->CloseDevice = NAS_CloseDevice;
impl->Deinitialize = NAS_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: is this true? */
return 1; /* this audio target is available. */
}
AudioBootStrap NAS_bootstrap = {
"nas", "Network Audio System", NAS_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_NAS */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,56 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_nasaudio_h
#define _SDL_nasaudio_h
#ifdef __sgi
#include <nas/audiolib.h>
#else
#include <audio/audiolib.h>
#endif
#include <sys/time.h>
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
AuServer *aud;
AuFlowID flow;
AuDeviceID dev;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
int written;
int really;
int bps;
struct timeval last_tv;
int buf_free;
};
#endif /* _SDL_nasaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,541 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_PAUDIO
/* Allow access to a raw mixing buffer */
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "SDL_stdinc.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_paudio.h"
#define DEBUG_AUDIO 0
/* A conflict within AIX 4.3.3 <sys/> headers and probably others as well.
* I guess nobody ever uses audio... Shame over AIX header files. */
#include <sys/machine.h>
#undef BIG_ENDIAN
#include <sys/audio.h>
/* Open the audio device for playback, and don't block if busy */
/* #define OPEN_FLAGS (O_WRONLY|O_NONBLOCK) */
#define OPEN_FLAGS O_WRONLY
/* Get the name of the audio device we use for output */
#ifndef _PATH_DEV_DSP
#define _PATH_DEV_DSP "/dev/%caud%c/%c"
#endif
static char devsettings[][3] = {
{'p', '0', '1'}, {'p', '0', '2'}, {'p', '0', '3'}, {'p', '0', '4'},
{'p', '1', '1'}, {'p', '1', '2'}, {'p', '1', '3'}, {'p', '1', '4'},
{'p', '2', '1'}, {'p', '2', '2'}, {'p', '2', '3'}, {'p', '2', '4'},
{'p', '3', '1'}, {'p', '3', '2'}, {'p', '3', '3'}, {'p', '3', '4'},
{'b', '0', '1'}, {'b', '0', '2'}, {'b', '0', '3'}, {'b', '0', '4'},
{'b', '1', '1'}, {'b', '1', '2'}, {'b', '1', '3'}, {'b', '1', '4'},
{'b', '2', '1'}, {'b', '2', '2'}, {'b', '2', '3'}, {'b', '2', '4'},
{'b', '3', '1'}, {'b', '3', '2'}, {'b', '3', '3'}, {'b', '3', '4'},
{'\0', '\0', '\0'}
};
static int
OpenUserDefinedDevice(char *path, int maxlen, int flags)
{
const char *audiodev;
int fd;
/* Figure out what our audio device is */
if ((audiodev = SDL_getenv("SDL_PATH_DSP")) == NULL) {
audiodev = SDL_getenv("AUDIODEV");
}
if (audiodev == NULL) {
return -1;
}
fd = open(audiodev, flags, 0);
if (path != NULL) {
SDL_strlcpy(path, audiodev, maxlen);
path[maxlen - 1] = '\0';
}
return fd;
}
static int
OpenAudioPath(char *path, int maxlen, int flags, int classic)
{
struct stat sb;
int cycle = 0;
int fd = OpenUserDefinedDevice(path, maxlen, flags);
if (fd != -1) {
return fd;
}
/* !!! FIXME: do we really need a table here? */
while (devsettings[cycle][0] != '\0') {
char audiopath[1024];
SDL_snprintf(audiopath, SDL_arraysize(audiopath),
_PATH_DEV_DSP,
devsettings[cycle][0],
devsettings[cycle][1], devsettings[cycle][2]);
if (stat(audiopath, &sb) == 0) {
fd = open(audiopath, flags, 0);
if (fd > 0) {
if (path != NULL) {
SDL_strlcpy(path, audiopath, maxlen);
}
return fd;
}
}
}
return -1;
}
/* This function waits until it is possible to write a full sound buffer */
static void
PAUDIO_WaitDevice(_THIS)
{
fd_set fdset;
/* 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 {
audio_buffer paud_bufinfo;
/* Use select() for audio synchronization */
struct timeval timeout;
FD_ZERO(&fdset);
FD_SET(this->hidden->audio_fd, &fdset);
if (ioctl(this->hidden->audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Couldn't get audio buffer information\n");
#endif
timeout.tv_sec = 10;
timeout.tv_usec = 0;
} else {
long ms_in_buf = paud_bufinfo.write_buf_time;
timeout.tv_sec = ms_in_buf / 1000;
ms_in_buf = ms_in_buf - timeout.tv_sec * 1000;
timeout.tv_usec = ms_in_buf * 1000;
#ifdef DEBUG_AUDIO
fprintf(stderr,
"Waiting for write_buf_time=%ld,%ld\n",
timeout.tv_sec, timeout.tv_usec);
#endif
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Waiting for audio to get ready\n");
#endif
if (select(this->hidden->audio_fd + 1, NULL, &fdset, NULL, &timeout)
<= 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 - %s\n", strerror(errno), 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
}
}
static void
PAUDIO_PlayDevice(_THIS)
{
int written = 0;
const Uint8 *mixbuf = this->hidden->mixbuf;
const size_t mixlen = this->hidden->mixlen;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
written = write(this->hidden->audio_fd, mixbuf, mixlen);
if ((written < 0) && ((errno == 0) || (errno == EAGAIN))) {
SDL_Delay(1); /* Let a little CPU time go by */
}
} while ((written < 0) &&
((errno == 0) || (errno == EAGAIN) || (errno == EINTR)));
/* 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);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
}
static Uint8 *
PAUDIO_GetDeviceBuf(_THIS)
{
return this->hidden->mixbuf;
}
static void
PAUDIO_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
const char *workaround = SDL_getenv("SDL_DSP_NOSELECT");
char audiodev[1024];
const char *err = NULL;
int format;
int bytes_per_sample;
SDL_AudioFormat test_format;
audio_init paud_init;
audio_buffer paud_bufinfo;
audio_status paud_status;
audio_control paud_control;
audio_change paud_change;
int fd = -1;
/* Initialize all variables that we clean on shutdown */
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));
/* Open the audio device */
fd = OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
this->hidden->audio_fd = fd;
if (fd < 0) {
PAUDIO_CloseDevice(this);
return SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
}
/*
* We can't set the buffer size - just ask the device for the maximum
* that we can have.
*/
if (ioctl(fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
PAUDIO_CloseDevice(this);
return SDL_SetError("Couldn't get audio buffer information");
}
if (this->spec.channels > 1)
this->spec.channels = 2;
else
this->spec.channels = 1;
/*
* Fields in the audio_init structure:
*
* Ignored by us:
*
* paud.loadpath[LOAD_PATH]; * DSP code to load, MWave chip only?
* paud.slot_number; * slot number of the adapter
* paud.device_id; * adapter identification number
*
* Input:
*
* paud.srate; * the sampling rate in Hz
* paud.bits_per_sample; * 8, 16, 32, ...
* paud.bsize; * block size for this rate
* paud.mode; * ADPCM, PCM, MU_LAW, A_LAW, SOURCE_MIX
* paud.channels; * 1=mono, 2=stereo
* paud.flags; * FIXED - fixed length data
* * LEFT_ALIGNED, RIGHT_ALIGNED (var len only)
* * TWOS_COMPLEMENT - 2's complement data
* * SIGNED - signed? comment seems wrong in sys/audio.h
* * BIG_ENDIAN
* paud.operation; * PLAY, RECORD
*
* Output:
*
* paud.flags; * PITCH - pitch is supported
* * INPUT - input is supported
* * OUTPUT - output is supported
* * MONITOR - monitor is supported
* * VOLUME - volume is supported
* * VOLUME_DELAY - volume delay is supported
* * BALANCE - balance is supported
* * BALANCE_DELAY - balance delay is supported
* * TREBLE - treble control is supported
* * BASS - bass control is supported
* * BESTFIT_PROVIDED - best fit returned
* * LOAD_CODE - DSP load needed
* paud.rc; * NO_PLAY - DSP code can't do play requests
* * NO_RECORD - DSP code can't do record requests
* * INVALID_REQUEST - request was invalid
* * CONFLICT - conflict with open's flags
* * OVERLOADED - out of DSP MIPS or memory
* paud.position_resolution; * smallest increment for position
*/
paud_init.srate = this->spec.freq;
paud_init.mode = PCM;
paud_init.operation = PLAY;
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;) {
#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;
break;
case AUDIO_S8:
bytes_per_sample = 1;
paud_init.bits_per_sample = 8;
paud_init.flags = SIGNED | TWOS_COMPLEMENT | FIXED;
format = 1;
break;
case AUDIO_S16LSB:
bytes_per_sample = 2;
paud_init.bits_per_sample = 16;
paud_init.flags = SIGNED | TWOS_COMPLEMENT | FIXED;
format = 1;
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;
break;
case AUDIO_U16LSB:
bytes_per_sample = 2;
paud_init.bits_per_sample = 16;
paud_init.flags = TWOS_COMPLEMENT | FIXED;
format = 1;
break;
case AUDIO_U16MSB:
bytes_per_sample = 2;
paud_init.bits_per_sample = 16;
paud_init.flags = BIG_ENDIAN | TWOS_COMPLEMENT | FIXED;
format = 1;
break;
default:
break;
}
if (!format) {
test_format = SDL_NextAudioFormat();
}
}
if (format == 0) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Couldn't find any hardware audio formats\n");
#endif
PAUDIO_CloseDevice(this);
return SDL_SetError("Couldn't find any hardware audio formats");
}
this->spec.format = test_format;
/*
* We know the buffer size and the max number of subsequent writes
* that can be pending. If more than one can pend, allow the application
* to do something like double buffering between our write buffer and
* the device's own buffer that we are filling with write() anyway.
*
* We calculate this->spec.samples like this because
* SDL_CalculateAudioSpec() will give put paud_bufinfo.write_buf_cap
* (or paud_bufinfo.write_buf_cap/2) into this->spec.size in return.
*/
if (paud_bufinfo.request_buf_cap == 1) {
this->spec.samples = paud_bufinfo.write_buf_cap
/ bytes_per_sample / this->spec.channels;
} else {
this->spec.samples = paud_bufinfo.write_buf_cap
/ bytes_per_sample / this->spec.channels / 2;
}
paud_init.bsize = bytes_per_sample * this->spec.channels;
SDL_CalculateAudioSpec(&this->spec);
/*
* The AIX paud device init can't modify the values of the audio_init
* structure that we pass to it. So we don't need any recalculation
* of this stuff and no reinit call as in linux dsp code.
*
* /dev/paud supports all of the encoding formats, so we don't need
* to do anything like reopening the device, either.
*/
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";
break;
case 2:
err = "Couldn't set audio format: DSP can't do record requests";
break;
case 4:
err = "Couldn't set audio format: request was invalid";
break;
case 5:
err = "Couldn't set audio format: conflict with open's flags";
break;
case 6:
err = "Couldn't set audio format: out of DSP MIPS or memory";
break;
default:
err = "Couldn't set audio format: not documented in sys/audio.h";
break;
}
}
if (err != NULL) {
PAUDIO_CloseDevice(this);
return SDL_SetError("Paudio: %s", err);
}
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
PAUDIO_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/*
* Set some paramters: full volume, first speaker that we can find.
* Ignore the other settings for now.
*/
paud_change.input = AUDIO_IGNORE; /* the new input source */
paud_change.output = OUTPUT_1; /* EXTERNAL_SPEAKER,INTERNAL_SPEAKER,OUTPUT_1 */
paud_change.monitor = AUDIO_IGNORE; /* the new monitor state */
paud_change.volume = 0x7fffffff; /* volume level [0-0x7fffffff] */
paud_change.volume_delay = AUDIO_IGNORE; /* the new volume delay */
paud_change.balance = 0x3fffffff; /* the new balance */
paud_change.balance_delay = AUDIO_IGNORE; /* the new balance delay */
paud_change.treble = AUDIO_IGNORE; /* the new treble state */
paud_change.bass = AUDIO_IGNORE; /* the new bass state */
paud_change.pitch = AUDIO_IGNORE; /* the new pitch state */
paud_control.ioctl_request = AUDIO_CHANGE;
paud_control.request_info = (char *) &paud_change;
if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
#ifdef DEBUG_AUDIO
fprintf(stderr, "Can't change audio display settings\n");
#endif
}
/*
* Tell the device to expect data. Actual start will wait for
* the first write() call.
*/
paud_control.ioctl_request = AUDIO_START;
paud_control.position = 0;
if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
PAUDIO_CloseDevice(this);
#ifdef DEBUG_AUDIO
fprintf(stderr, "Can't start audio play\n");
#endif
return SDL_SetError("Can't start audio play");
}
/* Check to see if we need to use select() workaround */
if (workaround != NULL) {
this->hidden->frame_ticks = (float) (this->spec.samples * 1000) /
this->spec.freq;
this->hidden->next_frame = SDL_GetTicks() + this->hidden->frame_ticks;
}
/* We're ready to rock and roll. :-) */
return 0;
}
static int
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;
}
close(fd);
/* Set the function pointers */
impl->OpenDevice = DSP_OpenDevice;
impl->PlayDevice = DSP_PlayDevice;
impl->PlayDevice = DSP_WaitDevice;
impl->GetDeviceBuf = DSP_GetDeviceBuf;
impl->CloseDevice = DSP_CloseDevice;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: add device enum! */
return 1; /* this audio target is available. */
}
AudioBootStrap PAUDIO_bootstrap = {
"paud", "AIX Paudio", PAUDIO_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_PAUDIO */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,47 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_paudaudio_h
#define _SDL_paudaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* The file descriptor for the audio device */
int audio_fd;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
/* Support for audio timing using a timer, in addition to select() */
float frame_ticks;
float next_frame;
};
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
#endif /* _SDL_paudaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,199 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_PSP
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include "SDL_audio.h"
#include "SDL_error.h"
#include "SDL_timer.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_pspaudio.h"
#include <pspaudio.h>
#include <pspthreadman.h>
/* The tag name used by PSP audio */
#define PSPAUD_DRIVER_NAME "psp"
static int
PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
int format, mixlen, i;
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));
switch (this->spec.format & 0xff) {
case 8:
case 16:
this->spec.format = AUDIO_S16LSB;
break;
default:
return SDL_SetError("Unsupported audio format");
}
/* The sample count must be a multiple of 64. */
this->spec.samples = PSP_AUDIO_SAMPLE_ALIGN(this->spec.samples);
this->spec.freq = 44100;
/* Update the fragment size as size in bytes. */
/* SDL_CalculateAudioSpec(this->spec); MOD */
switch (this->spec.format) {
case AUDIO_U8:
this->spec.silence = 0x80;
break;
default:
this->spec.silence = 0x00;
break;
}
this->spec.size = SDL_AUDIO_BITSIZE(this->spec.format) / 8;
this->spec.size *= this->spec.channels;
this->spec.size *= this->spec.samples;
/* ========================================== */
/* 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 = PSP_AUDIO_FORMAT_MONO;
} else {
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);
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 PSPAUD_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);
} else {
sceAudioOutputPannedBlocking(this->hidden->channel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, 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 PSPAUD_WaitDevice(_THIS)
{
/* Because we block when sending audio, there's no need for this function to do anything. */
}
static Uint8 *PSPAUD_GetDeviceBuf(_THIS)
{
return this->hidden->mixbufs[this->hidden->next_buffer];
}
static void PSPAUD_CloseDevice(_THIS)
{
if (this->hidden->channel >= 0) {
sceAudioChRelease(this->hidden->channel);
this->hidden->channel = -1;
}
if (this->hidden->rawbuf != NULL) {
free(this->hidden->rawbuf);
this->hidden->rawbuf = NULL;
}
}
static void PSPAUD_ThreadInit(_THIS)
{
/* Increase the priority of this audio thread by 1 to put it
ahead of other SDL threads. */
SceUID thid;
SceKernelThreadInfo status;
thid = sceKernelGetThreadId();
status.size = sizeof(SceKernelThreadInfo);
if (sceKernelReferThreadStatus(thid, &status) == 0) {
sceKernelChangeThreadPriority(thid, status.currentPriority - 1);
}
}
static int
PSPAUD_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->OpenDevice = PSPAUD_OpenDevice;
impl->PlayDevice = PSPAUD_PlayDevice;
impl->WaitDevice = PSPAUD_WaitDevice;
impl->GetDeviceBuf = PSPAUD_GetDeviceBuf;
impl->WaitDone = PSPAUD_WaitDevice;
impl->CloseDevice = PSPAUD_CloseDevice;
impl->ThreadInit = PSPAUD_ThreadInit;
/* PSP audio device */
impl->OnlyHasDefaultOutputDevice = 1;
/*
impl->HasCaptureSupport = 1;
impl->OnlyHasDefaultInputDevice = 1;
*/
/*
impl->DetectDevices = DSOUND_DetectDevices;
impl->Deinitialize = DSOUND_Deinitialize;
*/
return 1; /* this audio target is available. */
}
AudioBootStrap PSPAUD_bootstrap = {
"psp", "PSP audio driver", PSPAUD_Init, 0
};
/* SDL_AUDI */
#endif /* SDL_AUDIO_DRIVER_PSP */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,45 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_pspaudio_h
#define _SDL_pspaudio_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 output channel. */
int channel;
/* 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_pspaudio_h */
/* vim: ts=4 sw=4
*/

View File

@@ -0,0 +1,699 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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.
*/
/*
The PulseAudio target for SDL 1.3 is based on the 1.3 arts target, with
the appropriate parts replaced with the 1.2 PulseAudio target code. This
was the cleanest way to move it to 1.3. The 1.2 target was written by
Stéphan Kochen: stephan .a.t. kochen.nl
*/
#include "../../SDL_internal.h"
#include "SDL_assert.h"
#if SDL_AUDIO_DRIVER_PULSEAUDIO
/* Allow access to a raw mixing buffer */
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <pulse/pulseaudio.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_pulseaudio.h"
#include "SDL_loadso.h"
#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) {
return
x == PA_CONTEXT_CONNECTING ||
x == PA_CONTEXT_AUTHORIZING ||
x == PA_CONTEXT_SETTING_NAME ||
x == PA_CONTEXT_READY;
}
/** Return non-zero if the passed state is one of the connected states */
static SDL_INLINE int PA_STREAM_IS_GOOD(pa_stream_state_t x) {
return
x == PA_STREAM_CREATING ||
x == PA_STREAM_READY;
}
#endif /* pulseaudio <= 0.9.10 */
static const char *(*PULSEAUDIO_pa_get_library_version) (void);
static pa_channel_map *(*PULSEAUDIO_pa_channel_map_init_auto) (
pa_channel_map *, unsigned, pa_channel_map_def_t);
static const char * (*PULSEAUDIO_pa_strerror) (int);
static pa_mainloop * (*PULSEAUDIO_pa_mainloop_new) (void);
static pa_mainloop_api * (*PULSEAUDIO_pa_mainloop_get_api) (pa_mainloop *);
static int (*PULSEAUDIO_pa_mainloop_iterate) (pa_mainloop *, int, int *);
static int (*PULSEAUDIO_pa_mainloop_run) (pa_mainloop *, int *);
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 *);
static void (*PULSEAUDIO_pa_operation_cancel) (pa_operation *);
static void (*PULSEAUDIO_pa_operation_unref) (pa_operation *);
static pa_context * (*PULSEAUDIO_pa_context_new) (pa_mainloop_api *,
const char *);
static int (*PULSEAUDIO_pa_context_connect) (pa_context *, const char *,
pa_context_flags_t, const pa_spawn_api *);
static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_list) (pa_context *, pa_sink_info_cb_t, void *);
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_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 *);
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 *);
static pa_stream_state_t (*PULSEAUDIO_pa_stream_get_state) (pa_stream *);
static size_t (*PULSEAUDIO_pa_stream_writable_size) (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 *,
pa_stream_success_cb_t, void *);
static int (*PULSEAUDIO_pa_stream_disconnect) (pa_stream *);
static void (*PULSEAUDIO_pa_stream_unref) (pa_stream *);
static int load_pulseaudio_syms(void);
#ifdef SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC
static const char *pulseaudio_library = SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC;
static void *pulseaudio_handle = NULL;
static int
load_pulseaudio_sym(const char *fn, void **addr)
{
*addr = SDL_LoadFunction(pulseaudio_handle, fn);
if (*addr == NULL) {
/* Don't call SDL_SetError(): SDL_LoadFunction already did. */
return 0;
}
return 1;
}
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
#define SDL_PULSEAUDIO_SYM(x) \
if (!load_pulseaudio_sym(#x, (void **) (char *) &PULSEAUDIO_##x)) return -1
static void
UnloadPulseAudioLibrary(void)
{
if (pulseaudio_handle != NULL) {
SDL_UnloadObject(pulseaudio_handle);
pulseaudio_handle = NULL;
}
}
static int
LoadPulseAudioLibrary(void)
{
int retval = 0;
if (pulseaudio_handle == NULL) {
pulseaudio_handle = SDL_LoadObject(pulseaudio_library);
if (pulseaudio_handle == NULL) {
retval = -1;
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
} else {
retval = load_pulseaudio_syms();
if (retval < 0) {
UnloadPulseAudioLibrary();
}
}
}
return retval;
}
#else
#define SDL_PULSEAUDIO_SYM(x) PULSEAUDIO_##x = x
static void
UnloadPulseAudioLibrary(void)
{
}
static int
LoadPulseAudioLibrary(void)
{
load_pulseaudio_syms();
return 0;
}
#endif /* SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC */
static int
load_pulseaudio_syms(void)
{
SDL_PULSEAUDIO_SYM(pa_get_library_version);
SDL_PULSEAUDIO_SYM(pa_mainloop_new);
SDL_PULSEAUDIO_SYM(pa_mainloop_get_api);
SDL_PULSEAUDIO_SYM(pa_mainloop_iterate);
SDL_PULSEAUDIO_SYM(pa_mainloop_run);
SDL_PULSEAUDIO_SYM(pa_mainloop_quit);
SDL_PULSEAUDIO_SYM(pa_mainloop_free);
SDL_PULSEAUDIO_SYM(pa_operation_get_state);
SDL_PULSEAUDIO_SYM(pa_operation_cancel);
SDL_PULSEAUDIO_SYM(pa_operation_unref);
SDL_PULSEAUDIO_SYM(pa_context_new);
SDL_PULSEAUDIO_SYM(pa_context_connect);
SDL_PULSEAUDIO_SYM(pa_context_get_sink_info_list);
SDL_PULSEAUDIO_SYM(pa_context_get_source_info_list);
SDL_PULSEAUDIO_SYM(pa_context_get_sink_info_by_index);
SDL_PULSEAUDIO_SYM(pa_context_get_source_info_by_index);
SDL_PULSEAUDIO_SYM(pa_context_get_state);
SDL_PULSEAUDIO_SYM(pa_context_subscribe);
SDL_PULSEAUDIO_SYM(pa_context_set_subscribe_callback);
SDL_PULSEAUDIO_SYM(pa_context_disconnect);
SDL_PULSEAUDIO_SYM(pa_context_unref);
SDL_PULSEAUDIO_SYM(pa_stream_new);
SDL_PULSEAUDIO_SYM(pa_stream_connect_playback);
SDL_PULSEAUDIO_SYM(pa_stream_get_state);
SDL_PULSEAUDIO_SYM(pa_stream_writable_size);
SDL_PULSEAUDIO_SYM(pa_stream_write);
SDL_PULSEAUDIO_SYM(pa_stream_drain);
SDL_PULSEAUDIO_SYM(pa_stream_disconnect);
SDL_PULSEAUDIO_SYM(pa_stream_unref);
SDL_PULSEAUDIO_SYM(pa_channel_map_init_auto);
SDL_PULSEAUDIO_SYM(pa_strerror);
return 0;
}
static SDL_INLINE int
squashVersion(const int major, const int minor, const int patch)
{
return ((major & 0xFF) << 16) | ((minor & 0xFF) << 8) | (patch & 0xFF);
}
/* Workaround for older pulse: pa_context_new() must have non-NULL appname */
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. */
}
}
}
return "SDL Application"; /* oh well. */
}
static void
WaitForPulseOperation(pa_mainloop *mainloop, pa_operation *o)
{
/* This checks for NO errors currently. Either fix that, check results elsewhere, or do things you don't care about. */
if (mainloop && o) {
SDL_bool okay = SDL_TRUE;
while (okay && (PULSEAUDIO_pa_operation_get_state(o) == PA_OPERATION_RUNNING)) {
okay = (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1, NULL) >= 0);
}
PULSEAUDIO_pa_operation_unref(o);
}
}
static void
DisconnectFromPulseServer(pa_mainloop *mainloop, pa_context *context)
{
if (context) {
PULSEAUDIO_pa_context_disconnect(context);
PULSEAUDIO_pa_context_unref(context);
}
if (mainloop != NULL) {
PULSEAUDIO_pa_mainloop_free(mainloop);
}
}
static int
ConnectToPulseServer_Internal(pa_mainloop **_mainloop, pa_context **_context)
{
pa_mainloop *mainloop = NULL;
pa_context *context = NULL;
pa_mainloop_api *mainloop_api = NULL;
int state = 0;
*_mainloop = NULL;
*_context = NULL;
/* Set up a new main loop */
if (!(mainloop = PULSEAUDIO_pa_mainloop_new())) {
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) {
return SDL_SetError("pa_context_new() failed");
}
*_context = context;
/* Connect to the PulseAudio server */
if (PULSEAUDIO_pa_context_connect(context, NULL, 0, NULL) < 0) {
return SDL_SetError("Could not setup connection to PulseAudio");
}
do {
if (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1, NULL) < 0) {
return SDL_SetError("pa_mainloop_iterate() failed");
}
state = PULSEAUDIO_pa_context_get_state(context);
if (!PA_CONTEXT_IS_GOOD(state)) {
return SDL_SetError("Could not connect to PulseAudio");
}
} while (state != PA_CONTEXT_READY);
return 0; /* connected and ready! */
}
static int
ConnectToPulseServer(pa_mainloop **_mainloop, pa_context **_context)
{
const int retval = ConnectToPulseServer_Internal(_mainloop, _context);
if (retval < 0) {
DisconnectFromPulseServer(*_mainloop, *_context);
}
return retval;
}
/* This function waits until it is possible to write a full sound buffer */
static void
PULSEAUDIO_WaitDevice(_THIS)
{
struct SDL_PrivateAudioData *h = this->hidden;
while (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) {
SDL_OpenedAudioDeviceDisconnected(this);
return;
}
if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= h->mixlen) {
return;
}
}
}
static void
PULSEAUDIO_PlayDevice(_THIS)
{
/* Write the audio data */
struct SDL_PrivateAudioData *h = this->hidden;
if (this->enabled) {
if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0) {
SDL_OpenedAudioDeviceDisconnected(this);
}
}
}
static void
stream_drain_complete(pa_stream *s, int success, void *userdata)
{
/* no-op for pa_stream_drain() to use for callback. */
}
static void
PULSEAUDIO_WaitDone(_THIS)
{
if (this->enabled) {
struct SDL_PrivateAudioData *h = this->hidden;
pa_operation *o = PULSEAUDIO_pa_stream_drain(h->stream, stream_drain_complete, NULL);
if (o) {
while (PULSEAUDIO_pa_operation_get_state(o) != PA_OPERATION_DONE) {
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) {
PULSEAUDIO_pa_operation_cancel(o);
break;
}
}
PULSEAUDIO_pa_operation_unref(o);
}
}
}
static Uint8 *
PULSEAUDIO_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static void
PULSEAUDIO_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
SDL_free(this->hidden->device_name);
if (this->hidden->stream) {
PULSEAUDIO_pa_stream_disconnect(this->hidden->stream);
PULSEAUDIO_pa_stream_unref(this->hidden->stream);
}
DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context);
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static void
DeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
{
if (i) {
char **devname = (char **) data;
*devname = SDL_strdup(i->name);
}
}
static SDL_bool
FindDeviceName(struct SDL_PrivateAudioData *h, void *handle)
{
const uint32_t idx = ((uint32_t) ((size_t) handle)) - 1;
if (handle == NULL) { /* NULL == default device. */
return SDL_TRUE;
}
WaitForPulseOperation(h->mainloop, PULSEAUDIO_pa_context_get_sink_info_by_index(h->context, idx, DeviceNameCallback, &h->device_name));
return (h->device_name != NULL);
}
static int
PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
struct SDL_PrivateAudioData *h = NULL;
Uint16 test_format = 0;
pa_sample_spec paspec;
pa_buffer_attr paattr;
pa_channel_map pacmap;
pa_stream_flags_t flags = 0;
int state = 0;
/* Initialize all variables that we clean on shutdown */
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));
h = 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;) {
#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;
break;
case AUDIO_S16LSB:
paspec.format = PA_SAMPLE_S16LE;
break;
case AUDIO_S16MSB:
paspec.format = PA_SAMPLE_S16BE;
break;
case AUDIO_S32LSB:
paspec.format = PA_SAMPLE_S32LE;
break;
case AUDIO_S32MSB:
paspec.format = PA_SAMPLE_S32BE;
break;
case AUDIO_F32LSB:
paspec.format = PA_SAMPLE_FLOAT32LE;
break;
case AUDIO_F32MSB:
paspec.format = PA_SAMPLE_FLOAT32BE;
break;
default:
paspec.format = PA_SAMPLE_INVALID;
break;
}
if (paspec.format == PA_SAMPLE_INVALID) {
test_format = SDL_NextAudioFormat();
}
}
if (paspec.format == PA_SAMPLE_INVALID) {
PULSEAUDIO_CloseDevice(this);
return SDL_SetError("Couldn't find any hardware audio formats");
}
this->spec.format = test_format;
/* Calculate the final parameters for this audio specification */
#ifdef PA_STREAM_ADJUST_LATENCY
this->spec.samples /= 2; /* Mix in smaller chunck to avoid underruns */
#endif
SDL_CalculateAudioSpec(&this->spec);
/* Allocate mixing buffer */
h->mixlen = this->spec.size;
h->mixbuf = (Uint8 *) SDL_AllocAudioMem(h->mixlen);
if (h->mixbuf == NULL) {
PULSEAUDIO_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(h->mixbuf, this->spec.silence, this->spec.size);
paspec.channels = this->spec.channels;
paspec.rate = this->spec.freq;
/* Reduced prebuffering compared to the defaults. */
#ifdef PA_STREAM_ADJUST_LATENCY
/* 2x original requested bufsize */
paattr.tlength = h->mixlen * 4;
paattr.prebuf = -1;
paattr.maxlength = -1;
/* -1 can lead to pa_stream_writable_size() >= mixlen never being true */
paattr.minreq = h->mixlen;
flags = PA_STREAM_ADJUST_LATENCY;
#else
paattr.tlength = h->mixlen*2;
paattr.prebuf = h->mixlen*2;
paattr.maxlength = h->mixlen*2;
paattr.minreq = h->mixlen;
#endif
if (ConnectToPulseServer(&h->mainloop, &h->context) < 0) {
PULSEAUDIO_CloseDevice(this);
return SDL_SetError("Could not connect to PulseAudio server");
}
if (!FindDeviceName(h, handle)) {
PULSEAUDIO_CloseDevice(this);
return SDL_SetError("Requested PulseAudio sink missing?");
}
/* The SDL ALSA output hints us that we use Windows' channel mapping */
/* http://bugzilla.libsdl.org/show_bug.cgi?id=110 */
PULSEAUDIO_pa_channel_map_init_auto(&pacmap, this->spec.channels,
PA_CHANNEL_MAP_WAVEEX);
h->stream = PULSEAUDIO_pa_stream_new(
h->context,
"Simple DirectMedia Layer", /* stream description */
&paspec, /* sample format spec */
&pacmap /* channel map */
);
if (h->stream == NULL) {
PULSEAUDIO_CloseDevice(this);
return SDL_SetError("Could not set up PulseAudio stream");
}
/* now that we have multi-device support, don't move a stream from
a device that was unplugged to something else, unless we're default. */
if (h->device_name != NULL) {
flags |= PA_STREAM_DONT_MOVE;
}
if (PULSEAUDIO_pa_stream_connect_playback(h->stream, h->device_name, &paattr, flags,
NULL, NULL) < 0) {
PULSEAUDIO_CloseDevice(this);
return SDL_SetError("Could not connect PulseAudio stream");
}
do {
if (PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
PULSEAUDIO_CloseDevice(this);
return SDL_SetError("pa_mainloop_iterate() failed");
}
state = PULSEAUDIO_pa_stream_get_state(h->stream);
if (!PA_STREAM_IS_GOOD(state)) {
PULSEAUDIO_CloseDevice(this);
return SDL_SetError("Could not connect PulseAudio stream");
}
} while (state != PA_STREAM_READY);
/* We're ready to rock and roll. :-) */
return 0;
}
static pa_mainloop *hotplug_mainloop = NULL;
static pa_context *hotplug_context = NULL;
static SDL_Thread *hotplug_thread = NULL;
/* device handles are device index + 1, cast to void*, so we never pass a NULL. */
/* 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)
{
if (i) {
SDL_AddAudioDevice(SDL_FALSE, i->description, (void *) ((size_t) i->index+1));
}
}
/* This is called when PulseAudio adds a capture ("source") device. */
static void
SourceInfoCallback(pa_context *c, const pa_source_info *i, int is_last, void *data)
{
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));
}
}
}
/* This is called when PulseAudio has a device connected/removed/changed. */
static void
HotplugCallback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *data)
{
const SDL_bool added = ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW);
const SDL_bool removed = ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE);
if (added || removed) { /* we only care about add/remove events. */
const SDL_bool sink = ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK);
const SDL_bool source = ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
/* adds need sink details from the PulseAudio server. Another callback... */
if (added && sink) {
PULSEAUDIO_pa_context_get_sink_info_by_index(hotplug_context, idx, SinkInfoCallback, NULL);
} else if (added && source) {
PULSEAUDIO_pa_context_get_source_info_by_index(hotplug_context, idx, SourceInfoCallback, NULL);
} else if (removed && (sink || source)) {
/* removes we can handle just with the device index. */
SDL_RemoveAudioDevice(source != 0, (void *) ((size_t) idx+1));
}
}
}
/* this runs as a thread while the Pulse target is initialized to catch hotplug events. */
static int SDLCALL
HotplugThread(void *data)
{
pa_operation *o;
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_LOW);
PULSEAUDIO_pa_context_set_subscribe_callback(hotplug_context, HotplugCallback, NULL);
o = PULSEAUDIO_pa_context_subscribe(hotplug_context, PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE, NULL, NULL);
PULSEAUDIO_pa_operation_unref(o); /* don't wait for it, just do our thing. */
PULSEAUDIO_pa_mainloop_run(hotplug_mainloop, NULL);
return 0;
}
static void
PULSEAUDIO_DetectDevices()
{
WaitForPulseOperation(hotplug_mainloop, PULSEAUDIO_pa_context_get_sink_info_list(hotplug_context, SinkInfoCallback, NULL));
WaitForPulseOperation(hotplug_mainloop, PULSEAUDIO_pa_context_get_source_info_list(hotplug_context, SourceInfoCallback, NULL));
/* ok, we have a sane list, let's set up hotplug notifications now... */
hotplug_thread = SDL_CreateThread(HotplugThread, "PulseHotplug", NULL);
}
static void
PULSEAUDIO_Deinitialize(void)
{
if (hotplug_thread) {
PULSEAUDIO_pa_mainloop_quit(hotplug_mainloop, 0);
SDL_WaitThread(hotplug_thread, NULL);
hotplug_thread = NULL;
}
DisconnectFromPulseServer(hotplug_mainloop, hotplug_context);
hotplug_mainloop = NULL;
hotplug_context = NULL;
UnloadPulseAudioLibrary();
}
static int
PULSEAUDIO_Init(SDL_AudioDriverImpl * impl)
{
if (LoadPulseAudioLibrary() < 0) {
return 0;
}
if (ConnectToPulseServer(&hotplug_mainloop, &hotplug_context) < 0) {
UnloadPulseAudioLibrary();
return 0;
}
/* Set the function pointers */
impl->DetectDevices = PULSEAUDIO_DetectDevices;
impl->OpenDevice = PULSEAUDIO_OpenDevice;
impl->PlayDevice = PULSEAUDIO_PlayDevice;
impl->WaitDevice = PULSEAUDIO_WaitDevice;
impl->GetDeviceBuf = PULSEAUDIO_GetDeviceBuf;
impl->CloseDevice = PULSEAUDIO_CloseDevice;
impl->WaitDone = PULSEAUDIO_WaitDone;
impl->Deinitialize = PULSEAUDIO_Deinitialize;
return 1; /* this audio target is available. */
}
AudioBootStrap PULSEAUDIO_bootstrap = {
"pulseaudio", "PulseAudio", PULSEAUDIO_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_PULSEAUDIO */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,49 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_pulseaudio_h
#define _SDL_pulseaudio_h
#include <pulse/simple.h>
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
char *device_name;
/* pulseaudio structures */
pa_mainloop *mainloop;
pa_context *context;
pa_stream *stream;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
};
#endif /* _SDL_pulseaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,809 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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.
*/
/*
* !!! FIXME: streamline this a little by removing all the
* !!! FIXME: if (capture) {} else {} sections that are identical
* !!! FIXME: except for one flag.
*/
/* !!! FIXME: can this target support hotplugging? */
/* !!! FIXME: ...does SDL2 even support QNX? */
#include "../../SDL_internal.h"
#if SDL_AUDIO_DRIVER_QSA
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sched.h>
#include <sys/select.h>
#include <sys/neutrino.h>
#include <sys/asoundlib.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_qsa_audio.h"
/* default channel communication parameters */
#define DEFAULT_CPARAMS_RATE 44100
#define DEFAULT_CPARAMS_VOICES 1
#define DEFAULT_CPARAMS_FRAG_SIZE 4096
#define DEFAULT_CPARAMS_FRAGS_MIN 1
#define DEFAULT_CPARAMS_FRAGS_MAX 1
#define QSA_NO_WORKAROUNDS 0x00000000
#define QSA_MMAP_WORKAROUND 0x00000001
struct BuggyCards
{
char *cardname;
unsigned long bugtype;
};
#define QSA_WA_CARDS 3
#define QSA_MAX_CARD_NAME_LENGTH 33
struct BuggyCards buggycards[QSA_WA_CARDS] = {
{"Sound Blaster Live!", QSA_MMAP_WORKAROUND},
{"Vortex 8820", QSA_MMAP_WORKAROUND},
{"Vortex 8830", QSA_MMAP_WORKAROUND},
};
/* List of found devices */
#define QSA_MAX_DEVICES 32
#define QSA_MAX_NAME_LENGTH 81+16 /* Hardcoded in QSA, can't be changed */
typedef struct _QSA_Device
{
char name[QSA_MAX_NAME_LENGTH]; /* Long audio device name for SDL */
int cardno;
int deviceno;
} QSA_Device;
QSA_Device qsa_playback_device[QSA_MAX_DEVICES];
uint32_t qsa_playback_devices;
QSA_Device qsa_capture_device[QSA_MAX_DEVICES];
uint32_t qsa_capture_devices;
static SDL_INLINE int
QSA_SetError(const char *fn, int status)
{
return SDL_SetError("QSA: %s() failed: %s", fn, snd_strerror(status));
}
/* card names check to apply the workarounds */
static int
QSA_CheckBuggyCards(_THIS, unsigned long checkfor)
{
char scardname[QSA_MAX_CARD_NAME_LENGTH];
int it;
if (snd_card_get_name
(this->hidden->cardno, scardname, QSA_MAX_CARD_NAME_LENGTH - 1) < 0) {
return 0;
}
for (it = 0; it < QSA_WA_CARDS; it++) {
if (SDL_strcmp(buggycards[it].cardname, scardname) == 0) {
if (buggycards[it].bugtype == checkfor) {
return 1;
}
}
}
return 0;
}
/* !!! FIXME: does this need to be here? Does the SDL version not work? */
static void
QSA_ThreadInit(_THIS)
{
struct sched_param param;
int status;
/* Increase default 10 priority to 25 to avoid jerky sound */
status = SchedGet(0, 0, &param);
param.sched_priority = param.sched_curpriority + 15;
status = SchedSet(0, 0, SCHED_NOCHANGE, &param);
}
/* PCM channel parameters initialize function */
static void
QSA_InitAudioParams(snd_pcm_channel_params_t * cpars)
{
SDL_memset(cpars, 0, sizeof(snd_pcm_channel_params_t));
cpars->channel = SND_PCM_CHANNEL_PLAYBACK;
cpars->mode = SND_PCM_MODE_BLOCK;
cpars->start_mode = SND_PCM_START_DATA;
cpars->stop_mode = SND_PCM_STOP_STOP;
cpars->format.format = SND_PCM_SFMT_S16_LE;
cpars->format.interleave = 1;
cpars->format.rate = DEFAULT_CPARAMS_RATE;
cpars->format.voices = DEFAULT_CPARAMS_VOICES;
cpars->buf.block.frag_size = DEFAULT_CPARAMS_FRAG_SIZE;
cpars->buf.block.frags_min = DEFAULT_CPARAMS_FRAGS_MIN;
cpars->buf.block.frags_max = DEFAULT_CPARAMS_FRAGS_MAX;
}
/* This function waits until it is possible to write a full sound buffer */
static void
QSA_WaitDevice(_THIS)
{
fd_set wfds;
fd_set rfds;
int selectret;
struct timeval timeout;
if (!this->hidden->iscapture) {
FD_ZERO(&wfds);
FD_SET(this->hidden->audio_fd, &wfds);
} else {
FD_ZERO(&rfds);
FD_SET(this->hidden->audio_fd, &rfds);
}
do {
/* Setup timeout for playing one fragment equal to 2 seconds */
/* 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 ! */
timeout.tv_sec = 2;
timeout.tv_usec = 0;
this->hidden->timeout_on_wait = 0;
if (!this->hidden->iscapture) {
selectret =
select(this->hidden->audio_fd + 1, NULL, &wfds, NULL,
&timeout);
} else {
selectret =
select(this->hidden->audio_fd + 1, &rfds, NULL, NULL,
&timeout);
}
switch (selectret) {
case -1:
{
SDL_SetError("QSA: select() failed: %s", strerror(errno));
return;
}
break;
case 0:
{
SDL_SetError("QSA: timeout on buffer waiting occured");
this->hidden->timeout_on_wait = 1;
return;
}
break;
default:
{
if (!this->hidden->iscapture) {
if (FD_ISSET(this->hidden->audio_fd, &wfds)) {
return;
}
} else {
if (FD_ISSET(this->hidden->audio_fd, &rfds)) {
return;
}
}
}
break;
}
} while (1);
}
static void
QSA_PlayDevice(_THIS)
{
snd_pcm_channel_status_t cstatus;
int written;
int status;
int towrite;
void *pcmbuffer;
if ((!this->enabled) || (!this->hidden)) {
return;
}
towrite = this->spec.size;
pcmbuffer = this->hidden->pcm_buf;
/* Write the audio data, checking for EAGAIN (buffer full) and underrun */
do {
written =
snd_pcm_plugin_write(this->hidden->audio_handle, pcmbuffer,
towrite);
if (written != towrite) {
/* Check if samples playback got stuck somewhere in hardware or in */
/* the audio device driver */
if ((errno == EAGAIN) && (written == 0)) {
if (this->hidden->timeout_on_wait != 0) {
SDL_SetError("QSA: buffer playback timeout");
return;
}
}
/* Check for errors or conditions */
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
/* Let a little CPU time go by and try to write again */
SDL_Delay(1);
/* if we wrote some data */
towrite -= written;
pcmbuffer += written * this->spec.channels;
continue;
} else {
if ((errno == EINVAL) || (errno == EIO)) {
SDL_memset(&cstatus, 0, sizeof(cstatus));
if (!this->hidden->iscapture) {
cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
} else {
cstatus.channel = SND_PCM_CHANNEL_CAPTURE;
}
status =
snd_pcm_plugin_status(this->hidden->audio_handle,
&cstatus);
if (status < 0) {
QSA_SetError("snd_pcm_plugin_status", status);
return;
}
if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) ||
(cstatus.status == SND_PCM_STATUS_READY)) {
if (!this->hidden->iscapture) {
status =
snd_pcm_plugin_prepare(this->hidden->
audio_handle,
SND_PCM_CHANNEL_PLAYBACK);
} else {
status =
snd_pcm_plugin_prepare(this->hidden->
audio_handle,
SND_PCM_CHANNEL_CAPTURE);
}
if (status < 0) {
QSA_SetError("snd_pcm_plugin_prepare", status);
return;
}
}
continue;
} else {
return;
}
}
} else {
/* we wrote all remaining data */
towrite -= written;
pcmbuffer += written * this->spec.channels;
}
} while ((towrite > 0) && (this->enabled));
/* If we couldn't write, assume fatal error for now */
if (towrite != 0) {
SDL_OpenedAudioDeviceDisconnected(this);
}
}
static Uint8 *
QSA_GetDeviceBuf(_THIS)
{
return this->hidden->pcm_buf;
}
static void
QSA_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
if (this->hidden->audio_handle != NULL) {
if (!this->hidden->iscapture) {
/* Finish playing available samples */
snd_pcm_plugin_flush(this->hidden->audio_handle,
SND_PCM_CHANNEL_PLAYBACK);
} else {
/* Cancel unread samples during capture */
snd_pcm_plugin_flush(this->hidden->audio_handle,
SND_PCM_CHANNEL_CAPTURE);
}
snd_pcm_close(this->hidden->audio_handle);
this->hidden->audio_handle = NULL;
}
SDL_FreeAudioMem(this->hidden->pcm_buf);
this->hidden->pcm_buf = NULL;
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
const QSA_Device *device = (const QSA_Device *) handle;
int status = 0;
int format = 0;
SDL_AudioFormat test_format = 0;
int found = 0;
snd_pcm_channel_setup_t csetup;
snd_pcm_channel_params_t cparams;
/* Initialize all variables that we clean on shutdown */
this->hidden =
(struct SDL_PrivateAudioData *) SDL_calloc(1,
(sizeof
(struct
SDL_PrivateAudioData)));
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData));
/* Initialize channel transfer parameters to default */
QSA_InitAudioParams(&cparams);
/* Initialize channel direction: capture or playback */
this->hidden->iscapture = iscapture;
if (device != NULL) {
/* Open requested audio device */
this->hidden->deviceno = device->deviceno;
this->hidden->cardno = device->cardno;
status = snd_pcm_open(&this->hidden->audio_handle,
device->cardno, device->deviceno,
iscapture ? SND_PCM_OPEN_PLAYBACK : SND_PCM_OPEN_CAPTURE);
} else {
/* Open system default audio device */
status = snd_pcm_open_preferred(&this->hidden->audio_handle,
&this->hidden->cardno,
&this->hidden->deviceno,
iscapture ? SND_PCM_OPEN_PLAYBACK : SND_PCM_OPEN_CAPTURE);
}
/* Check if requested device is opened */
if (status < 0) {
this->hidden->audio_handle = NULL;
QSA_CloseDevice(this);
return QSA_SetError("snd_pcm_open", status);
}
if (!QSA_CheckBuggyCards(this, QSA_MMAP_WORKAROUND)) {
/* Disable QSA MMAP plugin for buggy audio drivers */
status =
snd_pcm_plugin_set_disable(this->hidden->audio_handle,
PLUGIN_DISABLE_MMAP);
if (status < 0) {
QSA_CloseDevice(this);
return QSA_SetError("snd_pcm_plugin_set_disable", status);
}
}
/* 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;) {
/* if match found set format to equivalent QSA format */
switch (test_format) {
case AUDIO_U8:
{
format = SND_PCM_SFMT_U8;
found = 1;
}
break;
case AUDIO_S8:
{
format = SND_PCM_SFMT_S8;
found = 1;
}
break;
case AUDIO_S16LSB:
{
format = SND_PCM_SFMT_S16_LE;
found = 1;
}
break;
case AUDIO_S16MSB:
{
format = SND_PCM_SFMT_S16_BE;
found = 1;
}
break;
case AUDIO_U16LSB:
{
format = SND_PCM_SFMT_U16_LE;
found = 1;
}
break;
case AUDIO_U16MSB:
{
format = SND_PCM_SFMT_U16_BE;
found = 1;
}
break;
case AUDIO_S32LSB:
{
format = SND_PCM_SFMT_S32_LE;
found = 1;
}
break;
case AUDIO_S32MSB:
{
format = SND_PCM_SFMT_S32_BE;
found = 1;
}
break;
case AUDIO_F32LSB:
{
format = SND_PCM_SFMT_FLOAT_LE;
found = 1;
}
break;
case AUDIO_F32MSB:
{
format = SND_PCM_SFMT_FLOAT_BE;
found = 1;
}
break;
default:
{
break;
}
}
if (!found) {
test_format = SDL_NextAudioFormat();
}
}
/* assumes test_format not 0 on success */
if (test_format == 0) {
QSA_CloseDevice(this);
return SDL_SetError("QSA: Couldn't find any hardware audio formats");
}
this->spec.format = test_format;
/* Set the audio format */
cparams.format.format = format;
/* Set mono/stereo/4ch/6ch/8ch audio */
cparams.format.voices = this->spec.channels;
/* Set rate */
cparams.format.rate = this->spec.freq;
/* Setup the transfer parameters according to cparams */
status = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams);
if (status < 0) {
QSA_CloseDevice(this);
return QSA_SetError("snd_pcm_channel_params", status);
}
/* Make sure channel is setup right one last time */
SDL_memset(&csetup, 0, sizeof(csetup));
if (!this->hidden->iscapture) {
csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
} else {
csetup.channel = SND_PCM_CHANNEL_CAPTURE;
}
/* Setup an audio channel */
if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) {
QSA_CloseDevice(this);
return SDL_SetError("QSA: Unable to setup channel");
}
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&this->spec);
this->hidden->pcm_len = this->spec.size;
if (this->hidden->pcm_len == 0) {
this->hidden->pcm_len =
csetup.buf.block.frag_size * this->spec.channels *
(snd_pcm_format_width(format) / 8);
}
/*
* Allocate memory to the audio buffer and initialize with silence
* (Note that buffer size must be a multiple of fragment size, so find
* closest multiple)
*/
this->hidden->pcm_buf =
(Uint8 *) SDL_AllocAudioMem(this->hidden->pcm_len);
if (this->hidden->pcm_buf == NULL) {
QSA_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->pcm_buf, this->spec.silence,
this->hidden->pcm_len);
/* get the file descriptor */
if (!this->hidden->iscapture) {
this->hidden->audio_fd =
snd_pcm_file_descriptor(this->hidden->audio_handle,
SND_PCM_CHANNEL_PLAYBACK);
} else {
this->hidden->audio_fd =
snd_pcm_file_descriptor(this->hidden->audio_handle,
SND_PCM_CHANNEL_CAPTURE);
}
if (this->hidden->audio_fd < 0) {
QSA_CloseDevice(this);
return QSA_SetError("snd_pcm_file_descriptor", status);
}
/* Prepare an audio channel */
if (!this->hidden->iscapture) {
/* Prepare audio playback */
status =
snd_pcm_plugin_prepare(this->hidden->audio_handle,
SND_PCM_CHANNEL_PLAYBACK);
} else {
/* Prepare audio capture */
status =
snd_pcm_plugin_prepare(this->hidden->audio_handle,
SND_PCM_CHANNEL_CAPTURE);
}
if (status < 0) {
QSA_CloseDevice(this);
return QSA_SetError("snd_pcm_plugin_prepare", status);
}
/* We're really ready to rock and roll. :-) */
return 0;
}
static void
QSA_DetectDevices(void)
{
uint32_t it;
uint32_t cards;
uint32_t devices;
int32_t status;
/* Detect amount of available devices */
/* this value can be changed in the runtime */
cards = snd_cards();
/* If io-audio manager is not running we will get 0 as number */
/* of available audio devices */
if (cards == 0) {
/* We have no any available audio devices */
return;
}
/* !!! FIXME: code duplication */
/* Find requested devices by type */
{ /* output devices */
/* Playback devices enumeration requested */
for (it = 0; it < cards; it++) {
devices = 0;
do {
status =
snd_card_get_longname(it,
qsa_playback_device
[qsa_playback_devices].name,
QSA_MAX_NAME_LENGTH);
if (status == EOK) {
snd_pcm_t *handle;
/* Add device number to device name */
sprintf(qsa_playback_device[qsa_playback_devices].name +
SDL_strlen(qsa_playback_device
[qsa_playback_devices].name), " d%d",
devices);
/* Store associated card number id */
qsa_playback_device[qsa_playback_devices].cardno = it;
/* Check if this device id could play anything */
status =
snd_pcm_open(&handle, it, devices,
SND_PCM_OPEN_PLAYBACK);
if (status == EOK) {
qsa_playback_device[qsa_playback_devices].deviceno =
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]);
qsa_playback_devices++;
}
} else {
/* Check if we got end of devices list */
if (status == -ENOENT) {
break;
}
}
} else {
break;
}
/* Check if we reached maximum devices count */
if (qsa_playback_devices >= QSA_MAX_DEVICES) {
break;
}
devices++;
} while (1);
/* Check if we reached maximum devices count */
if (qsa_playback_devices >= QSA_MAX_DEVICES) {
break;
}
}
}
{ /* capture devices */
/* Capture devices enumeration requested */
for (it = 0; it < cards; it++) {
devices = 0;
do {
status =
snd_card_get_longname(it,
qsa_capture_device
[qsa_capture_devices].name,
QSA_MAX_NAME_LENGTH);
if (status == EOK) {
snd_pcm_t *handle;
/* Add device number to device name */
sprintf(qsa_capture_device[qsa_capture_devices].name +
SDL_strlen(qsa_capture_device
[qsa_capture_devices].name), " d%d",
devices);
/* Store associated card number id */
qsa_capture_device[qsa_capture_devices].cardno = it;
/* Check if this device id could play anything */
status =
snd_pcm_open(&handle, it, devices,
SND_PCM_OPEN_CAPTURE);
if (status == EOK) {
qsa_capture_device[qsa_capture_devices].deviceno =
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]);
qsa_capture_devices++;
}
} else {
/* Check if we got end of devices list */
if (status == -ENOENT) {
break;
}
}
/* Check if we reached maximum devices count */
if (qsa_capture_devices >= QSA_MAX_DEVICES) {
break;
}
} else {
break;
}
devices++;
} while (1);
/* Check if we reached maximum devices count */
if (qsa_capture_devices >= QSA_MAX_DEVICES) {
break;
}
}
}
}
static void
QSA_WaitDone(_THIS)
{
if (!this->hidden->iscapture) {
if (this->hidden->audio_handle != NULL) {
/* Wait till last fragment is played and stop channel */
snd_pcm_plugin_flush(this->hidden->audio_handle,
SND_PCM_CHANNEL_PLAYBACK);
}
} else {
if (this->hidden->audio_handle != NULL) {
/* Discard all unread data and stop channel */
snd_pcm_plugin_flush(this->hidden->audio_handle,
SND_PCM_CHANNEL_CAPTURE);
}
}
}
static void
QSA_Deinitialize(void)
{
/* Clear devices array on shutdown */
SDL_memset(qsa_playback_device, 0x00,
sizeof(QSA_Device) * QSA_MAX_DEVICES);
SDL_memset(qsa_capture_device, 0x00,
sizeof(QSA_Device) * QSA_MAX_DEVICES);
qsa_playback_devices = 0;
qsa_capture_devices = 0;
}
static int
QSA_Init(SDL_AudioDriverImpl * impl)
{
snd_pcm_t *handle = NULL;
int32_t status = 0;
/* Clear devices array */
SDL_memset(qsa_playback_device, 0x00,
sizeof(QSA_Device) * QSA_MAX_DEVICES);
SDL_memset(qsa_capture_device, 0x00,
sizeof(QSA_Device) * QSA_MAX_DEVICES);
qsa_playback_devices = 0;
qsa_capture_devices = 0;
/* Set function pointers */
/* DeviceLock and DeviceUnlock functions are used default, */
/* provided by SDL, which uses pthread_mutex for lock/unlock */
impl->DetectDevices = QSA_DetectDevices;
impl->OpenDevice = QSA_OpenDevice;
impl->ThreadInit = QSA_ThreadInit;
impl->WaitDevice = QSA_WaitDevice;
impl->PlayDevice = QSA_PlayDevice;
impl->GetDeviceBuf = QSA_GetDeviceBuf;
impl->CloseDevice = QSA_CloseDevice;
impl->WaitDone = QSA_WaitDone;
impl->Deinitialize = QSA_Deinitialize;
impl->LockDevice = NULL;
impl->UnlockDevice = NULL;
impl->OnlyHasDefaultOutputDevice = 0;
impl->ProvidesOwnCallbackThread = 0;
impl->SkipMixerLock = 0;
impl->HasCaptureSupport = 1;
impl->OnlyHasDefaultOutputDevice = 0;
impl->OnlyHasDefaultInputDevice = 0;
/* Check if io-audio manager is running or not */
status = snd_cards();
if (status == 0) {
/* if no, return immediately */
return 1;
}
return 1; /* this audio target is available. */
}
AudioBootStrap QSAAUDIO_bootstrap = {
"qsa", "QNX QSA Audio", QSA_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_QSA */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,57 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_QSA_AUDIO_H__
#define __SDL_QSA_AUDIO_H__
#include <sys/asoundlib.h>
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice* this
struct SDL_PrivateAudioData
{
/* SDL capture state */
int iscapture;
/* The audio device handle */
int cardno;
int deviceno;
snd_pcm_t *audio_handle;
/* The audio file descriptor */
int audio_fd;
/* Select timeout status */
uint32_t timeout_on_wait;
/* Raw mixing buffer */
Uint8 *pcm_buf;
Uint32 pcm_len;
};
#endif /* __SDL_QSA_AUDIO_H__ */
/* vi: set ts=4 sw=4 expandtab: */

761
src/audio/sdlgenaudiocvt.pl Executable file
View File

@@ -0,0 +1,761 @@
#!/usr/bin/perl -w
use warnings;
use strict;
my @audiotypes = qw(
U8
S8
U16LSB
S16LSB
U16MSB
S16MSB
S32LSB
S32MSB
F32LSB
F32MSB
);
my @channels = ( 1, 2, 4, 6, 8 );
my %funcs;
my $custom_converters = 0;
sub getTypeConvertHashId {
my ($from, $to) = @_;
return "TYPECONVERTER $from/$to";
}
sub getResamplerHashId {
my ($from, $channels, $upsample, $multiple) = @_;
return "RESAMPLER $from/$channels/$upsample/$multiple";
}
sub outputHeader {
print <<EOF;
/* DO NOT EDIT! This file is generated by sdlgenaudiocvt.pl */
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_audio.h"
#include "SDL_audio_c.h"
#ifndef DEBUG_CONVERT
#define DEBUG_CONVERT 0
#endif
/* If you can guarantee your data and need space, you can eliminate code... */
/* Just build the arbitrary resamplers if you're saving code space. */
#ifndef LESS_RESAMPLERS
#define LESS_RESAMPLERS 0
#endif
/* Don't build any resamplers if you're REALLY saving code space. */
#ifndef NO_RESAMPLERS
#define NO_RESAMPLERS 0
#endif
/* Don't build any type converters if you're saving code space. */
#ifndef NO_CONVERTERS
#define NO_CONVERTERS 0
#endif
/* *INDENT-OFF* */
EOF
my @vals = ( 127, 32767, 2147483647 );
foreach (@vals) {
my $val = $_;
my $fval = 1.0 / $val;
print("#define DIVBY${val} ${fval}f\n");
}
print("\n");
}
sub outputFooter {
print <<EOF;
/* $custom_converters converters generated. */
/* *INDENT-ON* */
/* vi: set ts=4 sw=4 expandtab: */
EOF
}
sub splittype {
my $t = shift;
my ($signed, $size, $endian) = $t =~ /([USF])(\d+)([LM]SB|)/;
my $float = ($signed eq 'F') ? 1 : 0;
$signed = (($float) or ($signed eq 'S')) ? 1 : 0;
$endian = 'NONE' if ($endian eq '');
my $ctype = '';
if ($float) {
$ctype = (($size == 32) ? 'float' : 'double');
} else {
$ctype = (($signed) ? 'S' : 'U') . "int${size}";
}
return ($signed, $float, $size, $endian, $ctype);
}
sub getSwapFunc {
my ($size, $signed, $float, $endian, $val) = @_;
my $BEorLE = (($endian eq 'MSB') ? 'BE' : 'LE');
my $code = '';
if ($float) {
$code = "SDL_SwapFloat${BEorLE}($val)";
} else {
if ($size > 8) {
$code = "SDL_Swap${BEorLE}${size}($val)";
} else {
$code = $val;
}
if (($signed) and (!$float)) {
$code = "((Sint${size}) $code)";
}
}
return "${code}";
}
sub maxIntVal {
my $size = shift;
if ($size == 8) {
return 0x7F;
} elsif ($size == 16) {
return 0x7FFF;
} elsif ($size == 32) {
return 0x7FFFFFFF;
}
die("bug in script.\n");
}
sub getFloatToIntMult {
my $size = shift;
my $val = maxIntVal($size) . '.0';
$val .= 'f' if ($size < 32);
return $val;
}
sub getIntToFloatDivBy {
my $size = shift;
return 'DIVBY' . maxIntVal($size);
}
sub getSignFlipVal {
my $size = shift;
if ($size == 8) {
return '0x80';
} elsif ($size == 16) {
return '0x8000';
} elsif ($size == 32) {
return '0x80000000';
}
die("bug in script.\n");
}
sub buildCvtFunc {
my ($from, $to) = @_;
my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
my ($tsigned, $tfloat, $tsize, $tendian, $tctype) = splittype($to);
my $diffs = 0;
$diffs++ if ($fsize != $tsize);
$diffs++ if ($fsigned != $tsigned);
$diffs++ if ($ffloat != $tfloat);
$diffs++ if ($fendian ne $tendian);
return if ($diffs == 0);
my $hashid = getTypeConvertHashId($from, $to);
if (1) { # !!! FIXME: if ($diffs > 1) {
my $sym = "SDL_Convert_${from}_to_${to}";
$funcs{$hashid} = $sym;
$custom_converters++;
# Always unsigned for ints, for possible byteswaps.
my $srctype = (($ffloat) ? 'float' : "Uint${fsize}");
print <<EOF;
static void SDLCALL
${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
int i;
const $srctype *src;
$tctype *dst;
#if DEBUG_CONVERT
fprintf(stderr, "Converting AUDIO_${from} to AUDIO_${to}.\\n");
#endif
EOF
if ($fsize < $tsize) {
my $mult = $tsize / $fsize;
print <<EOF;
src = ((const $srctype *) (cvt->buf + cvt->len_cvt)) - 1;
dst = (($tctype *) (cvt->buf + cvt->len_cvt * $mult)) - 1;
for (i = cvt->len_cvt / sizeof ($srctype); i; --i, --src, --dst) {
EOF
} else {
print <<EOF;
src = (const $srctype *) cvt->buf;
dst = ($tctype *) cvt->buf;
for (i = cvt->len_cvt / sizeof ($srctype); i; --i, ++src, ++dst) {
EOF
}
# Have to convert to/from float/int.
# !!! FIXME: cast through double for int32<->float?
my $code = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, '*src');
if ($ffloat != $tfloat) {
if ($ffloat) {
my $mult = getFloatToIntMult($tsize);
if (!$tsigned) { # bump from -1.0f/1.0f to 0.0f/2.0f
$code = "($code + 1.0f)";
}
$code = "(($tctype) ($code * $mult))";
} else {
# $divby will be the reciprocal, to avoid pipeline stalls
# from floating point division...so multiply it.
my $divby = getIntToFloatDivBy($fsize);
$code = "(((float) $code) * $divby)";
if (!$fsigned) { # bump from 0.0f/2.0f to -1.0f/1.0f.
$code = "($code - 1.0f)";
}
}
} else {
# All integer conversions here.
if ($fsigned != $tsigned) {
my $signflipval = getSignFlipVal($fsize);
$code = "(($code) ^ $signflipval)";
}
my $shiftval = abs($fsize - $tsize);
if ($fsize < $tsize) {
$code = "((($tctype) $code) << $shiftval)";
} elsif ($fsize > $tsize) {
$code = "(($tctype) ($code >> $shiftval))";
}
}
my $swap = getSwapFunc($tsize, $tsigned, $tfloat, $tendian, 'val');
print <<EOF;
const $tctype val = $code;
*dst = ${swap};
}
EOF
if ($fsize > $tsize) {
my $divby = $fsize / $tsize;
print(" cvt->len_cvt /= $divby;\n");
} elsif ($fsize < $tsize) {
my $mult = $tsize / $fsize;
print(" cvt->len_cvt *= $mult;\n");
}
print <<EOF;
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index] (cvt, AUDIO_$to);
}
}
EOF
} else {
if ($fsigned != $tsigned) {
$funcs{$hashid} = 'SDL_ConvertSigned';
} elsif ($ffloat != $tfloat) {
$funcs{$hashid} = 'SDL_ConvertFloat';
} elsif ($fsize != $tsize) {
$funcs{$hashid} = 'SDL_ConvertSize';
} elsif ($fendian ne $tendian) {
$funcs{$hashid} = 'SDL_ConvertEndian';
} else {
die("error in script.\n");
}
}
}
sub buildTypeConverters {
print "#if !NO_CONVERTERS\n\n";
foreach (@audiotypes) {
my $from = $_;
foreach (@audiotypes) {
my $to = $_;
buildCvtFunc($from, $to);
}
}
print "#endif /* !NO_CONVERTERS */\n\n\n";
print "const SDL_AudioTypeFilters sdl_audio_type_filters[] =\n{\n";
print "#if !NO_CONVERTERS\n";
foreach (@audiotypes) {
my $from = $_;
foreach (@audiotypes) {
my $to = $_;
if ($from ne $to) {
my $hashid = getTypeConvertHashId($from, $to);
my $sym = $funcs{$hashid};
print(" { AUDIO_$from, AUDIO_$to, $sym },\n");
}
}
}
print "#endif /* !NO_CONVERTERS */\n";
print(" { 0, 0, NULL }\n");
print "};\n\n\n";
}
sub getBiggerCtype {
my ($isfloat, $size) = @_;
if ($isfloat) {
if ($size == 32) {
return 'double';
}
die("bug in script.\n");
}
if ($size == 8) {
return 'Sint16';
} elsif ($size == 16) {
return 'Sint32'
} elsif ($size == 32) {
return 'Sint64'
}
die("bug in script.\n");
}
# These handle arbitrary resamples...44100Hz to 48000Hz, for example.
# Man, this code is skanky.
sub buildArbitraryResampleFunc {
# !!! FIXME: we do a lot of unnecessary and ugly casting in here, due to getSwapFunc().
my ($from, $channels, $upsample) = @_;
my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
my $bigger = getBiggerCtype($ffloat, $fsize);
my $interp = ($ffloat) ? '* 0.5' : '>> 1';
my $resample = ($upsample) ? 'Upsample' : 'Downsample';
my $hashid = getResamplerHashId($from, $channels, $upsample, 0);
my $sym = "SDL_${resample}_${from}_${channels}c";
$funcs{$hashid} = $sym;
$custom_converters++;
my $fudge = $fsize * $channels * 2; # !!! FIXME
my $eps_adjust = ($upsample) ? 'dstsize' : 'srcsize';
my $incr = '';
my $incr2 = '';
my $block_align = $channels * $fsize/8;
# !!! FIXME: DEBUG_CONVERT should report frequencies.
print <<EOF;
static void SDLCALL
${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
#if DEBUG_CONVERT
fprintf(stderr, "$resample arbitrary (x%f) AUDIO_${from}, ${channels} channels.\\n", cvt->rate_incr);
#endif
const int srcsize = cvt->len_cvt - $fudge;
const int dstsize = (int) (((double)(cvt->len_cvt/${block_align})) * cvt->rate_incr) * ${block_align};
register int eps = 0;
EOF
my $endcomparison = '!=';
# Upsampling (growing the buffer) needs to work backwards, since we
# overwrite the buffer as we go.
if ($upsample) {
$endcomparison = '>='; # dst > target
print <<EOF;
$fctype *dst = (($fctype *) (cvt->buf + dstsize)) - $channels;
const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels;
const $fctype *target = ((const $fctype *) cvt->buf);
EOF
} else {
$endcomparison = '<'; # dst < target
print <<EOF;
$fctype *dst = ($fctype *) cvt->buf;
const $fctype *src = ($fctype *) cvt->buf;
const $fctype *target = (const $fctype *) (cvt->buf + dstsize);
EOF
}
for (my $i = 0; $i < $channels; $i++) {
my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
print <<EOF;
$fctype sample${idx} = $val;
EOF
}
for (my $i = 0; $i < $channels; $i++) {
my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
print <<EOF;
$fctype last_sample${idx} = sample${idx};
EOF
}
print <<EOF;
while (dst $endcomparison target) {
EOF
if ($upsample) {
for (my $i = 0; $i < $channels; $i++) {
# !!! FIXME: don't do this swap every write, just when the samples change.
my $idx = (($channels - $i) - 1);
my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "sample${idx}");
print <<EOF;
dst[$idx] = $val;
EOF
}
$incr = ($channels == 1) ? 'dst--' : "dst -= $channels";
$incr2 = ($channels == 1) ? 'src--' : "src -= $channels";
print <<EOF;
$incr;
eps += srcsize;
if ((eps << 1) >= dstsize) {
$incr2;
EOF
} else { # downsample.
$incr = ($channels == 1) ? 'src++' : "src += $channels";
print <<EOF;
$incr;
eps += dstsize;
if ((eps << 1) >= srcsize) {
EOF
for (my $i = 0; $i < $channels; $i++) {
my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "sample${i}");
print <<EOF;
dst[$i] = $val;
EOF
}
$incr = ($channels == 1) ? 'dst++' : "dst += $channels";
print <<EOF;
$incr;
EOF
}
for (my $i = 0; $i < $channels; $i++) {
my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
my $swapped = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
print <<EOF;
sample${idx} = ($fctype) (((($bigger) $swapped) + (($bigger) last_sample${idx})) $interp);
EOF
}
for (my $i = 0; $i < $channels; $i++) {
my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
print <<EOF;
last_sample${idx} = sample${idx};
EOF
}
print <<EOF;
eps -= $eps_adjust;
}
}
EOF
print <<EOF;
cvt->len_cvt = dstsize;
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index] (cvt, format);
}
}
EOF
}
# These handle clean resamples...doubling and quadrupling the sample rate, etc.
sub buildMultipleResampleFunc {
# !!! FIXME: we do a lot of unnecessary and ugly casting in here, due to getSwapFunc().
my ($from, $channels, $upsample, $multiple) = @_;
my ($fsigned, $ffloat, $fsize, $fendian, $fctype) = splittype($from);
my $bigger = getBiggerCtype($ffloat, $fsize);
my $interp = ($ffloat) ? '* 0.5' : '>> 1';
my $interp2 = ($ffloat) ? '* 0.25' : '>> 2';
my $mult3 = ($ffloat) ? '3.0' : '3';
my $lencvtop = ($upsample) ? '*' : '/';
my $resample = ($upsample) ? 'Upsample' : 'Downsample';
my $hashid = getResamplerHashId($from, $channels, $upsample, $multiple);
my $sym = "SDL_${resample}_${from}_${channels}c_x${multiple}";
$funcs{$hashid} = $sym;
$custom_converters++;
# !!! FIXME: DEBUG_CONVERT should report frequencies.
print <<EOF;
static void SDLCALL
${sym}(SDL_AudioCVT * cvt, SDL_AudioFormat format)
{
#if DEBUG_CONVERT
fprintf(stderr, "$resample (x${multiple}) AUDIO_${from}, ${channels} channels.\\n");
#endif
const int dstsize = cvt->len_cvt $lencvtop $multiple;
EOF
my $endcomparison = '!=';
# Upsampling (growing the buffer) needs to work backwards, since we
# overwrite the buffer as we go.
if ($upsample) {
$endcomparison = '>='; # dst > target
print <<EOF;
$fctype *dst = (($fctype *) (cvt->buf + dstsize)) - $channels * $multiple;
const $fctype *src = (($fctype *) (cvt->buf + cvt->len_cvt)) - $channels;
const $fctype *target = ((const $fctype *) cvt->buf);
EOF
} else {
$endcomparison = '<'; # dst < target
print <<EOF;
$fctype *dst = ($fctype *) cvt->buf;
const $fctype *src = ($fctype *) cvt->buf;
const $fctype *target = (const $fctype *) (cvt->buf + dstsize);
EOF
}
for (my $i = 0; $i < $channels; $i++) {
my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
print <<EOF;
$bigger last_sample${idx} = ($bigger) $val;
EOF
}
print <<EOF;
while (dst $endcomparison target) {
EOF
for (my $i = 0; $i < $channels; $i++) {
my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
my $val = getSwapFunc($fsize, $fsigned, $ffloat, $fendian, "src[$idx]");
print <<EOF;
const $bigger sample${idx} = ($bigger) $val;
EOF
}
my $incr = '';
if ($upsample) {
$incr = ($channels == 1) ? 'src--' : "src -= $channels";
} else {
my $amount = $channels * $multiple;
$incr = "src += $amount"; # can't ever be 1, so no "++" version.
}
print <<EOF;
$incr;
EOF
# !!! FIXME: This really begs for some Altivec or SSE, etc.
if ($upsample) {
if ($multiple == 2) {
for (my $i = $channels-1; $i >= 0; $i--) {
my $dsti = $i + $channels;
print <<EOF;
dst[$dsti] = ($fctype) ((sample${i} + last_sample${i}) $interp);
EOF
}
for (my $i = $channels-1; $i >= 0; $i--) {
my $dsti = $i;
print <<EOF;
dst[$dsti] = ($fctype) sample${i};
EOF
}
} elsif ($multiple == 4) {
for (my $i = $channels-1; $i >= 0; $i--) {
my $dsti = $i + ($channels * 3);
print <<EOF;
dst[$dsti] = ($fctype) ((sample${i} + ($mult3 * last_sample${i})) $interp2);
EOF
}
for (my $i = $channels-1; $i >= 0; $i--) {
my $dsti = $i + ($channels * 2);
print <<EOF;
dst[$dsti] = ($fctype) ((sample${i} + last_sample${i}) $interp);
EOF
}
for (my $i = $channels-1; $i >= 0; $i--) {
my $dsti = $i + ($channels * 1);
print <<EOF;
dst[$dsti] = ($fctype) ((($mult3 * sample${i}) + last_sample${i}) $interp2);
EOF
}
for (my $i = $channels-1; $i >= 0; $i--) {
my $dsti = $i + ($channels * 0);
print <<EOF;
dst[$dsti] = ($fctype) sample${i};
EOF
}
} else {
die('bug in program.'); # we only handle x2 and x4.
}
} else { # downsample.
if ($multiple == 2) {
for (my $i = 0; $i < $channels; $i++) {
print <<EOF;
dst[$i] = ($fctype) ((sample${i} + last_sample${i}) $interp);
EOF
}
} elsif ($multiple == 4) {
# !!! FIXME: interpolate all 4 samples?
for (my $i = 0; $i < $channels; $i++) {
print <<EOF;
dst[$i] = ($fctype) ((sample${i} + last_sample${i}) $interp);
EOF
}
} else {
die('bug in program.'); # we only handle x2 and x4.
}
}
for (my $i = 0; $i < $channels; $i++) {
my $idx = ($upsample) ? (($channels - $i) - 1) : $i;
print <<EOF;
last_sample${idx} = sample${idx};
EOF
}
if ($upsample) {
my $amount = $channels * $multiple;
$incr = "dst -= $amount"; # can't ever be 1, so no "--" version.
} else {
$incr = ($channels == 1) ? 'dst++' : "dst += $channels";
}
print <<EOF;
$incr;
}
cvt->len_cvt = dstsize;
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index] (cvt, format);
}
}
EOF
}
sub buildResamplers {
print "#if !NO_RESAMPLERS\n\n";
foreach (@audiotypes) {
my $from = $_;
foreach (@channels) {
my $channel = $_;
buildArbitraryResampleFunc($from, $channel, 1);
buildArbitraryResampleFunc($from, $channel, 0);
}
}
print "\n#if !LESS_RESAMPLERS\n\n";
foreach (@audiotypes) {
my $from = $_;
foreach (@channels) {
my $channel = $_;
for (my $multiple = 2; $multiple <= 4; $multiple += 2) {
buildMultipleResampleFunc($from, $channel, 1, $multiple);
buildMultipleResampleFunc($from, $channel, 0, $multiple);
}
}
}
print "#endif /* !LESS_RESAMPLERS */\n";
print "#endif /* !NO_RESAMPLERS */\n\n\n";
print "const SDL_AudioRateFilters sdl_audio_rate_filters[] =\n{\n";
print "#if !NO_RESAMPLERS\n";
foreach (@audiotypes) {
my $from = $_;
foreach (@channels) {
my $channel = $_;
for (my $upsample = 0; $upsample <= 1; $upsample++) {
my $hashid = getResamplerHashId($from, $channel, $upsample, 0);
my $sym = $funcs{$hashid};
print(" { AUDIO_$from, $channel, $upsample, 0, $sym },\n");
}
}
}
print "#if !LESS_RESAMPLERS\n";
foreach (@audiotypes) {
my $from = $_;
foreach (@channels) {
my $channel = $_;
for (my $multiple = 2; $multiple <= 4; $multiple += 2) {
for (my $upsample = 0; $upsample <= 1; $upsample++) {
my $hashid = getResamplerHashId($from, $channel, $upsample, $multiple);
my $sym = $funcs{$hashid};
print(" { AUDIO_$from, $channel, $upsample, $multiple, $sym },\n");
}
}
}
}
print "#endif /* !LESS_RESAMPLERS */\n";
print "#endif /* !NO_RESAMPLERS */\n";
print(" { 0, 0, 0, 0, NULL }\n");
print "};\n\n";
}
# mainline ...
outputHeader();
buildTypeConverters();
buildResamplers();
outputFooter();
exit 0;
# end of sdlgenaudiocvt.pl ...

View File

@@ -0,0 +1,332 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_SNDIO
/* OpenBSD sndio target */
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#include <unistd.h>
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_sndioaudio.h"
#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
#include "SDL_loadso.h"
#endif
static struct sio_hdl * (*SNDIO_sio_open)(const char *, unsigned int, int);
static void (*SNDIO_sio_close)(struct sio_hdl *);
static int (*SNDIO_sio_setpar)(struct sio_hdl *, struct sio_par *);
static int (*SNDIO_sio_getpar)(struct sio_hdl *, struct sio_par *);
static int (*SNDIO_sio_start)(struct sio_hdl *);
static int (*SNDIO_sio_stop)(struct sio_hdl *);
static size_t (*SNDIO_sio_read)(struct sio_hdl *, void *, size_t);
static size_t (*SNDIO_sio_write)(struct sio_hdl *, const void *, size_t);
static void (*SNDIO_sio_initpar)(struct sio_par *);
#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
static const char *sndio_library = SDL_AUDIO_DRIVER_SNDIO_DYNAMIC;
static void *sndio_handle = NULL;
static int
load_sndio_sym(const char *fn, void **addr)
{
*addr = SDL_LoadFunction(sndio_handle, fn);
if (*addr == NULL) {
/* Don't call SDL_SetError(): SDL_LoadFunction already did. */
return 0;
}
return 1;
}
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
#define SDL_SNDIO_SYM(x) \
if (!load_sndio_sym(#x, (void **) (char *) &SNDIO_##x)) return -1
#else
#define SDL_SNDIO_SYM(x) SNDIO_##x = x
#endif
static int
load_sndio_syms(void)
{
SDL_SNDIO_SYM(sio_open);
SDL_SNDIO_SYM(sio_close);
SDL_SNDIO_SYM(sio_setpar);
SDL_SNDIO_SYM(sio_getpar);
SDL_SNDIO_SYM(sio_start);
SDL_SNDIO_SYM(sio_stop);
SDL_SNDIO_SYM(sio_read);
SDL_SNDIO_SYM(sio_write);
SDL_SNDIO_SYM(sio_initpar);
return 0;
}
#undef SDL_SNDIO_SYM
#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
static void
UnloadSNDIOLibrary(void)
{
if (sndio_handle != NULL) {
SDL_UnloadObject(sndio_handle);
sndio_handle = NULL;
}
}
static int
LoadSNDIOLibrary(void)
{
int retval = 0;
if (sndio_handle == NULL) {
sndio_handle = SDL_LoadObject(sndio_library);
if (sndio_handle == NULL) {
retval = -1;
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
} else {
retval = load_sndio_syms();
if (retval < 0) {
UnloadSNDIOLibrary();
}
}
}
return retval;
}
#else
static void
UnloadSNDIOLibrary(void)
{
}
static int
LoadSNDIOLibrary(void)
{
load_sndio_syms();
return 0;
}
#endif /* SDL_AUDIO_DRIVER_SNDIO_DYNAMIC */
static void
SNDIO_WaitDevice(_THIS)
{
/* no-op; SNDIO_sio_write() blocks if necessary. */
}
static void
SNDIO_PlayDevice(_THIS)
{
const int written = SNDIO_sio_write(this->hidden->dev,
this->hidden->mixbuf,
this->hidden->mixlen);
/* If we couldn't write, assume fatal error for now */
if ( written == 0 ) {
SDL_OpenedAudioDeviceDisconnected(this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
}
static Uint8 *
SNDIO_GetDeviceBuf(_THIS)
{
return this->hidden->mixbuf;
}
static void
SNDIO_WaitDone(_THIS)
{
SNDIO_sio_stop(this->hidden->dev);
}
static void
SNDIO_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if ( this->hidden->dev != NULL ) {
SNDIO_sio_close(this->hidden->dev);
this->hidden->dev = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
struct sio_par par;
int status;
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));
this->hidden->mixlen = this->spec.size;
/* !!! FIXME: SIO_DEVANY can be a specific device... */
if ((this->hidden->dev = SNDIO_sio_open(SIO_DEVANY, SIO_PLAY, 0)) == NULL) {
SNDIO_CloseDevice(this);
return SDL_SetError("sio_open() failed");
}
SNDIO_sio_initpar(&par);
par.rate = this->spec.freq;
par.pchan = this->spec.channels;
par.round = this->spec.samples;
par.appbufsz = par.round * 2;
/* Try for a closest match on audio format */
status = -1;
while (test_format && (status < 0)) {
if (!SDL_AUDIO_ISFLOAT(test_format)) {
par.le = SDL_AUDIO_ISLITTLEENDIAN(test_format) ? 1 : 0;
par.sig = SDL_AUDIO_ISSIGNED(test_format) ? 1 : 0;
par.bits = SDL_AUDIO_BITSIZE(test_format);
if (SNDIO_sio_setpar(this->hidden->dev, &par) == 0) {
continue;
}
if (SNDIO_sio_getpar(this->hidden->dev, &par) == 0) {
SNDIO_CloseDevice(this);
return SDL_SetError("sio_getpar() failed");
}
if (par.bps != SIO_BPS(par.bits)) {
continue;
}
if ((par.bits == 8 * par.bps) || (par.msb)) {
status = 0;
break;
}
}
test_format = SDL_NextAudioFormat();
}
if (status < 0) {
SNDIO_CloseDevice(this);
return SDL_SetError("sndio: Couldn't find any hardware audio formats");
}
if ((par.bps == 4) && (par.sig) && (par.le))
this->spec.format = AUDIO_S32LSB;
else if ((par.bps == 4) && (par.sig) && (!par.le))
this->spec.format = AUDIO_S32MSB;
else if ((par.bps == 2) && (par.sig) && (par.le))
this->spec.format = AUDIO_S16LSB;
else if ((par.bps == 2) && (par.sig) && (!par.le))
this->spec.format = AUDIO_S16MSB;
else if ((par.bps == 2) && (!par.sig) && (par.le))
this->spec.format = AUDIO_U16LSB;
else if ((par.bps == 2) && (!par.sig) && (!par.le))
this->spec.format = AUDIO_U16MSB;
else if ((par.bps == 1) && (par.sig))
this->spec.format = AUDIO_S8;
else if ((par.bps == 1) && (!par.sig))
this->spec.format = AUDIO_U8;
else {
SNDIO_CloseDevice(this);
return SDL_SetError("sndio: Got unsupported hardware audio format.");
}
this->spec.freq = par.rate;
this->spec.channels = par.pchan;
this->spec.samples = par.round;
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&this->spec);
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
SNDIO_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
if (!SNDIO_sio_start(this->hidden->dev)) {
return SDL_SetError("sio_start() failed");
}
/* We're ready to rock and roll. :-) */
return 0;
}
static void
SNDIO_Deinitialize(void)
{
UnloadSNDIOLibrary();
}
static int
SNDIO_Init(SDL_AudioDriverImpl * impl)
{
if (LoadSNDIOLibrary() < 0) {
return 0;
}
/* Set the function pointers */
impl->OpenDevice = SNDIO_OpenDevice;
impl->WaitDevice = SNDIO_WaitDevice;
impl->PlayDevice = SNDIO_PlayDevice;
impl->GetDeviceBuf = SNDIO_GetDeviceBuf;
impl->WaitDone = SNDIO_WaitDone;
impl->CloseDevice = SNDIO_CloseDevice;
impl->Deinitialize = SNDIO_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: sndio can handle multiple devices. */
return 1; /* this audio target is available. */
}
AudioBootStrap SNDIO_bootstrap = {
"sndio", "OpenBSD sndio", SNDIO_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_SNDIO */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,45 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_sndioaudio_h
#define _SDL_sndioaudio_h
#include <sndio.h>
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* The audio device handle */
struct sio_hdl *dev;
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
};
#endif /* _SDL_sndioaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,428 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_SUNAUDIO
/* Allow access to a raw mixing buffer */
#include <fcntl.h>
#include <errno.h>
#ifdef __NETBSD__
#include <sys/ioctl.h>
#include <sys/audioio.h>
#endif
#ifdef __SVR4
#include <sys/audioio.h>
#else
#include <sys/time.h>
#include <sys/types.h>
#endif
#include <unistd.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_sunaudio.h"
/* Open the audio device for playback, and don't block if busy */
#if defined(AUDIO_GETINFO) && !defined(AUDIO_GETBUFINFO)
#define AUDIO_GETBUFINFO AUDIO_GETINFO
#endif
/* Audio driver functions */
static Uint8 snd2au(int sample);
/* Audio driver bootstrap functions */
static void
SUNAUDIO_DetectDevices(void)
{
SDL_EnumUnixAudioDevices(1, (int (*)(int)) NULL);
}
#ifdef DEBUG_AUDIO
void
CheckUnderflow(_THIS)
{
#ifdef AUDIO_GETBUFINFO
audio_info_t info;
int left;
ioctl(this->hidden->audio_fd, AUDIO_GETBUFINFO, &info);
left = (this->hidden->written - info.play.samples);
if (this->hidden->written && (left == 0)) {
fprintf(stderr, "audio underflow!\n");
}
#endif
}
#endif
static void
SUNAUDIO_WaitDevice(_THIS)
{
#ifdef AUDIO_GETBUFINFO
#define SLEEP_FUDGE 10 /* 10 ms scheduling fudge factor */
audio_info_t info;
Sint32 left;
ioctl(this->hidden->audio_fd, AUDIO_GETBUFINFO, &info);
left = (this->hidden->written - info.play.samples);
if (left > this->hidden->fragsize) {
Sint32 sleepy;
sleepy = ((left - this->hidden->fragsize) / this->hidden->frequency);
sleepy -= SLEEP_FUDGE;
if (sleepy > 0) {
SDL_Delay(sleepy);
}
}
#else
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(this->hidden->audio_fd, &fdset);
select(this->hidden->audio_fd + 1, NULL, &fdset, NULL, NULL);
#endif
}
static void
SUNAUDIO_PlayDevice(_THIS)
{
/* Write the audio data */
if (this->hidden->ulaw_only) {
/* Assuming that this->spec.freq >= 8000 Hz */
int accum, incr, pos;
Uint8 *aubuf;
accum = 0;
incr = this->spec.freq / 8;
aubuf = this->hidden->ulaw_buf;
switch (this->hidden->audio_fmt & 0xFF) {
case 8:
{
Uint8 *sndbuf;
sndbuf = this->hidden->mixbuf;
for (pos = 0; pos < this->hidden->fragsize; ++pos) {
*aubuf = snd2au((0x80 - *sndbuf) * 64);
accum += incr;
while (accum > 0) {
accum -= 1000;
sndbuf += 1;
}
aubuf += 1;
}
}
break;
case 16:
{
Sint16 *sndbuf;
sndbuf = (Sint16 *) this->hidden->mixbuf;
for (pos = 0; pos < this->hidden->fragsize; ++pos) {
*aubuf = snd2au(*sndbuf / 4);
accum += incr;
while (accum > 0) {
accum -= 1000;
sndbuf += 1;
}
aubuf += 1;
}
}
break;
}
#ifdef DEBUG_AUDIO
CheckUnderflow(this);
#endif
if (write(this->hidden->audio_fd, this->hidden->ulaw_buf,
this->hidden->fragsize) < 0) {
/* Assume fatal error, for now */
SDL_OpenedAudioDeviceDisconnected(this);
}
this->hidden->written += this->hidden->fragsize;
} else {
#ifdef DEBUG_AUDIO
CheckUnderflow(this);
#endif
if (write(this->hidden->audio_fd, this->hidden->mixbuf,
this->spec.size) < 0) {
/* Assume fatal error, for now */
SDL_OpenedAudioDeviceDisconnected(this);
}
this->hidden->written += this->hidden->fragsize;
}
}
static Uint8 *
SUNAUDIO_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static void
SUNAUDIO_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
SDL_free(this->hidden->ulaw_buf);
this->hidden->ulaw_buf = NULL;
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
SDL_AudioFormat format = 0;
audio_info_t info;
/* We don't care what the devname is...we'll try to open anything. */
/* ...but default to first name in the list... */
if (devname == NULL) {
devname = SDL_GetAudioDeviceName(0, iscapture);
if (devname == NULL) {
return SDL_SetError("No such audio device");
}
}
/* Initialize all variables that we clean on shutdown */
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));
/* Open the audio device */
this->hidden->audio_fd = open(devname, flags, 0);
if (this->hidden->audio_fd < 0) {
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
}
#ifdef AUDIO_SETINFO
int enc;
#endif
int desired_freq = this->spec.freq;
/* Determine the audio parameters from the AudioSpec */
switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
case 8:
{ /* Unsigned 8 bit audio data */
this->spec.format = AUDIO_U8;
#ifdef AUDIO_SETINFO
enc = AUDIO_ENCODING_LINEAR8;
#endif
}
break;
case 16:
{ /* Signed 16 bit audio data */
this->spec.format = AUDIO_S16SYS;
#ifdef AUDIO_SETINFO
enc = AUDIO_ENCODING_LINEAR;
#endif
}
break;
default:
{
/* !!! FIXME: fallback to conversion on unsupported types! */
return SDL_SetError("Unsupported audio format");
}
}
this->hidden->audio_fmt = this->spec.format;
this->hidden->ulaw_only = 0; /* modern Suns do support linear audio */
#ifdef AUDIO_SETINFO
for (;;) {
audio_info_t info;
AUDIO_INITINFO(&info); /* init all fields to "no change" */
/* Try to set the requested settings */
info.play.sample_rate = this->spec.freq;
info.play.channels = this->spec.channels;
info.play.precision = (enc == AUDIO_ENCODING_ULAW)
? 8 : this->spec.format & 0xff;
info.play.encoding = enc;
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == 0) {
/* Check to be sure we got what we wanted */
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
return SDL_SetError("Error getting audio parameters: %s",
strerror(errno));
}
if (info.play.encoding == enc
&& info.play.precision == (this->spec.format & 0xff)
&& info.play.channels == this->spec.channels) {
/* Yow! All seems to be well! */
this->spec.freq = info.play.sample_rate;
break;
}
}
switch (enc) {
case AUDIO_ENCODING_LINEAR8:
/* unsigned 8bit apparently not supported here */
enc = AUDIO_ENCODING_LINEAR;
this->spec.format = AUDIO_S16SYS;
break; /* try again */
case AUDIO_ENCODING_LINEAR:
/* linear 16bit didn't work either, resort to <20>-law */
enc = AUDIO_ENCODING_ULAW;
this->spec.channels = 1;
this->spec.freq = 8000;
this->spec.format = AUDIO_U8;
this->hidden->ulaw_only = 1;
break;
default:
/* oh well... */
return SDL_SetError("Error setting audio parameters: %s",
strerror(errno));
}
}
#endif /* AUDIO_SETINFO */
this->hidden->written = 0;
/* We can actually convert on-the-fly to U-Law */
if (this->hidden->ulaw_only) {
this->spec.freq = desired_freq;
this->hidden->fragsize = (this->spec.samples * 1000) /
(this->spec.freq / 8);
this->hidden->frequency = 8;
this->hidden->ulaw_buf = (Uint8 *) SDL_malloc(this->hidden->fragsize);
if (this->hidden->ulaw_buf == NULL) {
return SDL_OutOfMemory();
}
this->spec.channels = 1;
} else {
this->hidden->fragsize = this->spec.samples;
this->hidden->frequency = this->spec.freq / 1000;
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Audio device %s U-Law only\n",
this->hidden->ulaw_only ? "is" : "is not");
fprintf(stderr, "format=0x%x chan=%d freq=%d\n",
this->spec.format, this->spec.channels, this->spec.freq);
#endif
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(&this->spec);
/* Allocate mixing buffer */
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->spec.size);
if (this->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/* We're ready to rock and roll. :-) */
return 0;
}
/************************************************************************/
/* This function (snd2au()) copyrighted: */
/************************************************************************/
/* Copyright 1989 by Rich Gopstein and Harris Corporation */
/* */
/* Permission to use, copy, modify, and distribute this software */
/* and its documentation for any purpose and without fee is */
/* hereby granted, provided that the above copyright notice */
/* appears in all copies and that both that copyright notice and */
/* this permission notice appear in supporting documentation, and */
/* that the name of Rich Gopstein and Harris Corporation not be */
/* used in advertising or publicity pertaining to distribution */
/* of the software without specific, written prior permission. */
/* Rich Gopstein and Harris Corporation make no representations */
/* about the suitability of this software for any purpose. It */
/* provided "as is" without express or implied warranty. */
/************************************************************************/
static Uint8
snd2au(int sample)
{
int mask;
if (sample < 0) {
sample = -sample;
mask = 0x7f;
} else {
mask = 0xff;
}
if (sample < 32) {
sample = 0xF0 | (15 - sample / 2);
} else if (sample < 96) {
sample = 0xE0 | (15 - (sample - 32) / 4);
} else if (sample < 224) {
sample = 0xD0 | (15 - (sample - 96) / 8);
} else if (sample < 480) {
sample = 0xC0 | (15 - (sample - 224) / 16);
} else if (sample < 992) {
sample = 0xB0 | (15 - (sample - 480) / 32);
} else if (sample < 2016) {
sample = 0xA0 | (15 - (sample - 992) / 64);
} else if (sample < 4064) {
sample = 0x90 | (15 - (sample - 2016) / 128);
} else if (sample < 8160) {
sample = 0x80 | (15 - (sample - 4064) / 256);
} else {
sample = 0x80;
}
return (mask & sample);
}
static int
SUNAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->DetectDevices = SUNAUDIO_DetectDevices;
impl->OpenDevice = SUNAUDIO_OpenDevice;
impl->PlayDevice = SUNAUDIO_PlayDevice;
impl->WaitDevice = SUNAUDIO_WaitDevice;
impl->GetDeviceBuf = SUNAUDIO_GetDeviceBuf;
impl->CloseDevice = SUNAUDIO_CloseDevice;
impl->AllowsArbitraryDeviceNames = 1;
return 1; /* this audio target is available. */
}
AudioBootStrap SUNAUDIO_bootstrap = {
"audio", "UNIX /dev/audio interface", SUNAUDIO_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_SUNAUDIO */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,47 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_sunaudio_h
#define _SDL_sunaudio_h
#include "../SDL_sysaudio.h"
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
struct SDL_PrivateAudioData
{
/* The file descriptor for the audio device */
int audio_fd;
SDL_AudioFormat audio_fmt; /* The app audio format */
Uint8 *mixbuf; /* The app mixing buffer */
int ulaw_only; /* Flag -- does hardware only output U-law? */
Uint8 *ulaw_buf; /* The U-law mixing buffer */
Sint32 written; /* The number of samples written */
int fragsize; /* The audio fragment size in samples */
int frequency; /* The audio frequency in KHz */
};
#endif /* _SDL_sunaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

365
src/audio/winmm/SDL_winmm.c Normal file
View File

@@ -0,0 +1,365 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_WINMM
/* Allow access to a raw mixing buffer */
#include "../../core/windows/SDL_windows.h"
#include <mmsystem.h>
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "SDL_winmm.h"
#ifndef WAVE_FORMAT_IEEE_FLOAT
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
#endif
#define DETECT_DEV_IMPL(iscap, typ, capstyp) \
static void DetectWave##typ##Devs(void) { \
const UINT iscapture = iscap ? 1 : 0; \
const UINT devcount = wave##typ##GetNumDevs(); \
capstyp caps; \
UINT i; \
for (i = 0; i < devcount; i++) { \
if (wave##typ##GetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { \
char *name = WIN_StringToUTF8(caps.szPname); \
if (name != NULL) { \
SDL_AddAudioDevice((int) iscapture, name, (void *) ((size_t) i+1)); \
SDL_free(name); \
} \
} \
} \
}
DETECT_DEV_IMPL(SDL_FALSE, Out, WAVEOUTCAPS)
DETECT_DEV_IMPL(SDL_TRUE, In, WAVEINCAPS)
static void
WINMM_DetectDevices(void)
{
DetectWaveInDevs();
DetectWaveOutDevs();
}
static void CALLBACK
CaptureSound(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance,
DWORD_PTR dwParam1, DWORD_PTR dwParam2)
{
SDL_AudioDevice *this = (SDL_AudioDevice *) dwInstance;
/* Only service "buffer is filled" messages */
if (uMsg != WIM_DATA)
return;
/* Signal that we have a new buffer of data */
ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
}
/* The Win32 callback for filling the WAVE device */
static void CALLBACK
FillSound(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
DWORD_PTR dwParam1, DWORD_PTR dwParam2)
{
SDL_AudioDevice *this = (SDL_AudioDevice *) dwInstance;
/* Only service "buffer done playing" messages */
if (uMsg != WOM_DONE)
return;
/* Signal that we are done playing a buffer */
ReleaseSemaphore(this->hidden->audio_sem, 1, NULL);
}
static int
SetMMerror(char *function, MMRESULT code)
{
int len;
char errbuf[MAXERRORLENGTH];
wchar_t werrbuf[MAXERRORLENGTH];
SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: ", function);
len = SDL_static_cast(int, SDL_strlen(errbuf));
waveOutGetErrorText(code, werrbuf, MAXERRORLENGTH - len);
WideCharToMultiByte(CP_ACP, 0, werrbuf, -1, errbuf + len,
MAXERRORLENGTH - len, NULL, NULL);
return SDL_SetError("%s", errbuf);
}
static void
WINMM_WaitDevice(_THIS)
{
/* Wait for an audio chunk to finish */
WaitForSingleObject(this->hidden->audio_sem, INFINITE);
}
static Uint8 *
WINMM_GetDeviceBuf(_THIS)
{
return (Uint8 *) (this->hidden->
wavebuf[this->hidden->next_buffer].lpData);
}
static void
WINMM_PlayDevice(_THIS)
{
/* Queue it up */
waveOutWrite(this->hidden->hout,
&this->hidden->wavebuf[this->hidden->next_buffer],
sizeof(this->hidden->wavebuf[0]));
this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
}
static void
WINMM_WaitDone(_THIS)
{
int i, left;
do {
left = NUM_BUFFERS;
for (i = 0; i < NUM_BUFFERS; ++i) {
if (this->hidden->wavebuf[i].dwFlags & WHDR_DONE) {
--left;
}
}
if (left > 0) {
SDL_Delay(100);
}
} while (left > 0);
}
static void
WINMM_CloseDevice(_THIS)
{
/* Close up audio */
if (this->hidden != NULL) {
int i;
if (this->hidden->audio_sem) {
CloseHandle(this->hidden->audio_sem);
this->hidden->audio_sem = 0;
}
/* Clean up mixing buffers */
for (i = 0; i < NUM_BUFFERS; ++i) {
if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
waveOutUnprepareHeader(this->hidden->hout,
&this->hidden->wavebuf[i],
sizeof(this->hidden->wavebuf[i]));
this->hidden->wavebuf[i].dwUser = 0xFFFF;
}
}
/* Free raw mixing buffer */
SDL_free(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->hin) {
waveInClose(this->hidden->hin);
this->hidden->hin = 0;
}
if (this->hidden->hout) {
waveOutClose(this->hidden->hout);
this->hidden->hout = 0;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static SDL_bool
PrepWaveFormat(_THIS, UINT devId, WAVEFORMATEX *pfmt, const int iscapture)
{
SDL_zerop(pfmt);
if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
pfmt->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
} else {
pfmt->wFormatTag = WAVE_FORMAT_PCM;
}
pfmt->wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
pfmt->nChannels = this->spec.channels;
pfmt->nSamplesPerSec = this->spec.freq;
pfmt->nBlockAlign = pfmt->nChannels * (pfmt->wBitsPerSample / 8);
pfmt->nAvgBytesPerSec = pfmt->nSamplesPerSec * pfmt->nBlockAlign;
if (iscapture) {
return (waveInOpen(0, devId, pfmt, 0, 0, WAVE_FORMAT_QUERY) == 0);
} else {
return (waveOutOpen(0, devId, pfmt, 0, 0, WAVE_FORMAT_QUERY) == 0);
}
}
static int
WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
int valid_datatype = 0;
MMRESULT result;
WAVEFORMATEX waveformat;
UINT devId = WAVE_MAPPER; /* WAVE_MAPPER == choose system's default */
UINT i;
if (handle != NULL) { /* specific device requested? */
/* -1 because we increment the original value to avoid NULL. */
const size_t val = ((size_t) handle) - 1;
devId = (UINT) val;
}
/* Initialize all variables that we clean on shutdown */
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));
/* Initialize the wavebuf structures for closing */
for (i = 0; i < NUM_BUFFERS; ++i)
this->hidden->wavebuf[i].dwUser = 0xFFFF;
if (this->spec.channels > 2)
this->spec.channels = 2; /* !!! FIXME: is this right? */
while ((!valid_datatype) && (test_format)) {
switch (test_format) {
case AUDIO_U8:
case AUDIO_S16:
case AUDIO_S32:
case AUDIO_F32:
this->spec.format = test_format;
if (PrepWaveFormat(this, devId, &waveformat, iscapture)) {
valid_datatype = 1;
} else {
test_format = SDL_NextAudioFormat();
}
break;
default:
test_format = SDL_NextAudioFormat();
break;
}
}
if (!valid_datatype) {
WINMM_CloseDevice(this);
return SDL_SetError("Unsupported audio format");
}
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(&this->spec);
/* Open the audio device */
if (iscapture) {
result = waveInOpen(&this->hidden->hin, devId, &waveformat,
(DWORD_PTR) CaptureSound, (DWORD_PTR) this,
CALLBACK_FUNCTION);
} else {
result = waveOutOpen(&this->hidden->hout, devId, &waveformat,
(DWORD_PTR) FillSound, (DWORD_PTR) this,
CALLBACK_FUNCTION);
}
if (result != MMSYSERR_NOERROR) {
WINMM_CloseDevice(this);
return SetMMerror("waveOutOpen()", result);
}
#ifdef SOUND_DEBUG
/* Check the sound device we retrieved */
{
WAVEOUTCAPS caps;
result = waveOutGetDevCaps((UINT) this->hidden->hout,
&caps, sizeof(caps));
if (result != MMSYSERR_NOERROR) {
WINMM_CloseDevice(this);
return SetMMerror("waveOutGetDevCaps()", result);
}
printf("Audio device: %s\n", caps.szPname);
}
#endif
/* Create the audio buffer semaphore */
this->hidden->audio_sem =
CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
if (this->hidden->audio_sem == NULL) {
WINMM_CloseDevice(this);
return SDL_SetError("Couldn't create semaphore");
}
/* Create the sound buffers */
this->hidden->mixbuf =
(Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
if (this->hidden->mixbuf == NULL) {
WINMM_CloseDevice(this);
return SDL_OutOfMemory();
}
for (i = 0; i < NUM_BUFFERS; ++i) {
SDL_memset(&this->hidden->wavebuf[i], 0,
sizeof(this->hidden->wavebuf[i]));
this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
this->hidden->wavebuf[i].lpData =
(LPSTR) & this->hidden->mixbuf[i * this->spec.size];
result = waveOutPrepareHeader(this->hidden->hout,
&this->hidden->wavebuf[i],
sizeof(this->hidden->wavebuf[i]));
if (result != MMSYSERR_NOERROR) {
WINMM_CloseDevice(this);
return SetMMerror("waveOutPrepareHeader()", result);
}
}
return 0; /* Ready to go! */
}
static int
WINMM_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->DetectDevices = WINMM_DetectDevices;
impl->OpenDevice = WINMM_OpenDevice;
impl->PlayDevice = WINMM_PlayDevice;
impl->WaitDevice = WINMM_WaitDevice;
impl->WaitDone = WINMM_WaitDone;
impl->GetDeviceBuf = WINMM_GetDeviceBuf;
impl->CloseDevice = WINMM_CloseDevice;
return 1; /* this audio target is available. */
}
AudioBootStrap WINMM_bootstrap = {
"winmm", "Windows Waveform Audio", WINMM_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_WINMM */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,45 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_winmm_h
#define _SDL_winmm_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
{
HWAVEOUT hout;
HWAVEIN hin;
HANDLE audio_sem;
Uint8 *mixbuf; /* The raw allocated mixing buffer */
WAVEHDR wavebuf[NUM_BUFFERS]; /* Wave audio fragments */
int next_buffer;
};
#endif /* _SDL_winmm_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,526 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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.
*/
/* WinRT NOTICE:
A few changes to SDL's XAudio2 backend were warranted by API
changes to Windows. Many, but not all of these are documented by Microsoft
at:
http://blogs.msdn.com/b/chuckw/archive/2012/04/02/xaudio2-and-windows-8-consumer-preview.aspx
1. Windows' thread synchronization function, CreateSemaphore, was removed
from WinRT. SDL's semaphore API was substituted instead.
2. The method calls, IXAudio2::GetDeviceCount and IXAudio2::GetDeviceDetails
were removed from the XAudio2 API. Microsoft is telling developers to
use APIs in Windows::Foundation instead.
For SDL, the missing methods were reimplemented using the APIs Microsoft
said to use.
3. CoInitialize and CoUninitialize are not available in WinRT.
These calls were removed, as COM will have been initialized earlier,
at least by the call to the WinRT app's main function
(aka 'int main(Platform::Array<Platform::String^>^)). (DLudwig:
This was my understanding of how WinRT: the 'main' function uses
a tag of [MTAThread], which should initialize COM. My understanding
of COM is somewhat limited, and I may be incorrect here.)
4. IXAudio2::CreateMasteringVoice changed its integer-based 'DeviceIndex'
argument to a string-based one, 'szDeviceId'. In WinRT, the
string-based argument will be used.
*/
#include "../../SDL_internal.h"
#if SDL_AUDIO_DRIVER_XAUDIO2
#include "../../core/windows/SDL_windows.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "../SDL_sysaudio.h"
#include "SDL_assert.h"
#ifdef __GNUC__
/* The configure script already did any necessary checking */
# define SDL_XAUDIO2_HAS_SDK 1
#elif defined(__WINRT__)
/* WinRT always has access to the XAudio 2 SDK */
# define SDL_XAUDIO2_HAS_SDK
#else
/* XAudio2 exists as of the March 2008 DirectX SDK
The XAudio2 implementation available in the Windows 8 SDK targets Windows 8 and newer.
If you want to build SDL with XAudio2 support you should install the DirectX SDK.
*/
#include <dxsdkver.h>
#if (!defined(_DXSDK_BUILD_MAJOR) || (_DXSDK_BUILD_MAJOR < 1284))
# pragma message("Your DirectX SDK is too old. Disabling XAudio2 support.")
#else
# define SDL_XAUDIO2_HAS_SDK 1
#endif
#endif
#ifdef SDL_XAUDIO2_HAS_SDK
/* Check to see if we're compiling for XAudio 2.8, or higher. */
#ifdef WINVER
#if WINVER >= 0x0602 /* Windows 8 SDK or higher? */
#define SDL_XAUDIO2_WIN8 1
#endif
#endif
/* The XAudio header file, when #include'd on WinRT, will only compile in C++
files, but not C. A few preprocessor-based hacks are defined below in order
to get xaudio2.h to compile in the C/non-C++ file, SDL_xaudio2.c.
*/
#ifdef __WINRT__
#define uuid(x)
#define DX_BUILD
#endif
#define INITGUID 1
#include <xaudio2.h>
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *this
#ifdef __WINRT__
#include "SDL_xaudio2_winrthelpers.h"
#endif
/* Fixes bug 1210 where some versions of gcc need named parameters */
#ifdef __GNUC__
#ifdef THIS
#undef THIS
#endif
#define THIS INTERFACE *p
#ifdef THIS_
#undef THIS_
#endif
#define THIS_ INTERFACE *p,
#endif
struct SDL_PrivateAudioData
{
IXAudio2 *ixa2;
IXAudio2SourceVoice *source;
IXAudio2MasteringVoice *mastering;
SDL_sem * semaphore;
Uint8 *mixbuf;
int mixlen;
Uint8 *nextbuf;
};
static void
XAUDIO2_DetectDevices(void)
{
IXAudio2 *ixa2 = NULL;
UINT32 devcount = 0;
UINT32 i = 0;
if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
SDL_SetError("XAudio2: XAudio2Create() failed at detection.");
return;
} else if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) {
SDL_SetError("XAudio2: IXAudio2::GetDeviceCount() failed.");
IXAudio2_Release(ixa2);
return;
}
for (i = 0; i < devcount; i++) {
XAUDIO2_DEVICE_DETAILS details;
if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) {
char *str = WIN_StringToUTF8(details.DisplayName);
if (str != NULL) {
SDL_AddAudioDevice(SDL_FALSE, str, (void *) ((size_t) i+1));
SDL_free(str); /* SDL_AddAudioDevice made a copy of the string. */
}
}
}
IXAudio2_Release(ixa2);
}
static void STDMETHODCALLTYPE
VoiceCBOnBufferEnd(THIS_ void *data)
{
/* Just signal the SDL audio thread and get out of XAudio2's way. */
SDL_AudioDevice *this = (SDL_AudioDevice *) data;
SDL_SemPost(this->hidden->semaphore);
}
static void STDMETHODCALLTYPE
VoiceCBOnVoiceError(THIS_ void *data, HRESULT Error)
{
SDL_AudioDevice *this = (SDL_AudioDevice *) data;
SDL_OpenedAudioDeviceDisconnected(this);
}
/* no-op callbacks... */
static void STDMETHODCALLTYPE VoiceCBOnStreamEnd(THIS) {}
static void STDMETHODCALLTYPE VoiceCBOnVoiceProcessPassStart(THIS_ UINT32 b) {}
static void STDMETHODCALLTYPE VoiceCBOnVoiceProcessPassEnd(THIS) {}
static void STDMETHODCALLTYPE VoiceCBOnBufferStart(THIS_ void *data) {}
static void STDMETHODCALLTYPE VoiceCBOnLoopEnd(THIS_ void *data) {}
static Uint8 *
XAUDIO2_GetDeviceBuf(_THIS)
{
return this->hidden->nextbuf;
}
static void
XAUDIO2_PlayDevice(_THIS)
{
XAUDIO2_BUFFER buffer;
Uint8 *mixbuf = this->hidden->mixbuf;
Uint8 *nextbuf = this->hidden->nextbuf;
const int mixlen = this->hidden->mixlen;
IXAudio2SourceVoice *source = this->hidden->source;
HRESULT result = S_OK;
if (!this->enabled) { /* shutting down? */
return;
}
/* Submit the next filled buffer */
SDL_zero(buffer);
buffer.AudioBytes = mixlen;
buffer.pAudioData = nextbuf;
buffer.pContext = this;
if (nextbuf == mixbuf) {
nextbuf += mixlen;
} else {
nextbuf = mixbuf;
}
this->hidden->nextbuf = nextbuf;
result = IXAudio2SourceVoice_SubmitSourceBuffer(source, &buffer, NULL);
if (result == XAUDIO2_E_DEVICE_INVALIDATED) {
/* !!! FIXME: possibly disconnected or temporary lost. Recover? */
}
if (result != S_OK) { /* uhoh, panic! */
IXAudio2SourceVoice_FlushSourceBuffers(source);
SDL_OpenedAudioDeviceDisconnected(this);
}
}
static void
XAUDIO2_WaitDevice(_THIS)
{
if (this->enabled) {
SDL_SemWait(this->hidden->semaphore);
}
}
static void
XAUDIO2_WaitDone(_THIS)
{
IXAudio2SourceVoice *source = this->hidden->source;
XAUDIO2_VOICE_STATE state;
SDL_assert(!this->enabled); /* flag that stops playing. */
IXAudio2SourceVoice_Discontinuity(source);
#if SDL_XAUDIO2_WIN8
IXAudio2SourceVoice_GetState(source, &state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
#else
IXAudio2SourceVoice_GetState(source, &state);
#endif
while (state.BuffersQueued > 0) {
SDL_SemWait(this->hidden->semaphore);
#if SDL_XAUDIO2_WIN8
IXAudio2SourceVoice_GetState(source, &state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
#else
IXAudio2SourceVoice_GetState(source, &state);
#endif
}
}
static void
XAUDIO2_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
IXAudio2 *ixa2 = this->hidden->ixa2;
IXAudio2SourceVoice *source = this->hidden->source;
IXAudio2MasteringVoice *mastering = this->hidden->mastering;
if (source != NULL) {
IXAudio2SourceVoice_Stop(source, 0, XAUDIO2_COMMIT_NOW);
IXAudio2SourceVoice_FlushSourceBuffers(source);
IXAudio2SourceVoice_DestroyVoice(source);
}
if (ixa2 != NULL) {
IXAudio2_StopEngine(ixa2);
}
if (mastering != NULL) {
IXAudio2MasteringVoice_DestroyVoice(mastering);
}
if (ixa2 != NULL) {
IXAudio2_Release(ixa2);
}
SDL_free(this->hidden->mixbuf);
if (this->hidden->semaphore != NULL) {
SDL_DestroySemaphore(this->hidden->semaphore);
}
SDL_free(this->hidden);
this->hidden = NULL;
}
}
static int
XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
HRESULT result = S_OK;
WAVEFORMATEX waveformat;
int valid_format = 0;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
IXAudio2 *ixa2 = NULL;
IXAudio2SourceVoice *source = NULL;
#if defined(SDL_XAUDIO2_WIN8)
LPCWSTR devId = NULL;
#else
UINT32 devId = 0; /* 0 == system default device. */
#endif
static IXAudio2VoiceCallbackVtbl callbacks_vtable = {
VoiceCBOnVoiceProcessPassStart,
VoiceCBOnVoiceProcessPassEnd,
VoiceCBOnStreamEnd,
VoiceCBOnBufferStart,
VoiceCBOnBufferEnd,
VoiceCBOnLoopEnd,
VoiceCBOnVoiceError
};
static IXAudio2VoiceCallback callbacks = { &callbacks_vtable };
#if defined(SDL_XAUDIO2_WIN8)
/* !!! FIXME: hook up hotplugging. */
#else
if (handle != NULL) { /* specific device requested? */
/* -1 because we increment the original value to avoid NULL. */
const size_t val = ((size_t) handle) - 1;
devId = (UINT32) val;
}
#endif
if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
return SDL_SetError("XAudio2: XAudio2Create() failed at open.");
}
/*
XAUDIO2_DEBUG_CONFIGURATION debugConfig;
debugConfig.TraceMask = XAUDIO2_LOG_ERRORS; //XAUDIO2_LOG_WARNINGS | XAUDIO2_LOG_DETAIL | XAUDIO2_LOG_FUNC_CALLS | XAUDIO2_LOG_TIMING | XAUDIO2_LOG_LOCKS | XAUDIO2_LOG_MEMORY | XAUDIO2_LOG_STREAMING;
debugConfig.BreakMask = XAUDIO2_LOG_ERRORS; //XAUDIO2_LOG_WARNINGS;
debugConfig.LogThreadID = TRUE;
debugConfig.LogFileline = TRUE;
debugConfig.LogFunctionName = TRUE;
debugConfig.LogTiming = TRUE;
ixa2->SetDebugConfiguration(&debugConfig);
*/
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
IXAudio2_Release(ixa2);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
this->hidden->ixa2 = ixa2;
this->hidden->semaphore = SDL_CreateSemaphore(1);
if (this->hidden->semaphore == NULL) {
XAUDIO2_CloseDevice(this);
return SDL_SetError("XAudio2: CreateSemaphore() failed!");
}
while ((!valid_format) && (test_format)) {
switch (test_format) {
case AUDIO_U8:
case AUDIO_S16:
case AUDIO_S32:
case AUDIO_F32:
this->spec.format = test_format;
valid_format = 1;
break;
}
test_format = SDL_NextAudioFormat();
}
if (!valid_format) {
XAUDIO2_CloseDevice(this);
return SDL_SetError("XAudio2: Unsupported audio format");
}
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(&this->spec);
/* We feed a Source, it feeds the Mastering, which feeds the device. */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_malloc(2 * this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
XAUDIO2_CloseDevice(this);
return SDL_OutOfMemory();
}
this->hidden->nextbuf = this->hidden->mixbuf;
SDL_memset(this->hidden->mixbuf, 0, 2 * this->hidden->mixlen);
/* We use XAUDIO2_DEFAULT_CHANNELS instead of this->spec.channels. On
Xbox360, this means 5.1 output, but on Windows, it means "figure out
what the system has." It might be preferable to let XAudio2 blast
stereo output to appropriate surround sound configurations
instead of clamping to 2 channels, even though we'll configure the
Source Voice for whatever number of channels you supply. */
#if SDL_XAUDIO2_WIN8
result = IXAudio2_CreateMasteringVoice(ixa2, &this->hidden->mastering,
XAUDIO2_DEFAULT_CHANNELS,
this->spec.freq, 0, devId, NULL, AudioCategory_GameEffects);
#else
result = IXAudio2_CreateMasteringVoice(ixa2, &this->hidden->mastering,
XAUDIO2_DEFAULT_CHANNELS,
this->spec.freq, 0, devId, NULL);
#endif
if (result != S_OK) {
XAUDIO2_CloseDevice(this);
return SDL_SetError("XAudio2: Couldn't create mastering voice");
}
SDL_zero(waveformat);
if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
waveformat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
} else {
waveformat.wFormatTag = WAVE_FORMAT_PCM;
}
waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
waveformat.nChannels = this->spec.channels;
waveformat.nSamplesPerSec = this->spec.freq;
waveformat.nBlockAlign =
waveformat.nChannels * (waveformat.wBitsPerSample / 8);
waveformat.nAvgBytesPerSec =
waveformat.nSamplesPerSec * waveformat.nBlockAlign;
waveformat.cbSize = sizeof(waveformat);
#ifdef __WINRT__
// DLudwig: for now, make XAudio2 do sample rate conversion, just to
// get the loopwave test to work.
//
// TODO, WinRT: consider removing WinRT-specific source-voice creation code from SDL_xaudio2.c
result = IXAudio2_CreateSourceVoice(ixa2, &source, &waveformat,
0,
1.0f, &callbacks, NULL, NULL);
#else
result = IXAudio2_CreateSourceVoice(ixa2, &source, &waveformat,
XAUDIO2_VOICE_NOSRC |
XAUDIO2_VOICE_NOPITCH,
1.0f, &callbacks, NULL, NULL);
#endif
if (result != S_OK) {
XAUDIO2_CloseDevice(this);
return SDL_SetError("XAudio2: Couldn't create source voice");
}
this->hidden->source = source;
/* Start everything playing! */
result = IXAudio2_StartEngine(ixa2);
if (result != S_OK) {
XAUDIO2_CloseDevice(this);
return SDL_SetError("XAudio2: Couldn't start engine");
}
result = IXAudio2SourceVoice_Start(source, 0, XAUDIO2_COMMIT_NOW);
if (result != S_OK) {
XAUDIO2_CloseDevice(this);
return SDL_SetError("XAudio2: Couldn't start source voice");
}
return 0; /* good to go. */
}
static void
XAUDIO2_Deinitialize(void)
{
#if defined(__WIN32__)
WIN_CoUninitialize();
#endif
}
#endif /* SDL_XAUDIO2_HAS_SDK */
static int
XAUDIO2_Init(SDL_AudioDriverImpl * impl)
{
#ifndef SDL_XAUDIO2_HAS_SDK
SDL_SetError("XAudio2: SDL was built without XAudio2 support (old DirectX SDK).");
return 0; /* no XAudio2 support, ever. Update your SDK! */
#else
/* XAudio2Create() is a macro that uses COM; we don't load the .dll */
IXAudio2 *ixa2 = NULL;
#if defined(__WIN32__)
// TODO, WinRT: Investigate using CoInitializeEx here
if (FAILED(WIN_CoInitialize())) {
SDL_SetError("XAudio2: CoInitialize() failed");
return 0;
}
#endif
if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
#if defined(__WIN32__)
WIN_CoUninitialize();
#endif
SDL_SetError("XAudio2: XAudio2Create() failed at initialization");
return 0; /* not available. */
}
IXAudio2_Release(ixa2);
/* Set the function pointers */
impl->DetectDevices = XAUDIO2_DetectDevices;
impl->OpenDevice = XAUDIO2_OpenDevice;
impl->PlayDevice = XAUDIO2_PlayDevice;
impl->WaitDevice = XAUDIO2_WaitDevice;
impl->WaitDone = XAUDIO2_WaitDone;
impl->GetDeviceBuf = XAUDIO2_GetDeviceBuf;
impl->CloseDevice = XAUDIO2_CloseDevice;
impl->Deinitialize = XAUDIO2_Deinitialize;
/* !!! FIXME: We can apparently use a C++ interface on Windows 8
* !!! FIXME: (Windows::Devices::Enumeration::DeviceInformation) for device
* !!! FIXME: detection, but it's not implemented here yet.
* !!! FIXME: see http://blogs.msdn.com/b/chuckw/archive/2012/04/02/xaudio2-and-windows-8-consumer-preview.aspx
* !!! FIXME: for now, force the default device.
*/
#if defined(SDL_XAUDIO2_WIN8) || defined(__WINRT__)
impl->OnlyHasDefaultOutputDevice = 1;
#endif
return 1; /* this audio target is available. */
#endif
}
AudioBootStrap XAUDIO2_bootstrap = {
"xaudio2", "XAudio2", XAUDIO2_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_XAUDIO2 */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,90 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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 <xaudio2.h>
#include "SDL_xaudio2_winrthelpers.h"
#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
using Windows::Devices::Enumeration::DeviceClass;
using Windows::Devices::Enumeration::DeviceInformation;
using Windows::Devices::Enumeration::DeviceInformationCollection;
#endif
extern "C" HRESULT __cdecl IXAudio2_GetDeviceCount(IXAudio2 * ixa2, UINT32 * devcount)
{
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
// There doesn't seem to be any audio device enumeration on Windows Phone.
// In lieu of this, just treat things as if there is one and only one
// audio device.
*devcount = 1;
return S_OK;
#else
// TODO, WinRT: make xaudio2 device enumeration only happen once, and in the background
auto operation = DeviceInformation::FindAllAsync(DeviceClass::AudioRender);
while (operation->Status != Windows::Foundation::AsyncStatus::Completed)
{
}
DeviceInformationCollection^ devices = operation->GetResults();
*devcount = devices->Size;
return S_OK;
#endif
}
extern "C" HRESULT IXAudio2_GetDeviceDetails(IXAudio2 * unused, UINT32 index, XAUDIO2_DEVICE_DETAILS * details)
{
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
// Windows Phone doesn't seem to have the same device enumeration APIs that
// Windows 8/RT has, or it doesn't have them at all. In lieu of this,
// just treat things as if there is one, and only one, default device.
if (index != 0)
{
return XAUDIO2_E_INVALID_CALL;
}
if (details)
{
wcsncpy_s(details->DeviceID, ARRAYSIZE(details->DeviceID), L"default", _TRUNCATE);
wcsncpy_s(details->DisplayName, ARRAYSIZE(details->DisplayName), L"default", _TRUNCATE);
}
return S_OK;
#else
auto operation = DeviceInformation::FindAllAsync(DeviceClass::AudioRender);
while (operation->Status != Windows::Foundation::AsyncStatus::Completed)
{
}
DeviceInformationCollection^ devices = operation->GetResults();
if (index >= devices->Size)
{
return XAUDIO2_E_INVALID_CALL;
}
DeviceInformation^ d = devices->GetAt(index);
if (details)
{
wcsncpy_s(details->DeviceID, ARRAYSIZE(details->DeviceID), d->Id->Data(), _TRUNCATE);
wcsncpy_s(details->DisplayName, ARRAYSIZE(details->DisplayName), d->Name->Data(), _TRUNCATE);
}
return S_OK;
#endif
}

View File

@@ -0,0 +1,70 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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.
*/
//
// Re-implementation of methods removed from XAudio2 (in WinRT):
//
typedef struct XAUDIO2_DEVICE_DETAILS
{
WCHAR DeviceID[256];
WCHAR DisplayName[256];
/* Other fields exist in the pre-Windows 8 version of this struct, however
they weren't used by SDL, so they weren't added.
*/
} XAUDIO2_DEVICE_DETAILS;
#ifdef __cplusplus
extern "C" {
#endif
HRESULT IXAudio2_GetDeviceCount(IXAudio2 * unused, UINT32 * devcount);
HRESULT IXAudio2_GetDeviceDetails(IXAudio2 * unused, UINT32 index, XAUDIO2_DEVICE_DETAILS * details);
#ifdef __cplusplus
}
#endif
//
// C-style macros to call XAudio2's methods in C++:
//
#ifdef __cplusplus
/*
#define IXAudio2_CreateMasteringVoice(A, B, C, D, E, F, G) (A)->CreateMasteringVoice((B), (C), (D), (E), (F), (G))
#define IXAudio2_CreateSourceVoice(A, B, C, D, E, F, G, H) (A)->CreateSourceVoice((B), (C), (D), (E), (F), (G), (H))
#define IXAudio2_QueryInterface(A, B, C) (A)->QueryInterface((B), (C))
#define IXAudio2_Release(A) (A)->Release()
#define IXAudio2_StartEngine(A) (A)->StartEngine()
#define IXAudio2_StopEngine(A) (A)->StopEngine()
#define IXAudio2MasteringVoice_DestroyVoice(A) (A)->DestroyVoice()
#define IXAudio2SourceVoice_DestroyVoice(A) (A)->DestroyVoice()
#define IXAudio2SourceVoice_Discontinuity(A) (A)->Discontinuity()
#define IXAudio2SourceVoice_FlushSourceBuffers(A) (A)->FlushSourceBuffers()
#define IXAudio2SourceVoice_GetState(A, B) (A)->GetState((B))
#define IXAudio2SourceVoice_Start(A, B, C) (A)->Start((B), (C))
#define IXAudio2SourceVoice_Stop(A, B, C) (A)->Stop((B), (C))
#define IXAudio2SourceVoice_SubmitSourceBuffer(A, B, C) (A)->SubmitSourceBuffer((B), (C))
*/
#endif // ifdef __cplusplus

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,93 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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"
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
/* *INDENT-OFF* */
extern "C" {
/* *INDENT-ON* */
#endif
#include <EGL/eglplatform.h>
#include <android/native_window_jni.h>
#include "SDL_rect.h"
/* Interface from the SDL library into the Android Java activity */
/* extern SDL_bool Android_JNI_CreateContext(int majorVersion, int minorVersion, int red, int green, int blue, int alpha, int buffer, int depth, int stencil, int buffers, int samples);
extern SDL_bool Android_JNI_DeleteContext(void); */
extern void Android_JNI_SwapWindow();
extern void Android_JNI_SetActivityTitle(const char *title);
extern SDL_bool Android_JNI_GetAccelerometerValues(float values[3]);
extern void Android_JNI_ShowTextInput(SDL_Rect *inputRect);
extern void Android_JNI_HideTextInput();
extern ANativeWindow* Android_JNI_GetNativeWindow(void);
/* Audio support */
extern int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames);
extern void* Android_JNI_GetAudioBuffer();
extern void Android_JNI_WriteAudioBuffer();
extern void Android_JNI_CloseAudioDevice();
#include "SDL_rwops.h"
int Android_JNI_FileOpen(SDL_RWops* ctx, const char* fileName, const char* mode);
Sint64 Android_JNI_FileSize(SDL_RWops* ctx);
Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence);
size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer, size_t size, size_t maxnum);
size_t Android_JNI_FileWrite(SDL_RWops* ctx, const void* buffer, size_t size, size_t num);
int Android_JNI_FileClose(SDL_RWops* ctx);
/* Clipboard support */
int Android_JNI_SetClipboardText(const char* text);
char* Android_JNI_GetClipboardText();
SDL_bool Android_JNI_HasClipboardText();
/* Power support */
int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seconds, int* percent);
/* Joystick support */
void Android_JNI_PollInputDevices();
/* Video */
void Android_JNI_SuspendScreenSaver(SDL_bool suspend);
/* Touch support */
int Android_JNI_GetTouchDeviceIds(int **ids);
/* Threads */
#include <jni.h>
JNIEnv *Android_JNI_GetEnv(void);
int Android_JNI_SetupThread(void);
jclass Android_JNI_GetActivityClass(void);
/* Generic messages */
int Android_JNI_SendMessage(int command, int param);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
/* *INDENT-OFF* */
}
/* *INDENT-ON* */
#endif
/* vi: set ts=4 sw=4 expandtab: */

238
src/core/linux/SDL_dbus.c Normal file
View File

@@ -0,0 +1,238 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_dbus.h"
#if SDL_USE_LIBDBUS
/* we never link directly to libdbus. */
#include "SDL_loadso.h"
static const char *dbus_library = "libdbus-1.so.3";
static void *dbus_handle = NULL;
static unsigned int screensaver_cookie = 0;
static SDL_DBusContext dbus = {0};
static int
load_dbus_syms(void)
{
#define SDL_DBUS_SYM2(x, y) \
if (!(dbus.x = SDL_LoadFunction(dbus_handle, #y))) return -1
#define SDL_DBUS_SYM(x) \
SDL_DBUS_SYM2(x, dbus_##x)
SDL_DBUS_SYM(bus_get_private);
SDL_DBUS_SYM(bus_register);
SDL_DBUS_SYM(bus_add_match);
SDL_DBUS_SYM(connection_open_private);
SDL_DBUS_SYM(connection_set_exit_on_disconnect);
SDL_DBUS_SYM(connection_get_is_connected);
SDL_DBUS_SYM(connection_add_filter);
SDL_DBUS_SYM(connection_send);
SDL_DBUS_SYM(connection_send_with_reply_and_block);
SDL_DBUS_SYM(connection_close);
SDL_DBUS_SYM(connection_unref);
SDL_DBUS_SYM(connection_flush);
SDL_DBUS_SYM(connection_read_write);
SDL_DBUS_SYM(connection_dispatch);
SDL_DBUS_SYM(message_is_signal);
SDL_DBUS_SYM(message_new_method_call);
SDL_DBUS_SYM(message_append_args);
SDL_DBUS_SYM(message_get_args);
SDL_DBUS_SYM(message_iter_init);
SDL_DBUS_SYM(message_iter_next);
SDL_DBUS_SYM(message_iter_get_basic);
SDL_DBUS_SYM(message_iter_get_arg_type);
SDL_DBUS_SYM(message_iter_recurse);
SDL_DBUS_SYM(message_unref);
SDL_DBUS_SYM(error_init);
SDL_DBUS_SYM(error_is_set);
SDL_DBUS_SYM(error_free);
SDL_DBUS_SYM(get_local_machine_id);
SDL_DBUS_SYM(free);
SDL_DBUS_SYM(shutdown);
#undef SDL_DBUS_SYM
#undef SDL_DBUS_SYM2
return 0;
}
static void
UnloadDBUSLibrary(void)
{
if (dbus_handle != NULL) {
SDL_UnloadObject(dbus_handle);
dbus_handle = NULL;
}
}
static int
LoadDBUSLibrary(void)
{
int retval = 0;
if (dbus_handle == NULL) {
dbus_handle = SDL_LoadObject(dbus_library);
if (dbus_handle == NULL) {
retval = -1;
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
} else {
retval = load_dbus_syms();
if (retval < 0) {
UnloadDBUSLibrary();
}
}
}
return retval;
}
void
SDL_DBus_Init(void)
{
if (!dbus.session_conn && LoadDBUSLibrary() != -1) {
DBusError err;
dbus.error_init(&err);
dbus.session_conn = dbus.bus_get_private(DBUS_BUS_SESSION, &err);
if (dbus.error_is_set(&err)) {
dbus.error_free(&err);
if (dbus.session_conn) {
dbus.connection_unref(dbus.session_conn);
dbus.session_conn = NULL;
}
return; /* oh well */
}
dbus.connection_set_exit_on_disconnect(dbus.session_conn, 0);
}
}
void
SDL_DBus_Quit(void)
{
if (dbus.session_conn) {
dbus.connection_close(dbus.session_conn);
dbus.connection_unref(dbus.session_conn);
dbus.shutdown();
SDL_memset(&dbus, 0, sizeof(dbus));
}
UnloadDBUSLibrary();
}
SDL_DBusContext *
SDL_DBus_GetContext(void)
{
if(!dbus_handle || !dbus.session_conn){
SDL_DBus_Init();
}
if(dbus_handle && dbus.session_conn){
return &dbus;
} else {
return NULL;
}
}
void
SDL_DBus_ScreensaverTickle(void)
{
DBusConnection *conn = dbus.session_conn;
if (conn != NULL) {
DBusMessage *msg = dbus.message_new_method_call("org.gnome.ScreenSaver",
"/org/gnome/ScreenSaver",
"org.gnome.ScreenSaver",
"SimulateUserActivity");
if (msg != NULL) {
if (dbus.connection_send(conn, msg, NULL)) {
dbus.connection_flush(conn);
}
dbus.message_unref(msg);
}
}
}
SDL_bool
SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
{
DBusConnection *conn = dbus.session_conn;
if (conn == NULL)
return SDL_FALSE;
if (inhibit &&
screensaver_cookie != 0)
return SDL_TRUE;
if (!inhibit &&
screensaver_cookie == 0)
return SDL_TRUE;
if (inhibit) {
const char *app = "My SDL application";
const char *reason = "Playing a game";
DBusMessage *msg = dbus.message_new_method_call("org.freedesktop.ScreenSaver",
"/org/freedesktop/ScreenSaver",
"org.freedesktop.ScreenSaver",
"Inhibit");
if (msg != NULL) {
dbus.message_append_args (msg,
DBUS_TYPE_STRING, &app,
DBUS_TYPE_STRING, &reason,
DBUS_TYPE_INVALID);
}
if (msg != NULL) {
DBusMessage *reply;
reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
if (reply) {
if (!dbus.message_get_args(reply, NULL,
DBUS_TYPE_UINT32, &screensaver_cookie,
DBUS_TYPE_INVALID))
screensaver_cookie = 0;
dbus.message_unref(reply);
}
dbus.message_unref(msg);
}
if (screensaver_cookie == 0) {
return SDL_FALSE;
}
return SDL_TRUE;
} else {
DBusMessage *msg = dbus.message_new_method_call("org.freedesktop.ScreenSaver",
"/org/freedesktop/ScreenSaver",
"org.freedesktop.ScreenSaver",
"UnInhibit");
dbus.message_append_args (msg,
DBUS_TYPE_UINT32, &screensaver_cookie,
DBUS_TYPE_INVALID);
if (msg != NULL) {
if (dbus.connection_send(conn, msg, NULL)) {
dbus.connection_flush(conn);
}
dbus.message_unref(msg);
}
screensaver_cookie = 0;
return SDL_TRUE;
}
}
#endif

80
src/core/linux/SDL_dbus.h Normal file
View File

@@ -0,0 +1,80 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_dbus_h
#define _SDL_dbus_h
#ifdef HAVE_DBUS_DBUS_H
#define SDL_USE_LIBDBUS 1
#include "SDL_stdinc.h"
#include <dbus/dbus.h>
typedef struct SDL_DBusContext {
DBusConnection *session_conn;
DBusConnection *(*bus_get_private)(DBusBusType, DBusError *);
dbus_bool_t (*bus_register)(DBusConnection *, DBusError *);
void (*bus_add_match)(DBusConnection *, const char *, DBusError *);
DBusConnection * (*connection_open_private)(const char *, DBusError *);
void (*connection_set_exit_on_disconnect)(DBusConnection *, dbus_bool_t);
dbus_bool_t (*connection_get_is_connected)(DBusConnection *);
dbus_bool_t (*connection_add_filter)(DBusConnection *, DBusHandleMessageFunction,
void *, DBusFreeFunction);
dbus_bool_t (*connection_send)(DBusConnection *, DBusMessage *, dbus_uint32_t *);
DBusMessage *(*connection_send_with_reply_and_block)(DBusConnection *, DBusMessage *, int, DBusError *);
void (*connection_close)(DBusConnection *);
void (*connection_unref)(DBusConnection *);
void (*connection_flush)(DBusConnection *);
dbus_bool_t (*connection_read_write)(DBusConnection *, int);
DBusDispatchStatus (*connection_dispatch)(DBusConnection *);
dbus_bool_t (*message_is_signal)(DBusMessage *, const char *, const char *);
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_get_args)(DBusMessage *, DBusError *, int, ...);
dbus_bool_t (*message_iter_init)(DBusMessage *, DBusMessageIter *);
dbus_bool_t (*message_iter_next)(DBusMessageIter *);
void (*message_iter_get_basic)(DBusMessageIter *, void *);
int (*message_iter_get_arg_type)(DBusMessageIter *);
void (*message_iter_recurse)(DBusMessageIter *, DBusMessageIter *);
void (*message_unref)(DBusMessage *);
void (*error_init)(DBusError *);
dbus_bool_t (*error_is_set)(const DBusError *);
void (*error_free)(DBusError *);
char *(*get_local_machine_id)(void);
void (*free)(void *);
void (*shutdown)(void);
} SDL_DBusContext;
extern void SDL_DBus_Init(void);
extern void SDL_DBus_Quit(void);
extern SDL_DBusContext * SDL_DBus_GetContext(void);
extern void SDL_DBus_ScreensaverTickle(void);
extern SDL_bool SDL_DBus_ScreensaverInhibit(SDL_bool inhibit);
#endif /* HAVE_DBUS_DBUS_H */
#endif /* _SDL_dbus_h */
/* vi: set ts=4 sw=4 expandtab: */

809
src/core/linux/SDL_evdev.c Normal file
View File

@@ -0,0 +1,809 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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"
#ifdef SDL_INPUT_LINUXEV
/* This is based on the linux joystick driver */
/* References: https://www.kernel.org/doc/Documentation/input/input.txt
* https://www.kernel.org/doc/Documentation/input/event-codes.txt
* /usr/include/linux/input.h
* The evtest application is also useful to debug the protocol
*/
#include "SDL_evdev.h"
#define _THIS SDL_EVDEV_PrivateData *_this
static _THIS = NULL;
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <limits.h> /* For the definition of PATH_MAX */
#include <linux/input.h>
#ifdef SDL_INPUT_LINUXKD
#include <linux/kd.h>
#include <linux/keyboard.h>
#endif
/* We need this to prevent keystrokes from appear in the console */
#ifndef KDSKBMUTE
#define KDSKBMUTE 0x4B51
#endif
#ifndef KDSKBMODE
#define KDSKBMODE 0x4B45
#endif
#ifndef K_OFF
#define K_OFF 0x04
#endif
#include "SDL.h"
#include "SDL_assert.h"
#include "SDL_endian.h"
#include "../../core/linux/SDL_udev.h"
#include "SDL_scancode.h"
#include "../../events/SDL_events_c.h"
/* This isn't defined in older Linux kernel headers */
#ifndef SYN_DROPPED
#define SYN_DROPPED 3
#endif
static SDL_Scancode SDL_EVDEV_translate_keycode(int keycode);
static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
static int SDL_EVDEV_device_removed(const char *devpath);
#if SDL_USE_LIBUDEV
static int SDL_EVDEV_device_added(const char *devpath);
void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
#endif /* SDL_USE_LIBUDEV */
static SDL_Scancode EVDEV_Keycodes[] = {
SDL_SCANCODE_UNKNOWN, /* KEY_RESERVED 0 */
SDL_SCANCODE_ESCAPE, /* KEY_ESC 1 */
SDL_SCANCODE_1, /* KEY_1 2 */
SDL_SCANCODE_2, /* KEY_2 3 */
SDL_SCANCODE_3, /* KEY_3 4 */
SDL_SCANCODE_4, /* KEY_4 5 */
SDL_SCANCODE_5, /* KEY_5 6 */
SDL_SCANCODE_6, /* KEY_6 7 */
SDL_SCANCODE_7, /* KEY_7 8 */
SDL_SCANCODE_8, /* KEY_8 9 */
SDL_SCANCODE_9, /* KEY_9 10 */
SDL_SCANCODE_0, /* KEY_0 11 */
SDL_SCANCODE_MINUS, /* KEY_MINUS 12 */
SDL_SCANCODE_EQUALS, /* KEY_EQUAL 13 */
SDL_SCANCODE_BACKSPACE, /* KEY_BACKSPACE 14 */
SDL_SCANCODE_TAB, /* KEY_TAB 15 */
SDL_SCANCODE_Q, /* KEY_Q 16 */
SDL_SCANCODE_W, /* KEY_W 17 */
SDL_SCANCODE_E, /* KEY_E 18 */
SDL_SCANCODE_R, /* KEY_R 19 */
SDL_SCANCODE_T, /* KEY_T 20 */
SDL_SCANCODE_Y, /* KEY_Y 21 */
SDL_SCANCODE_U, /* KEY_U 22 */
SDL_SCANCODE_I, /* KEY_I 23 */
SDL_SCANCODE_O, /* KEY_O 24 */
SDL_SCANCODE_P, /* KEY_P 25 */
SDL_SCANCODE_LEFTBRACKET, /* KEY_LEFTBRACE 26 */
SDL_SCANCODE_RIGHTBRACKET, /* KEY_RIGHTBRACE 27 */
SDL_SCANCODE_RETURN, /* KEY_ENTER 28 */
SDL_SCANCODE_LCTRL, /* KEY_LEFTCTRL 29 */
SDL_SCANCODE_A, /* KEY_A 30 */
SDL_SCANCODE_S, /* KEY_S 31 */
SDL_SCANCODE_D, /* KEY_D 32 */
SDL_SCANCODE_F, /* KEY_F 33 */
SDL_SCANCODE_G, /* KEY_G 34 */
SDL_SCANCODE_H, /* KEY_H 35 */
SDL_SCANCODE_J, /* KEY_J 36 */
SDL_SCANCODE_K, /* KEY_K 37 */
SDL_SCANCODE_L, /* KEY_L 38 */
SDL_SCANCODE_SEMICOLON, /* KEY_SEMICOLON 39 */
SDL_SCANCODE_APOSTROPHE, /* KEY_APOSTROPHE 40 */
SDL_SCANCODE_GRAVE, /* KEY_GRAVE 41 */
SDL_SCANCODE_LSHIFT, /* KEY_LEFTSHIFT 42 */
SDL_SCANCODE_BACKSLASH, /* KEY_BACKSLASH 43 */
SDL_SCANCODE_Z, /* KEY_Z 44 */
SDL_SCANCODE_X, /* KEY_X 45 */
SDL_SCANCODE_C, /* KEY_C 46 */
SDL_SCANCODE_V, /* KEY_V 47 */
SDL_SCANCODE_B, /* KEY_B 48 */
SDL_SCANCODE_N, /* KEY_N 49 */
SDL_SCANCODE_M, /* KEY_M 50 */
SDL_SCANCODE_COMMA, /* KEY_COMMA 51 */
SDL_SCANCODE_PERIOD, /* KEY_DOT 52 */
SDL_SCANCODE_SLASH, /* KEY_SLASH 53 */
SDL_SCANCODE_RSHIFT, /* KEY_RIGHTSHIFT 54 */
SDL_SCANCODE_KP_MULTIPLY, /* KEY_KPASTERISK 55 */
SDL_SCANCODE_LALT, /* KEY_LEFTALT 56 */
SDL_SCANCODE_SPACE, /* KEY_SPACE 57 */
SDL_SCANCODE_CAPSLOCK, /* KEY_CAPSLOCK 58 */
SDL_SCANCODE_F1, /* KEY_F1 59 */
SDL_SCANCODE_F2, /* KEY_F2 60 */
SDL_SCANCODE_F3, /* KEY_F3 61 */
SDL_SCANCODE_F4, /* KEY_F4 62 */
SDL_SCANCODE_F5, /* KEY_F5 63 */
SDL_SCANCODE_F6, /* KEY_F6 64 */
SDL_SCANCODE_F7, /* KEY_F7 65 */
SDL_SCANCODE_F8, /* KEY_F8 66 */
SDL_SCANCODE_F9, /* KEY_F9 67 */
SDL_SCANCODE_F10, /* KEY_F10 68 */
SDL_SCANCODE_NUMLOCKCLEAR, /* KEY_NUMLOCK 69 */
SDL_SCANCODE_SCROLLLOCK, /* KEY_SCROLLLOCK 70 */
SDL_SCANCODE_KP_7, /* KEY_KP7 71 */
SDL_SCANCODE_KP_8, /* KEY_KP8 72 */
SDL_SCANCODE_KP_9, /* KEY_KP9 73 */
SDL_SCANCODE_KP_MINUS, /* KEY_KPMINUS 74 */
SDL_SCANCODE_KP_4, /* KEY_KP4 75 */
SDL_SCANCODE_KP_5, /* KEY_KP5 76 */
SDL_SCANCODE_KP_6, /* KEY_KP6 77 */
SDL_SCANCODE_KP_PLUS, /* KEY_KPPLUS 78 */
SDL_SCANCODE_KP_1, /* KEY_KP1 79 */
SDL_SCANCODE_KP_2, /* KEY_KP2 80 */
SDL_SCANCODE_KP_3, /* KEY_KP3 81 */
SDL_SCANCODE_KP_0, /* KEY_KP0 82 */
SDL_SCANCODE_KP_PERIOD, /* KEY_KPDOT 83 */
SDL_SCANCODE_UNKNOWN, /* 84 */
SDL_SCANCODE_LANG5, /* KEY_ZENKAKUHANKAKU 85 */
SDL_SCANCODE_UNKNOWN, /* KEY_102ND 86 */
SDL_SCANCODE_F11, /* KEY_F11 87 */
SDL_SCANCODE_F12, /* KEY_F12 88 */
SDL_SCANCODE_UNKNOWN, /* KEY_RO 89 */
SDL_SCANCODE_LANG3, /* KEY_KATAKANA 90 */
SDL_SCANCODE_LANG4, /* KEY_HIRAGANA 91 */
SDL_SCANCODE_UNKNOWN, /* KEY_HENKAN 92 */
SDL_SCANCODE_LANG3, /* KEY_KATAKANAHIRAGANA 93 */
SDL_SCANCODE_UNKNOWN, /* KEY_MUHENKAN 94 */
SDL_SCANCODE_KP_COMMA, /* KEY_KPJPCOMMA 95 */
SDL_SCANCODE_KP_ENTER, /* KEY_KPENTER 96 */
SDL_SCANCODE_RCTRL, /* KEY_RIGHTCTRL 97 */
SDL_SCANCODE_KP_DIVIDE, /* KEY_KPSLASH 98 */
SDL_SCANCODE_SYSREQ, /* KEY_SYSRQ 99 */
SDL_SCANCODE_RALT, /* KEY_RIGHTALT 100 */
SDL_SCANCODE_UNKNOWN, /* KEY_LINEFEED 101 */
SDL_SCANCODE_HOME, /* KEY_HOME 102 */
SDL_SCANCODE_UP, /* KEY_UP 103 */
SDL_SCANCODE_PAGEUP, /* KEY_PAGEUP 104 */
SDL_SCANCODE_LEFT, /* KEY_LEFT 105 */
SDL_SCANCODE_RIGHT, /* KEY_RIGHT 106 */
SDL_SCANCODE_END, /* KEY_END 107 */
SDL_SCANCODE_DOWN, /* KEY_DOWN 108 */
SDL_SCANCODE_PAGEDOWN, /* KEY_PAGEDOWN 109 */
SDL_SCANCODE_INSERT, /* KEY_INSERT 110 */
SDL_SCANCODE_DELETE, /* KEY_DELETE 111 */
SDL_SCANCODE_UNKNOWN, /* KEY_MACRO 112 */
SDL_SCANCODE_MUTE, /* KEY_MUTE 113 */
SDL_SCANCODE_VOLUMEDOWN, /* KEY_VOLUMEDOWN 114 */
SDL_SCANCODE_VOLUMEUP, /* KEY_VOLUMEUP 115 */
SDL_SCANCODE_POWER, /* KEY_POWER 116 SC System Power Down */
SDL_SCANCODE_KP_EQUALS, /* KEY_KPEQUAL 117 */
SDL_SCANCODE_KP_MINUS, /* KEY_KPPLUSMINUS 118 */
SDL_SCANCODE_PAUSE, /* KEY_PAUSE 119 */
SDL_SCANCODE_UNKNOWN, /* KEY_SCALE 120 AL Compiz Scale (Expose) */
SDL_SCANCODE_KP_COMMA, /* KEY_KPCOMMA 121 */
SDL_SCANCODE_LANG1, /* KEY_HANGEUL,KEY_HANGUEL 122 */
SDL_SCANCODE_LANG2, /* KEY_HANJA 123 */
SDL_SCANCODE_INTERNATIONAL3,/* KEY_YEN 124 */
SDL_SCANCODE_LGUI, /* KEY_LEFTMETA 125 */
SDL_SCANCODE_RGUI, /* KEY_RIGHTMETA 126 */
SDL_SCANCODE_APPLICATION, /* KEY_COMPOSE 127 */
SDL_SCANCODE_STOP, /* KEY_STOP 128 AC Stop */
SDL_SCANCODE_AGAIN, /* KEY_AGAIN 129 */
SDL_SCANCODE_UNKNOWN, /* KEY_PROPS 130 AC Properties */
SDL_SCANCODE_UNDO, /* KEY_UNDO 131 AC Undo */
SDL_SCANCODE_UNKNOWN, /* KEY_FRONT 132 */
SDL_SCANCODE_COPY, /* KEY_COPY 133 AC Copy */
SDL_SCANCODE_UNKNOWN, /* KEY_OPEN 134 AC Open */
SDL_SCANCODE_PASTE, /* KEY_PASTE 135 AC Paste */
SDL_SCANCODE_FIND, /* KEY_FIND 136 AC Search */
SDL_SCANCODE_CUT, /* KEY_CUT 137 AC Cut */
SDL_SCANCODE_HELP, /* KEY_HELP 138 AL Integrated Help Center */
SDL_SCANCODE_MENU, /* KEY_MENU 139 Menu (show menu) */
SDL_SCANCODE_CALCULATOR, /* KEY_CALC 140 AL Calculator */
SDL_SCANCODE_UNKNOWN, /* KEY_SETUP 141 */
SDL_SCANCODE_SLEEP, /* KEY_SLEEP 142 SC System Sleep */
SDL_SCANCODE_UNKNOWN, /* KEY_WAKEUP 143 System Wake Up */
SDL_SCANCODE_UNKNOWN, /* KEY_FILE 144 AL Local Machine Browser */
SDL_SCANCODE_UNKNOWN, /* KEY_SENDFILE 145 */
SDL_SCANCODE_UNKNOWN, /* KEY_DELETEFILE 146 */
SDL_SCANCODE_UNKNOWN, /* KEY_XFER 147 */
SDL_SCANCODE_APP1, /* KEY_PROG1 148 */
SDL_SCANCODE_APP1, /* KEY_PROG2 149 */
SDL_SCANCODE_WWW, /* KEY_WWW 150 AL Internet Browser */
SDL_SCANCODE_UNKNOWN, /* KEY_MSDOS 151 */
SDL_SCANCODE_UNKNOWN, /* KEY_COFFEE,KEY_SCREENLOCK 152 AL Terminal Lock/Screensaver */
SDL_SCANCODE_UNKNOWN, /* KEY_DIRECTION 153 */
SDL_SCANCODE_UNKNOWN, /* KEY_CYCLEWINDOWS 154 */
SDL_SCANCODE_MAIL, /* KEY_MAIL 155 */
SDL_SCANCODE_AC_BOOKMARKS, /* KEY_BOOKMARKS 156 AC Bookmarks */
SDL_SCANCODE_COMPUTER, /* KEY_COMPUTER 157 */
SDL_SCANCODE_AC_BACK, /* KEY_BACK 158 AC Back */
SDL_SCANCODE_AC_FORWARD, /* KEY_FORWARD 159 AC Forward */
SDL_SCANCODE_UNKNOWN, /* KEY_CLOSECD 160 */
SDL_SCANCODE_EJECT, /* KEY_EJECTCD 161 */
SDL_SCANCODE_UNKNOWN, /* KEY_EJECTCLOSECD 162 */
SDL_SCANCODE_AUDIONEXT, /* KEY_NEXTSONG 163 */
SDL_SCANCODE_AUDIOPLAY, /* KEY_PLAYPAUSE 164 */
SDL_SCANCODE_AUDIOPREV, /* KEY_PREVIOUSSONG 165 */
SDL_SCANCODE_AUDIOSTOP, /* KEY_STOPCD 166 */
SDL_SCANCODE_UNKNOWN, /* KEY_RECORD 167 */
SDL_SCANCODE_UNKNOWN, /* KEY_REWIND 168 */
SDL_SCANCODE_UNKNOWN, /* KEY_PHONE 169 Media Select Telephone */
SDL_SCANCODE_UNKNOWN, /* KEY_ISO 170 */
SDL_SCANCODE_UNKNOWN, /* KEY_CONFIG 171 AL Consumer Control Configuration */
SDL_SCANCODE_AC_HOME, /* KEY_HOMEPAGE 172 AC Home */
SDL_SCANCODE_AC_REFRESH, /* KEY_REFRESH 173 AC Refresh */
SDL_SCANCODE_UNKNOWN, /* KEY_EXIT 174 AC Exit */
SDL_SCANCODE_UNKNOWN, /* KEY_MOVE 175 */
SDL_SCANCODE_UNKNOWN, /* KEY_EDIT 176 */
SDL_SCANCODE_UNKNOWN, /* KEY_SCROLLUP 177 */
SDL_SCANCODE_UNKNOWN, /* KEY_SCROLLDOWN 178 */
SDL_SCANCODE_KP_LEFTPAREN, /* KEY_KPLEFTPAREN 179 */
SDL_SCANCODE_KP_RIGHTPAREN, /* KEY_KPRIGHTPAREN 180 */
SDL_SCANCODE_UNKNOWN, /* KEY_NEW 181 AC New */
SDL_SCANCODE_AGAIN, /* KEY_REDO 182 AC Redo/Repeat */
SDL_SCANCODE_F13, /* KEY_F13 183 */
SDL_SCANCODE_F14, /* KEY_F14 184 */
SDL_SCANCODE_F15, /* KEY_F15 185 */
SDL_SCANCODE_F16, /* KEY_F16 186 */
SDL_SCANCODE_F17, /* KEY_F17 187 */
SDL_SCANCODE_F18, /* KEY_F18 188 */
SDL_SCANCODE_F19, /* KEY_F19 189 */
SDL_SCANCODE_F20, /* KEY_F20 190 */
SDL_SCANCODE_F21, /* KEY_F21 191 */
SDL_SCANCODE_F22, /* KEY_F22 192 */
SDL_SCANCODE_F23, /* KEY_F23 193 */
SDL_SCANCODE_F24, /* KEY_F24 194 */
SDL_SCANCODE_UNKNOWN, /* 195 */
SDL_SCANCODE_UNKNOWN, /* 196 */
SDL_SCANCODE_UNKNOWN, /* 197 */
SDL_SCANCODE_UNKNOWN, /* 198 */
SDL_SCANCODE_UNKNOWN, /* 199 */
SDL_SCANCODE_UNKNOWN, /* KEY_PLAYCD 200 */
SDL_SCANCODE_UNKNOWN, /* KEY_PAUSECD 201 */
SDL_SCANCODE_UNKNOWN, /* KEY_PROG3 202 */
SDL_SCANCODE_UNKNOWN, /* KEY_PROG4 203 */
SDL_SCANCODE_UNKNOWN, /* KEY_DASHBOARD 204 AL Dashboard */
SDL_SCANCODE_UNKNOWN, /* KEY_SUSPEND 205 */
SDL_SCANCODE_UNKNOWN, /* KEY_CLOSE 206 AC Close */
SDL_SCANCODE_UNKNOWN, /* KEY_PLAY 207 */
SDL_SCANCODE_UNKNOWN, /* KEY_FASTFORWARD 208 */
SDL_SCANCODE_UNKNOWN, /* KEY_BASSBOOST 209 */
SDL_SCANCODE_UNKNOWN, /* KEY_PRINT 210 AC Print */
SDL_SCANCODE_UNKNOWN, /* KEY_HP 211 */
SDL_SCANCODE_UNKNOWN, /* KEY_CAMERA 212 */
SDL_SCANCODE_UNKNOWN, /* KEY_SOUND 213 */
SDL_SCANCODE_UNKNOWN, /* KEY_QUESTION 214 */
SDL_SCANCODE_UNKNOWN, /* KEY_EMAIL 215 */
SDL_SCANCODE_UNKNOWN, /* KEY_CHAT 216 */
SDL_SCANCODE_UNKNOWN, /* KEY_SEARCH 217 */
SDL_SCANCODE_UNKNOWN, /* KEY_CONNECT 218 */
SDL_SCANCODE_UNKNOWN, /* KEY_FINANCE 219 AL Checkbook/Finance */
SDL_SCANCODE_UNKNOWN, /* KEY_SPORT 220 */
SDL_SCANCODE_UNKNOWN, /* KEY_SHOP 221 */
SDL_SCANCODE_UNKNOWN, /* KEY_ALTERASE 222 */
SDL_SCANCODE_UNKNOWN, /* KEY_CANCEL 223 AC Cancel */
SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESSDOWN 224 */
SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESSUP 225 */
SDL_SCANCODE_UNKNOWN, /* KEY_MEDIA 226 */
SDL_SCANCODE_UNKNOWN, /* KEY_SWITCHVIDEOMODE 227 Cycle between available video outputs (Monitor/LCD/TV-out/etc) */
SDL_SCANCODE_UNKNOWN, /* KEY_KBDILLUMTOGGLE 228 */
SDL_SCANCODE_UNKNOWN, /* KEY_KBDILLUMDOWN 229 */
SDL_SCANCODE_UNKNOWN, /* KEY_KBDILLUMUP 230 */
SDL_SCANCODE_UNKNOWN, /* KEY_SEND 231 AC Send */
SDL_SCANCODE_UNKNOWN, /* KEY_REPLY 232 AC Reply */
SDL_SCANCODE_UNKNOWN, /* KEY_FORWARDMAIL 233 AC Forward Msg */
SDL_SCANCODE_UNKNOWN, /* KEY_SAVE 234 AC Save */
SDL_SCANCODE_UNKNOWN, /* KEY_DOCUMENTS 235 */
SDL_SCANCODE_UNKNOWN, /* KEY_BATTERY 236 */
SDL_SCANCODE_UNKNOWN, /* KEY_BLUETOOTH 237 */
SDL_SCANCODE_UNKNOWN, /* KEY_WLAN 238 */
SDL_SCANCODE_UNKNOWN, /* KEY_UWB 239 */
SDL_SCANCODE_UNKNOWN, /* KEY_UNKNOWN 240 */
SDL_SCANCODE_UNKNOWN, /* KEY_VIDEO_NEXT 241 drive next video source */
SDL_SCANCODE_UNKNOWN, /* KEY_VIDEO_PREV 242 drive previous video source */
SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESS_CYCLE 243 brightness up, after max is min */
SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESS_ZERO 244 brightness off, use ambient */
SDL_SCANCODE_UNKNOWN, /* KEY_DISPLAY_OFF 245 display device to off state */
SDL_SCANCODE_UNKNOWN, /* KEY_WIMAX 246 */
SDL_SCANCODE_UNKNOWN, /* KEY_RFKILL 247 Key that controls all radios */
SDL_SCANCODE_UNKNOWN, /* KEY_MICMUTE 248 Mute / unmute the microphone */
};
static Uint8 EVDEV_MouseButtons[] = {
SDL_BUTTON_LEFT, /* BTN_LEFT 0x110 */
SDL_BUTTON_RIGHT, /* BTN_RIGHT 0x111 */
SDL_BUTTON_MIDDLE, /* BTN_MIDDLE 0x112 */
SDL_BUTTON_X1, /* BTN_SIDE 0x113 */
SDL_BUTTON_X2, /* BTN_EXTRA 0x114 */
SDL_BUTTON_X2 + 1, /* BTN_FORWARD 0x115 */
SDL_BUTTON_X2 + 2, /* BTN_BACK 0x116 */
SDL_BUTTON_X2 + 3 /* BTN_TASK 0x117 */
};
static char* EVDEV_consoles[] = {
"/proc/self/fd/0",
"/dev/tty",
"/dev/tty0",
"/dev/tty1",
"/dev/tty2",
"/dev/tty3",
"/dev/tty4",
"/dev/tty5",
"/dev/tty6",
"/dev/vc/0",
"/dev/console"
};
#define IS_CONSOLE(fd) isatty (fd) && ioctl(fd, KDGKBTYPE, &arg) == 0 && ((arg == KB_101) || (arg == KB_84))
static int SDL_EVDEV_get_console_fd(void)
{
int fd, i;
char arg = 0;
/* Try a few consoles to see which one we have read access to */
for( i = 0; i < SDL_arraysize(EVDEV_consoles); i++) {
fd = open(EVDEV_consoles[i], O_RDONLY);
if (fd >= 0) {
if (IS_CONSOLE(fd)) return fd;
close(fd);
}
}
/* Try stdin, stdout, stderr */
for( fd = 0; fd < 3; fd++) {
if (IS_CONSOLE(fd)) return fd;
}
/* We won't be able to send SDL_TEXTINPUT events */
return -1;
}
/* Prevent keystrokes from reaching the tty */
static int SDL_EVDEV_mute_keyboard(int tty, int *kb_mode)
{
char arg;
*kb_mode = 0; /* FIXME: Is this a sane default in case KDGKBMODE fails? */
if (!IS_CONSOLE(tty)) {
return SDL_SetError("Tried to mute an invalid tty");
}
ioctl(tty, KDGKBMODE, kb_mode); /* It's not fatal if this fails */
if (ioctl(tty, KDSKBMUTE, 1) && ioctl(tty, KDSKBMODE, K_OFF)) {
return SDL_SetError("EVDEV: Failed muting keyboard");
}
return 0;
}
/* Restore the keyboard mode for given tty */
static void SDL_EVDEV_unmute_keyboard(int tty, int kb_mode)
{
if (ioctl(tty, KDSKBMUTE, 0) && ioctl(tty, KDSKBMODE, kb_mode)) {
SDL_Log("EVDEV: Failed restoring keyboard mode");
}
}
/* Read /sys/class/tty/tty0/active and open the tty */
static int SDL_EVDEV_get_active_tty()
{
int fd, len;
char ttyname[NAME_MAX + 1];
char ttypath[PATH_MAX+1] = "/dev/";
char arg;
fd = open("/sys/class/tty/tty0/active", O_RDONLY);
if (fd < 0) {
return SDL_SetError("Could not determine which tty is active");
}
len = read(fd, ttyname, NAME_MAX);
close(fd);
if (len <= 0) {
return SDL_SetError("Could not read which tty is active");
}
if (ttyname[len-1] == '\n') {
ttyname[len-1] = '\0';
}
else {
ttyname[len] = '\0';
}
SDL_strlcat(ttypath, ttyname, PATH_MAX);
fd = open(ttypath, O_RDWR | O_NOCTTY);
if (fd < 0) {
return SDL_SetError("Could not open tty: %s", ttypath);
}
if (!IS_CONSOLE(fd)) {
close(fd);
return SDL_SetError("Invalid tty obtained: %s", ttypath);
}
return fd;
}
int
SDL_EVDEV_Init(void)
{
int retval = 0;
if (_this == NULL) {
_this = (SDL_EVDEV_PrivateData *) SDL_calloc(1, sizeof(*_this));
if(_this == NULL) {
return SDL_OutOfMemory();
}
#if SDL_USE_LIBUDEV
if (SDL_UDEV_Init() < 0) {
SDL_free(_this);
_this = NULL;
return -1;
}
/* Set up the udev callback */
if ( SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
SDL_EVDEV_Quit();
return -1;
}
/* Force a scan to build the initial device list */
SDL_UDEV_Scan();
#else
/* TODO: Scan the devices manually, like a caveman */
#endif /* SDL_USE_LIBUDEV */
/* We need a physical terminal (not PTS) to be able to translate key code to symbols via the kernel tables */
_this->console_fd = SDL_EVDEV_get_console_fd();
/* Mute the keyboard so keystrokes only generate evdev events and do not leak through to the console */
_this->tty = STDIN_FILENO;
if (SDL_EVDEV_mute_keyboard(_this->tty, &_this->kb_mode) < 0) {
/* stdin is not a tty, probably we were launched remotely, so we try to disable the active tty */
_this->tty = SDL_EVDEV_get_active_tty();
if (_this->tty >= 0) {
if (SDL_EVDEV_mute_keyboard(_this->tty, &_this->kb_mode) < 0) {
close(_this->tty);
_this->tty = -1;
}
}
}
}
_this->ref_count += 1;
return retval;
}
void
SDL_EVDEV_Quit(void)
{
if (_this == NULL) {
return;
}
_this->ref_count -= 1;
if (_this->ref_count < 1) {
#if SDL_USE_LIBUDEV
SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback);
SDL_UDEV_Quit();
#endif /* SDL_USE_LIBUDEV */
if (_this->console_fd >= 0) {
close(_this->console_fd);
}
if (_this->tty >= 0) {
SDL_EVDEV_unmute_keyboard(_this->tty, _this->kb_mode);
close(_this->tty);
}
/* Remove existing devices */
while(_this->first != NULL) {
SDL_EVDEV_device_removed(_this->first->path);
}
SDL_assert(_this->first == NULL);
SDL_assert(_this->last == NULL);
SDL_assert(_this->numdevices == 0);
SDL_free(_this);
_this = NULL;
}
}
#if SDL_USE_LIBUDEV
void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
{
if (devpath == NULL) {
return;
}
if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE|SDL_UDEV_DEVICE_KEYBOARD))) {
return;
}
switch( udev_type ) {
case SDL_UDEV_DEVICEADDED:
SDL_EVDEV_device_added(devpath);
break;
case SDL_UDEV_DEVICEREMOVED:
SDL_EVDEV_device_removed(devpath);
break;
default:
break;
}
}
#endif /* SDL_USE_LIBUDEV */
void
SDL_EVDEV_Poll(void)
{
struct input_event events[32];
int i, len;
SDL_evdevlist_item *item;
SDL_Scancode scan_code;
int mouse_button;
SDL_Mouse *mouse;
#ifdef SDL_INPUT_LINUXKD
Uint16 modstate;
struct kbentry kbe;
static char keysym[8];
char *end;
Uint32 kval;
#endif
if (!_this) {
return;
}
#if SDL_USE_LIBUDEV
SDL_UDEV_Poll();
#endif
mouse = SDL_GetMouse();
for (item = _this->first; item != NULL; item = item->next) {
while ((len = read(item->fd, events, (sizeof events))) > 0) {
len /= sizeof(events[0]);
for (i = 0; i < len; ++i) {
switch (events[i].type) {
case EV_KEY:
if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) {
mouse_button = events[i].code - BTN_MOUSE;
if (events[i].value == 0) {
SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]);
} else if (events[i].value == 1) {
SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]);
}
break;
}
/* Probably keyboard */
scan_code = SDL_EVDEV_translate_keycode(events[i].code);
if (scan_code != SDL_SCANCODE_UNKNOWN) {
if (events[i].value == 0) {
SDL_SendKeyboardKey(SDL_RELEASED, scan_code);
} else if (events[i].value == 1 || events[i].value == 2 /* Key repeated */ ) {
SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
#ifdef SDL_INPUT_LINUXKD
if (_this->console_fd >= 0) {
kbe.kb_index = events[i].code;
/* Convert the key to an UTF-8 char */
/* Ref: http://www.linuxjournal.com/article/2783 */
modstate = SDL_GetModState();
kbe.kb_table = 0;
/* Ref: http://graphics.stanford.edu/~seander/bithacks.html#ConditionalSetOrClearBitsWithoutBranching */
kbe.kb_table |= -( (modstate & KMOD_LCTRL) != 0) & (1 << KG_CTRLL | 1 << KG_CTRL);
kbe.kb_table |= -( (modstate & KMOD_RCTRL) != 0) & (1 << KG_CTRLR | 1 << KG_CTRL);
kbe.kb_table |= -( (modstate & KMOD_LSHIFT) != 0) & (1 << KG_SHIFTL | 1 << KG_SHIFT);
kbe.kb_table |= -( (modstate & KMOD_RSHIFT) != 0) & (1 << KG_SHIFTR | 1 << KG_SHIFT);
kbe.kb_table |= -( (modstate & KMOD_LALT) != 0) & (1 << KG_ALT);
kbe.kb_table |= -( (modstate & KMOD_RALT) != 0) & (1 << KG_ALTGR);
if (ioctl(_this->console_fd, KDGKBENT, (unsigned long)&kbe) == 0 &&
((KTYP(kbe.kb_value) == KT_LATIN) || (KTYP(kbe.kb_value) == KT_ASCII) || (KTYP(kbe.kb_value) == KT_LETTER)))
{
kval = KVAL(kbe.kb_value);
/* While there's a KG_CAPSSHIFT symbol, it's not useful to build the table index with it
* because 1 << KG_CAPSSHIFT overflows the 8 bits of kb_table
* So, we do the CAPS LOCK logic here. Note that isalpha depends on the locale!
*/
if ( modstate & KMOD_CAPS && isalpha(kval) ) {
if ( isupper(kval) ) {
kval = tolower(kval);
} else {
kval = toupper(kval);
}
}
/* Convert to UTF-8 and send */
end = SDL_UCS4ToUTF8( kval, keysym);
*end = '\0';
SDL_SendKeyboardText(keysym);
}
}
#endif /* SDL_INPUT_LINUXKD */
}
}
break;
case EV_ABS:
switch(events[i].code) {
case ABS_X:
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
break;
case ABS_Y:
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value);
break;
default:
break;
}
break;
case EV_REL:
switch(events[i].code) {
case REL_X:
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0);
break;
case REL_Y:
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);
break;
case REL_HWHEEL:
SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0, SDL_MOUSEWHEEL_NORMAL);
break;
default:
break;
}
break;
case EV_SYN:
switch (events[i].code) {
case SYN_DROPPED:
SDL_EVDEV_sync_device(item);
break;
default:
break;
}
break;
}
}
}
}
}
static SDL_Scancode
SDL_EVDEV_translate_keycode(int keycode)
{
SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
if (keycode < SDL_arraysize(EVDEV_Keycodes)) {
scancode = EVDEV_Keycodes[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 mailing list <sdl@libsdl.org> EVDEV KeyCode %d \n", keycode);
}
return scancode;
}
static void
SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
{
/* TODO: get full state of device and report whatever is required */
}
#if SDL_USE_LIBUDEV
static int
SDL_EVDEV_device_added(const char *devpath)
{
SDL_evdevlist_item *item;
/* Check to make sure it's not already in list. */
for (item = _this->first; item != NULL; item = item->next) {
if (strcmp(devpath, item->path) == 0) {
return -1; /* already have this one */
}
}
item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
if (item == NULL) {
return SDL_OutOfMemory();
}
item->fd = open(devpath, O_RDONLY, 0);
if (item->fd < 0) {
SDL_free(item);
return SDL_SetError("Unable to open %s", devpath);
}
item->path = SDL_strdup(devpath);
if (item->path == NULL) {
close(item->fd);
SDL_free(item);
return SDL_OutOfMemory();
}
/* Non blocking read mode */
fcntl(item->fd, F_SETFL, O_NONBLOCK);
if (_this->last == NULL) {
_this->first = _this->last = item;
} else {
_this->last->next = item;
_this->last = item;
}
SDL_EVDEV_sync_device(item);
return _this->numdevices++;
}
#endif /* SDL_USE_LIBUDEV */
static int
SDL_EVDEV_device_removed(const char *devpath)
{
SDL_evdevlist_item *item;
SDL_evdevlist_item *prev = NULL;
for (item = _this->first; item != NULL; item = item->next) {
/* found it, remove it. */
if ( strcmp(devpath, item->path) ==0 ) {
if (prev != NULL) {
prev->next = item->next;
} else {
SDL_assert(_this->first == item);
_this->first = item->next;
}
if (item == _this->last) {
_this->last = prev;
}
close(item->fd);
SDL_free(item->path);
SDL_free(item);
_this->numdevices--;
return 0;
}
prev = item;
}
return -1;
}
#endif /* SDL_INPUT_LINUXEV */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,59 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_evdev_h
#define _SDL_evdev_h
#ifdef SDL_INPUT_LINUXEV
#include "SDL_events.h"
#include <sys/stat.h>
typedef struct SDL_evdevlist_item
{
char *path;
int fd;
struct SDL_evdevlist_item *next;
} SDL_evdevlist_item;
typedef struct SDL_EVDEV_PrivateData
{
SDL_evdevlist_item *first;
SDL_evdevlist_item *last;
int numdevices;
int ref_count;
int console_fd;
int kb_mode;
int tty;
} SDL_EVDEV_PrivateData;
extern int SDL_EVDEV_Init(void);
extern void SDL_EVDEV_Quit(void);
extern void SDL_EVDEV_Poll(void);
#endif /* SDL_INPUT_LINUXEV */
#endif /* _SDL_evdev_h */
/* vi: set ts=4 sw=4 expandtab: */

676
src/core/linux/SDL_ibus.c Normal file
View File

@@ -0,0 +1,676 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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"
#ifdef HAVE_IBUS_IBUS_H
#include "SDL.h"
#include "SDL_syswm.h"
#include "SDL_ibus.h"
#include "SDL_dbus.h"
#include "../../video/SDL_sysvideo.h"
#include "../../events/SDL_keyboard_c.h"
#if SDL_VIDEO_DRIVER_X11
#include "../../video/x11/SDL_x11video.h"
#endif
#include <sys/inotify.h>
#include <unistd.h>
#include <fcntl.h>
static const char IBUS_SERVICE[] = "org.freedesktop.IBus";
static const char IBUS_PATH[] = "/org/freedesktop/IBus";
static const char IBUS_INTERFACE[] = "org.freedesktop.IBus";
static const char IBUS_INPUT_INTERFACE[] = "org.freedesktop.IBus.InputContext";
static char *input_ctx_path = NULL;
static SDL_Rect ibus_cursor_rect = {0};
static DBusConnection *ibus_conn = NULL;
static char *ibus_addr_file = NULL;
int inotify_fd = -1, inotify_wd = -1;
static Uint32
IBus_ModState(void)
{
Uint32 ibus_mods = 0;
SDL_Keymod sdl_mods = SDL_GetModState();
/* Not sure about MOD3, MOD4 and HYPER mappings */
if (sdl_mods & KMOD_LSHIFT) ibus_mods |= IBUS_SHIFT_MASK;
if (sdl_mods & KMOD_CAPS) ibus_mods |= IBUS_LOCK_MASK;
if (sdl_mods & KMOD_LCTRL) ibus_mods |= IBUS_CONTROL_MASK;
if (sdl_mods & KMOD_LALT) ibus_mods |= IBUS_MOD1_MASK;
if (sdl_mods & KMOD_NUM) ibus_mods |= IBUS_MOD2_MASK;
if (sdl_mods & KMOD_MODE) ibus_mods |= IBUS_MOD5_MASK;
if (sdl_mods & KMOD_LGUI) ibus_mods |= IBUS_SUPER_MASK;
if (sdl_mods & KMOD_RGUI) ibus_mods |= IBUS_META_MASK;
return ibus_mods;
}
static const char *
IBus_GetVariantText(DBusConnection *conn, DBusMessageIter *iter, SDL_DBusContext *dbus)
{
/* The text we need is nested weirdly, use dbus-monitor to see the structure better */
const char *text = NULL;
const char *struct_id = NULL;
DBusMessageIter sub1, sub2;
if (dbus->message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT) {
return NULL;
}
dbus->message_iter_recurse(iter, &sub1);
if (dbus->message_iter_get_arg_type(&sub1) != DBUS_TYPE_STRUCT) {
return NULL;
}
dbus->message_iter_recurse(&sub1, &sub2);
if (dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
return NULL;
}
dbus->message_iter_get_basic(&sub2, &struct_id);
if (!struct_id || SDL_strncmp(struct_id, "IBusText", sizeof("IBusText")) != 0) {
return NULL;
}
dbus->message_iter_next(&sub2);
dbus->message_iter_next(&sub2);
if (dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
return NULL;
}
dbus->message_iter_get_basic(&sub2, &text);
return text;
}
static size_t
IBus_utf8_strlen(const char *str)
{
size_t utf8_len = 0;
const char *p;
for (p = str; *p; ++p) {
if (!((*p & 0x80) && !(*p & 0x40))) {
++utf8_len;
}
}
return utf8_len;
}
static DBusHandlerResult
IBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *user_data)
{
SDL_DBusContext *dbus = (SDL_DBusContext *)user_data;
if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "CommitText")) {
DBusMessageIter iter;
const char *text;
dbus->message_iter_init(msg, &iter);
text = IBus_GetVariantText(conn, &iter, dbus);
if (text && *text) {
char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
size_t text_bytes = SDL_strlen(text), i = 0;
while (i < text_bytes) {
size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
SDL_SendKeyboardText(buf);
i += sz;
}
}
return DBUS_HANDLER_RESULT_HANDLED;
}
if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "UpdatePreeditText")) {
DBusMessageIter iter;
const char *text;
dbus->message_iter_init(msg, &iter);
text = IBus_GetVariantText(conn, &iter, dbus);
if (text && *text) {
char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
size_t text_bytes = SDL_strlen(text), i = 0;
size_t cursor = 0;
while (i < text_bytes) {
size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
size_t chars = IBus_utf8_strlen(buf);
SDL_SendEditingText(buf, cursor, chars);
i += sz;
cursor += chars;
}
}
SDL_IBus_UpdateTextRect(NULL);
return DBUS_HANDLER_RESULT_HANDLED;
}
if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "HidePreeditText")) {
SDL_SendEditingText("", 0, 0);
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static char *
IBus_ReadAddressFromFile(const char *file_path)
{
char addr_buf[1024];
SDL_bool success = SDL_FALSE;
FILE *addr_file;
addr_file = fopen(file_path, "r");
if (!addr_file) {
return NULL;
}
while (fgets(addr_buf, sizeof(addr_buf), addr_file)) {
if (SDL_strncmp(addr_buf, "IBUS_ADDRESS=", sizeof("IBUS_ADDRESS=")-1) == 0) {
size_t sz = SDL_strlen(addr_buf);
if (addr_buf[sz-1] == '\n') addr_buf[sz-1] = 0;
if (addr_buf[sz-2] == '\r') addr_buf[sz-2] = 0;
success = SDL_TRUE;
break;
}
}
fclose(addr_file);
if (success) {
return SDL_strdup(addr_buf + (sizeof("IBUS_ADDRESS=") - 1));
} else {
return NULL;
}
}
static char *
IBus_GetDBusAddressFilename(void)
{
SDL_DBusContext *dbus;
const char *disp_env;
char config_dir[PATH_MAX];
char *display = NULL;
const char *addr;
const char *conf_env;
char *key;
char file_path[PATH_MAX];
const char *host;
char *disp_num, *screen_num;
if (ibus_addr_file) {
return SDL_strdup(ibus_addr_file);
}
dbus = SDL_DBus_GetContext();
if (!dbus) {
return NULL;
}
/* Use this environment variable if it exists. */
addr = SDL_getenv("IBUS_ADDRESS");
if (addr && *addr) {
return SDL_strdup(addr);
}
/* Otherwise, we have to get the hostname, display, machine id, config dir
and look up the address from a filepath using all those bits, eek. */
disp_env = SDL_getenv("DISPLAY");
if (!disp_env || !*disp_env) {
display = SDL_strdup(":0.0");
} else {
display = SDL_strdup(disp_env);
}
host = display;
disp_num = SDL_strrchr(display, ':');
screen_num = SDL_strrchr(display, '.');
if (!disp_num) {
SDL_free(display);
return NULL;
}
*disp_num = 0;
disp_num++;
if (screen_num) {
*screen_num = 0;
}
if (!*host) {
host = "unix";
}
SDL_memset(config_dir, 0, sizeof(config_dir));
conf_env = SDL_getenv("XDG_CONFIG_HOME");
if (conf_env && *conf_env) {
SDL_strlcpy(config_dir, conf_env, sizeof(config_dir));
} else {
const char *home_env = SDL_getenv("HOME");
if (!home_env || !*home_env) {
SDL_free(display);
return NULL;
}
SDL_snprintf(config_dir, sizeof(config_dir), "%s/.config", home_env);
}
key = dbus->get_local_machine_id();
SDL_memset(file_path, 0, sizeof(file_path));
SDL_snprintf(file_path, sizeof(file_path), "%s/ibus/bus/%s-%s-%s",
config_dir, key, host, disp_num);
dbus->free(key);
SDL_free(display);
return SDL_strdup(file_path);
}
static SDL_bool IBus_CheckConnection(SDL_DBusContext *dbus);
static void
IBus_SetCapabilities(void *data, const char *name, const char *old_val,
const char *internal_editing)
{
SDL_DBusContext *dbus = SDL_DBus_GetContext();
if (IBus_CheckConnection(dbus)) {
DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
input_ctx_path,
IBUS_INPUT_INTERFACE,
"SetCapabilities");
if (msg) {
Uint32 caps = IBUS_CAP_FOCUS;
if (!(internal_editing && *internal_editing == '1')) {
caps |= IBUS_CAP_PREEDIT_TEXT;
}
dbus->message_append_args(msg,
DBUS_TYPE_UINT32, &caps,
DBUS_TYPE_INVALID);
}
if (msg) {
if (dbus->connection_send(ibus_conn, msg, NULL)) {
dbus->connection_flush(ibus_conn);
}
dbus->message_unref(msg);
}
}
}
static SDL_bool
IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr)
{
const char *path = NULL;
SDL_bool result = SDL_FALSE;
DBusMessage *msg;
ibus_conn = dbus->connection_open_private(addr, NULL);
if (!ibus_conn) {
return SDL_FALSE;
}
dbus->connection_flush(ibus_conn);
if (!dbus->bus_register(ibus_conn, NULL)) {
ibus_conn = NULL;
return SDL_FALSE;
}
dbus->connection_flush(ibus_conn);
msg = dbus->message_new_method_call(IBUS_SERVICE, IBUS_PATH, IBUS_INTERFACE, "CreateInputContext");
if (msg) {
const char *client_name = "SDL2_Application";
dbus->message_append_args(msg,
DBUS_TYPE_STRING, &client_name,
DBUS_TYPE_INVALID);
}
if (msg) {
DBusMessage *reply;
reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 1000, NULL);
if (reply) {
if (dbus->message_get_args(reply, NULL,
DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID)) {
if (input_ctx_path) {
SDL_free(input_ctx_path);
}
input_ctx_path = SDL_strdup(path);
result = SDL_TRUE;
}
dbus->message_unref(reply);
}
dbus->message_unref(msg);
}
if (result) {
SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL);
dbus->bus_add_match(ibus_conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL);
dbus->connection_add_filter(ibus_conn, &IBus_MessageFilter, dbus, NULL);
dbus->connection_flush(ibus_conn);
}
SDL_IBus_SetFocus(SDL_GetKeyboardFocus() != NULL);
SDL_IBus_UpdateTextRect(NULL);
return result;
}
static SDL_bool
IBus_CheckConnection(SDL_DBusContext *dbus)
{
if (!dbus) return SDL_FALSE;
if (ibus_conn && dbus->connection_get_is_connected(ibus_conn)) {
return SDL_TRUE;
}
if (inotify_fd > 0 && inotify_wd > 0) {
char buf[1024];
ssize_t readsize = read(inotify_fd, buf, sizeof(buf));
if (readsize > 0) {
char *p;
SDL_bool file_updated = SDL_FALSE;
for (p = buf; p < buf + readsize; /**/) {
struct inotify_event *event = (struct inotify_event*) p;
if (event->len > 0) {
char *addr_file_no_path = SDL_strrchr(ibus_addr_file, '/');
if (!addr_file_no_path) return SDL_FALSE;
if (SDL_strcmp(addr_file_no_path + 1, event->name) == 0) {
file_updated = SDL_TRUE;
break;
}
}
p += sizeof(struct inotify_event) + event->len;
}
if (file_updated) {
char *addr = IBus_ReadAddressFromFile(ibus_addr_file);
if (addr) {
SDL_bool result = IBus_SetupConnection(dbus, addr);
SDL_free(addr);
return result;
}
}
}
}
return SDL_FALSE;
}
SDL_bool
SDL_IBus_Init(void)
{
SDL_bool result = SDL_FALSE;
SDL_DBusContext *dbus = SDL_DBus_GetContext();
if (dbus) {
char *addr_file = IBus_GetDBusAddressFilename();
char *addr;
char *addr_file_dir;
if (!addr_file) {
return SDL_FALSE;
}
ibus_addr_file = SDL_strdup(addr_file);
addr = IBus_ReadAddressFromFile(addr_file);
if (!addr) {
return SDL_FALSE;
}
if (inotify_fd < 0) {
inotify_fd = inotify_init();
fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
}
addr_file_dir = SDL_strrchr(addr_file, '/');
if (addr_file_dir) {
*addr_file_dir = 0;
}
inotify_wd = inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY);
SDL_free(addr_file);
if (addr) {
result = IBus_SetupConnection(dbus, addr);
SDL_free(addr);
}
}
return result;
}
void
SDL_IBus_Quit(void)
{
SDL_DBusContext *dbus;
if (input_ctx_path) {
SDL_free(input_ctx_path);
input_ctx_path = NULL;
}
if (ibus_addr_file) {
SDL_free(ibus_addr_file);
ibus_addr_file = NULL;
}
dbus = SDL_DBus_GetContext();
if (dbus && ibus_conn) {
dbus->connection_close(ibus_conn);
dbus->connection_unref(ibus_conn);
}
if (inotify_fd > 0 && inotify_wd > 0) {
inotify_rm_watch(inotify_fd, inotify_wd);
inotify_wd = -1;
}
SDL_DelHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL);
SDL_memset(&ibus_cursor_rect, 0, sizeof(ibus_cursor_rect));
}
static void
IBus_SimpleMessage(const char *method)
{
SDL_DBusContext *dbus = SDL_DBus_GetContext();
if (IBus_CheckConnection(dbus)) {
DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
input_ctx_path,
IBUS_INPUT_INTERFACE,
method);
if (msg) {
if (dbus->connection_send(ibus_conn, msg, NULL)) {
dbus->connection_flush(ibus_conn);
}
dbus->message_unref(msg);
}
}
}
void
SDL_IBus_SetFocus(SDL_bool focused)
{
const char *method = focused ? "FocusIn" : "FocusOut";
IBus_SimpleMessage(method);
}
void
SDL_IBus_Reset(void)
{
IBus_SimpleMessage("Reset");
}
SDL_bool
SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
{
SDL_bool result = SDL_FALSE;
SDL_DBusContext *dbus = SDL_DBus_GetContext();
if (IBus_CheckConnection(dbus)) {
DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
input_ctx_path,
IBUS_INPUT_INTERFACE,
"ProcessKeyEvent");
if (msg) {
Uint32 mods = IBus_ModState();
dbus->message_append_args(msg,
DBUS_TYPE_UINT32, &keysym,
DBUS_TYPE_UINT32, &keycode,
DBUS_TYPE_UINT32, &mods,
DBUS_TYPE_INVALID);
}
if (msg) {
DBusMessage *reply;
reply = dbus->connection_send_with_reply_and_block(ibus_conn, msg, 300, NULL);
if (reply) {
if (!dbus->message_get_args(reply, NULL,
DBUS_TYPE_BOOLEAN, &result,
DBUS_TYPE_INVALID)) {
result = SDL_FALSE;
}
dbus->message_unref(reply);
}
dbus->message_unref(msg);
}
}
SDL_IBus_UpdateTextRect(NULL);
return result;
}
void
SDL_IBus_UpdateTextRect(SDL_Rect *rect)
{
SDL_Window *focused_win;
SDL_SysWMinfo info;
int x = 0, y = 0;
SDL_DBusContext *dbus;
if (rect) {
SDL_memcpy(&ibus_cursor_rect, rect, sizeof(ibus_cursor_rect));
}
focused_win = SDL_GetKeyboardFocus();
if (!focused_win) {
return;
}
SDL_VERSION(&info.version);
if (!SDL_GetWindowWMInfo(focused_win, &info)) {
return;
}
SDL_GetWindowPosition(focused_win, &x, &y);
#if SDL_VIDEO_DRIVER_X11
if (info.subsystem == SDL_SYSWM_X11) {
SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(focused_win)->driverdata;
Display *x_disp = info.info.x11.display;
Window x_win = info.info.x11.window;
int x_screen = displaydata->screen;
Window unused;
X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &y, &unused);
}
#endif
x += ibus_cursor_rect.x;
y += ibus_cursor_rect.y;
dbus = SDL_DBus_GetContext();
if (IBus_CheckConnection(dbus)) {
DBusMessage *msg = dbus->message_new_method_call(IBUS_SERVICE,
input_ctx_path,
IBUS_INPUT_INTERFACE,
"SetCursorLocation");
if (msg) {
dbus->message_append_args(msg,
DBUS_TYPE_INT32, &x,
DBUS_TYPE_INT32, &y,
DBUS_TYPE_INT32, &ibus_cursor_rect.w,
DBUS_TYPE_INT32, &ibus_cursor_rect.h,
DBUS_TYPE_INVALID);
}
if (msg) {
if (dbus->connection_send(ibus_conn, msg, NULL)) {
dbus->connection_flush(ibus_conn);
}
dbus->message_unref(msg);
}
}
}
void
SDL_IBus_PumpEvents(void)
{
SDL_DBusContext *dbus = SDL_DBus_GetContext();
if (IBus_CheckConnection(dbus)) {
dbus->connection_read_write(ibus_conn, 0);
while (dbus->connection_dispatch(ibus_conn) == DBUS_DISPATCH_DATA_REMAINS) {
/* Do nothing, actual work happens in IBus_MessageFilter */
}
}
}
#endif

58
src/core/linux/SDL_ibus.h Normal file
View File

@@ -0,0 +1,58 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_ibus_h
#define _SDL_ibus_h
#ifdef HAVE_IBUS_IBUS_H
#define SDL_USE_IBUS 1
#include "SDL_stdinc.h"
#include <ibus-1.0/ibus.h>
extern SDL_bool SDL_IBus_Init(void);
extern void SDL_IBus_Quit(void);
/* Lets the IBus server know about changes in window focus */
extern void SDL_IBus_SetFocus(SDL_bool focused);
/* Closes the candidate list and resets any text currently being edited */
extern void SDL_IBus_Reset(void);
/* Sends a keypress event to IBus, returns SDL_TRUE if IBus used this event to
update its candidate list or change input methods. PumpEvents should be
called some time after this, to recieve the TextInput / TextEditing event back. */
extern SDL_bool SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
/* Update the position of IBus' candidate list. If rect is NULL then this will
just reposition it relative to the focused window's new position. */
extern void SDL_IBus_UpdateTextRect(SDL_Rect *window_relative_rect);
/* Checks DBus for new IBus events, and calls SDL_SendKeyboardText /
SDL_SendEditingText for each event it finds */
extern void SDL_IBus_PumpEvents();
#endif /* HAVE_IBUS_IBUS_H */
#endif /* _SDL_ibus_h */
/* vi: set ts=4 sw=4 expandtab: */

529
src/core/linux/SDL_udev.c Normal file
View File

@@ -0,0 +1,529 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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.
*/
/*
* To list the properties of a device, try something like:
* udevadm info -a -n snd/hwC0D0 (for a sound card)
* udevadm info --query=all -n input/event3 (for a keyboard, mouse, etc)
* udevadm info --query=property -n input/event2
*/
#include "SDL_udev.h"
#ifdef SDL_USE_LIBUDEV
#include <linux/input.h>
#include "SDL.h"
static char* SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" };
#define _THIS SDL_UDEV_PrivateData *_this
static _THIS = NULL;
static SDL_bool SDL_UDEV_load_sym(const char *fn, void **addr);
static int SDL_UDEV_load_syms(void);
static SDL_bool SDL_UDEV_hotplug_update_available(void);
static void device_event(SDL_UDEV_deviceevent type, struct udev_device *dev);
static SDL_bool
SDL_UDEV_load_sym(const char *fn, void **addr)
{
*addr = SDL_LoadFunction(_this->udev_handle, fn);
if (*addr == NULL) {
/* Don't call SDL_SetError(): SDL_LoadFunction already did. */
return SDL_FALSE;
}
return SDL_TRUE;
}
static int
SDL_UDEV_load_syms(void)
{
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
#define SDL_UDEV_SYM(x) \
if (!SDL_UDEV_load_sym(#x, (void **) (char *) & _this->x)) return -1
SDL_UDEV_SYM(udev_device_get_action);
SDL_UDEV_SYM(udev_device_get_devnode);
SDL_UDEV_SYM(udev_device_get_subsystem);
SDL_UDEV_SYM(udev_device_get_parent_with_subsystem_devtype);
SDL_UDEV_SYM(udev_device_get_property_value);
SDL_UDEV_SYM(udev_device_get_sysattr_value);
SDL_UDEV_SYM(udev_device_new_from_syspath);
SDL_UDEV_SYM(udev_device_unref);
SDL_UDEV_SYM(udev_enumerate_add_match_property);
SDL_UDEV_SYM(udev_enumerate_add_match_subsystem);
SDL_UDEV_SYM(udev_enumerate_get_list_entry);
SDL_UDEV_SYM(udev_enumerate_new);
SDL_UDEV_SYM(udev_enumerate_scan_devices);
SDL_UDEV_SYM(udev_enumerate_unref);
SDL_UDEV_SYM(udev_list_entry_get_name);
SDL_UDEV_SYM(udev_list_entry_get_next);
SDL_UDEV_SYM(udev_monitor_enable_receiving);
SDL_UDEV_SYM(udev_monitor_filter_add_match_subsystem_devtype);
SDL_UDEV_SYM(udev_monitor_get_fd);
SDL_UDEV_SYM(udev_monitor_new_from_netlink);
SDL_UDEV_SYM(udev_monitor_receive_device);
SDL_UDEV_SYM(udev_monitor_unref);
SDL_UDEV_SYM(udev_new);
SDL_UDEV_SYM(udev_unref);
SDL_UDEV_SYM(udev_device_new_from_devnum);
SDL_UDEV_SYM(udev_device_get_devnum);
#undef SDL_UDEV_SYM
return 0;
}
static SDL_bool
SDL_UDEV_hotplug_update_available(void)
{
if (_this->udev_mon != NULL) {
const int fd = _this->udev_monitor_get_fd(_this->udev_mon);
fd_set fds;
struct timeval tv;
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = 0;
tv.tv_usec = 0;
if ((select(fd+1, &fds, NULL, NULL, &tv) > 0) && (FD_ISSET(fd, &fds))) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
int
SDL_UDEV_Init(void)
{
int retval = 0;
if (_this == NULL) {
_this = (SDL_UDEV_PrivateData *) SDL_calloc(1, sizeof(*_this));
if(_this == NULL) {
return SDL_OutOfMemory();
}
retval = SDL_UDEV_LoadLibrary();
if (retval < 0) {
SDL_UDEV_Quit();
return retval;
}
/* Set up udev monitoring
* Listen for input devices (mouse, keyboard, joystick, etc) and sound devices
*/
_this->udev = _this->udev_new();
if (_this->udev == NULL) {
SDL_UDEV_Quit();
return SDL_SetError("udev_new() failed");
}
_this->udev_mon = _this->udev_monitor_new_from_netlink(_this->udev, "udev");
if (_this->udev_mon == NULL) {
SDL_UDEV_Quit();
return SDL_SetError("udev_monitor_new_from_netlink() failed");
}
_this->udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "input", NULL);
_this->udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "sound", NULL);
_this->udev_monitor_enable_receiving(_this->udev_mon);
/* Do an initial scan of existing devices */
SDL_UDEV_Scan();
}
_this->ref_count += 1;
return retval;
}
void
SDL_UDEV_Quit(void)
{
SDL_UDEV_CallbackList *item;
if (_this == NULL) {
return;
}
_this->ref_count -= 1;
if (_this->ref_count < 1) {
if (_this->udev_mon != NULL) {
_this->udev_monitor_unref(_this->udev_mon);
_this->udev_mon = NULL;
}
if (_this->udev != NULL) {
_this->udev_unref(_this->udev);
_this->udev = NULL;
}
/* Remove existing devices */
while (_this->first != NULL) {
item = _this->first;
_this->first = _this->first->next;
SDL_free(item);
}
SDL_UDEV_UnloadLibrary();
SDL_free(_this);
_this = NULL;
}
}
void
SDL_UDEV_Scan(void)
{
struct udev_enumerate *enumerate = NULL;
struct udev_list_entry *devs = NULL;
struct udev_list_entry *item = NULL;
if (_this == NULL) {
return;
}
enumerate = _this->udev_enumerate_new(_this->udev);
if (enumerate == NULL) {
SDL_UDEV_Quit();
SDL_SetError("udev_monitor_new_from_netlink() failed");
return;
}
_this->udev_enumerate_add_match_subsystem(enumerate, "input");
_this->udev_enumerate_add_match_subsystem(enumerate, "sound");
_this->udev_enumerate_scan_devices(enumerate);
devs = _this->udev_enumerate_get_list_entry(enumerate);
for (item = devs; item; item = _this->udev_list_entry_get_next(item)) {
const char *path = _this->udev_list_entry_get_name(item);
struct udev_device *dev = _this->udev_device_new_from_syspath(_this->udev, path);
if (dev != NULL) {
device_event(SDL_UDEV_DEVICEADDED, dev);
_this->udev_device_unref(dev);
}
}
_this->udev_enumerate_unref(enumerate);
}
void
SDL_UDEV_UnloadLibrary(void)
{
if (_this == NULL) {
return;
}
if (_this->udev_handle != NULL) {
SDL_UnloadObject(_this->udev_handle);
_this->udev_handle = NULL;
}
}
int
SDL_UDEV_LoadLibrary(void)
{
int retval = 0, i;
if (_this == NULL) {
return SDL_SetError("UDEV not initialized");
}
if (_this->udev_handle == NULL) {
for( i = 0 ; i < SDL_arraysize(SDL_UDEV_LIBS); i++) {
_this->udev_handle = SDL_LoadObject(SDL_UDEV_LIBS[i]);
if (_this->udev_handle != NULL) {
retval = SDL_UDEV_load_syms();
if (retval < 0) {
SDL_UDEV_UnloadLibrary();
}
else {
break;
}
}
}
if (_this->udev_handle == NULL) {
retval = -1;
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
}
}
return retval;
}
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
#define OFF(x) ((x)%BITS_PER_LONG)
#define BIT(x) (1UL<<OFF(x))
#define LONG(x) ((x)/BITS_PER_LONG)
#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
static void get_caps(struct udev_device *dev, struct udev_device *pdev, const char *attr, unsigned long *bitmask, size_t bitmask_len)
{
const char *value;
char text[4096];
char *word;
int i;
unsigned long v;
SDL_memset(bitmask, 0, bitmask_len*sizeof(*bitmask));
value = _this->udev_device_get_sysattr_value(pdev, attr);
if (!value) {
return;
}
SDL_strlcpy(text, value, sizeof(text));
i = 0;
while ((word = SDL_strrchr(text, ' ')) != NULL) {
v = SDL_strtoul(word+1, NULL, 16);
if (i < bitmask_len) {
bitmask[i] = v;
}
++i;
*word = '\0';
}
v = SDL_strtoul(text, NULL, 16);
if (i < bitmask_len) {
bitmask[i] = v;
}
}
static int
guess_device_class(struct udev_device *dev)
{
int devclass = 0;
struct udev_device *pdev;
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)];
unsigned long keyboard_mask;
/* walk up the parental chain until we find the real input device; the
* argument is very likely a subdevice of this, like eventN */
pdev = dev;
while (pdev && !_this->udev_device_get_sysattr_value(pdev, "capabilities/ev")) {
pdev = _this->udev_device_get_parent_with_subsystem_devtype(pdev, "input", NULL);
}
if (!pdev) {
return 0;
}
get_caps(dev, pdev, "capabilities/ev", bitmask_ev, SDL_arraysize(bitmask_ev));
get_caps(dev, pdev, "capabilities/abs", bitmask_abs, SDL_arraysize(bitmask_abs));
get_caps(dev, pdev, "capabilities/rel", bitmask_rel, SDL_arraysize(bitmask_rel));
get_caps(dev, pdev, "capabilities/key", bitmask_key, SDL_arraysize(bitmask_key));
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)) {
; /* 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)) {
; /* 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 */
}
/* 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;
}
static void
device_event(SDL_UDEV_deviceevent type, struct udev_device *dev)
{
const char *subsystem;
const char *val = NULL;
int devclass = 0;
const char *path;
SDL_UDEV_CallbackList *item;
path = _this->udev_device_get_devnode(dev);
if (path == NULL) {
return;
}
subsystem = _this->udev_device_get_subsystem(dev);
if (SDL_strcmp(subsystem, "sound") == 0) {
devclass = SDL_UDEV_DEVICE_SOUND;
} else if (SDL_strcmp(subsystem, "input") == 0) {
/* udev rules reference: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c */
val = _this->udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_JOYSTICK;
}
val = _this->udev_device_get_property_value(dev, "ID_INPUT_MOUSE");
if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_MOUSE;
}
/* The undocumented rule is:
- All devices with keys get ID_INPUT_KEY
- From this subset, if they have ESC, numbers, and Q to D, it also gets ID_INPUT_KEYBOARD
Ref: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c#n183
*/
val = _this->udev_device_get_property_value(dev, "ID_INPUT_KEY");
if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_KEYBOARD;
}
if (devclass == 0) {
/* Fall back to old style input classes */
val = _this->udev_device_get_property_value(dev, "ID_CLASS");
if (val != NULL) {
if (SDL_strcmp(val, "joystick") == 0) {
devclass = SDL_UDEV_DEVICE_JOYSTICK;
} else if (SDL_strcmp(val, "mouse") == 0) {
devclass = SDL_UDEV_DEVICE_MOUSE;
} else if (SDL_strcmp(val, "kbd") == 0) {
devclass = SDL_UDEV_DEVICE_KEYBOARD;
} else {
return;
}
} else {
/* We could be linked with libudev on a system that doesn't have udev running */
devclass = guess_device_class(dev);
}
}
} else {
return;
}
/* Process callbacks */
for (item = _this->first; item != NULL; item = item->next) {
item->callback(type, devclass, path);
}
}
void
SDL_UDEV_Poll(void)
{
struct udev_device *dev = NULL;
const char *action = NULL;
if (_this == NULL) {
return;
}
while (SDL_UDEV_hotplug_update_available()) {
dev = _this->udev_monitor_receive_device(_this->udev_mon);
if (dev == NULL) {
break;
}
action = _this->udev_device_get_action(dev);
if (SDL_strcmp(action, "add") == 0) {
device_event(SDL_UDEV_DEVICEADDED, dev);
} else if (SDL_strcmp(action, "remove") == 0) {
device_event(SDL_UDEV_DEVICEREMOVED, dev);
}
_this->udev_device_unref(dev);
}
}
int
SDL_UDEV_AddCallback(SDL_UDEV_Callback cb)
{
SDL_UDEV_CallbackList *item;
item = (SDL_UDEV_CallbackList *) SDL_calloc(1, sizeof (SDL_UDEV_CallbackList));
if (item == NULL) {
return SDL_OutOfMemory();
}
item->callback = cb;
if (_this->last == NULL) {
_this->first = _this->last = item;
} else {
_this->last->next = item;
_this->last = item;
}
return 1;
}
void
SDL_UDEV_DelCallback(SDL_UDEV_Callback cb)
{
SDL_UDEV_CallbackList *item;
SDL_UDEV_CallbackList *prev = NULL;
for (item = _this->first; item != NULL; item = item->next) {
/* found it, remove it. */
if (item->callback == cb) {
if (prev != NULL) {
prev->next = item->next;
} else {
SDL_assert(_this->first == item);
_this->first = item->next;
}
if (item == _this->last) {
_this->last = prev;
}
SDL_free(item);
return;
}
prev = item;
}
}
#endif /* SDL_USE_LIBUDEV */

117
src/core/linux/SDL_udev.h Normal file
View File

@@ -0,0 +1,117 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_udev_h
#define _SDL_udev_h
#if HAVE_LIBUDEV_H
#ifndef SDL_USE_LIBUDEV
#define SDL_USE_LIBUDEV 1
#endif
#include "SDL_loadso.h"
#include "SDL_events.h"
#include <libudev.h>
#include <sys/time.h>
#include <sys/types.h>
/**
* \brief Device type
*/
typedef enum
{
SDL_UDEV_DEVICEADDED = 0x0001,
SDL_UDEV_DEVICEREMOVED
} SDL_UDEV_deviceevent;
/* A device can be any combination of these classes */
typedef enum
{
SDL_UDEV_DEVICE_MOUSE = 0x0001,
SDL_UDEV_DEVICE_KEYBOARD = 0x0002,
SDL_UDEV_DEVICE_JOYSTICK = 0x0004,
SDL_UDEV_DEVICE_SOUND = 0x0008
} SDL_UDEV_deviceclass;
typedef void (*SDL_UDEV_Callback)(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
typedef struct SDL_UDEV_CallbackList {
SDL_UDEV_Callback callback;
struct SDL_UDEV_CallbackList *next;
} SDL_UDEV_CallbackList;
typedef struct SDL_UDEV_PrivateData
{
const char *udev_library;
void *udev_handle;
struct udev *udev;
struct udev_monitor *udev_mon;
int ref_count;
SDL_UDEV_CallbackList *first, *last;
/* Function pointers */
const char *(*udev_device_get_action)(struct udev_device *);
const char *(*udev_device_get_devnode)(struct udev_device *);
const char *(*udev_device_get_subsystem)(struct udev_device *);
struct udev_device *(*udev_device_get_parent_with_subsystem_devtype)(struct udev_device *udev_device, const char *subsystem, const char *devtype);
const char *(*udev_device_get_property_value)(struct udev_device *, const char *);
const char *(*udev_device_get_sysattr_value)(struct udev_device *udev_device, const char *sysattr);
struct udev_device *(*udev_device_new_from_syspath)(struct udev *, const char *);
void (*udev_device_unref)(struct udev_device *);
int (*udev_enumerate_add_match_property)(struct udev_enumerate *, const char *, const char *);
int (*udev_enumerate_add_match_subsystem)(struct udev_enumerate *, const char *);
struct udev_list_entry *(*udev_enumerate_get_list_entry)(struct udev_enumerate *);
struct udev_enumerate *(*udev_enumerate_new)(struct udev *);
int (*udev_enumerate_scan_devices)(struct udev_enumerate *);
void (*udev_enumerate_unref)(struct udev_enumerate *);
const char *(*udev_list_entry_get_name)(struct udev_list_entry *);
struct udev_list_entry *(*udev_list_entry_get_next)(struct udev_list_entry *);
int (*udev_monitor_enable_receiving)(struct udev_monitor *);
int (*udev_monitor_filter_add_match_subsystem_devtype)(struct udev_monitor *, const char *, const char *);
int (*udev_monitor_get_fd)(struct udev_monitor *);
struct udev_monitor *(*udev_monitor_new_from_netlink)(struct udev *, const char *);
struct udev_device *(*udev_monitor_receive_device)(struct udev_monitor *);
void (*udev_monitor_unref)(struct udev_monitor *);
struct udev *(*udev_new)(void);
void (*udev_unref)(struct udev *);
struct udev_device * (*udev_device_new_from_devnum)(struct udev *udev, char type, dev_t devnum);
dev_t (*udev_device_get_devnum) (struct udev_device *udev_device);
} SDL_UDEV_PrivateData;
extern int SDL_UDEV_Init(void);
extern void SDL_UDEV_Quit(void);
extern void SDL_UDEV_UnloadLibrary(void);
extern int SDL_UDEV_LoadLibrary(void);
extern void SDL_UDEV_Poll(void);
extern void SDL_UDEV_Scan(void);
extern int SDL_UDEV_AddCallback(SDL_UDEV_Callback cb);
extern void SDL_UDEV_DelCallback(SDL_UDEV_Callback cb);
#endif /* HAVE_LIBUDEV_H */
#endif /* _SDL_udev_h */

View File

@@ -0,0 +1,111 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_directx_h
#define _SDL_directx_h
/* Include all of the DirectX 8.0 headers and adds any necessary tweaks */
#include "SDL_windows.h"
#include <mmsystem.h>
#ifndef WIN32
#define WIN32
#endif
#undef WINNT
/* Far pointers don't exist in 32-bit code */
#ifndef FAR
#define FAR
#endif
/* Error codes not yet included in Win32 API header files */
#ifndef MAKE_HRESULT
#define MAKE_HRESULT(sev,fac,code) \
((HRESULT)(((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))))
#endif
#ifndef S_OK
#define S_OK (HRESULT)0x00000000L
#endif
#ifndef SUCCEEDED
#define SUCCEEDED(x) ((HRESULT)(x) >= 0)
#endif
#ifndef FAILED
#define FAILED(x) ((HRESULT)(x)<0)
#endif
#ifndef E_FAIL
#define E_FAIL (HRESULT)0x80000008L
#endif
#ifndef E_NOINTERFACE
#define E_NOINTERFACE (HRESULT)0x80004002L
#endif
#ifndef E_OUTOFMEMORY
#define E_OUTOFMEMORY (HRESULT)0x8007000EL
#endif
#ifndef E_INVALIDARG
#define E_INVALIDARG (HRESULT)0x80070057L
#endif
#ifndef E_NOTIMPL
#define E_NOTIMPL (HRESULT)0x80004001L
#endif
#ifndef REGDB_E_CLASSNOTREG
#define REGDB_E_CLASSNOTREG (HRESULT)0x80040154L
#endif
/* Severity codes */
#ifndef SEVERITY_ERROR
#define SEVERITY_ERROR 1
#endif
/* Error facility codes */
#ifndef FACILITY_WIN32
#define FACILITY_WIN32 7
#endif
#ifndef FIELD_OFFSET
#define FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field))
#endif
/* DirectX headers (if it isn't included, I haven't tested it yet)
*/
/* We need these defines to mark what version of DirectX API we use */
#define DIRECTDRAW_VERSION 0x0700
#define DIRECTSOUND_VERSION 0x0800
#define DIRECTINPUT_VERSION 0x0800 /* Need version 7 for force feedback. Need version 8 so IDirectInput8_EnumDevices doesn't leak like a sieve... */
#ifdef HAVE_DDRAW_H
#include <ddraw.h>
#endif
#ifdef HAVE_DSOUND_H
#include <dsound.h>
#endif
#ifdef HAVE_DINPUT_H
#include <dinput.h>
#else
typedef struct { int unused; } DIDEVICEINSTANCE;
#endif
#endif /* _SDL_directx_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,129 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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 defined(__WIN32__) || defined(__WINRT__)
#include "SDL_windows.h"
#include "SDL_error.h"
#include "SDL_assert.h"
#include <objbase.h> /* for CoInitialize/CoUninitialize (Win32 only) */
#ifndef _WIN32_WINNT_VISTA
#define _WIN32_WINNT_VISTA 0x0600
#endif
/* Sets an error message based on GetLastError() */
int
WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr)
{
TCHAR buffer[1024];
char *message;
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0,
buffer, SDL_arraysize(buffer), NULL);
message = WIN_StringToUTF8(buffer);
SDL_SetError("%s%s%s", prefix ? prefix : "", prefix ? ": " : "", message);
SDL_free(message);
return -1;
}
/* Sets an error message based on GetLastError() */
int
WIN_SetError(const char *prefix)
{
return WIN_SetErrorFromHRESULT(prefix, GetLastError());
}
HRESULT
WIN_CoInitialize(void)
{
/* SDL handles any threading model, so initialize with the default, which
is compatible with OLE and if that doesn't work, try multi-threaded mode.
If you need multi-threaded mode, call CoInitializeEx() before SDL_Init()
*/
#ifdef __WINRT__
/* DLudwig: On WinRT, it is assumed that COM was initialized in main().
CoInitializeEx is available (not CoInitialize though), however
on WinRT, main() is typically declared with the [MTAThread]
attribute, which, AFAIK, should initialize COM.
*/
return S_OK;
#else
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (hr == RPC_E_CHANGED_MODE) {
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
}
/* S_FALSE means success, but someone else already initialized. */
/* You still need to call CoUninitialize in this case! */
if (hr == S_FALSE) {
return S_OK;
}
return hr;
#endif
}
void
WIN_CoUninitialize(void)
{
#ifndef __WINRT__
CoUninitialize();
#endif
}
#ifndef __WINRT__
static BOOL
IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
{
OSVERSIONINFOEXW osvi;
DWORDLONG const dwlConditionMask = VerSetConditionMask(
VerSetConditionMask(
VerSetConditionMask(
0, VER_MAJORVERSION, VER_GREATER_EQUAL ),
VER_MINORVERSION, VER_GREATER_EQUAL ),
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL );
SDL_zero(osvi);
osvi.dwOSVersionInfoSize = sizeof(osvi);
osvi.dwMajorVersion = wMajorVersion;
osvi.dwMinorVersion = wMinorVersion;
osvi.wServicePackMajor = wServicePackMajor;
return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
}
#endif
BOOL WIN_IsWindowsVistaOrGreater()
{
#ifdef __WINRT__
return TRUE;
#else
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0);
#endif
}
#endif /* __WIN32__ */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,64 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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.
*/
/* This is an include file for windows.h with the SDL build settings */
#ifndef _INCLUDED_WINDOWS_H
#define _INCLUDED_WINDOWS_H
#if defined(__WIN32__)
#define WIN32_LEAN_AND_MEAN
#define STRICT
#ifndef UNICODE
#define UNICODE 1
#endif
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x501 /* Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices(), 0x501 for raw input */
#endif
#include <windows.h>
/* Routines to convert from UTF8 to native Windows text */
#if UNICODE
#define WIN_StringToUTF8(S) SDL_iconv_string("UTF-8", "UTF-16LE", (char *)(S), (SDL_wcslen(S)+1)*sizeof(WCHAR))
#define WIN_UTF8ToString(S) (WCHAR *)SDL_iconv_string("UTF-16LE", "UTF-8", (char *)(S), SDL_strlen(S)+1)
#else
/* !!! FIXME: UTF8ToString() can just be a SDL_strdup() here. */
#define WIN_StringToUTF8(S) SDL_iconv_string("UTF-8", "ASCII", (char *)(S), (SDL_strlen(S)+1))
#define WIN_UTF8ToString(S) SDL_iconv_string("ASCII", "UTF-8", (char *)(S), SDL_strlen(S)+1)
#endif
/* Sets an error message based on a given HRESULT */
extern int WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr);
/* Sets an error message based on GetLastError(). Always return -1. */
extern int WIN_SetError(const char *prefix);
/* Wrap up the oddities of CoInitialize() into a common function. */
extern HRESULT WIN_CoInitialize(void);
extern void WIN_CoUninitialize(void);
/* Returns SDL_TRUE if we're running on Windows Vista and newer */
extern BOOL WIN_IsWindowsVistaOrGreater();
#endif /* _INCLUDED_WINDOWS_H */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,129 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_assert.h"
#include "SDL_xinput.h"
#ifdef HAVE_XINPUT_H
XInputGetState_t SDL_XInputGetState = NULL;
XInputSetState_t SDL_XInputSetState = NULL;
XInputGetCapabilities_t SDL_XInputGetCapabilities = NULL;
DWORD SDL_XInputVersion = 0;
static HANDLE s_pXInputDLL = 0;
static int s_XInputDLLRefCount = 0;
#ifdef __WINRT__
int
WIN_LoadXInputDLL(void)
{
/* Getting handles to system dlls (via LoadLibrary and its variants) is not
* supported on WinRT, thus, pointers to XInput's functions can't be
* retrieved via GetProcAddress.
*
* When on WinRT, assume that XInput is already loaded, and directly map
* its XInput.h-declared functions to the SDL_XInput* set of function
* pointers.
*
* Side-note: XInputGetStateEx is not available for use in WinRT.
* This seems to mean that support for the guide button is not available
* in WinRT, unfortunately.
*/
SDL_XInputGetState = (XInputGetState_t)XInputGetState;
SDL_XInputSetState = (XInputSetState_t)XInputSetState;
SDL_XInputGetCapabilities = (XInputGetCapabilities_t)XInputGetCapabilities;
/* XInput 1.4 ships with Windows 8 and 8.1: */
SDL_XInputVersion = (1 << 16) | 4;
return 0;
}
void
WIN_UnloadXInputDLL(void)
{
}
#else /* !__WINRT__ */
int
WIN_LoadXInputDLL(void)
{
DWORD version = 0;
if (s_pXInputDLL) {
SDL_assert(s_XInputDLLRefCount > 0);
s_XInputDLLRefCount++;
return 0; /* already loaded */
}
version = (1 << 16) | 4;
s_pXInputDLL = LoadLibrary(L"XInput1_4.dll"); /* 1.4 Ships with Windows 8. */
if (!s_pXInputDLL) {
version = (1 << 16) | 3;
s_pXInputDLL = LoadLibrary(L"XInput1_3.dll"); /* 1.3 Ships with Vista and Win7, can be installed as a redistributable component. */
}
if (!s_pXInputDLL) {
s_pXInputDLL = LoadLibrary(L"bin\\XInput1_3.dll");
}
if (!s_pXInputDLL) {
return -1;
}
SDL_assert(s_XInputDLLRefCount == 0);
SDL_XInputVersion = version;
s_XInputDLLRefCount = 1;
/* 100 is the ordinal for _XInputGetStateEx, which returns the same struct as XinputGetState, but with extra data in wButtons for the guide button, we think... */
SDL_XInputGetState = (XInputGetState_t)GetProcAddress((HMODULE)s_pXInputDLL, (LPCSTR)100);
SDL_XInputSetState = (XInputSetState_t)GetProcAddress((HMODULE)s_pXInputDLL, "XInputSetState");
SDL_XInputGetCapabilities = (XInputGetCapabilities_t)GetProcAddress((HMODULE)s_pXInputDLL, "XInputGetCapabilities");
if (!SDL_XInputGetState || !SDL_XInputSetState || !SDL_XInputGetCapabilities) {
WIN_UnloadXInputDLL();
return -1;
}
return 0;
}
void
WIN_UnloadXInputDLL(void)
{
if (s_pXInputDLL) {
SDL_assert(s_XInputDLLRefCount > 0);
if (--s_XInputDLLRefCount == 0) {
FreeLibrary(s_pXInputDLL);
s_pXInputDLL = NULL;
}
} else {
SDL_assert(s_XInputDLLRefCount == 0);
}
}
#endif /* __WINRT__ */
#endif /* HAVE_XINPUT_H */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,134 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_xinput_h
#define _SDL_xinput_h
#ifdef HAVE_XINPUT_H
#include "SDL_windows.h"
#include <xinput.h>
#ifndef XUSER_MAX_COUNT
#define XUSER_MAX_COUNT 4
#endif
#ifndef XUSER_INDEX_ANY
#define XUSER_INDEX_ANY 0x000000FF
#endif
#ifndef XINPUT_CAPS_FFB_SUPPORTED
#define XINPUT_CAPS_FFB_SUPPORTED 0x0001
#endif
#ifndef XINPUT_DEVSUBTYPE_UNKNOWN
#define XINPUT_DEVSUBTYPE_UNKNOWN 0x00
#endif
#ifndef XINPUT_DEVSUBTYPE_GAMEPAD
#define XINPUT_DEVSUBTYPE_GAMEPAD 0x01
#endif
#ifndef XINPUT_DEVSUBTYPE_WHEEL
#define XINPUT_DEVSUBTYPE_WHEEL 0x02
#endif
#ifndef XINPUT_DEVSUBTYPE_ARCADE_STICK
#define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03
#endif
#ifndef XINPUT_DEVSUBTYPE_FLIGHT_STICK
#define XINPUT_DEVSUBTYPE_FLIGHT_STICK 0x04
#endif
#ifndef XINPUT_DEVSUBTYPE_DANCE_PAD
#define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05
#endif
#ifndef XINPUT_DEVSUBTYPE_GUITAR
#define XINPUT_DEVSUBTYPE_GUITAR 0x06
#endif
#ifndef XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE
#define XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE 0x07
#endif
#ifndef XINPUT_DEVSUBTYPE_DRUM_KIT
#define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08
#endif
#ifndef XINPUT_DEVSUBTYPE_GUITAR_BASS
#define XINPUT_DEVSUBTYPE_GUITAR_BASS 0x0B
#endif
#ifndef XINPUT_DEVSUBTYPE_ARCADE_PAD
#define XINPUT_DEVSUBTYPE_ARCADE_PAD 0x13
#endif
#ifndef XINPUT_GAMEPAD_GUIDE
#define XINPUT_GAMEPAD_GUIDE 0x0400
#endif
/* typedef's for XInput structs we use */
typedef struct
{
WORD wButtons;
BYTE bLeftTrigger;
BYTE bRightTrigger;
SHORT sThumbLX;
SHORT sThumbLY;
SHORT sThumbRX;
SHORT sThumbRY;
DWORD dwPaddingReserved;
} XINPUT_GAMEPAD_EX;
typedef struct
{
DWORD dwPacketNumber;
XINPUT_GAMEPAD_EX Gamepad;
} XINPUT_STATE_EX;
/* Forward decl's for XInput API's we load dynamically and use if available */
typedef DWORD (WINAPI *XInputGetState_t)
(
DWORD dwUserIndex, /* [in] Index of the gamer associated with the device */
XINPUT_STATE_EX* pState /* [out] Receives the current state */
);
typedef DWORD (WINAPI *XInputSetState_t)
(
DWORD dwUserIndex, /* [in] Index of the gamer associated with the device */
XINPUT_VIBRATION* pVibration /* [in, out] The vibration information to send to the controller */
);
typedef DWORD (WINAPI *XInputGetCapabilities_t)
(
DWORD dwUserIndex, /* [in] Index of the gamer associated with the device */
DWORD dwFlags, /* [in] Input flags that identify the device type */
XINPUT_CAPABILITIES* pCapabilities /* [out] Receives the capabilities */
);
extern int WIN_LoadXInputDLL(void);
extern void WIN_UnloadXInputDLL(void);
extern XInputGetState_t SDL_XInputGetState;
extern XInputSetState_t SDL_XInputSetState;
extern XInputGetCapabilities_t SDL_XInputGetCapabilities;
extern DWORD SDL_XInputVersion; /* ((major << 16) & 0xFF00) | (minor & 0xFF) */
#define XINPUTGETSTATE SDL_XInputGetState
#define XINPUTSETSTATE SDL_XInputSetState
#define XINPUTGETCAPABILITIES SDL_XInputGetCapabilities
#endif /* HAVE_XINPUT_H */
#endif /* _SDL_xinput_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,37 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_system.h"
#include "SDL_winrtapp_direct3d.h"
#include "SDL_winrtapp_xaml.h"
int (*WINRT_SDLAppEntryPoint)(int, char **) = NULL;
extern "C" DECLSPEC int
SDL_WinRTRunApp(int (*mainFunction)(int, char **), void * xamlBackgroundPanel)
{
if (xamlBackgroundPanel) {
return SDL_WinRTInitXAMLApp(mainFunction, xamlBackgroundPanel);
} else {
return SDL_WinRTInitNonXAMLApp(mainFunction);
}
}

View File

@@ -0,0 +1,31 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_config.h"
#ifndef _SDL_winrtapp_common_h
#define _SDL_winrtapp_common_h
/* A pointer to the app's C-style main() function (which is a different
function than the WinRT app's actual entry point).
*/
extern int (*WINRT_SDLAppEntryPoint)(int, char **);
#endif // ifndef _SDL_winrtapp_common_h

View File

@@ -0,0 +1,738 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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"
/* Standard C++11 includes */
#include <functional>
#include <string>
#include <sstream>
using namespace std;
/* Windows includes */
#include "ppltasks.h"
using namespace concurrency;
using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::Devices::Input;
using namespace Windows::Graphics::Display;
using namespace Windows::Foundation;
using namespace Windows::System;
using namespace Windows::UI::Core;
using namespace Windows::UI::Input;
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
using namespace Windows::Phone::UI::Input;
#endif
/* SDL includes */
extern "C" {
#include "../../SDL_internal.h"
#include "SDL_assert.h"
#include "SDL_events.h"
#include "SDL_hints.h"
#include "SDL_log.h"
#include "SDL_main.h"
#include "SDL_stdinc.h"
#include "SDL_render.h"
#include "../../video/SDL_sysvideo.h"
//#include "../../SDL_hints_c.h"
#include "../../events/SDL_events_c.h"
#include "../../events/SDL_keyboard_c.h"
#include "../../events/SDL_mouse_c.h"
#include "../../events/SDL_windowevents_c.h"
#include "../../render/SDL_sysrender.h"
#include "../windows/SDL_windows.h"
}
#include "../../video/winrt/SDL_winrtevents_c.h"
#include "../../video/winrt/SDL_winrtvideo_cpp.h"
#include "SDL_winrtapp_common.h"
#include "SDL_winrtapp_direct3d.h"
#if SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED
/* Calling IDXGIDevice3::Trim on the active Direct3D 11.x device is necessary
* when Windows 8.1 apps are about to get suspended.
*/
extern "C" void D3D11_Trim(SDL_Renderer *);
#endif
// Compile-time debugging options:
// To enable, uncomment; to disable, comment them out.
//#define LOG_POINTER_EVENTS 1
//#define LOG_WINDOW_EVENTS 1
//#define LOG_ORIENTATION_EVENTS 1
// HACK, DLudwig: record a reference to the global, WinRT 'app'/view.
// SDL/WinRT will use this throughout its code.
//
// TODO, WinRT: consider replacing SDL_WinRTGlobalApp with something
// non-global, such as something created inside
// SDL_InitSubSystem(SDL_INIT_VIDEO), or something inside
// SDL_CreateWindow().
SDL_WinRTApp ^ SDL_WinRTGlobalApp = nullptr;
ref class SDLApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
{
public:
virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView();
};
IFrameworkView^ SDLApplicationSource::CreateView()
{
// TODO, WinRT: see if this function (CreateView) can ever get called
// more than once. For now, just prevent it from ever assigning
// SDL_WinRTGlobalApp more than once.
SDL_assert(!SDL_WinRTGlobalApp);
SDL_WinRTApp ^ app = ref new SDL_WinRTApp();
if (!SDL_WinRTGlobalApp)
{
SDL_WinRTGlobalApp = app;
}
return app;
}
int SDL_WinRTInitNonXAMLApp(int (*mainFunction)(int, char **))
{
WINRT_SDLAppEntryPoint = mainFunction;
auto direct3DApplicationSource = ref new SDLApplicationSource();
CoreApplication::Run(direct3DApplicationSource);
return 0;
}
static void WINRT_SetDisplayOrientationsPreference(void *userdata, const char *name, const char *oldValue, const char *newValue)
{
SDL_assert(SDL_strcmp(name, SDL_HINT_ORIENTATIONS) == 0);
/* HACK: prevent SDL from altering an app's .appxmanifest-set orientation
* from being changed on startup, by detecting when SDL_HINT_ORIENTATIONS
* is getting registered.
*
* TODO, WinRT: consider reading in an app's .appxmanifest file, and apply its orientation when 'newValue == NULL'.
*/
if ((oldValue == NULL) && (newValue == NULL)) {
return;
}
// Start with no orientation flags, then add each in as they're parsed
// from newValue.
unsigned int orientationFlags = 0;
if (newValue) {
std::istringstream tokenizer(newValue);
while (!tokenizer.eof()) {
std::string orientationName;
std::getline(tokenizer, orientationName, ' ');
if (orientationName == "LandscapeLeft") {
orientationFlags |= (unsigned int) DisplayOrientations::LandscapeFlipped;
} else if (orientationName == "LandscapeRight") {
orientationFlags |= (unsigned int) DisplayOrientations::Landscape;
} else if (orientationName == "Portrait") {
orientationFlags |= (unsigned int) DisplayOrientations::Portrait;
} else if (orientationName == "PortraitUpsideDown") {
orientationFlags |= (unsigned int) DisplayOrientations::PortraitFlipped;
}
}
}
// If no valid orientation flags were specified, use a reasonable set of defaults:
if (!orientationFlags) {
// TODO, WinRT: consider seeing if an app's default orientation flags can be found out via some API call(s).
orientationFlags = (unsigned int) ( \
DisplayOrientations::Landscape |
DisplayOrientations::LandscapeFlipped |
DisplayOrientations::Portrait |
DisplayOrientations::PortraitFlipped);
}
// Set the orientation/rotation preferences. Please note that this does
// not constitute a 100%-certain lock of a given set of possible
// orientations. According to Microsoft's documentation on WinRT [1]
// when a device is not capable of being rotated, Windows may ignore
// the orientation preferences, and stick to what the device is capable of
// displaying.
//
// [1] Documentation on the 'InitialRotationPreference' setting for a
// Windows app's manifest file describes how some orientation/rotation
// preferences may be ignored. See
// http://msdn.microsoft.com/en-us/library/windows/apps/hh700343.aspx
// for details. Microsoft's "Display orientation sample" also gives an
// outline of how Windows treats device rotation
// (http://code.msdn.microsoft.com/Display-Orientation-Sample-19a58e93).
WINRT_DISPLAY_PROPERTY(AutoRotationPreferences) = (DisplayOrientations) orientationFlags;
}
static void
WINRT_ProcessWindowSizeChange()
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
// Make the new window size be the one true fullscreen mode.
// This change was initially done, in part, to allow the Direct3D 11.1
// renderer to receive window-resize events as a device rotates.
// Before, rotating a device from landscape, to portrait, and then
// back to landscape would cause the Direct3D 11.1 swap buffer to
// not get resized appropriately. SDL would, on the rotation from
// landscape to portrait, re-resize the SDL window to it's initial
// size (landscape). On the subsequent rotation, SDL would drop the
// window-resize event as it appeared the SDL window didn't change
// size, and the Direct3D 11.1 renderer wouldn't resize its swap
// chain.
SDL_DisplayMode newDisplayMode;
if (WINRT_CalcDisplayModeUsingNativeWindow(&newDisplayMode) != 0) {
return;
}
// Make note of the old display mode, and it's old driverdata.
SDL_DisplayMode oldDisplayMode;
SDL_zero(oldDisplayMode);
if (_this) {
oldDisplayMode = _this->displays[0].desktop_mode;
}
// Setup the new display mode in the appropriate spots.
if (_this) {
// Make a full copy of the display mode for display_modes[0],
// one with with a separately malloced 'driverdata' field.
// SDL_VideoQuit(), if called, will attempt to free the driverdata
// fields in 'desktop_mode' and each entry in the 'display_modes'
// array.
if (_this->displays[0].display_modes[0].driverdata) {
// Free the previous mode's memory
SDL_free(_this->displays[0].display_modes[0].driverdata);
_this->displays[0].display_modes[0].driverdata = NULL;
}
if (WINRT_DuplicateDisplayMode(&(_this->displays[0].display_modes[0]), &newDisplayMode) != 0) {
// Uh oh, something went wrong. A malloc call probably failed.
SDL_free(newDisplayMode.driverdata);
return;
}
// Install 'newDisplayMode' into 'current_mode' and 'desktop_mode'.
_this->displays[0].current_mode = newDisplayMode;
_this->displays[0].desktop_mode = newDisplayMode;
}
if (WINRT_GlobalSDLWindow) {
// If the window size changed, send a resize event to SDL and its host app:
int window_w = 0;
int window_h = 0;
SDL_GetWindowSize(WINRT_GlobalSDLWindow, &window_w, &window_h);
if ((window_w != newDisplayMode.w) || (window_h != newDisplayMode.h)) {
SDL_SendWindowEvent(
WINRT_GlobalSDLWindow,
SDL_WINDOWEVENT_RESIZED,
newDisplayMode.w,
newDisplayMode.h);
} else {
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
// HACK: Make sure that orientation changes
// lead to the Direct3D renderer's viewport getting updated:
//
// For some reason, this doesn't seem to need to be done on Windows 8.x,
// even when going from Landscape to LandscapeFlipped. It only seems to
// be needed on Windows Phone, at least when I tested on my devices.
// I'm not currently sure why this is, but it seems to work fine. -- David L.
//
// TODO, WinRT: do more extensive research into why orientation changes on Win 8.x don't need D3D changes, or if they might, in some cases
const DisplayOrientations oldOrientation = ((SDL_DisplayModeData *)oldDisplayMode.driverdata)->currentOrientation;
const DisplayOrientations newOrientation = ((SDL_DisplayModeData *)newDisplayMode.driverdata)->currentOrientation;
if (oldOrientation != newOrientation)
{
SDL_SendWindowEvent(
WINRT_GlobalSDLWindow,
SDL_WINDOWEVENT_SIZE_CHANGED,
newDisplayMode.w,
newDisplayMode.h);
}
#endif
}
}
// Finally, free the 'driverdata' field of the old 'desktop_mode'.
if (oldDisplayMode.driverdata) {
SDL_free(oldDisplayMode.driverdata);
oldDisplayMode.driverdata = NULL;
}
}
SDL_WinRTApp::SDL_WinRTApp() :
m_windowClosed(false),
m_windowVisible(true)
{
}
void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView)
{
applicationView->Activated +=
ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &SDL_WinRTApp::OnActivated);
CoreApplication::Suspending +=
ref new EventHandler<SuspendingEventArgs^>(this, &SDL_WinRTApp::OnSuspending);
CoreApplication::Resuming +=
ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnResuming);
CoreApplication::Exiting +=
ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnExiting);
}
#if NTDDI_VERSION > NTDDI_WIN8
void SDL_WinRTApp::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
#else
void SDL_WinRTApp::OnOrientationChanged(Object^ sender)
#endif
{
#if LOG_ORIENTATION_EVENTS==1
CoreWindow^ window = CoreWindow::GetForCurrentThread();
if (window) {
SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Size={%f,%f}\n",
__FUNCTION__,
WINRT_DISPLAY_PROPERTY(CurrentOrientation),
WINRT_DISPLAY_PROPERTY(NativeOrientation),
WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
window->Bounds.Width,
window->Bounds.Height);
} else {
SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n",
__FUNCTION__,
WINRT_DISPLAY_PROPERTY(CurrentOrientation),
WINRT_DISPLAY_PROPERTY(NativeOrientation),
WINRT_DISPLAY_PROPERTY(AutoRotationPreferences));
}
#endif
WINRT_ProcessWindowSizeChange();
}
void SDL_WinRTApp::SetWindow(CoreWindow^ window)
{
#if LOG_WINDOW_EVENTS==1
SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, window Size={%f,%f}\n",
__FUNCTION__,
WINRT_DISPLAY_PROPERTY(CurrentOrientation),
WINRT_DISPLAY_PROPERTY(NativeOrientation),
WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
window->Bounds.Width,
window->Bounds.Height);
#endif
window->SizeChanged +=
ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &SDL_WinRTApp::OnWindowSizeChanged);
window->VisibilityChanged +=
ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &SDL_WinRTApp::OnVisibilityChanged);
window->Closed +=
ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &SDL_WinRTApp::OnWindowClosed);
#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0);
#endif
window->PointerPressed +=
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerPressed);
window->PointerMoved +=
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerMoved);
window->PointerReleased +=
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerReleased);
window->PointerWheelChanged +=
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerWheelChanged);
#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
// Retrieves relative-only mouse movements:
Windows::Devices::Input::MouseDevice::GetForCurrentView()->MouseMoved +=
ref new TypedEventHandler<MouseDevice^, MouseEventArgs^>(this, &SDL_WinRTApp::OnMouseMoved);
#endif
window->KeyDown +=
ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyDown);
window->KeyUp +=
ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyUp);
window->CharacterReceived +=
ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &SDL_WinRTApp::OnCharacterReceived);
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
HardwareButtons::BackPressed +=
ref new EventHandler<BackPressedEventArgs^>(this, &SDL_WinRTApp::OnBackButtonPressed);
#endif
#if NTDDI_VERSION > NTDDI_WIN8
DisplayInformation::GetForCurrentView()->OrientationChanged +=
ref new TypedEventHandler<Windows::Graphics::Display::DisplayInformation^, Object^>(this, &SDL_WinRTApp::OnOrientationChanged);
#else
DisplayProperties::OrientationChanged +=
ref new DisplayPropertiesEventHandler(this, &SDL_WinRTApp::OnOrientationChanged);
#endif
// Register the hint, SDL_HINT_ORIENTATIONS, with SDL.
// TODO, WinRT: see if an app's default orientation can be found out via WinRT API(s), then set the initial value of SDL_HINT_ORIENTATIONS accordingly.
SDL_AddHintCallback(SDL_HINT_ORIENTATIONS, WINRT_SetDisplayOrientationsPreference, NULL);
#if WINAPI_FAMILY == WINAPI_FAMILY_APP // for Windows 8/8.1/RT apps... (and not Phone apps)
// Make sure we know when a user has opened the app's settings pane.
// This is needed in order to display a privacy policy, which needs
// to be done for network-enabled apps, as per Windows Store requirements.
using namespace Windows::UI::ApplicationSettings;
SettingsPane::GetForCurrentView()->CommandsRequested +=
ref new TypedEventHandler<SettingsPane^, SettingsPaneCommandsRequestedEventArgs^>
(this, &SDL_WinRTApp::OnSettingsPaneCommandsRequested);
#endif
}
void SDL_WinRTApp::Load(Platform::String^ entryPoint)
{
}
void SDL_WinRTApp::Run()
{
SDL_SetMainReady();
if (WINRT_SDLAppEntryPoint)
{
// TODO, WinRT: pass the C-style main() a reasonably realistic
// representation of command line arguments.
int argc = 0;
char **argv = NULL;
WINRT_SDLAppEntryPoint(argc, argv);
}
}
static bool IsSDLWindowEventPending(SDL_WindowEventID windowEventID)
{
SDL_Event events[128];
const int count = SDL_PeepEvents(events, sizeof(events)/sizeof(SDL_Event), SDL_PEEKEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT);
for (int i = 0; i < count; ++i) {
if (events[i].window.event == windowEventID) {
return true;
}
}
return false;
}
bool SDL_WinRTApp::ShouldWaitForAppResumeEvents()
{
/* Don't wait if the app is visible: */
if (m_windowVisible) {
return false;
}
/* Don't wait until the window-hide events finish processing.
* Do note that if an app-suspend event is sent (as indicated
* by SDL_APP_WILLENTERBACKGROUND and SDL_APP_DIDENTERBACKGROUND
* events), then this code may be a moot point, as WinRT's
* own event pump (aka ProcessEvents()) will pause regardless
* of what we do here. This happens on Windows Phone 8, to note.
* Windows 8.x apps, on the other hand, may get a chance to run
* these.
*/
if (IsSDLWindowEventPending(SDL_WINDOWEVENT_HIDDEN)) {
return false;
} else if (IsSDLWindowEventPending(SDL_WINDOWEVENT_FOCUS_LOST)) {
return false;
} else if (IsSDLWindowEventPending(SDL_WINDOWEVENT_MINIMIZED)) {
return false;
}
return true;
}
void SDL_WinRTApp::PumpEvents()
{
if (!m_windowClosed) {
if (!ShouldWaitForAppResumeEvents()) {
/* This is the normal way in which events should be pumped.
* 'ProcessAllIfPresent' will make ProcessEvents() process anywhere
* from zero to N events, and will then return.
*/
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
} else {
/* This style of event-pumping, with 'ProcessOneAndAllPending',
* will cause anywhere from one to N events to be processed. If
* at least one event is processed, the call will return. If
* no events are pending, then the call will wait until one is
* available, and will not return (to the caller) until this
* happens! This should only occur when the app is hidden.
*/
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
}
}
}
void SDL_WinRTApp::Uninitialize()
{
}
#if WINAPI_FAMILY == WINAPI_FAMILY_APP
void SDL_WinRTApp::OnSettingsPaneCommandsRequested(
Windows::UI::ApplicationSettings::SettingsPane ^p,
Windows::UI::ApplicationSettings::SettingsPaneCommandsRequestedEventArgs ^args)
{
using namespace Platform;
using namespace Windows::UI::ApplicationSettings;
using namespace Windows::UI::Popups;
String ^privacyPolicyURL = nullptr; // a URL to an app's Privacy Policy
String ^privacyPolicyLabel = nullptr; // label/link text
const char *tmpHintValue = NULL; // SDL_GetHint-retrieved value, used immediately
wchar_t *tmpStr = NULL; // used for UTF8 to UCS2 conversion
// Setup a 'Privacy Policy' link, if one is available (via SDL_GetHint):
tmpHintValue = SDL_GetHint(SDL_HINT_WINRT_PRIVACY_POLICY_URL);
if (tmpHintValue && tmpHintValue[0] != '\0') {
// Convert the privacy policy's URL to UCS2:
tmpStr = WIN_UTF8ToString(tmpHintValue);
privacyPolicyURL = ref new String(tmpStr);
SDL_free(tmpStr);
// Optionally retrieve custom label-text for the link. If this isn't
// available, a default value will be used instead.
tmpHintValue = SDL_GetHint(SDL_HINT_WINRT_PRIVACY_POLICY_LABEL);
if (tmpHintValue && tmpHintValue[0] != '\0') {
tmpStr = WIN_UTF8ToString(tmpHintValue);
privacyPolicyLabel = ref new String(tmpStr);
SDL_free(tmpStr);
} else {
privacyPolicyLabel = ref new String(L"Privacy Policy");
}
// Register the link, along with a handler to be called if and when it is
// clicked:
auto cmd = ref new SettingsCommand(L"privacyPolicy", privacyPolicyLabel,
ref new UICommandInvokedHandler([=](IUICommand ^) {
Windows::System::Launcher::LaunchUriAsync(ref new Uri(privacyPolicyURL));
}));
args->Request->ApplicationCommands->Append(cmd);
}
}
#endif // if WINAPI_FAMILY == WINAPI_FAMILY_APP
void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
{
#if LOG_WINDOW_EVENTS==1
SDL_Log("%s, size={%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, WINRT_GlobalSDLWindow?=%s\n",
__FUNCTION__,
args->Size.Width, args->Size.Height,
WINRT_DISPLAY_PROPERTY(CurrentOrientation),
WINRT_DISPLAY_PROPERTY(NativeOrientation),
WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
(WINRT_GlobalSDLWindow ? "yes" : "no"));
#endif
WINRT_ProcessWindowSizeChange();
}
void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
{
#if LOG_WINDOW_EVENTS==1
SDL_Log("%s, visible?=%s, WINRT_GlobalSDLWindow?=%s\n",
__FUNCTION__,
(args->Visible ? "yes" : "no"),
(WINRT_GlobalSDLWindow ? "yes" : "no"));
#endif
m_windowVisible = args->Visible;
if (WINRT_GlobalSDLWindow) {
SDL_bool wasSDLWindowSurfaceValid = WINRT_GlobalSDLWindow->surface_valid;
if (args->Visible) {
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SHOWN, 0, 0);
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_RESTORED, 0, 0);
} else {
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_HIDDEN, 0, 0);
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
}
// HACK: Prevent SDL's window-hide handling code, which currently
// triggers a fake window resize (possibly erronously), from
// marking the SDL window's surface as invalid.
//
// A better solution to this probably involves figuring out if the
// fake window resize can be prevented.
WINRT_GlobalSDLWindow->surface_valid = wasSDLWindowSurfaceValid;
}
}
void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
{
#if LOG_WINDOW_EVENTS==1
SDL_Log("%s\n", __FUNCTION__);
#endif
m_windowClosed = true;
}
void SDL_WinRTApp::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
{
CoreWindow::GetForCurrentThread()->Activate();
}
void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
{
// Save app state asynchronously after requesting a deferral. Holding a deferral
// indicates that the application is busy performing suspending operations. Be
// aware that a deferral may not be held indefinitely. After about five seconds,
// the app will be forced to exit.
// ... but first, let the app know it's about to go to the background.
// The separation of events may be important, given that the deferral
// runs in a separate thread. This'll make SDL_APP_WILLENTERBACKGROUND
// the only event among the two that runs in the main thread. Given
// that a few WinRT operations can only be done from the main thread
// (things that access the WinRT CoreWindow are one example of this),
// this could be important.
SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
create_task([this, deferral]()
{
// Send an app did-enter-background event immediately to observers.
// CoreDispatcher::ProcessEvents, which is the backbone on which
// SDL_WinRTApp::PumpEvents is built, will not return to its caller
// once it sends out a suspend event. Any events posted to SDL's
// event queue won't get received until the WinRT app is resumed.
// SDL_AddEventWatch() may be used to receive app-suspend events on
// WinRT.
SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
// Let the Direct3D 11 renderer prepare for the app to be backgrounded.
// This is necessary for Windows 8.1, possibly elsewhere in the future.
// More details at: http://msdn.microsoft.com/en-us/library/windows/apps/Hh994929.aspx
#if SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED
if (WINRT_GlobalSDLWindow) {
SDL_Renderer * renderer = SDL_GetRenderer(WINRT_GlobalSDLWindow);
if (renderer && (SDL_strcmp(renderer->info.name, "direct3d11") == 0)) {
D3D11_Trim(renderer);
}
}
#endif
deferral->Complete();
});
}
void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args)
{
// Restore any data or state that was unloaded on suspend. By default, data
// and state are persisted when resuming from suspend. Note that these events
// do not occur if the app was previously terminated.
SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
}
void SDL_WinRTApp::OnExiting(Platform::Object^ sender, Platform::Object^ args)
{
SDL_SendAppEvent(SDL_APP_TERMINATING);
}
static void
WINRT_LogPointerEvent(const char * header, Windows::UI::Core::PointerEventArgs ^ args, Windows::Foundation::Point transformedPoint)
{
Windows::UI::Input::PointerPoint ^ pt = args->CurrentPoint;
SDL_Log("%s: Position={%f,%f}, Transformed Pos={%f, %f}, MouseWheelDelta=%d, FrameId=%d, PointerId=%d, SDL button=%d\n",
header,
pt->Position.X, pt->Position.Y,
transformedPoint.X, transformedPoint.Y,
pt->Properties->MouseWheelDelta,
pt->FrameId,
pt->PointerId,
WINRT_GetSDLButtonForPointerPoint(pt));
}
void SDL_WinRTApp::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
{
#if LOG_POINTER_EVENTS
WINRT_LogPointerEvent("pointer pressed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
#endif
WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
}
void SDL_WinRTApp::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args)
{
#if LOG_POINTER_EVENTS
WINRT_LogPointerEvent("pointer moved", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
#endif
WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
}
void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args)
{
#if LOG_POINTER_EVENTS
WINRT_LogPointerEvent("pointer released", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
#endif
WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
}
void SDL_WinRTApp::OnPointerWheelChanged(CoreWindow^ sender, PointerEventArgs^ args)
{
#if LOG_POINTER_EVENTS
WINRT_LogPointerEvent("pointer wheel changed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
#endif
WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
}
void SDL_WinRTApp::OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args)
{
WINRT_ProcessMouseMovedEvent(WINRT_GlobalSDLWindow, args);
}
void SDL_WinRTApp::OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
{
WINRT_ProcessKeyDownEvent(args);
}
void SDL_WinRTApp::OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
{
WINRT_ProcessKeyUpEvent(args);
}
void SDL_WinRTApp::OnCharacterReceived(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CharacterReceivedEventArgs^ args)
{
WINRT_ProcessCharacterReceivedEvent(args);
}
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args)
{
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_AC_BACK);
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_AC_BACK);
const char *hint = SDL_GetHint(SDL_HINT_WINRT_HANDLE_BACK_BUTTON);
if (hint) {
if (*hint == '1') {
args->Handled = true;
}
}
}
#endif

View File

@@ -0,0 +1,83 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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 <Windows.h>
extern int SDL_WinRTInitNonXAMLApp(int (*mainFunction)(int, char **));
ref class SDL_WinRTApp sealed : public Windows::ApplicationModel::Core::IFrameworkView
{
public:
SDL_WinRTApp();
// IFrameworkView Methods.
virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView);
virtual void SetWindow(Windows::UI::Core::CoreWindow^ window);
virtual void Load(Platform::String^ entryPoint);
virtual void Run();
virtual void Uninitialize();
internal:
// SDL-specific methods
void PumpEvents();
protected:
bool ShouldWaitForAppResumeEvents();
// Event Handlers.
#if WINAPI_FAMILY == WINAPI_FAMILY_APP // for Windows 8/8.1/RT apps... (and not Phone apps)
void OnSettingsPaneCommandsRequested(
Windows::UI::ApplicationSettings::SettingsPane ^p,
Windows::UI::ApplicationSettings::SettingsPaneCommandsRequestedEventArgs ^args);
#endif // if WINAPI_FAMILY == WINAPI_FAMILY_APP
#if NTDDI_VERSION > NTDDI_WIN8
void OnOrientationChanged(Windows::Graphics::Display::DisplayInformation^ sender, Platform::Object^ args);
#else
void OnOrientationChanged(Platform::Object^ sender);
#endif
void OnWindowSizeChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ args);
void OnLogicalDpiChanged(Platform::Object^ sender);
void OnActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args);
void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args);
void OnResuming(Platform::Object^ sender, Platform::Object^ args);
void OnExiting(Platform::Object^ sender, Platform::Object^ args);
void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args);
void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
void OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
void OnPointerReleased(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
void OnPointerWheelChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
void OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
void OnMouseMoved(Windows::Devices::Input::MouseDevice^ mouseDevice, Windows::Devices::Input::MouseEventArgs^ args);
void OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args);
void OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args);
void OnCharacterReceived(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CharacterReceivedEventArgs^ args);
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
void OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args);
#endif
private:
bool m_windowClosed;
bool m_windowVisible;
};
extern SDL_WinRTApp ^ SDL_WinRTGlobalApp;

View File

@@ -0,0 +1,160 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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.
*/
/* Windows includes */
#include <agile.h>
#include <Windows.h>
#if WINAPI_FAMILY == WINAPI_FAMILY_APP
#include <windows.ui.xaml.media.dxinterop.h>
#endif
/* SDL includes */
#include "../../SDL_internal.h"
#include "SDL.h"
#include "../../video/winrt/SDL_winrtevents_c.h"
#include "../../video/winrt/SDL_winrtvideo_cpp.h"
#include "SDL_winrtapp_common.h"
#include "SDL_winrtapp_xaml.h"
/* SDL-internal globals: */
SDL_bool WINRT_XAMLWasEnabled = SDL_FALSE;
#if WINAPI_FAMILY == WINAPI_FAMILY_APP
extern "C"
ISwapChainBackgroundPanelNative * WINRT_GlobalSwapChainBackgroundPanelNative = NULL;
static Windows::Foundation::EventRegistrationToken WINRT_XAMLAppEventToken;
#endif
/*
* Input event handlers (XAML)
*/
#if WINAPI_FAMILY == WINAPI_FAMILY_APP
static void
WINRT_OnPointerPressedViaXAML(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args)
{
WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args->GetCurrentPoint(nullptr));
}
static void
WINRT_OnPointerMovedViaXAML(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args)
{
WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args->GetCurrentPoint(nullptr));
}
static void
WINRT_OnPointerReleasedViaXAML(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args)
{
WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->GetCurrentPoint(nullptr));
}
static void
WINRT_OnPointerWheelChangedViaXAML(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args)
{
WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args->GetCurrentPoint(nullptr));
}
#endif // WINAPI_FAMILY == WINAPI_FAMILY_APP
/*
* XAML-to-SDL Rendering Callback
*/
#if WINAPI_FAMILY == WINAPI_FAMILY_APP
static void
WINRT_OnRenderViaXAML(_In_ Platform::Object^ sender, _In_ Platform::Object^ args)
{
WINRT_CycleXAMLThread();
}
#endif // WINAPI_FAMILY == WINAPI_FAMILY_APP
/*
* SDL + XAML Initialization
*/
int
SDL_WinRTInitXAMLApp(int (*mainFunction)(int, char **), void * backgroundPanelAsIInspectable)
{
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
return SDL_SetError("XAML support is not yet available in Windows Phone.");
#else
// Declare C++/CX namespaces:
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::UI::Core;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
// Make sure we have a valid XAML element (to draw onto):
if ( ! backgroundPanelAsIInspectable) {
return SDL_SetError("'backgroundPanelAsIInspectable' can't be NULL");
}
Platform::Object ^ backgroundPanel = reinterpret_cast<Object ^>((IInspectable *) backgroundPanelAsIInspectable);
SwapChainBackgroundPanel ^swapChainBackgroundPanel = dynamic_cast<SwapChainBackgroundPanel ^>(backgroundPanel);
if ( ! swapChainBackgroundPanel) {
return SDL_SetError("An unknown or unsupported type of XAML control was specified.");
}
// Setup event handlers:
swapChainBackgroundPanel->PointerPressed += ref new PointerEventHandler(WINRT_OnPointerPressedViaXAML);
swapChainBackgroundPanel->PointerReleased += ref new PointerEventHandler(WINRT_OnPointerReleasedViaXAML);
swapChainBackgroundPanel->PointerWheelChanged += ref new PointerEventHandler(WINRT_OnPointerWheelChangedViaXAML);
swapChainBackgroundPanel->PointerMoved += ref new PointerEventHandler(WINRT_OnPointerMovedViaXAML);
// Setup for rendering:
IInspectable *panelInspectable = (IInspectable*) reinterpret_cast<IInspectable*>(swapChainBackgroundPanel);
panelInspectable->QueryInterface(__uuidof(ISwapChainBackgroundPanelNative), (void **)&WINRT_GlobalSwapChainBackgroundPanelNative);
WINRT_XAMLAppEventToken = CompositionTarget::Rendering::add(ref new EventHandler<Object^>(WINRT_OnRenderViaXAML));
// Make sure the app is ready to call the SDL-centric main() function:
WINRT_SDLAppEntryPoint = mainFunction;
SDL_SetMainReady();
// Make sure video-init knows that we're initializing XAML:
SDL_bool oldXAMLWasEnabledValue = WINRT_XAMLWasEnabled;
WINRT_XAMLWasEnabled = SDL_TRUE;
// Make sure video modes are detected now, while we still have access to the WinRT
// CoreWindow. WinRT will not allow the app's CoreWindow to be accessed via the
// SDL/WinRT thread.
if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
// SDL_InitSubSystem will, on error, set the SDL error. Let that propogate to
// the caller to here:
WINRT_XAMLWasEnabled = oldXAMLWasEnabledValue;
return -1;
}
// All done, for now.
return 0;
#endif // WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP / else
}

View File

@@ -0,0 +1,33 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_config.h"
#ifndef _SDL_winrtapp_xaml_h
#define _SDL_winrtapp_xaml_h
#include "SDL_stdinc.h"
#ifdef __cplusplus
extern SDL_bool WINRT_XAMLWasEnabled;
extern int SDL_WinRTInitXAMLApp(int (*mainFunction)(int, char **), void * backgroundPanelAsIInspectable);
#endif // ifdef __cplusplus
#endif // ifndef _SDL_winrtapp_xaml_h

799
src/cpuinfo/SDL_cpuinfo.c Normal file
View File

@@ -0,0 +1,799 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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.
*/
#ifdef TEST_MAIN
#include "SDL_config.h"
#else
#include "../SDL_internal.h"
#endif
#if defined(__WIN32__)
#include "../core/windows/SDL_windows.h"
#endif
/* CPU feature detection for SDL */
#include "SDL_cpuinfo.h"
#ifdef HAVE_SYSCONF
#include <unistd.h>
#endif
#ifdef HAVE_SYSCTLBYNAME
#include <sys/types.h>
#include <sys/sysctl.h>
#endif
#if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))
#include <sys/sysctl.h> /* For AltiVec check */
#elif defined(__OpenBSD__) && defined(__powerpc__)
#include <sys/param.h>
#include <sys/sysctl.h> /* For AltiVec check */
#include <machine/cpu.h>
#elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
#include <signal.h>
#include <setjmp.h>
#endif
#define CPU_HAS_RDTSC 0x00000001
#define CPU_HAS_ALTIVEC 0x00000002
#define CPU_HAS_MMX 0x00000004
#define CPU_HAS_3DNOW 0x00000008
#define CPU_HAS_SSE 0x00000010
#define CPU_HAS_SSE2 0x00000020
#define CPU_HAS_SSE3 0x00000040
#define CPU_HAS_SSE41 0x00000100
#define CPU_HAS_SSE42 0x00000200
#define CPU_HAS_AVX 0x00000400
#define CPU_HAS_AVX2 0x00000800
#if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ && !__OpenBSD__
/* This is the brute force way of detecting instruction sets...
the idea is borrowed from the libmpeg2 library - thanks!
*/
static jmp_buf jmpbuf;
static void
illegal_instruction(int sig)
{
longjmp(jmpbuf, 1);
}
#endif /* HAVE_SETJMP */
static int
CPU_haveCPUID(void)
{
int has_CPUID = 0;
/* *INDENT-OFF* */
#ifndef SDL_CPUINFO_DISABLED
#if defined(__GNUC__) && defined(i386)
__asm__ (
" pushfl # Get original EFLAGS \n"
" popl %%eax \n"
" movl %%eax,%%ecx \n"
" xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
" pushl %%eax # Save new EFLAGS value on stack \n"
" popfl # Replace current EFLAGS value \n"
" pushfl # Get new EFLAGS \n"
" popl %%eax # Store new EFLAGS in EAX \n"
" xorl %%ecx,%%eax # Can not toggle ID bit, \n"
" jz 1f # Processor=80486 \n"
" movl $1,%0 # We have CPUID support \n"
"1: \n"
: "=m" (has_CPUID)
:
: "%eax", "%ecx"
);
#elif defined(__GNUC__) && defined(__x86_64__)
/* Technically, if this is being compiled under __x86_64__ then it has
CPUid by definition. But it's nice to be able to prove it. :) */
__asm__ (
" pushfq # Get original EFLAGS \n"
" popq %%rax \n"
" movq %%rax,%%rcx \n"
" xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
" pushq %%rax # Save new EFLAGS value on stack \n"
" popfq # Replace current EFLAGS value \n"
" pushfq # Get new EFLAGS \n"
" popq %%rax # Store new EFLAGS in EAX \n"
" xorl %%ecx,%%eax # Can not toggle ID bit, \n"
" jz 1f # Processor=80486 \n"
" movl $1,%0 # We have CPUID support \n"
"1: \n"
: "=m" (has_CPUID)
:
: "%rax", "%rcx"
);
#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
__asm {
pushfd ; Get original EFLAGS
pop eax
mov ecx, eax
xor eax, 200000h ; Flip ID bit in EFLAGS
push eax ; Save new EFLAGS value on stack
popfd ; Replace current EFLAGS value
pushfd ; Get new EFLAGS
pop eax ; Store new EFLAGS in EAX
xor eax, ecx ; Can not toggle ID bit,
jz done ; Processor=80486
mov has_CPUID,1 ; We have CPUID support
done:
}
#elif defined(_MSC_VER) && defined(_M_X64)
has_CPUID = 1;
#elif defined(__sun) && defined(__i386)
__asm (
" pushfl \n"
" popl %eax \n"
" movl %eax,%ecx \n"
" xorl $0x200000,%eax \n"
" pushl %eax \n"
" popfl \n"
" pushfl \n"
" popl %eax \n"
" xorl %ecx,%eax \n"
" jz 1f \n"
" movl $1,-8(%ebp) \n"
"1: \n"
);
#elif defined(__sun) && defined(__amd64)
__asm (
" pushfq \n"
" popq %rax \n"
" movq %rax,%rcx \n"
" xorl $0x200000,%eax \n"
" pushq %rax \n"
" popfq \n"
" pushfq \n"
" popq %rax \n"
" xorl %ecx,%eax \n"
" jz 1f \n"
" movl $1,-8(%rbp) \n"
"1: \n"
);
#endif
#endif
/* *INDENT-ON* */
return has_CPUID;
}
#if defined(__GNUC__) && defined(i386)
#define cpuid(func, a, b, c, d) \
__asm__ __volatile__ ( \
" pushl %%ebx \n" \
" xorl %%ecx,%%ecx \n" \
" cpuid \n" \
" movl %%ebx, %%esi \n" \
" popl %%ebx \n" : \
"=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
#elif defined(__GNUC__) && defined(__x86_64__)
#define cpuid(func, a, b, c, d) \
__asm__ __volatile__ ( \
" pushq %%rbx \n" \
" xorq %%rcx,%%rcx \n" \
" cpuid \n" \
" movq %%rbx, %%rsi \n" \
" popq %%rbx \n" : \
"=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
#define cpuid(func, a, b, c, d) \
__asm { \
__asm mov eax, func \
__asm xor ecx, ecx \
__asm cpuid \
__asm mov a, eax \
__asm mov b, ebx \
__asm mov c, ecx \
__asm mov d, edx \
}
#elif defined(_MSC_VER) && defined(_M_X64)
#define cpuid(func, a, b, c, d) \
{ \
int CPUInfo[4]; \
__cpuid(CPUInfo, func); \
a = CPUInfo[0]; \
b = CPUInfo[1]; \
c = CPUInfo[2]; \
d = CPUInfo[3]; \
}
#else
#define cpuid(func, a, b, c, d) \
a = b = c = d = 0
#endif
static int
CPU_getCPUIDFeatures(void)
{
int features = 0;
int a, b, c, d;
cpuid(0, a, b, c, d);
if (a >= 1) {
cpuid(1, a, b, c, d);
features = d;
}
return features;
}
static SDL_bool
CPU_OSSavesYMM(void)
{
int a, b, c, d;
/* Check to make sure we can call xgetbv */
cpuid(0, a, b, c, d);
if (a < 1) {
return SDL_FALSE;
}
cpuid(1, a, b, c, d);
if (!(c & 0x08000000)) {
return SDL_FALSE;
}
/* Call xgetbv to see if YMM register state is saved */
a = 0;
#if defined(__GNUC__) && (defined(i386) || defined(__x86_64__))
asm(".byte 0x0f, 0x01, 0xd0" : "=a" (a) : "c" (0) : "%edx");
#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) && (_MSC_FULL_VER >= 160040219) /* VS2010 SP1 */
a = (int)_xgetbv(0);
#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
__asm
{
xor ecx, ecx
_asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0
mov a, eax
}
#endif
return ((a & 6) == 6) ? SDL_TRUE : SDL_FALSE;
}
static int
CPU_haveRDTSC(void)
{
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeatures() & 0x00000010);
}
return 0;
}
static int
CPU_haveAltiVec(void)
{
volatile int altivec = 0;
#ifndef SDL_CPUINFO_DISABLED
#if (defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__))
#ifdef __OpenBSD__
int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
#else
int selectors[2] = { CTL_HW, HW_VECTORUNIT };
#endif
int hasVectorUnit = 0;
size_t length = sizeof(hasVectorUnit);
int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
if (0 == error)
altivec = (hasVectorUnit != 0);
#elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
void (*handler) (int sig);
handler = signal(SIGILL, illegal_instruction);
if (setjmp(jmpbuf) == 0) {
asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
altivec = 1;
}
signal(SIGILL, handler);
#endif
#endif
return altivec;
}
static int
CPU_haveMMX(void)
{
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeatures() & 0x00800000);
}
return 0;
}
static int
CPU_have3DNow(void)
{
if (CPU_haveCPUID()) {
int a, b, c, d;
cpuid(0x80000000, a, b, c, d);
if (a >= 0x80000001) {
cpuid(0x80000001, a, b, c, d);
return (d & 0x80000000);
}
}
return 0;
}
static int
CPU_haveSSE(void)
{
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeatures() & 0x02000000);
}
return 0;
}
static int
CPU_haveSSE2(void)
{
if (CPU_haveCPUID()) {
return (CPU_getCPUIDFeatures() & 0x04000000);
}
return 0;
}
static int
CPU_haveSSE3(void)
{
if (CPU_haveCPUID()) {
int a, b, c, d;
cpuid(0, a, b, c, d);
if (a >= 1) {
cpuid(1, a, b, c, d);
return (c & 0x00000001);
}
}
return 0;
}
static int
CPU_haveSSE41(void)
{
if (CPU_haveCPUID()) {
int a, b, c, d;
cpuid(0, a, b, c, d);
if (a >= 1) {
cpuid(1, a, b, c, d);
return (c & 0x00080000);
}
}
return 0;
}
static int
CPU_haveSSE42(void)
{
if (CPU_haveCPUID()) {
int a, b, c, d;
cpuid(0, a, b, c, d);
if (a >= 1) {
cpuid(1, a, b, c, d);
return (c & 0x00100000);
}
}
return 0;
}
static int
CPU_haveAVX(void)
{
if (CPU_haveCPUID() && CPU_OSSavesYMM()) {
int a, b, c, d;
cpuid(0, a, b, c, d);
if (a >= 1) {
cpuid(1, a, b, c, d);
return (c & 0x10000000);
}
}
return 0;
}
static int
CPU_haveAVX2(void)
{
if (CPU_haveCPUID() && CPU_OSSavesYMM()) {
int a, b, c, d;
cpuid(0, a, b, c, d);
if (a >= 7) {
cpuid(7, a, b, c, d);
return (b & 0x00000020);
}
}
return 0;
}
static int SDL_CPUCount = 0;
int
SDL_GetCPUCount(void)
{
if (!SDL_CPUCount) {
#ifndef SDL_CPUINFO_DISABLED
#if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
if (SDL_CPUCount <= 0) {
SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN);
}
#endif
#ifdef HAVE_SYSCTLBYNAME
if (SDL_CPUCount <= 0) {
size_t size = sizeof(SDL_CPUCount);
sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
}
#endif
#ifdef __WIN32__
if (SDL_CPUCount <= 0) {
SYSTEM_INFO info;
GetSystemInfo(&info);
SDL_CPUCount = info.dwNumberOfProcessors;
}
#endif
#endif
/* There has to be at least 1, right? :) */
if (SDL_CPUCount <= 0) {
SDL_CPUCount = 1;
}
}
return SDL_CPUCount;
}
/* Oh, such a sweet sweet trick, just not very useful. :) */
static const char *
SDL_GetCPUType(void)
{
static char SDL_CPUType[13];
if (!SDL_CPUType[0]) {
int i = 0;
if (CPU_haveCPUID()) {
int a, b, c, d;
cpuid(0x00000000, a, b, c, d);
(void) a;
SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUType[i++] = (char)(b & 0xff);
SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUType[i++] = (char)(d & 0xff);
SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUType[i++] = (char)(c & 0xff);
}
if (!SDL_CPUType[0]) {
SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
}
}
return SDL_CPUType;
}
#ifdef TEST_MAIN /* !!! FIXME: only used for test at the moment. */
static const char *
SDL_GetCPUName(void)
{
static char SDL_CPUName[48];
if (!SDL_CPUName[0]) {
int i = 0;
int a, b, c, d;
if (CPU_haveCPUID()) {
cpuid(0x80000000, a, b, c, d);
if (a >= 0x80000004) {
cpuid(0x80000002, a, b, c, d);
SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
cpuid(0x80000003, a, b, c, d);
SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
cpuid(0x80000004, a, b, c, d);
SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
}
}
if (!SDL_CPUName[0]) {
SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
}
}
return SDL_CPUName;
}
#endif
int
SDL_GetCPUCacheLineSize(void)
{
const char *cpuType = SDL_GetCPUType();
int a, b, c, d;
(void) a; (void) b; (void) c; (void) d;
if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
cpuid(0x00000001, a, b, c, d);
return (((b >> 8) & 0xff) * 8);
} else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
cpuid(0x80000005, a, b, c, d);
return (c & 0xff);
} else {
/* Just make a guess here... */
return SDL_CACHELINE_SIZE;
}
}
static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
static Uint32
SDL_GetCPUFeatures(void)
{
if (SDL_CPUFeatures == 0xFFFFFFFF) {
SDL_CPUFeatures = 0;
if (CPU_haveRDTSC()) {
SDL_CPUFeatures |= CPU_HAS_RDTSC;
}
if (CPU_haveAltiVec()) {
SDL_CPUFeatures |= CPU_HAS_ALTIVEC;
}
if (CPU_haveMMX()) {
SDL_CPUFeatures |= CPU_HAS_MMX;
}
if (CPU_have3DNow()) {
SDL_CPUFeatures |= CPU_HAS_3DNOW;
}
if (CPU_haveSSE()) {
SDL_CPUFeatures |= CPU_HAS_SSE;
}
if (CPU_haveSSE2()) {
SDL_CPUFeatures |= CPU_HAS_SSE2;
}
if (CPU_haveSSE3()) {
SDL_CPUFeatures |= CPU_HAS_SSE3;
}
if (CPU_haveSSE41()) {
SDL_CPUFeatures |= CPU_HAS_SSE41;
}
if (CPU_haveSSE42()) {
SDL_CPUFeatures |= CPU_HAS_SSE42;
}
if (CPU_haveAVX()) {
SDL_CPUFeatures |= CPU_HAS_AVX;
}
if (CPU_haveAVX2()) {
SDL_CPUFeatures |= CPU_HAS_AVX2;
}
}
return SDL_CPUFeatures;
}
SDL_bool
SDL_HasRDTSC(void)
{
if (SDL_GetCPUFeatures() & CPU_HAS_RDTSC) {
return SDL_TRUE;
}
return SDL_FALSE;
}
SDL_bool
SDL_HasAltiVec(void)
{
if (SDL_GetCPUFeatures() & CPU_HAS_ALTIVEC) {
return SDL_TRUE;
}
return SDL_FALSE;
}
SDL_bool
SDL_HasMMX(void)
{
if (SDL_GetCPUFeatures() & CPU_HAS_MMX) {
return SDL_TRUE;
}
return SDL_FALSE;
}
SDL_bool
SDL_Has3DNow(void)
{
if (SDL_GetCPUFeatures() & CPU_HAS_3DNOW) {
return SDL_TRUE;
}
return SDL_FALSE;
}
SDL_bool
SDL_HasSSE(void)
{
if (SDL_GetCPUFeatures() & CPU_HAS_SSE) {
return SDL_TRUE;
}
return SDL_FALSE;
}
SDL_bool
SDL_HasSSE2(void)
{
if (SDL_GetCPUFeatures() & CPU_HAS_SSE2) {
return SDL_TRUE;
}
return SDL_FALSE;
}
SDL_bool
SDL_HasSSE3(void)
{
if (SDL_GetCPUFeatures() & CPU_HAS_SSE3) {
return SDL_TRUE;
}
return SDL_FALSE;
}
SDL_bool
SDL_HasSSE41(void)
{
if (SDL_GetCPUFeatures() & CPU_HAS_SSE41) {
return SDL_TRUE;
}
return SDL_FALSE;
}
SDL_bool
SDL_HasSSE42(void)
{
if (SDL_GetCPUFeatures() & CPU_HAS_SSE42) {
return SDL_TRUE;
}
return SDL_FALSE;
}
SDL_bool
SDL_HasAVX(void)
{
if (SDL_GetCPUFeatures() & CPU_HAS_AVX) {
return SDL_TRUE;
}
return SDL_FALSE;
}
SDL_bool
SDL_HasAVX2(void)
{
if (SDL_GetCPUFeatures() & CPU_HAS_AVX2) {
return SDL_TRUE;
}
return SDL_FALSE;
}
static int SDL_SystemRAM = 0;
int
SDL_GetSystemRAM(void)
{
if (!SDL_SystemRAM) {
#ifndef SDL_CPUINFO_DISABLED
#if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
if (SDL_SystemRAM <= 0) {
SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
}
#endif
#ifdef HAVE_SYSCTLBYNAME
if (SDL_SystemRAM <= 0) {
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#ifdef HW_REALMEM
int mib[2] = {CTL_HW, HW_REALMEM};
#else
/* might only report up to 2 GiB */
int mib[2] = {CTL_HW, HW_PHYSMEM};
#endif /* HW_REALMEM */
#else
int mib[2] = {CTL_HW, HW_MEMSIZE};
#endif /* __FreeBSD__ || __FreeBSD_kernel__ */
Uint64 memsize = 0;
size_t len = sizeof(memsize);
if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
SDL_SystemRAM = (int)(memsize / (1024*1024));
}
}
#endif
#ifdef __WIN32__
if (SDL_SystemRAM <= 0) {
MEMORYSTATUSEX stat;
stat.dwLength = sizeof(stat);
if (GlobalMemoryStatusEx(&stat)) {
SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
}
}
#endif
#endif
}
return SDL_SystemRAM;
}
#ifdef TEST_MAIN
#include <stdio.h>
int
main()
{
printf("CPU count: %d\n", SDL_GetCPUCount());
printf("CPU type: %s\n", SDL_GetCPUType());
printf("CPU name: %s\n", SDL_GetCPUName());
printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize());
printf("RDTSC: %d\n", SDL_HasRDTSC());
printf("Altivec: %d\n", SDL_HasAltiVec());
printf("MMX: %d\n", SDL_HasMMX());
printf("3DNow: %d\n", SDL_Has3DNow());
printf("SSE: %d\n", SDL_HasSSE());
printf("SSE2: %d\n", SDL_HasSSE2());
printf("SSE3: %d\n", SDL_HasSSE3());
printf("SSE4.1: %d\n", SDL_HasSSE41());
printf("SSE4.2: %d\n", SDL_HasSSE42());
printf("AVX: %d\n", SDL_HasAVX());
printf("AVX2: %d\n", SDL_HasAVX2());
printf("RAM: %d MB\n", SDL_GetSystemRAM());
return 0;
}
#endif /* TEST_MAIN */
/* vi: set ts=4 sw=4 expandtab: */

319
src/dynapi/SDL_dynapi.c Normal file
View File

@@ -0,0 +1,319 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_config.h"
#include "SDL_dynapi.h"
#if SDL_DYNAMIC_API
#include "SDL.h"
/* !!! FIXME: Shouldn't these be included in SDL.h? */
#include "SDL_shape.h"
#include "SDL_syswm.h"
/* This is the version of the dynamic API. This doesn't match the SDL version
and should not change until there's been a major revamp in API/ABI.
So 2.0.5 adds functions over 2.0.4? This number doesn't change;
the sizeof (jump_table) changes instead. But 2.1.0 changes how a function
works in an incompatible way or removes a function? This number changes,
since sizeof (jump_table) isn't sufficient anymore. It's likely
we'll forget to bump every time we add a function, so this is the
failsafe switch for major API change decisions. Respect it and use it
sparingly. */
#define SDL_DYNAPI_VERSION 1
static void SDL_InitDynamicAPI(void);
/* BE CAREFUL CALLING ANY SDL CODE IN HERE, IT WILL BLOW UP.
Even self-contained stuff might call SDL_Error and break everything. */
/* behold, the macro salsa! */
/* !!! FIXME: ...disabled...until we write it. :) */
#define DISABLE_JUMP_MAGIC 1
#if DISABLE_JUMP_MAGIC
/* Can't use the macro for varargs nonsense. This is atrocious. */
#define SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, logname, prio) \
_static void SDL_Log##logname##name(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
va_list ap; initcall; va_start(ap, fmt); \
jump_table.SDL_LogMessageV(category, SDL_LOG_PRIORITY_##prio, fmt, ap); \
va_end(ap); \
}
#define SDL_DYNAPI_VARARGS(_static, name, initcall) \
_static int SDL_SetError##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
char buf[512]; /* !!! FIXME: dynamic allocation */ \
va_list ap; initcall; va_start(ap, fmt); \
jump_table.SDL_vsnprintf(buf, sizeof (buf), fmt, ap); \
va_end(ap); \
return jump_table.SDL_SetError("%s", buf); \
} \
_static int SDL_sscanf##name(const char *buf, SDL_SCANF_FORMAT_STRING const char *fmt, ...) { \
int retval; va_list ap; initcall; va_start(ap, fmt); \
retval = jump_table.SDL_vsscanf(buf, fmt, ap); \
va_end(ap); \
return retval; \
} \
_static int SDL_snprintf##name(SDL_OUT_Z_CAP(maxlen) char *buf, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
int retval; va_list ap; initcall; va_start(ap, fmt); \
retval = jump_table.SDL_vsnprintf(buf, maxlen, fmt, ap); \
va_end(ap); \
return retval; \
} \
_static void SDL_Log##name(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
va_list ap; initcall; va_start(ap, fmt); \
jump_table.SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap); \
va_end(ap); \
} \
_static void SDL_LogMessage##name(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) { \
va_list ap; initcall; va_start(ap, fmt); \
jump_table.SDL_LogMessageV(category, priority, fmt, ap); \
va_end(ap); \
} \
SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Verbose, VERBOSE) \
SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Debug, DEBUG) \
SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Info, INFO) \
SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Warn, WARN) \
SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Error, ERROR) \
SDL_DYNAPI_VARARGS_LOGFN(_static, name, initcall, Critical, CRITICAL)
#endif
/* Typedefs for function pointers for jump table, and predeclare funcs */
/* The DEFAULT funcs will init jump table and then call real function. */
/* The REAL funcs are the actual functions, name-mangled to not clash. */
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) \
typedef rc (*SDL_DYNAPIFN_##fn) params; \
static rc fn##_DEFAULT params; \
extern rc fn##_REAL params;
#include "SDL_dynapi_procs.h"
#undef SDL_DYNAPI_PROC
/* The jump table! */
typedef struct {
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) SDL_DYNAPIFN_##fn fn;
#include "SDL_dynapi_procs.h"
#undef SDL_DYNAPI_PROC
} SDL_DYNAPI_jump_table;
/* Predeclare the default functions for initializing the jump table. */
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) static rc fn##_DEFAULT params;
#include "SDL_dynapi_procs.h"
#undef SDL_DYNAPI_PROC
/* The actual jump table. */
static SDL_DYNAPI_jump_table jump_table = {
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) fn##_DEFAULT,
#include "SDL_dynapi_procs.h"
#undef SDL_DYNAPI_PROC
};
/* Default functions init the function table then call right thing. */
#if DISABLE_JUMP_MAGIC
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) \
static rc fn##_DEFAULT params { \
SDL_InitDynamicAPI(); \
ret jump_table.fn args; \
}
#define SDL_DYNAPI_PROC_NO_VARARGS 1
#include "SDL_dynapi_procs.h"
#undef SDL_DYNAPI_PROC
#undef SDL_DYNAPI_PROC_NO_VARARGS
SDL_DYNAPI_VARARGS(static, _DEFAULT, SDL_InitDynamicAPI())
#else
/* !!! FIXME: need the jump magic. */
#error Write me.
#endif
/* Public API functions to jump into the jump table. */
#if DISABLE_JUMP_MAGIC
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) \
rc fn params { ret jump_table.fn args; }
#define SDL_DYNAPI_PROC_NO_VARARGS 1
#include "SDL_dynapi_procs.h"
#undef SDL_DYNAPI_PROC
#undef SDL_DYNAPI_PROC_NO_VARARGS
SDL_DYNAPI_VARARGS(,,)
#else
/* !!! FIXME: need the jump magic. */
#error Write me.
#endif
/* Here's the exported entry point that fills in the jump table. */
/* Use specific types when an "int" might suffice to keep this sane. */
typedef Sint32 (SDLCALL *SDL_DYNAPI_ENTRYFN)(Uint32 apiver, void *table, Uint32 tablesize);
extern DECLSPEC Sint32 SDLCALL SDL_DYNAPI_entry(Uint32, void *, Uint32);
Sint32
SDL_DYNAPI_entry(Uint32 apiver, void *table, Uint32 tablesize)
{
SDL_DYNAPI_jump_table *output_jump_table = (SDL_DYNAPI_jump_table *) table;
if (apiver != SDL_DYNAPI_VERSION) {
/* !!! FIXME: can maybe handle older versions? */
return -1; /* not compatible. */
} else if (tablesize > sizeof (jump_table)) {
return -1; /* newer version of SDL with functions we can't provide. */
}
/* Init our jump table first. */
#define SDL_DYNAPI_PROC(rc,fn,params,args,ret) jump_table.fn = fn##_REAL;
#include "SDL_dynapi_procs.h"
#undef SDL_DYNAPI_PROC
/* Then the external table... */
if (output_jump_table != &jump_table) {
jump_table.SDL_memcpy(output_jump_table, &jump_table, tablesize);
}
/* Safe to call SDL functions now; jump table is initialized! */
return 0; /* success! */
}
/* Obviously we can't use SDL_LoadObject() to load SDL. :) */
/* Also obviously, we never close the loaded library. */
#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
{
HANDLE lib = LoadLibraryA(fname);
void *retval = NULL;
if (lib) {
retval = GetProcAddress(lib, sym);
if (retval == NULL) {
FreeLibrary(lib);
}
}
return retval;
}
#elif defined(__HAIKU__)
#include <os/kernel/image.h>
static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
{
image_id lib = load_add_on(fname);
void *retval = NULL;
if (lib >= 0) {
if (get_image_symbol(lib, sym, B_SYMBOL_TYPE_TEXT, &retval) != B_NO_ERROR) {
unload_add_on(lib);
retval = NULL;
}
}
return retval;
}
#elif defined(unix) || defined(__unix__) || defined(__APPLE__)
#include <dlfcn.h>
static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
{
void *lib = dlopen(fname, RTLD_NOW | RTLD_LOCAL);
void *retval = NULL;
if (lib != NULL) {
retval = dlsym(lib, sym);
if (retval == NULL) {
dlclose(lib);
}
}
return retval;
}
#else
#error Please define your platform.
#endif
static void
SDL_InitDynamicAPILocked(void)
{
const char *libname = SDL_getenv_REAL("SDL_DYNAMIC_API");
SDL_DYNAPI_ENTRYFN entry = SDL_DYNAPI_entry; /* funcs from here by default. */
if (libname) {
entry = (SDL_DYNAPI_ENTRYFN) get_sdlapi_entry(libname, "SDL_DYNAPI_entry");
if (!entry) {
/* !!! FIXME: fail to startup here instead? */
/* !!! FIXME: definitely warn user. */
/* Just fill in the function pointers from this library. */
entry = SDL_DYNAPI_entry;
}
}
if (entry(SDL_DYNAPI_VERSION, &jump_table, sizeof (jump_table)) < 0) {
/* !!! FIXME: fail to startup here instead? */
/* !!! FIXME: definitely warn user. */
/* Just fill in the function pointers from this library. */
if (entry != SDL_DYNAPI_entry) {
if (!SDL_DYNAPI_entry(SDL_DYNAPI_VERSION, &jump_table, sizeof (jump_table))) {
/* !!! FIXME: now we're screwed. Should definitely abort now. */
}
}
}
/* we intentionally never close the newly-loaded lib, of course. */
}
static void
SDL_InitDynamicAPI(void)
{
/* So the theory is that every function in the jump table defaults to
* calling this function, and then replaces itself with a version that
* doesn't call this function anymore. But it's possible that, in an
* extreme corner case, you can have a second thread hit this function
* while the jump table is being initialized by the first.
* In this case, a spinlock is really painful compared to what spinlocks
* _should_ be used for, but this would only happen once, and should be
* insanely rare, as you would have to spin a thread outside of SDL (as
* SDL_CreateThread() would also call this function before building the
* new thread).
*/
static volatile SDL_bool already_initialized = SDL_FALSE;
/* SDL_AtomicLock calls SDL mutex functions to emulate if
SDL_ATOMIC_DISABLED, which we can't do here, so in such a
configuration, you're on your own. */
#if !SDL_ATOMIC_DISABLED
static SDL_SpinLock lock = 0;
SDL_AtomicLock_REAL(&lock);
#endif
if (!already_initialized) {
SDL_InitDynamicAPILocked();
already_initialized = SDL_TRUE;
}
#if !SDL_ATOMIC_DISABLED
SDL_AtomicUnlock_REAL(&lock);
#endif
}
#endif /* SDL_DYNAMIC_API */
/* vi: set ts=4 sw=4 expandtab: */

61
src/dynapi/SDL_dynapi.h Normal file
View File

@@ -0,0 +1,61 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_dynapi_h
#define _SDL_dynapi_h
/* IMPORTANT:
This is the master switch to disabling the dynamic API. We made it so you
have to hand-edit an internal source file in SDL to turn it off; you
can do it if you want it badly enough, but hopefully you won't want to.
You should understand the ramifications of turning this off: it makes it
hard to update your SDL in the field, and impossible if you've statically
linked SDL into your app. Understand that platforms change, and if we can't
drop in an updated SDL, your application can definitely break some time
in the future, even if it's fine today.
To be sure, as new system-level video and audio APIs are introduced, an
updated SDL can transparently take advantage of them, but your program will
not without this feature. Think hard before turning it off.
*/
#ifdef SDL_DYNAMIC_API /* Tried to force it on the command line? */
#error Nope, you have to edit this file to force this off.
#endif
#ifdef __APPLE__
#include "TargetConditionals.h"
#endif
#if TARGET_OS_IPHONE || __native_client__ || __EMSCRIPTEN__ /* probably not useful on iOS, NACL or Emscripten. */
#define SDL_DYNAMIC_API 0
#elif SDL_BUILDING_WINRT /* probaly not useful on WinRT, given current .dll loading restrictions */
#define SDL_DYNAMIC_API 0
#elif defined(__clang_analyzer__)
#define SDL_DYNAMIC_API 0 /* Turn off for static analysis, so reports are more clear. */
#endif
/* everyone else. This is where we turn on the API if nothing forced it off. */
#ifndef SDL_DYNAMIC_API
#define SDL_DYNAMIC_API 1
#endif
#endif
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,594 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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.
*/
/* vi: set ts=4 sw=4 expandtab: */
/* DO NOT EDIT THIS FILE BY HAND. It is autogenerated by gendynapi.pl. */
#if !SDL_DYNAMIC_API
#error You should not be here.
#endif
/* so annoying. */
#if defined(__thumb__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__))
#define SDL_MemoryBarrierRelease SDL_MemoryBarrierRelease_REAL
#define SDL_MemoryBarrierAcquire SDL_MemoryBarrierAcquire_REAL
#endif
#define SDL_SetError SDL_SetError_REAL
#define SDL_Log SDL_Log_REAL
#define SDL_LogVerbose SDL_LogVerbose_REAL
#define SDL_LogDebug SDL_LogDebug_REAL
#define SDL_LogInfo SDL_LogInfo_REAL
#define SDL_LogWarn SDL_LogWarn_REAL
#define SDL_LogError SDL_LogError_REAL
#define SDL_LogCritical SDL_LogCritical_REAL
#define SDL_LogMessage SDL_LogMessage_REAL
#define SDL_sscanf SDL_sscanf_REAL
#define SDL_snprintf SDL_snprintf_REAL
#define SDL_CreateThread SDL_CreateThread_REAL
#define SDL_RWFromFP SDL_RWFromFP_REAL
#define SDL_RegisterApp SDL_RegisterApp_REAL
#define SDL_UnregisterApp SDL_UnregisterApp_REAL
#define SDL_Direct3D9GetAdapterIndex SDL_Direct3D9GetAdapterIndex_REAL
#define SDL_RenderGetD3D9Device SDL_RenderGetD3D9Device_REAL
#define SDL_iPhoneSetAnimationCallback SDL_iPhoneSetAnimationCallback_REAL
#define SDL_iPhoneSetEventPump SDL_iPhoneSetEventPump_REAL
#define SDL_AndroidGetJNIEnv SDL_AndroidGetJNIEnv_REAL
#define SDL_AndroidGetActivity SDL_AndroidGetActivity_REAL
#define SDL_AndroidGetInternalStoragePath SDL_AndroidGetInternalStoragePath_REAL
#define SDL_AndroidGetExternalStorageState SDL_AndroidGetExternalStorageState_REAL
#define SDL_AndroidGetExternalStoragePath SDL_AndroidGetExternalStoragePath_REAL
#define SDL_Init SDL_Init_REAL
#define SDL_InitSubSystem SDL_InitSubSystem_REAL
#define SDL_QuitSubSystem SDL_QuitSubSystem_REAL
#define SDL_WasInit SDL_WasInit_REAL
#define SDL_Quit SDL_Quit_REAL
#define SDL_ReportAssertion SDL_ReportAssertion_REAL
#define SDL_SetAssertionHandler SDL_SetAssertionHandler_REAL
#define SDL_GetAssertionReport SDL_GetAssertionReport_REAL
#define SDL_ResetAssertionReport SDL_ResetAssertionReport_REAL
#define SDL_AtomicTryLock SDL_AtomicTryLock_REAL
#define SDL_AtomicLock SDL_AtomicLock_REAL
#define SDL_AtomicUnlock SDL_AtomicUnlock_REAL
#define SDL_AtomicCAS SDL_AtomicCAS_REAL
#define SDL_AtomicSet SDL_AtomicSet_REAL
#define SDL_AtomicGet SDL_AtomicGet_REAL
#define SDL_AtomicAdd SDL_AtomicAdd_REAL
#define SDL_AtomicCASPtr SDL_AtomicCASPtr_REAL
#define SDL_AtomicSetPtr SDL_AtomicSetPtr_REAL
#define SDL_AtomicGetPtr SDL_AtomicGetPtr_REAL
#define SDL_GetNumAudioDrivers SDL_GetNumAudioDrivers_REAL
#define SDL_GetAudioDriver SDL_GetAudioDriver_REAL
#define SDL_AudioInit SDL_AudioInit_REAL
#define SDL_AudioQuit SDL_AudioQuit_REAL
#define SDL_GetCurrentAudioDriver SDL_GetCurrentAudioDriver_REAL
#define SDL_OpenAudio SDL_OpenAudio_REAL
#define SDL_GetNumAudioDevices SDL_GetNumAudioDevices_REAL
#define SDL_GetAudioDeviceName SDL_GetAudioDeviceName_REAL
#define SDL_OpenAudioDevice SDL_OpenAudioDevice_REAL
#define SDL_GetAudioStatus SDL_GetAudioStatus_REAL
#define SDL_GetAudioDeviceStatus SDL_GetAudioDeviceStatus_REAL
#define SDL_PauseAudio SDL_PauseAudio_REAL
#define SDL_PauseAudioDevice SDL_PauseAudioDevice_REAL
#define SDL_LoadWAV_RW SDL_LoadWAV_RW_REAL
#define SDL_FreeWAV SDL_FreeWAV_REAL
#define SDL_BuildAudioCVT SDL_BuildAudioCVT_REAL
#define SDL_ConvertAudio SDL_ConvertAudio_REAL
#define SDL_MixAudio SDL_MixAudio_REAL
#define SDL_MixAudioFormat SDL_MixAudioFormat_REAL
#define SDL_LockAudio SDL_LockAudio_REAL
#define SDL_LockAudioDevice SDL_LockAudioDevice_REAL
#define SDL_UnlockAudio SDL_UnlockAudio_REAL
#define SDL_UnlockAudioDevice SDL_UnlockAudioDevice_REAL
#define SDL_CloseAudio SDL_CloseAudio_REAL
#define SDL_CloseAudioDevice SDL_CloseAudioDevice_REAL
#define SDL_SetClipboardText SDL_SetClipboardText_REAL
#define SDL_GetClipboardText SDL_GetClipboardText_REAL
#define SDL_HasClipboardText SDL_HasClipboardText_REAL
#define SDL_GetCPUCount SDL_GetCPUCount_REAL
#define SDL_GetCPUCacheLineSize SDL_GetCPUCacheLineSize_REAL
#define SDL_HasRDTSC SDL_HasRDTSC_REAL
#define SDL_HasAltiVec SDL_HasAltiVec_REAL
#define SDL_HasMMX SDL_HasMMX_REAL
#define SDL_Has3DNow SDL_Has3DNow_REAL
#define SDL_HasSSE SDL_HasSSE_REAL
#define SDL_HasSSE2 SDL_HasSSE2_REAL
#define SDL_HasSSE3 SDL_HasSSE3_REAL
#define SDL_HasSSE41 SDL_HasSSE41_REAL
#define SDL_HasSSE42 SDL_HasSSE42_REAL
#define SDL_GetSystemRAM SDL_GetSystemRAM_REAL
#define SDL_GetError SDL_GetError_REAL
#define SDL_ClearError SDL_ClearError_REAL
#define SDL_Error SDL_Error_REAL
#define SDL_PumpEvents SDL_PumpEvents_REAL
#define SDL_PeepEvents SDL_PeepEvents_REAL
#define SDL_HasEvent SDL_HasEvent_REAL
#define SDL_HasEvents SDL_HasEvents_REAL
#define SDL_FlushEvent SDL_FlushEvent_REAL
#define SDL_FlushEvents SDL_FlushEvents_REAL
#define SDL_PollEvent SDL_PollEvent_REAL
#define SDL_WaitEvent SDL_WaitEvent_REAL
#define SDL_WaitEventTimeout SDL_WaitEventTimeout_REAL
#define SDL_PushEvent SDL_PushEvent_REAL
#define SDL_SetEventFilter SDL_SetEventFilter_REAL
#define SDL_GetEventFilter SDL_GetEventFilter_REAL
#define SDL_AddEventWatch SDL_AddEventWatch_REAL
#define SDL_DelEventWatch SDL_DelEventWatch_REAL
#define SDL_FilterEvents SDL_FilterEvents_REAL
#define SDL_EventState SDL_EventState_REAL
#define SDL_RegisterEvents SDL_RegisterEvents_REAL
#define SDL_GetBasePath SDL_GetBasePath_REAL
#define SDL_GetPrefPath SDL_GetPrefPath_REAL
#define SDL_GameControllerAddMapping SDL_GameControllerAddMapping_REAL
#define SDL_GameControllerMappingForGUID SDL_GameControllerMappingForGUID_REAL
#define SDL_GameControllerMapping SDL_GameControllerMapping_REAL
#define SDL_IsGameController SDL_IsGameController_REAL
#define SDL_GameControllerNameForIndex SDL_GameControllerNameForIndex_REAL
#define SDL_GameControllerOpen SDL_GameControllerOpen_REAL
#define SDL_GameControllerName SDL_GameControllerName_REAL
#define SDL_GameControllerGetAttached SDL_GameControllerGetAttached_REAL
#define SDL_GameControllerGetJoystick SDL_GameControllerGetJoystick_REAL
#define SDL_GameControllerEventState SDL_GameControllerEventState_REAL
#define SDL_GameControllerUpdate SDL_GameControllerUpdate_REAL
#define SDL_GameControllerGetAxisFromString SDL_GameControllerGetAxisFromString_REAL
#define SDL_GameControllerGetStringForAxis SDL_GameControllerGetStringForAxis_REAL
#define SDL_GameControllerGetBindForAxis SDL_GameControllerGetBindForAxis_REAL
#define SDL_GameControllerGetAxis SDL_GameControllerGetAxis_REAL
#define SDL_GameControllerGetButtonFromString SDL_GameControllerGetButtonFromString_REAL
#define SDL_GameControllerGetStringForButton SDL_GameControllerGetStringForButton_REAL
#define SDL_GameControllerGetBindForButton SDL_GameControllerGetBindForButton_REAL
#define SDL_GameControllerGetButton SDL_GameControllerGetButton_REAL
#define SDL_GameControllerClose SDL_GameControllerClose_REAL
#define SDL_RecordGesture SDL_RecordGesture_REAL
#define SDL_SaveAllDollarTemplates SDL_SaveAllDollarTemplates_REAL
#define SDL_SaveDollarTemplate SDL_SaveDollarTemplate_REAL
#define SDL_LoadDollarTemplates SDL_LoadDollarTemplates_REAL
#define SDL_NumHaptics SDL_NumHaptics_REAL
#define SDL_HapticName SDL_HapticName_REAL
#define SDL_HapticOpen SDL_HapticOpen_REAL
#define SDL_HapticOpened SDL_HapticOpened_REAL
#define SDL_HapticIndex SDL_HapticIndex_REAL
#define SDL_MouseIsHaptic SDL_MouseIsHaptic_REAL
#define SDL_HapticOpenFromMouse SDL_HapticOpenFromMouse_REAL
#define SDL_JoystickIsHaptic SDL_JoystickIsHaptic_REAL
#define SDL_HapticOpenFromJoystick SDL_HapticOpenFromJoystick_REAL
#define SDL_HapticClose SDL_HapticClose_REAL
#define SDL_HapticNumEffects SDL_HapticNumEffects_REAL
#define SDL_HapticNumEffectsPlaying SDL_HapticNumEffectsPlaying_REAL
#define SDL_HapticQuery SDL_HapticQuery_REAL
#define SDL_HapticNumAxes SDL_HapticNumAxes_REAL
#define SDL_HapticEffectSupported SDL_HapticEffectSupported_REAL
#define SDL_HapticNewEffect SDL_HapticNewEffect_REAL
#define SDL_HapticUpdateEffect SDL_HapticUpdateEffect_REAL
#define SDL_HapticRunEffect SDL_HapticRunEffect_REAL
#define SDL_HapticStopEffect SDL_HapticStopEffect_REAL
#define SDL_HapticDestroyEffect SDL_HapticDestroyEffect_REAL
#define SDL_HapticGetEffectStatus SDL_HapticGetEffectStatus_REAL
#define SDL_HapticSetGain SDL_HapticSetGain_REAL
#define SDL_HapticSetAutocenter SDL_HapticSetAutocenter_REAL
#define SDL_HapticPause SDL_HapticPause_REAL
#define SDL_HapticUnpause SDL_HapticUnpause_REAL
#define SDL_HapticStopAll SDL_HapticStopAll_REAL
#define SDL_HapticRumbleSupported SDL_HapticRumbleSupported_REAL
#define SDL_HapticRumbleInit SDL_HapticRumbleInit_REAL
#define SDL_HapticRumblePlay SDL_HapticRumblePlay_REAL
#define SDL_HapticRumbleStop SDL_HapticRumbleStop_REAL
#define SDL_SetHintWithPriority SDL_SetHintWithPriority_REAL
#define SDL_SetHint SDL_SetHint_REAL
#define SDL_GetHint SDL_GetHint_REAL
#define SDL_AddHintCallback SDL_AddHintCallback_REAL
#define SDL_DelHintCallback SDL_DelHintCallback_REAL
#define SDL_ClearHints SDL_ClearHints_REAL
#define SDL_NumJoysticks SDL_NumJoysticks_REAL
#define SDL_JoystickNameForIndex SDL_JoystickNameForIndex_REAL
#define SDL_JoystickOpen SDL_JoystickOpen_REAL
#define SDL_JoystickName SDL_JoystickName_REAL
#define SDL_JoystickGetDeviceGUID SDL_JoystickGetDeviceGUID_REAL
#define SDL_JoystickGetGUID SDL_JoystickGetGUID_REAL
#define SDL_JoystickGetGUIDString SDL_JoystickGetGUIDString_REAL
#define SDL_JoystickGetGUIDFromString SDL_JoystickGetGUIDFromString_REAL
#define SDL_JoystickGetAttached SDL_JoystickGetAttached_REAL
#define SDL_JoystickInstanceID SDL_JoystickInstanceID_REAL
#define SDL_JoystickNumAxes SDL_JoystickNumAxes_REAL
#define SDL_JoystickNumBalls SDL_JoystickNumBalls_REAL
#define SDL_JoystickNumHats SDL_JoystickNumHats_REAL
#define SDL_JoystickNumButtons SDL_JoystickNumButtons_REAL
#define SDL_JoystickUpdate SDL_JoystickUpdate_REAL
#define SDL_JoystickEventState SDL_JoystickEventState_REAL
#define SDL_JoystickGetAxis SDL_JoystickGetAxis_REAL
#define SDL_JoystickGetHat SDL_JoystickGetHat_REAL
#define SDL_JoystickGetBall SDL_JoystickGetBall_REAL
#define SDL_JoystickGetButton SDL_JoystickGetButton_REAL
#define SDL_JoystickClose SDL_JoystickClose_REAL
#define SDL_GetKeyboardFocus SDL_GetKeyboardFocus_REAL
#define SDL_GetKeyboardState SDL_GetKeyboardState_REAL
#define SDL_GetModState SDL_GetModState_REAL
#define SDL_SetModState SDL_SetModState_REAL
#define SDL_GetKeyFromScancode SDL_GetKeyFromScancode_REAL
#define SDL_GetScancodeFromKey SDL_GetScancodeFromKey_REAL
#define SDL_GetScancodeName SDL_GetScancodeName_REAL
#define SDL_GetScancodeFromName SDL_GetScancodeFromName_REAL
#define SDL_GetKeyName SDL_GetKeyName_REAL
#define SDL_GetKeyFromName SDL_GetKeyFromName_REAL
#define SDL_StartTextInput SDL_StartTextInput_REAL
#define SDL_IsTextInputActive SDL_IsTextInputActive_REAL
#define SDL_StopTextInput SDL_StopTextInput_REAL
#define SDL_SetTextInputRect SDL_SetTextInputRect_REAL
#define SDL_HasScreenKeyboardSupport SDL_HasScreenKeyboardSupport_REAL
#define SDL_IsScreenKeyboardShown SDL_IsScreenKeyboardShown_REAL
#define SDL_LoadObject SDL_LoadObject_REAL
#define SDL_LoadFunction SDL_LoadFunction_REAL
#define SDL_UnloadObject SDL_UnloadObject_REAL
#define SDL_LogSetAllPriority SDL_LogSetAllPriority_REAL
#define SDL_LogSetPriority SDL_LogSetPriority_REAL
#define SDL_LogGetPriority SDL_LogGetPriority_REAL
#define SDL_LogResetPriorities SDL_LogResetPriorities_REAL
#define SDL_LogMessageV SDL_LogMessageV_REAL
#define SDL_LogGetOutputFunction SDL_LogGetOutputFunction_REAL
#define SDL_LogSetOutputFunction SDL_LogSetOutputFunction_REAL
#define SDL_SetMainReady SDL_SetMainReady_REAL
#define SDL_ShowMessageBox SDL_ShowMessageBox_REAL
#define SDL_ShowSimpleMessageBox SDL_ShowSimpleMessageBox_REAL
#define SDL_GetMouseFocus SDL_GetMouseFocus_REAL
#define SDL_GetMouseState SDL_GetMouseState_REAL
#define SDL_GetRelativeMouseState SDL_GetRelativeMouseState_REAL
#define SDL_WarpMouseInWindow SDL_WarpMouseInWindow_REAL
#define SDL_SetRelativeMouseMode SDL_SetRelativeMouseMode_REAL
#define SDL_GetRelativeMouseMode SDL_GetRelativeMouseMode_REAL
#define SDL_CreateCursor SDL_CreateCursor_REAL
#define SDL_CreateColorCursor SDL_CreateColorCursor_REAL
#define SDL_CreateSystemCursor SDL_CreateSystemCursor_REAL
#define SDL_SetCursor SDL_SetCursor_REAL
#define SDL_GetCursor SDL_GetCursor_REAL
#define SDL_GetDefaultCursor SDL_GetDefaultCursor_REAL
#define SDL_FreeCursor SDL_FreeCursor_REAL
#define SDL_ShowCursor SDL_ShowCursor_REAL
#define SDL_CreateMutex SDL_CreateMutex_REAL
#define SDL_LockMutex SDL_LockMutex_REAL
#define SDL_TryLockMutex SDL_TryLockMutex_REAL
#define SDL_UnlockMutex SDL_UnlockMutex_REAL
#define SDL_DestroyMutex SDL_DestroyMutex_REAL
#define SDL_CreateSemaphore SDL_CreateSemaphore_REAL
#define SDL_DestroySemaphore SDL_DestroySemaphore_REAL
#define SDL_SemWait SDL_SemWait_REAL
#define SDL_SemTryWait SDL_SemTryWait_REAL
#define SDL_SemWaitTimeout SDL_SemWaitTimeout_REAL
#define SDL_SemPost SDL_SemPost_REAL
#define SDL_SemValue SDL_SemValue_REAL
#define SDL_CreateCond SDL_CreateCond_REAL
#define SDL_DestroyCond SDL_DestroyCond_REAL
#define SDL_CondSignal SDL_CondSignal_REAL
#define SDL_CondBroadcast SDL_CondBroadcast_REAL
#define SDL_CondWait SDL_CondWait_REAL
#define SDL_CondWaitTimeout SDL_CondWaitTimeout_REAL
#define SDL_GetPixelFormatName SDL_GetPixelFormatName_REAL
#define SDL_PixelFormatEnumToMasks SDL_PixelFormatEnumToMasks_REAL
#define SDL_MasksToPixelFormatEnum SDL_MasksToPixelFormatEnum_REAL
#define SDL_AllocFormat SDL_AllocFormat_REAL
#define SDL_FreeFormat SDL_FreeFormat_REAL
#define SDL_AllocPalette SDL_AllocPalette_REAL
#define SDL_SetPixelFormatPalette SDL_SetPixelFormatPalette_REAL
#define SDL_SetPaletteColors SDL_SetPaletteColors_REAL
#define SDL_FreePalette SDL_FreePalette_REAL
#define SDL_MapRGB SDL_MapRGB_REAL
#define SDL_MapRGBA SDL_MapRGBA_REAL
#define SDL_GetRGB SDL_GetRGB_REAL
#define SDL_GetRGBA SDL_GetRGBA_REAL
#define SDL_CalculateGammaRamp SDL_CalculateGammaRamp_REAL
#define SDL_GetPlatform SDL_GetPlatform_REAL
#define SDL_GetPowerInfo SDL_GetPowerInfo_REAL
#define SDL_HasIntersection SDL_HasIntersection_REAL
#define SDL_IntersectRect SDL_IntersectRect_REAL
#define SDL_UnionRect SDL_UnionRect_REAL
#define SDL_EnclosePoints SDL_EnclosePoints_REAL
#define SDL_IntersectRectAndLine SDL_IntersectRectAndLine_REAL
#define SDL_GetNumRenderDrivers SDL_GetNumRenderDrivers_REAL
#define SDL_GetRenderDriverInfo SDL_GetRenderDriverInfo_REAL
#define SDL_CreateWindowAndRenderer SDL_CreateWindowAndRenderer_REAL
#define SDL_CreateRenderer SDL_CreateRenderer_REAL
#define SDL_CreateSoftwareRenderer SDL_CreateSoftwareRenderer_REAL
#define SDL_GetRenderer SDL_GetRenderer_REAL
#define SDL_GetRendererInfo SDL_GetRendererInfo_REAL
#define SDL_GetRendererOutputSize SDL_GetRendererOutputSize_REAL
#define SDL_CreateTexture SDL_CreateTexture_REAL
#define SDL_CreateTextureFromSurface SDL_CreateTextureFromSurface_REAL
#define SDL_QueryTexture SDL_QueryTexture_REAL
#define SDL_SetTextureColorMod SDL_SetTextureColorMod_REAL
#define SDL_GetTextureColorMod SDL_GetTextureColorMod_REAL
#define SDL_SetTextureAlphaMod SDL_SetTextureAlphaMod_REAL
#define SDL_GetTextureAlphaMod SDL_GetTextureAlphaMod_REAL
#define SDL_SetTextureBlendMode SDL_SetTextureBlendMode_REAL
#define SDL_GetTextureBlendMode SDL_GetTextureBlendMode_REAL
#define SDL_UpdateTexture SDL_UpdateTexture_REAL
#define SDL_UpdateYUVTexture SDL_UpdateYUVTexture_REAL
#define SDL_LockTexture SDL_LockTexture_REAL
#define SDL_UnlockTexture SDL_UnlockTexture_REAL
#define SDL_RenderTargetSupported SDL_RenderTargetSupported_REAL
#define SDL_SetRenderTarget SDL_SetRenderTarget_REAL
#define SDL_GetRenderTarget SDL_GetRenderTarget_REAL
#define SDL_RenderSetLogicalSize SDL_RenderSetLogicalSize_REAL
#define SDL_RenderGetLogicalSize SDL_RenderGetLogicalSize_REAL
#define SDL_RenderSetViewport SDL_RenderSetViewport_REAL
#define SDL_RenderGetViewport SDL_RenderGetViewport_REAL
#define SDL_RenderSetClipRect SDL_RenderSetClipRect_REAL
#define SDL_RenderGetClipRect SDL_RenderGetClipRect_REAL
#define SDL_RenderSetScale SDL_RenderSetScale_REAL
#define SDL_RenderGetScale SDL_RenderGetScale_REAL
#define SDL_SetRenderDrawColor SDL_SetRenderDrawColor_REAL
#define SDL_GetRenderDrawColor SDL_GetRenderDrawColor_REAL
#define SDL_SetRenderDrawBlendMode SDL_SetRenderDrawBlendMode_REAL
#define SDL_GetRenderDrawBlendMode SDL_GetRenderDrawBlendMode_REAL
#define SDL_RenderClear SDL_RenderClear_REAL
#define SDL_RenderDrawPoint SDL_RenderDrawPoint_REAL
#define SDL_RenderDrawPoints SDL_RenderDrawPoints_REAL
#define SDL_RenderDrawLine SDL_RenderDrawLine_REAL
#define SDL_RenderDrawLines SDL_RenderDrawLines_REAL
#define SDL_RenderDrawRect SDL_RenderDrawRect_REAL
#define SDL_RenderDrawRects SDL_RenderDrawRects_REAL
#define SDL_RenderFillRect SDL_RenderFillRect_REAL
#define SDL_RenderFillRects SDL_RenderFillRects_REAL
#define SDL_RenderCopy SDL_RenderCopy_REAL
#define SDL_RenderCopyEx SDL_RenderCopyEx_REAL
#define SDL_RenderReadPixels SDL_RenderReadPixels_REAL
#define SDL_RenderPresent SDL_RenderPresent_REAL
#define SDL_DestroyTexture SDL_DestroyTexture_REAL
#define SDL_DestroyRenderer SDL_DestroyRenderer_REAL
#define SDL_GL_BindTexture SDL_GL_BindTexture_REAL
#define SDL_GL_UnbindTexture SDL_GL_UnbindTexture_REAL
#define SDL_RWFromFile SDL_RWFromFile_REAL
#define SDL_RWFromMem SDL_RWFromMem_REAL
#define SDL_RWFromConstMem SDL_RWFromConstMem_REAL
#define SDL_AllocRW SDL_AllocRW_REAL
#define SDL_FreeRW SDL_FreeRW_REAL
#define SDL_ReadU8 SDL_ReadU8_REAL
#define SDL_ReadLE16 SDL_ReadLE16_REAL
#define SDL_ReadBE16 SDL_ReadBE16_REAL
#define SDL_ReadLE32 SDL_ReadLE32_REAL
#define SDL_ReadBE32 SDL_ReadBE32_REAL
#define SDL_ReadLE64 SDL_ReadLE64_REAL
#define SDL_ReadBE64 SDL_ReadBE64_REAL
#define SDL_WriteU8 SDL_WriteU8_REAL
#define SDL_WriteLE16 SDL_WriteLE16_REAL
#define SDL_WriteBE16 SDL_WriteBE16_REAL
#define SDL_WriteLE32 SDL_WriteLE32_REAL
#define SDL_WriteBE32 SDL_WriteBE32_REAL
#define SDL_WriteLE64 SDL_WriteLE64_REAL
#define SDL_WriteBE64 SDL_WriteBE64_REAL
#define SDL_CreateShapedWindow SDL_CreateShapedWindow_REAL
#define SDL_IsShapedWindow SDL_IsShapedWindow_REAL
#define SDL_SetWindowShape SDL_SetWindowShape_REAL
#define SDL_GetShapedWindowMode SDL_GetShapedWindowMode_REAL
#define SDL_malloc SDL_malloc_REAL
#define SDL_calloc SDL_calloc_REAL
#define SDL_realloc SDL_realloc_REAL
#define SDL_free SDL_free_REAL
#define SDL_getenv SDL_getenv_REAL
#define SDL_setenv SDL_setenv_REAL
#define SDL_qsort SDL_qsort_REAL
#define SDL_abs SDL_abs_REAL
#define SDL_isdigit SDL_isdigit_REAL
#define SDL_isspace SDL_isspace_REAL
#define SDL_toupper SDL_toupper_REAL
#define SDL_tolower SDL_tolower_REAL
#define SDL_memset SDL_memset_REAL
#define SDL_memcpy SDL_memcpy_REAL
#define SDL_memmove SDL_memmove_REAL
#define SDL_memcmp SDL_memcmp_REAL
#define SDL_wcslen SDL_wcslen_REAL
#define SDL_wcslcpy SDL_wcslcpy_REAL
#define SDL_wcslcat SDL_wcslcat_REAL
#define SDL_strlen SDL_strlen_REAL
#define SDL_strlcpy SDL_strlcpy_REAL
#define SDL_utf8strlcpy SDL_utf8strlcpy_REAL
#define SDL_strlcat SDL_strlcat_REAL
#define SDL_strdup SDL_strdup_REAL
#define SDL_strrev SDL_strrev_REAL
#define SDL_strupr SDL_strupr_REAL
#define SDL_strlwr SDL_strlwr_REAL
#define SDL_strchr SDL_strchr_REAL
#define SDL_strrchr SDL_strrchr_REAL
#define SDL_strstr SDL_strstr_REAL
#define SDL_itoa SDL_itoa_REAL
#define SDL_uitoa SDL_uitoa_REAL
#define SDL_ltoa SDL_ltoa_REAL
#define SDL_ultoa SDL_ultoa_REAL
#define SDL_lltoa SDL_lltoa_REAL
#define SDL_ulltoa SDL_ulltoa_REAL
#define SDL_atoi SDL_atoi_REAL
#define SDL_atof SDL_atof_REAL
#define SDL_strtol SDL_strtol_REAL
#define SDL_strtoul SDL_strtoul_REAL
#define SDL_strtoll SDL_strtoll_REAL
#define SDL_strtoull SDL_strtoull_REAL
#define SDL_strtod SDL_strtod_REAL
#define SDL_strcmp SDL_strcmp_REAL
#define SDL_strncmp SDL_strncmp_REAL
#define SDL_strcasecmp SDL_strcasecmp_REAL
#define SDL_strncasecmp SDL_strncasecmp_REAL
#define SDL_vsnprintf SDL_vsnprintf_REAL
#define SDL_acos SDL_acos_REAL
#define SDL_asin SDL_asin_REAL
#define SDL_atan SDL_atan_REAL
#define SDL_atan2 SDL_atan2_REAL
#define SDL_ceil SDL_ceil_REAL
#define SDL_copysign SDL_copysign_REAL
#define SDL_cos SDL_cos_REAL
#define SDL_cosf SDL_cosf_REAL
#define SDL_fabs SDL_fabs_REAL
#define SDL_floor SDL_floor_REAL
#define SDL_log SDL_log_REAL
#define SDL_pow SDL_pow_REAL
#define SDL_scalbn SDL_scalbn_REAL
#define SDL_sin SDL_sin_REAL
#define SDL_sinf SDL_sinf_REAL
#define SDL_sqrt SDL_sqrt_REAL
#define SDL_iconv_open SDL_iconv_open_REAL
#define SDL_iconv_close SDL_iconv_close_REAL
#define SDL_iconv SDL_iconv_REAL
#define SDL_iconv_string SDL_iconv_string_REAL
#define SDL_CreateRGBSurface SDL_CreateRGBSurface_REAL
#define SDL_CreateRGBSurfaceFrom SDL_CreateRGBSurfaceFrom_REAL
#define SDL_FreeSurface SDL_FreeSurface_REAL
#define SDL_SetSurfacePalette SDL_SetSurfacePalette_REAL
#define SDL_LockSurface SDL_LockSurface_REAL
#define SDL_UnlockSurface SDL_UnlockSurface_REAL
#define SDL_LoadBMP_RW SDL_LoadBMP_RW_REAL
#define SDL_SaveBMP_RW SDL_SaveBMP_RW_REAL
#define SDL_SetSurfaceRLE SDL_SetSurfaceRLE_REAL
#define SDL_SetColorKey SDL_SetColorKey_REAL
#define SDL_GetColorKey SDL_GetColorKey_REAL
#define SDL_SetSurfaceColorMod SDL_SetSurfaceColorMod_REAL
#define SDL_GetSurfaceColorMod SDL_GetSurfaceColorMod_REAL
#define SDL_SetSurfaceAlphaMod SDL_SetSurfaceAlphaMod_REAL
#define SDL_GetSurfaceAlphaMod SDL_GetSurfaceAlphaMod_REAL
#define SDL_SetSurfaceBlendMode SDL_SetSurfaceBlendMode_REAL
#define SDL_GetSurfaceBlendMode SDL_GetSurfaceBlendMode_REAL
#define SDL_SetClipRect SDL_SetClipRect_REAL
#define SDL_GetClipRect SDL_GetClipRect_REAL
#define SDL_ConvertSurface SDL_ConvertSurface_REAL
#define SDL_ConvertSurfaceFormat SDL_ConvertSurfaceFormat_REAL
#define SDL_ConvertPixels SDL_ConvertPixels_REAL
#define SDL_FillRect SDL_FillRect_REAL
#define SDL_FillRects SDL_FillRects_REAL
#define SDL_UpperBlit SDL_UpperBlit_REAL
#define SDL_LowerBlit SDL_LowerBlit_REAL
#define SDL_SoftStretch SDL_SoftStretch_REAL
#define SDL_UpperBlitScaled SDL_UpperBlitScaled_REAL
#define SDL_LowerBlitScaled SDL_LowerBlitScaled_REAL
#define SDL_GetWindowWMInfo SDL_GetWindowWMInfo_REAL
#define SDL_GetThreadName SDL_GetThreadName_REAL
#define SDL_ThreadID SDL_ThreadID_REAL
#define SDL_GetThreadID SDL_GetThreadID_REAL
#define SDL_SetThreadPriority SDL_SetThreadPriority_REAL
#define SDL_WaitThread SDL_WaitThread_REAL
#define SDL_DetachThread SDL_DetachThread_REAL
#define SDL_TLSCreate SDL_TLSCreate_REAL
#define SDL_TLSGet SDL_TLSGet_REAL
#define SDL_TLSSet SDL_TLSSet_REAL
#define SDL_GetTicks SDL_GetTicks_REAL
#define SDL_GetPerformanceCounter SDL_GetPerformanceCounter_REAL
#define SDL_GetPerformanceFrequency SDL_GetPerformanceFrequency_REAL
#define SDL_Delay SDL_Delay_REAL
#define SDL_AddTimer SDL_AddTimer_REAL
#define SDL_RemoveTimer SDL_RemoveTimer_REAL
#define SDL_GetNumTouchDevices SDL_GetNumTouchDevices_REAL
#define SDL_GetTouchDevice SDL_GetTouchDevice_REAL
#define SDL_GetNumTouchFingers SDL_GetNumTouchFingers_REAL
#define SDL_GetTouchFinger SDL_GetTouchFinger_REAL
#define SDL_GetVersion SDL_GetVersion_REAL
#define SDL_GetRevision SDL_GetRevision_REAL
#define SDL_GetRevisionNumber SDL_GetRevisionNumber_REAL
#define SDL_GetNumVideoDrivers SDL_GetNumVideoDrivers_REAL
#define SDL_GetVideoDriver SDL_GetVideoDriver_REAL
#define SDL_VideoInit SDL_VideoInit_REAL
#define SDL_VideoQuit SDL_VideoQuit_REAL
#define SDL_GetCurrentVideoDriver SDL_GetCurrentVideoDriver_REAL
#define SDL_GetNumVideoDisplays SDL_GetNumVideoDisplays_REAL
#define SDL_GetDisplayName SDL_GetDisplayName_REAL
#define SDL_GetDisplayBounds SDL_GetDisplayBounds_REAL
#define SDL_GetNumDisplayModes SDL_GetNumDisplayModes_REAL
#define SDL_GetDisplayMode SDL_GetDisplayMode_REAL
#define SDL_GetDesktopDisplayMode SDL_GetDesktopDisplayMode_REAL
#define SDL_GetCurrentDisplayMode SDL_GetCurrentDisplayMode_REAL
#define SDL_GetClosestDisplayMode SDL_GetClosestDisplayMode_REAL
#define SDL_GetWindowDisplayIndex SDL_GetWindowDisplayIndex_REAL
#define SDL_SetWindowDisplayMode SDL_SetWindowDisplayMode_REAL
#define SDL_GetWindowDisplayMode SDL_GetWindowDisplayMode_REAL
#define SDL_GetWindowPixelFormat SDL_GetWindowPixelFormat_REAL
#define SDL_CreateWindow SDL_CreateWindow_REAL
#define SDL_CreateWindowFrom SDL_CreateWindowFrom_REAL
#define SDL_GetWindowID SDL_GetWindowID_REAL
#define SDL_GetWindowFromID SDL_GetWindowFromID_REAL
#define SDL_GetWindowFlags SDL_GetWindowFlags_REAL
#define SDL_SetWindowTitle SDL_SetWindowTitle_REAL
#define SDL_GetWindowTitle SDL_GetWindowTitle_REAL
#define SDL_SetWindowIcon SDL_SetWindowIcon_REAL
#define SDL_SetWindowData SDL_SetWindowData_REAL
#define SDL_GetWindowData SDL_GetWindowData_REAL
#define SDL_SetWindowPosition SDL_SetWindowPosition_REAL
#define SDL_GetWindowPosition SDL_GetWindowPosition_REAL
#define SDL_SetWindowSize SDL_SetWindowSize_REAL
#define SDL_GetWindowSize SDL_GetWindowSize_REAL
#define SDL_SetWindowMinimumSize SDL_SetWindowMinimumSize_REAL
#define SDL_GetWindowMinimumSize SDL_GetWindowMinimumSize_REAL
#define SDL_SetWindowMaximumSize SDL_SetWindowMaximumSize_REAL
#define SDL_GetWindowMaximumSize SDL_GetWindowMaximumSize_REAL
#define SDL_SetWindowBordered SDL_SetWindowBordered_REAL
#define SDL_ShowWindow SDL_ShowWindow_REAL
#define SDL_HideWindow SDL_HideWindow_REAL
#define SDL_RaiseWindow SDL_RaiseWindow_REAL
#define SDL_MaximizeWindow SDL_MaximizeWindow_REAL
#define SDL_MinimizeWindow SDL_MinimizeWindow_REAL
#define SDL_RestoreWindow SDL_RestoreWindow_REAL
#define SDL_SetWindowFullscreen SDL_SetWindowFullscreen_REAL
#define SDL_GetWindowSurface SDL_GetWindowSurface_REAL
#define SDL_UpdateWindowSurface SDL_UpdateWindowSurface_REAL
#define SDL_UpdateWindowSurfaceRects SDL_UpdateWindowSurfaceRects_REAL
#define SDL_SetWindowGrab SDL_SetWindowGrab_REAL
#define SDL_GetWindowGrab SDL_GetWindowGrab_REAL
#define SDL_SetWindowBrightness SDL_SetWindowBrightness_REAL
#define SDL_GetWindowBrightness SDL_GetWindowBrightness_REAL
#define SDL_SetWindowGammaRamp SDL_SetWindowGammaRamp_REAL
#define SDL_GetWindowGammaRamp SDL_GetWindowGammaRamp_REAL
#define SDL_DestroyWindow SDL_DestroyWindow_REAL
#define SDL_IsScreenSaverEnabled SDL_IsScreenSaverEnabled_REAL
#define SDL_EnableScreenSaver SDL_EnableScreenSaver_REAL
#define SDL_DisableScreenSaver SDL_DisableScreenSaver_REAL
#define SDL_GL_LoadLibrary SDL_GL_LoadLibrary_REAL
#define SDL_GL_GetProcAddress SDL_GL_GetProcAddress_REAL
#define SDL_GL_UnloadLibrary SDL_GL_UnloadLibrary_REAL
#define SDL_GL_ExtensionSupported SDL_GL_ExtensionSupported_REAL
#define SDL_GL_SetAttribute SDL_GL_SetAttribute_REAL
#define SDL_GL_GetAttribute SDL_GL_GetAttribute_REAL
#define SDL_GL_CreateContext SDL_GL_CreateContext_REAL
#define SDL_GL_MakeCurrent SDL_GL_MakeCurrent_REAL
#define SDL_GL_GetCurrentWindow SDL_GL_GetCurrentWindow_REAL
#define SDL_GL_GetCurrentContext SDL_GL_GetCurrentContext_REAL
#define SDL_GL_GetDrawableSize SDL_GL_GetDrawableSize_REAL
#define SDL_GL_SetSwapInterval SDL_GL_SetSwapInterval_REAL
#define SDL_GL_GetSwapInterval SDL_GL_GetSwapInterval_REAL
#define SDL_GL_SwapWindow SDL_GL_SwapWindow_REAL
#define SDL_GL_DeleteContext SDL_GL_DeleteContext_REAL
#define SDL_vsscanf SDL_vsscanf_REAL
#define SDL_GameControllerAddMappingsFromRW SDL_GameControllerAddMappingsFromRW_REAL
#define SDL_GL_ResetAttributes SDL_GL_ResetAttributes_REAL
#define SDL_HasAVX SDL_HasAVX_REAL
#define SDL_GetDefaultAssertionHandler SDL_GetDefaultAssertionHandler_REAL
#define SDL_GetAssertionHandler SDL_GetAssertionHandler_REAL
#define SDL_DXGIGetOutputInfo SDL_DXGIGetOutputInfo_REAL
#define SDL_RenderIsClipEnabled SDL_RenderIsClipEnabled_REAL
#define SDL_WinRTRunApp SDL_WinRTRunApp_REAL
#define SDL_WarpMouseGlobal SDL_WarpMouseGlobal_REAL
#define SDL_WinRTGetFSPathUNICODE SDL_WinRTGetFSPathUNICODE_REAL
#define SDL_WinRTGetFSPathUTF8 SDL_WinRTGetFSPathUTF8_REAL
#define SDL_WinRTRunApp SDL_WinRTRunApp_REAL
#define SDL_sqrtf SDL_sqrtf_REAL
#define SDL_tan SDL_tan_REAL
#define SDL_tanf SDL_tanf_REAL
#define SDL_CaptureMouse SDL_CaptureMouse_REAL
#define SDL_SetWindowHitTest SDL_SetWindowHitTest_REAL
#define SDL_GetGlobalMouseState SDL_GetGlobalMouseState_REAL
#define SDL_HasAVX2 SDL_HasAVX2_REAL
#define SDL_QueueAudio SDL_QueueAudio_REAL
#define SDL_GetQueuedAudioSize SDL_GetQueuedAudioSize_REAL
#define SDL_ClearQueuedAudio SDL_ClearQueuedAudio_REAL
#define SDL_GetGrabbedWindow SDL_GetGrabbedWindow_REAL

View File

@@ -0,0 +1,626 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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.
*/
/* vi: set ts=4 sw=4 expandtab: */
/*
DO NOT EDIT THIS FILE BY HAND. It is autogenerated by gendynapi.pl.
NEVER REARRANGE THIS FILE, THE ORDER IS ABI LAW.
Changing this file means bumping SDL_DYNAPI_VERSION. You can safely add
new items to the end of the file, though.
Also, this file gets included multiple times, don't add #pragma once, etc.
*/
/* direct jump magic can use these, the rest needs special code. */
#if !SDL_DYNAPI_PROC_NO_VARARGS
SDL_DYNAPI_PROC(int,SDL_SetError,(SDL_PRINTF_FORMAT_STRING const char *a, ...),(a),return)
SDL_DYNAPI_PROC(void,SDL_Log,(SDL_PRINTF_FORMAT_STRING const char *a, ...),(a),)
SDL_DYNAPI_PROC(void,SDL_LogVerbose,(int a, SDL_PRINTF_FORMAT_STRING const char *b, ...),(a,b),)
SDL_DYNAPI_PROC(void,SDL_LogDebug,(int a, SDL_PRINTF_FORMAT_STRING const char *b, ...),(a,b),)
SDL_DYNAPI_PROC(void,SDL_LogInfo,(int a, SDL_PRINTF_FORMAT_STRING const char *b, ...),(a,b),)
SDL_DYNAPI_PROC(void,SDL_LogWarn,(int a, SDL_PRINTF_FORMAT_STRING const char *b, ...),(a,b),)
SDL_DYNAPI_PROC(void,SDL_LogError,(int a, SDL_PRINTF_FORMAT_STRING const char *b, ...),(a,b),)
SDL_DYNAPI_PROC(void,SDL_LogCritical,(int a, SDL_PRINTF_FORMAT_STRING const char *b, ...),(a,b),)
SDL_DYNAPI_PROC(void,SDL_LogMessage,(int a, SDL_LogPriority b, SDL_PRINTF_FORMAT_STRING const char *c, ...),(a,b,c),)
SDL_DYNAPI_PROC(int,SDL_sscanf,(const char *a, SDL_SCANF_FORMAT_STRING const char *b, ...),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_snprintf,(SDL_OUT_Z_CAP(b) char *a, size_t b, SDL_PRINTF_FORMAT_STRING const char *c, ...),(a,b,c),return)
#endif
#ifdef SDL_CreateThread
#undef SDL_CreateThread
#endif
#if defined(__WIN32__) && !defined(HAVE_LIBC)
SDL_DYNAPI_PROC(SDL_Thread*,SDL_CreateThread,(SDL_ThreadFunction a, const char *b, void *c, pfnSDL_CurrentBeginThread d, pfnSDL_CurrentEndThread e),(a,b,c,d,e),return)
#else
SDL_DYNAPI_PROC(SDL_Thread*,SDL_CreateThread,(SDL_ThreadFunction a, const char *b, void *c),(a,b,c),return)
#endif
#ifdef HAVE_STDIO_H
SDL_DYNAPI_PROC(SDL_RWops*,SDL_RWFromFP,(FILE *a, SDL_bool b),(a,b),return)
#else
SDL_DYNAPI_PROC(SDL_RWops*,SDL_RWFromFP,(void *a, SDL_bool b),(a,b),return)
#endif
/* so annoying. */
#if defined(__thumb__) && (defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__))
SDL_DYNAPI_PROC(void,SDL_MemoryBarrierRelease,(void),(),)
SDL_DYNAPI_PROC(void,SDL_MemoryBarrierAcquire,(void),(),)
#endif
#ifdef __WIN32__
SDL_DYNAPI_PROC(int,SDL_RegisterApp,(char *a, Uint32 b, void *c),(a,b,c),return)
SDL_DYNAPI_PROC(void,SDL_UnregisterApp,(void),(),)
SDL_DYNAPI_PROC(int,SDL_Direct3D9GetAdapterIndex,(int a),(a),return)
SDL_DYNAPI_PROC(IDirect3DDevice9*,SDL_RenderGetD3D9Device,(SDL_Renderer *a),(a),return)
#endif
#if defined(__IPHONEOS__) && __IPHONEOS__
SDL_DYNAPI_PROC(int,SDL_iPhoneSetAnimationCallback,(SDL_Window *a, int b, void c, void *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(void,SDL_iPhoneSetEventPump,(SDL_bool a),(a),)
#endif
#if defined(__ANDROID__) && __ANDROID__
SDL_DYNAPI_PROC(void*,SDL_AndroidGetJNIEnv,(void),(),return)
SDL_DYNAPI_PROC(void*,SDL_AndroidGetActivity,(void),(),return)
SDL_DYNAPI_PROC(const char*,SDL_AndroidGetInternalStoragePath,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_AndroidGetExternalStorageState,(void),(),return)
SDL_DYNAPI_PROC(const char*,SDL_AndroidGetExternalStoragePath,(void),(),return)
#endif
SDL_DYNAPI_PROC(int,SDL_Init,(Uint32 a),(a),return)
SDL_DYNAPI_PROC(int,SDL_InitSubSystem,(Uint32 a),(a),return)
SDL_DYNAPI_PROC(void,SDL_QuitSubSystem,(Uint32 a),(a),)
SDL_DYNAPI_PROC(Uint32,SDL_WasInit,(Uint32 a),(a),return)
SDL_DYNAPI_PROC(void,SDL_Quit,(void),(),)
SDL_DYNAPI_PROC(SDL_assert_state,SDL_ReportAssertion,(SDL_assert_data *a, const char *b, const char *c, int d),(a,b,c,d),return)
SDL_DYNAPI_PROC(void,SDL_SetAssertionHandler,(SDL_AssertionHandler a, void *b),(a,b),)
SDL_DYNAPI_PROC(const SDL_assert_data*,SDL_GetAssertionReport,(void),(),return)
SDL_DYNAPI_PROC(void,SDL_ResetAssertionReport,(void),(),)
SDL_DYNAPI_PROC(SDL_bool,SDL_AtomicTryLock,(SDL_SpinLock *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_AtomicLock,(SDL_SpinLock *a),(a),)
SDL_DYNAPI_PROC(void,SDL_AtomicUnlock,(SDL_SpinLock *a),(a),)
SDL_DYNAPI_PROC(SDL_bool,SDL_AtomicCAS,(SDL_atomic_t *a, int b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_AtomicSet,(SDL_atomic_t *a, int b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_AtomicGet,(SDL_atomic_t *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_AtomicAdd,(SDL_atomic_t *a, int b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_AtomicCASPtr,(void **a, void *b, void *c),(a,b,c),return)
SDL_DYNAPI_PROC(void*,SDL_AtomicSetPtr,(void **a, void *b),(a,b),return)
SDL_DYNAPI_PROC(void*,SDL_AtomicGetPtr,(void **a),(a),return)
SDL_DYNAPI_PROC(int,SDL_GetNumAudioDrivers,(void),(),return)
SDL_DYNAPI_PROC(const char*,SDL_GetAudioDriver,(int a),(a),return)
SDL_DYNAPI_PROC(int,SDL_AudioInit,(const char *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_AudioQuit,(void),(),)
SDL_DYNAPI_PROC(const char*,SDL_GetCurrentAudioDriver,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_OpenAudio,(SDL_AudioSpec *a, SDL_AudioSpec *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GetNumAudioDevices,(int a),(a),return)
SDL_DYNAPI_PROC(const char*,SDL_GetAudioDeviceName,(int a, int b),(a,b),return)
SDL_DYNAPI_PROC(SDL_AudioDeviceID,SDL_OpenAudioDevice,(const char *a, int b, const SDL_AudioSpec *c, SDL_AudioSpec *d, int e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(SDL_AudioStatus,SDL_GetAudioStatus,(void),(),return)
SDL_DYNAPI_PROC(SDL_AudioStatus,SDL_GetAudioDeviceStatus,(SDL_AudioDeviceID a),(a),return)
SDL_DYNAPI_PROC(void,SDL_PauseAudio,(int a),(a),)
SDL_DYNAPI_PROC(void,SDL_PauseAudioDevice,(SDL_AudioDeviceID a, int b),(a,b),)
SDL_DYNAPI_PROC(SDL_AudioSpec*,SDL_LoadWAV_RW,(SDL_RWops *a, int b, SDL_AudioSpec *c, Uint8 **d, Uint32 *e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(void,SDL_FreeWAV,(Uint8 *a),(a),)
SDL_DYNAPI_PROC(int,SDL_BuildAudioCVT,(SDL_AudioCVT *a, SDL_AudioFormat b, Uint8 c, int d, SDL_AudioFormat e, Uint8 f, int g),(a,b,c,d,e,f,g),return)
SDL_DYNAPI_PROC(int,SDL_ConvertAudio,(SDL_AudioCVT *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_MixAudio,(Uint8 *a, const Uint8 *b, Uint32 c, int d),(a,b,c,d),)
SDL_DYNAPI_PROC(void,SDL_MixAudioFormat,(Uint8 *a, const Uint8 *b, SDL_AudioFormat c, Uint32 d, int e),(a,b,c,d,e),)
SDL_DYNAPI_PROC(void,SDL_LockAudio,(void),(),)
SDL_DYNAPI_PROC(void,SDL_LockAudioDevice,(SDL_AudioDeviceID a),(a),)
SDL_DYNAPI_PROC(void,SDL_UnlockAudio,(void),(),)
SDL_DYNAPI_PROC(void,SDL_UnlockAudioDevice,(SDL_AudioDeviceID a),(a),)
SDL_DYNAPI_PROC(void,SDL_CloseAudio,(void),(),)
SDL_DYNAPI_PROC(void,SDL_CloseAudioDevice,(SDL_AudioDeviceID a),(a),)
SDL_DYNAPI_PROC(int,SDL_SetClipboardText,(const char *a),(a),return)
SDL_DYNAPI_PROC(char*,SDL_GetClipboardText,(void),(),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasClipboardText,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_GetCPUCount,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_GetCPUCacheLineSize,(void),(),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasRDTSC,(void),(),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasAltiVec,(void),(),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasMMX,(void),(),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_Has3DNow,(void),(),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasSSE,(void),(),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasSSE2,(void),(),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasSSE3,(void),(),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasSSE41,(void),(),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasSSE42,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_GetSystemRAM,(void),(),return)
SDL_DYNAPI_PROC(const char*,SDL_GetError,(void),(),return)
SDL_DYNAPI_PROC(void,SDL_ClearError,(void),(),)
SDL_DYNAPI_PROC(int,SDL_Error,(SDL_errorcode a),(a),return)
SDL_DYNAPI_PROC(void,SDL_PumpEvents,(void),(),)
SDL_DYNAPI_PROC(int,SDL_PeepEvents,(SDL_Event *a, int b, SDL_eventaction c, Uint32 d, Uint32 e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasEvent,(Uint32 a),(a),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasEvents,(Uint32 a, Uint32 b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_FlushEvent,(Uint32 a),(a),)
SDL_DYNAPI_PROC(void,SDL_FlushEvents,(Uint32 a, Uint32 b),(a,b),)
SDL_DYNAPI_PROC(int,SDL_PollEvent,(SDL_Event *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_WaitEvent,(SDL_Event *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_WaitEventTimeout,(SDL_Event *a, int b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_PushEvent,(SDL_Event *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_SetEventFilter,(SDL_EventFilter a, void *b),(a,b),)
SDL_DYNAPI_PROC(SDL_bool,SDL_GetEventFilter,(SDL_EventFilter *a, void **b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_AddEventWatch,(SDL_EventFilter a, void *b),(a,b),)
SDL_DYNAPI_PROC(void,SDL_DelEventWatch,(SDL_EventFilter a, void *b),(a,b),)
SDL_DYNAPI_PROC(void,SDL_FilterEvents,(SDL_EventFilter a, void *b),(a,b),)
SDL_DYNAPI_PROC(Uint8,SDL_EventState,(Uint32 a, int b),(a,b),return)
SDL_DYNAPI_PROC(Uint32,SDL_RegisterEvents,(int a),(a),return)
SDL_DYNAPI_PROC(char*,SDL_GetBasePath,(void),(),return)
SDL_DYNAPI_PROC(char*,SDL_GetPrefPath,(const char *a, const char *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GameControllerAddMapping,(const char *a),(a),return)
SDL_DYNAPI_PROC(char*,SDL_GameControllerMappingForGUID,(SDL_JoystickGUID a),(a),return)
SDL_DYNAPI_PROC(char*,SDL_GameControllerMapping,(SDL_GameController *a),(a),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_IsGameController,(int a),(a),return)
SDL_DYNAPI_PROC(const char*,SDL_GameControllerNameForIndex,(int a),(a),return)
SDL_DYNAPI_PROC(SDL_GameController*,SDL_GameControllerOpen,(int a),(a),return)
SDL_DYNAPI_PROC(const char*,SDL_GameControllerName,(SDL_GameController *a),(a),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_GameControllerGetAttached,(SDL_GameController *a),(a),return)
SDL_DYNAPI_PROC(SDL_Joystick*,SDL_GameControllerGetJoystick,(SDL_GameController *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_GameControllerEventState,(int a),(a),return)
SDL_DYNAPI_PROC(void,SDL_GameControllerUpdate,(void),(),)
SDL_DYNAPI_PROC(SDL_GameControllerAxis,SDL_GameControllerGetAxisFromString,(const char *a),(a),return)
SDL_DYNAPI_PROC(const char*,SDL_GameControllerGetStringForAxis,(SDL_GameControllerAxis a),(a),return)
SDL_DYNAPI_PROC(SDL_GameControllerButtonBind,SDL_GameControllerGetBindForAxis,(SDL_GameController *a, SDL_GameControllerAxis b),(a,b),return)
SDL_DYNAPI_PROC(Sint16,SDL_GameControllerGetAxis,(SDL_GameController *a, SDL_GameControllerAxis b),(a,b),return)
SDL_DYNAPI_PROC(SDL_GameControllerButton,SDL_GameControllerGetButtonFromString,(const char *a),(a),return)
SDL_DYNAPI_PROC(const char*,SDL_GameControllerGetStringForButton,(SDL_GameControllerButton a),(a),return)
SDL_DYNAPI_PROC(SDL_GameControllerButtonBind,SDL_GameControllerGetBindForButton,(SDL_GameController *a, SDL_GameControllerButton b),(a,b),return)
SDL_DYNAPI_PROC(Uint8,SDL_GameControllerGetButton,(SDL_GameController *a, SDL_GameControllerButton b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_GameControllerClose,(SDL_GameController *a),(a),)
SDL_DYNAPI_PROC(int,SDL_RecordGesture,(SDL_TouchID a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SaveAllDollarTemplates,(SDL_RWops *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SaveDollarTemplate,(SDL_GestureID a, SDL_RWops *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_LoadDollarTemplates,(SDL_TouchID a, SDL_RWops *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_NumHaptics,(void),(),return)
SDL_DYNAPI_PROC(const char*,SDL_HapticName,(int a),(a),return)
SDL_DYNAPI_PROC(SDL_Haptic*,SDL_HapticOpen,(int a),(a),return)
SDL_DYNAPI_PROC(int,SDL_HapticOpened,(int a),(a),return)
SDL_DYNAPI_PROC(int,SDL_HapticIndex,(SDL_Haptic *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_MouseIsHaptic,(void),(),return)
SDL_DYNAPI_PROC(SDL_Haptic*,SDL_HapticOpenFromMouse,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_JoystickIsHaptic,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(SDL_Haptic*,SDL_HapticOpenFromJoystick,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_HapticClose,(SDL_Haptic *a),(a),)
SDL_DYNAPI_PROC(int,SDL_HapticNumEffects,(SDL_Haptic *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_HapticNumEffectsPlaying,(SDL_Haptic *a),(a),return)
SDL_DYNAPI_PROC(unsigned int,SDL_HapticQuery,(SDL_Haptic *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_HapticNumAxes,(SDL_Haptic *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_HapticEffectSupported,(SDL_Haptic *a, SDL_HapticEffect *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_HapticNewEffect,(SDL_Haptic *a, SDL_HapticEffect *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_HapticUpdateEffect,(SDL_Haptic *a, int b, SDL_HapticEffect *c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_HapticRunEffect,(SDL_Haptic *a, int b, Uint32 c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_HapticStopEffect,(SDL_Haptic *a, int b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_HapticDestroyEffect,(SDL_Haptic *a, int b),(a,b),)
SDL_DYNAPI_PROC(int,SDL_HapticGetEffectStatus,(SDL_Haptic *a, int b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_HapticSetGain,(SDL_Haptic *a, int b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_HapticSetAutocenter,(SDL_Haptic *a, int b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_HapticPause,(SDL_Haptic *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_HapticUnpause,(SDL_Haptic *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_HapticStopAll,(SDL_Haptic *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_HapticRumbleSupported,(SDL_Haptic *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_HapticRumbleInit,(SDL_Haptic *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_HapticRumblePlay,(SDL_Haptic *a, float b, Uint32 c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_HapticRumbleStop,(SDL_Haptic *a),(a),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_SetHintWithPriority,(const char *a, const char *b, SDL_HintPriority c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_SetHint,(const char *a, const char *b),(a,b),return)
SDL_DYNAPI_PROC(const char*,SDL_GetHint,(const char *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_AddHintCallback,(const char *a, SDL_HintCallback b, void *c),(a,b,c),)
SDL_DYNAPI_PROC(void,SDL_DelHintCallback,(const char *a, SDL_HintCallback b, void *c),(a,b,c),)
SDL_DYNAPI_PROC(void,SDL_ClearHints,(void),(),)
SDL_DYNAPI_PROC(int,SDL_NumJoysticks,(void),(),return)
SDL_DYNAPI_PROC(const char*,SDL_JoystickNameForIndex,(int a),(a),return)
SDL_DYNAPI_PROC(SDL_Joystick*,SDL_JoystickOpen,(int a),(a),return)
SDL_DYNAPI_PROC(const char*,SDL_JoystickName,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(SDL_JoystickGUID,SDL_JoystickGetDeviceGUID,(int a),(a),return)
SDL_DYNAPI_PROC(SDL_JoystickGUID,SDL_JoystickGetGUID,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_JoystickGetGUIDString,(SDL_JoystickGUID a, char *b, int c),(a,b,c),)
SDL_DYNAPI_PROC(SDL_JoystickGUID,SDL_JoystickGetGUIDFromString,(const char *a),(a),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_JoystickGetAttached,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(SDL_JoystickID,SDL_JoystickInstanceID,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_JoystickNumAxes,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_JoystickNumBalls,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_JoystickNumHats,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_JoystickNumButtons,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_JoystickUpdate,(void),(),)
SDL_DYNAPI_PROC(int,SDL_JoystickEventState,(int a),(a),return)
SDL_DYNAPI_PROC(Sint16,SDL_JoystickGetAxis,(SDL_Joystick *a, int b),(a,b),return)
SDL_DYNAPI_PROC(Uint8,SDL_JoystickGetHat,(SDL_Joystick *a, int b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_JoystickGetBall,(SDL_Joystick *a, int b, int *c, int *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(Uint8,SDL_JoystickGetButton,(SDL_Joystick *a, int b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_JoystickClose,(SDL_Joystick *a),(a),)
SDL_DYNAPI_PROC(SDL_Window*,SDL_GetKeyboardFocus,(void),(),return)
SDL_DYNAPI_PROC(const Uint8*,SDL_GetKeyboardState,(int *a),(a),return)
SDL_DYNAPI_PROC(SDL_Keymod,SDL_GetModState,(void),(),return)
SDL_DYNAPI_PROC(void,SDL_SetModState,(SDL_Keymod a),(a),)
SDL_DYNAPI_PROC(SDL_Keycode,SDL_GetKeyFromScancode,(SDL_Scancode a),(a),return)
SDL_DYNAPI_PROC(SDL_Scancode,SDL_GetScancodeFromKey,(SDL_Keycode a),(a),return)
SDL_DYNAPI_PROC(const char*,SDL_GetScancodeName,(SDL_Scancode a),(a),return)
SDL_DYNAPI_PROC(SDL_Scancode,SDL_GetScancodeFromName,(const char *a),(a),return)
SDL_DYNAPI_PROC(const char*,SDL_GetKeyName,(SDL_Keycode a),(a),return)
SDL_DYNAPI_PROC(SDL_Keycode,SDL_GetKeyFromName,(const char *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_StartTextInput,(void),(),)
SDL_DYNAPI_PROC(SDL_bool,SDL_IsTextInputActive,(void),(),return)
SDL_DYNAPI_PROC(void,SDL_StopTextInput,(void),(),)
SDL_DYNAPI_PROC(void,SDL_SetTextInputRect,(SDL_Rect *a),(a),)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasScreenKeyboardSupport,(void),(),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_IsScreenKeyboardShown,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(void*,SDL_LoadObject,(const char *a),(a),return)
SDL_DYNAPI_PROC(void*,SDL_LoadFunction,(void *a, const char *b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_UnloadObject,(void *a),(a),)
SDL_DYNAPI_PROC(void,SDL_LogSetAllPriority,(SDL_LogPriority a),(a),)
SDL_DYNAPI_PROC(void,SDL_LogSetPriority,(int a, SDL_LogPriority b),(a,b),)
SDL_DYNAPI_PROC(SDL_LogPriority,SDL_LogGetPriority,(int a),(a),return)
SDL_DYNAPI_PROC(void,SDL_LogResetPriorities,(void),(),)
SDL_DYNAPI_PROC(void,SDL_LogMessageV,(int a, SDL_LogPriority b, const char *c, va_list d),(a,b,c,d),)
SDL_DYNAPI_PROC(void,SDL_LogGetOutputFunction,(SDL_LogOutputFunction *a, void **b),(a,b),)
SDL_DYNAPI_PROC(void,SDL_LogSetOutputFunction,(SDL_LogOutputFunction a, void *b),(a,b),)
SDL_DYNAPI_PROC(void,SDL_SetMainReady,(void),(),)
SDL_DYNAPI_PROC(int,SDL_ShowMessageBox,(const SDL_MessageBoxData *a, int *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_ShowSimpleMessageBox,(Uint32 a, const char *b, const char *c, SDL_Window *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(SDL_Window*,SDL_GetMouseFocus,(void),(),return)
SDL_DYNAPI_PROC(Uint32,SDL_GetMouseState,(int *a, int *b),(a,b),return)
SDL_DYNAPI_PROC(Uint32,SDL_GetRelativeMouseState,(int *a, int *b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_WarpMouseInWindow,(SDL_Window *a, int b, int c),(a,b,c),)
SDL_DYNAPI_PROC(int,SDL_SetRelativeMouseMode,(SDL_bool a),(a),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_GetRelativeMouseMode,(void),(),return)
SDL_DYNAPI_PROC(SDL_Cursor*,SDL_CreateCursor,(const Uint8 *a, const Uint8 *b, int c, int d, int e, int f),(a,b,c,d,e,f),return)
SDL_DYNAPI_PROC(SDL_Cursor*,SDL_CreateColorCursor,(SDL_Surface *a, int b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_Cursor*,SDL_CreateSystemCursor,(SDL_SystemCursor a),(a),return)
SDL_DYNAPI_PROC(void,SDL_SetCursor,(SDL_Cursor *a),(a),)
SDL_DYNAPI_PROC(SDL_Cursor*,SDL_GetCursor,(void),(),return)
SDL_DYNAPI_PROC(SDL_Cursor*,SDL_GetDefaultCursor,(void),(),return)
SDL_DYNAPI_PROC(void,SDL_FreeCursor,(SDL_Cursor *a),(a),)
SDL_DYNAPI_PROC(int,SDL_ShowCursor,(int a),(a),return)
SDL_DYNAPI_PROC(SDL_mutex*,SDL_CreateMutex,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_LockMutex,(SDL_mutex *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_TryLockMutex,(SDL_mutex *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_UnlockMutex,(SDL_mutex *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_DestroyMutex,(SDL_mutex *a),(a),)
SDL_DYNAPI_PROC(SDL_sem*,SDL_CreateSemaphore,(Uint32 a),(a),return)
SDL_DYNAPI_PROC(void,SDL_DestroySemaphore,(SDL_sem *a),(a),)
SDL_DYNAPI_PROC(int,SDL_SemWait,(SDL_sem *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SemTryWait,(SDL_sem *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SemWaitTimeout,(SDL_sem *a, Uint32 b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_SemPost,(SDL_sem *a),(a),return)
SDL_DYNAPI_PROC(Uint32,SDL_SemValue,(SDL_sem *a),(a),return)
SDL_DYNAPI_PROC(SDL_cond*,SDL_CreateCond,(void),(),return)
SDL_DYNAPI_PROC(void,SDL_DestroyCond,(SDL_cond *a),(a),)
SDL_DYNAPI_PROC(int,SDL_CondSignal,(SDL_cond *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_CondBroadcast,(SDL_cond *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_CondWait,(SDL_cond *a, SDL_mutex *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_CondWaitTimeout,(SDL_cond *a, SDL_mutex *b, Uint32 c),(a,b,c),return)
SDL_DYNAPI_PROC(const char*,SDL_GetPixelFormatName,(Uint32 a),(a),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_PixelFormatEnumToMasks,(Uint32 a, int *b, Uint32 *c, Uint32 *d, Uint32 *e, Uint32 *f),(a,b,c,d,e,f),return)
SDL_DYNAPI_PROC(Uint32,SDL_MasksToPixelFormatEnum,(int a, Uint32 b, Uint32 c, Uint32 d, Uint32 e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(SDL_PixelFormat*,SDL_AllocFormat,(Uint32 a),(a),return)
SDL_DYNAPI_PROC(void,SDL_FreeFormat,(SDL_PixelFormat *a),(a),)
SDL_DYNAPI_PROC(SDL_Palette*,SDL_AllocPalette,(int a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SetPixelFormatPalette,(SDL_PixelFormat *a, SDL_Palette *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_SetPaletteColors,(SDL_Palette *a, const SDL_Color *b, int c, int d),(a,b,c,d),return)
SDL_DYNAPI_PROC(void,SDL_FreePalette,(SDL_Palette *a),(a),)
SDL_DYNAPI_PROC(Uint32,SDL_MapRGB,(const SDL_PixelFormat *a, Uint8 b, Uint8 c, Uint8 d),(a,b,c,d),return)
SDL_DYNAPI_PROC(Uint32,SDL_MapRGBA,(const SDL_PixelFormat *a, Uint8 b, Uint8 c, Uint8 d, Uint8 e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(void,SDL_GetRGB,(Uint32 a, const SDL_PixelFormat *b, Uint8 *c, Uint8 *d, Uint8 *e),(a,b,c,d,e),)
SDL_DYNAPI_PROC(void,SDL_GetRGBA,(Uint32 a, const SDL_PixelFormat *b, Uint8 *c, Uint8 *d, Uint8 *e, Uint8 *f),(a,b,c,d,e,f),)
SDL_DYNAPI_PROC(void,SDL_CalculateGammaRamp,(float a, Uint16 *b),(a,b),)
SDL_DYNAPI_PROC(const char*,SDL_GetPlatform,(void),(),return)
SDL_DYNAPI_PROC(SDL_PowerState,SDL_GetPowerInfo,(int *a, int *b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasIntersection,(const SDL_Rect *a, const SDL_Rect *b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_IntersectRect,(const SDL_Rect *a, const SDL_Rect *b, SDL_Rect *c),(a,b,c),return)
SDL_DYNAPI_PROC(void,SDL_UnionRect,(const SDL_Rect *a, const SDL_Rect *b, SDL_Rect *c),(a,b,c),)
SDL_DYNAPI_PROC(SDL_bool,SDL_EnclosePoints,(const SDL_Point *a, int b, const SDL_Rect *c, SDL_Rect *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_IntersectRectAndLine,(const SDL_Rect *a, int *b, int *c, int *d, int *e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(int,SDL_GetNumRenderDrivers,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_GetRenderDriverInfo,(int a, SDL_RendererInfo *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_CreateWindowAndRenderer,(int a, int b, Uint32 c, SDL_Window **d, SDL_Renderer **e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(SDL_Renderer*,SDL_CreateRenderer,(SDL_Window *a, int b, Uint32 c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_Renderer*,SDL_CreateSoftwareRenderer,(SDL_Surface *a),(a),return)
SDL_DYNAPI_PROC(SDL_Renderer*,SDL_GetRenderer,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_GetRendererInfo,(SDL_Renderer *a, SDL_RendererInfo *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GetRendererOutputSize,(SDL_Renderer *a, int *b, int *c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_Texture*,SDL_CreateTexture,(SDL_Renderer *a, Uint32 b, int c, int d, int e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(SDL_Texture*,SDL_CreateTextureFromSurface,(SDL_Renderer *a, SDL_Surface *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_QueryTexture,(SDL_Texture *a, Uint32 *b, int *c, int *d, int *e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(int,SDL_SetTextureColorMod,(SDL_Texture *a, Uint8 b, Uint8 c, Uint8 d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_GetTextureColorMod,(SDL_Texture *a, Uint8 *b, Uint8 *c, Uint8 *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_SetTextureAlphaMod,(SDL_Texture *a, Uint8 b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GetTextureAlphaMod,(SDL_Texture *a, Uint8 *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_SetTextureBlendMode,(SDL_Texture *a, SDL_BlendMode b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GetTextureBlendMode,(SDL_Texture *a, SDL_BlendMode *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_UpdateTexture,(SDL_Texture *a, const SDL_Rect *b, const void *c, int d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_UpdateYUVTexture,(SDL_Texture *a, const SDL_Rect *b, const Uint8 *c, int d, const Uint8 *e, int f, const Uint8 *g, int h),(a,b,c,d,e,f,g,h),return)
SDL_DYNAPI_PROC(int,SDL_LockTexture,(SDL_Texture *a, const SDL_Rect *b, void **c, int *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(void,SDL_UnlockTexture,(SDL_Texture *a),(a),)
SDL_DYNAPI_PROC(SDL_bool,SDL_RenderTargetSupported,(SDL_Renderer *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SetRenderTarget,(SDL_Renderer *a, SDL_Texture *b),(a,b),return)
SDL_DYNAPI_PROC(SDL_Texture*,SDL_GetRenderTarget,(SDL_Renderer *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_RenderSetLogicalSize,(SDL_Renderer *a, int b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(void,SDL_RenderGetLogicalSize,(SDL_Renderer *a, int *b, int *c),(a,b,c),)
SDL_DYNAPI_PROC(int,SDL_RenderSetViewport,(SDL_Renderer *a, const SDL_Rect *b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_RenderGetViewport,(SDL_Renderer *a, SDL_Rect *b),(a,b),)
SDL_DYNAPI_PROC(int,SDL_RenderSetClipRect,(SDL_Renderer *a, const SDL_Rect *b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_RenderGetClipRect,(SDL_Renderer *a, SDL_Rect *b),(a,b),)
SDL_DYNAPI_PROC(int,SDL_RenderSetScale,(SDL_Renderer *a, float b, float c),(a,b,c),return)
SDL_DYNAPI_PROC(void,SDL_RenderGetScale,(SDL_Renderer *a, float *b, float *c),(a,b,c),)
SDL_DYNAPI_PROC(int,SDL_SetRenderDrawColor,(SDL_Renderer *a, Uint8 b, Uint8 c, Uint8 d, Uint8 e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(int,SDL_GetRenderDrawColor,(SDL_Renderer *a, Uint8 *b, Uint8 *c, Uint8 *d, Uint8 *e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(int,SDL_SetRenderDrawBlendMode,(SDL_Renderer *a, SDL_BlendMode b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GetRenderDrawBlendMode,(SDL_Renderer *a, SDL_BlendMode *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_RenderClear,(SDL_Renderer *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_RenderDrawPoint,(SDL_Renderer *a, int b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_RenderDrawPoints,(SDL_Renderer *a, const SDL_Point *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_RenderDrawLine,(SDL_Renderer *a, int b, int c, int d, int e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(int,SDL_RenderDrawLines,(SDL_Renderer *a, const SDL_Point *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_RenderDrawRect,(SDL_Renderer *a, const SDL_Rect *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_RenderDrawRects,(SDL_Renderer *a, const SDL_Rect *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_RenderFillRect,(SDL_Renderer *a, const SDL_Rect *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_RenderFillRects,(SDL_Renderer *a, const SDL_Rect *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_RenderCopy,(SDL_Renderer *a, SDL_Texture *b, const SDL_Rect *c, const SDL_Rect *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_RenderCopyEx,(SDL_Renderer *a, SDL_Texture *b, const SDL_Rect *c, const SDL_Rect *d, const double e, const SDL_Point *f, const SDL_RendererFlip g),(a,b,c,d,e,f,g),return)
SDL_DYNAPI_PROC(int,SDL_RenderReadPixels,(SDL_Renderer *a, const SDL_Rect *b, Uint32 c, void *d, int e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(void,SDL_RenderPresent,(SDL_Renderer *a),(a),)
SDL_DYNAPI_PROC(void,SDL_DestroyTexture,(SDL_Texture *a),(a),)
SDL_DYNAPI_PROC(void,SDL_DestroyRenderer,(SDL_Renderer *a),(a),)
SDL_DYNAPI_PROC(int,SDL_GL_BindTexture,(SDL_Texture *a, float *b, float *c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_GL_UnbindTexture,(SDL_Texture *a),(a),return)
SDL_DYNAPI_PROC(SDL_RWops*,SDL_RWFromFile,(const char *a, const char *b),(a,b),return)
SDL_DYNAPI_PROC(SDL_RWops*,SDL_RWFromMem,(void *a, int b),(a,b),return)
SDL_DYNAPI_PROC(SDL_RWops*,SDL_RWFromConstMem,(const void *a, int b),(a,b),return)
SDL_DYNAPI_PROC(SDL_RWops*,SDL_AllocRW,(void),(),return)
SDL_DYNAPI_PROC(void,SDL_FreeRW,(SDL_RWops *a),(a),)
SDL_DYNAPI_PROC(Uint8,SDL_ReadU8,(SDL_RWops *a),(a),return)
SDL_DYNAPI_PROC(Uint16,SDL_ReadLE16,(SDL_RWops *a),(a),return)
SDL_DYNAPI_PROC(Uint16,SDL_ReadBE16,(SDL_RWops *a),(a),return)
SDL_DYNAPI_PROC(Uint32,SDL_ReadLE32,(SDL_RWops *a),(a),return)
SDL_DYNAPI_PROC(Uint32,SDL_ReadBE32,(SDL_RWops *a),(a),return)
SDL_DYNAPI_PROC(Uint64,SDL_ReadLE64,(SDL_RWops *a),(a),return)
SDL_DYNAPI_PROC(Uint64,SDL_ReadBE64,(SDL_RWops *a),(a),return)
SDL_DYNAPI_PROC(size_t,SDL_WriteU8,(SDL_RWops *a, Uint8 b),(a,b),return)
SDL_DYNAPI_PROC(size_t,SDL_WriteLE16,(SDL_RWops *a, Uint16 b),(a,b),return)
SDL_DYNAPI_PROC(size_t,SDL_WriteBE16,(SDL_RWops *a, Uint16 b),(a,b),return)
SDL_DYNAPI_PROC(size_t,SDL_WriteLE32,(SDL_RWops *a, Uint32 b),(a,b),return)
SDL_DYNAPI_PROC(size_t,SDL_WriteBE32,(SDL_RWops *a, Uint32 b),(a,b),return)
SDL_DYNAPI_PROC(size_t,SDL_WriteLE64,(SDL_RWops *a, Uint64 b),(a,b),return)
SDL_DYNAPI_PROC(size_t,SDL_WriteBE64,(SDL_RWops *a, Uint64 b),(a,b),return)
SDL_DYNAPI_PROC(SDL_Window*,SDL_CreateShapedWindow,(const char *a, unsigned int b, unsigned int c, unsigned int d, unsigned int e, Uint32 f),(a,b,c,d,e,f),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_IsShapedWindow,(const SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SetWindowShape,(SDL_Window *a, SDL_Surface *b, SDL_WindowShapeMode *c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_GetShapedWindowMode,(SDL_Window *a, SDL_WindowShapeMode *b),(a,b),return)
SDL_DYNAPI_PROC(void*,SDL_malloc,(size_t a),(a),return)
SDL_DYNAPI_PROC(void*,SDL_calloc,(size_t a, size_t b),(a,b),return)
SDL_DYNAPI_PROC(void*,SDL_realloc,(void *a, size_t b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_free,(void *a),(a),)
SDL_DYNAPI_PROC(char*,SDL_getenv,(const char *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_setenv,(const char *a, const char *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(void,SDL_qsort,(void *a, size_t b, size_t c, int (*d)(const void *, const void *)),(a,b,c,d),)
SDL_DYNAPI_PROC(int,SDL_abs,(int a),(a),return)
SDL_DYNAPI_PROC(int,SDL_isdigit,(int a),(a),return)
SDL_DYNAPI_PROC(int,SDL_isspace,(int a),(a),return)
SDL_DYNAPI_PROC(int,SDL_toupper,(int a),(a),return)
SDL_DYNAPI_PROC(int,SDL_tolower,(int a),(a),return)
SDL_DYNAPI_PROC(void*,SDL_memset,(SDL_OUT_BYTECAP(c) void *a, int b, size_t c),(a,b,c),return)
SDL_DYNAPI_PROC(void*,SDL_memcpy,(SDL_OUT_BYTECAP(c) void *a, SDL_IN_BYTECAP(c) const void *b, size_t c),(a,b,c),return)
SDL_DYNAPI_PROC(void*,SDL_memmove,(SDL_OUT_BYTECAP(c) void *a, SDL_IN_BYTECAP(c) const void *b, size_t c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_memcmp,(const void *a, const void *b, size_t c),(a,b,c),return)
SDL_DYNAPI_PROC(size_t,SDL_wcslen,(const wchar_t *a),(a),return)
SDL_DYNAPI_PROC(size_t,SDL_wcslcpy,(SDL_OUT_Z_CAP(c) wchar_t *a, const wchar_t *b, size_t c),(a,b,c),return)
SDL_DYNAPI_PROC(size_t,SDL_wcslcat,(SDL_INOUT_Z_CAP(c) wchar_t *a, const wchar_t *b, size_t c),(a,b,c),return)
SDL_DYNAPI_PROC(size_t,SDL_strlen,(const char *a),(a),return)
SDL_DYNAPI_PROC(size_t,SDL_strlcpy,(SDL_OUT_Z_CAP(c) char *a, const char *b, size_t c),(a,b,c),return)
SDL_DYNAPI_PROC(size_t,SDL_utf8strlcpy,(SDL_OUT_Z_CAP(c) char *a, const char *b, size_t c),(a,b,c),return)
SDL_DYNAPI_PROC(size_t,SDL_strlcat,(SDL_INOUT_Z_CAP(c) char *a, const char *b, size_t c),(a,b,c),return)
SDL_DYNAPI_PROC(char*,SDL_strdup,(const char *a),(a),return)
SDL_DYNAPI_PROC(char*,SDL_strrev,(char *a),(a),return)
SDL_DYNAPI_PROC(char*,SDL_strupr,(char *a),(a),return)
SDL_DYNAPI_PROC(char*,SDL_strlwr,(char *a),(a),return)
SDL_DYNAPI_PROC(char*,SDL_strchr,(const char *a, int b),(a,b),return)
SDL_DYNAPI_PROC(char*,SDL_strrchr,(const char *a, int b),(a,b),return)
SDL_DYNAPI_PROC(char*,SDL_strstr,(const char *a, const char *b),(a,b),return)
SDL_DYNAPI_PROC(char*,SDL_itoa,(int a, char *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(char*,SDL_uitoa,(unsigned int a, char *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(char*,SDL_ltoa,(long a, char *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(char*,SDL_ultoa,(unsigned long a, char *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(char*,SDL_lltoa,(Sint64 a, char *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(char*,SDL_ulltoa,(Uint64 a, char *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_atoi,(const char *a),(a),return)
SDL_DYNAPI_PROC(double,SDL_atof,(const char *a),(a),return)
SDL_DYNAPI_PROC(long,SDL_strtol,(const char *a, char **b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(unsigned long,SDL_strtoul,(const char *a, char **b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(Sint64,SDL_strtoll,(const char *a, char **b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(Uint64,SDL_strtoull,(const char *a, char **b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(double,SDL_strtod,(const char *a, char **b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_strcmp,(const char *a, const char *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_strncmp,(const char *a, const char *b, size_t c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_strcasecmp,(const char *a, const char *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_strncasecmp,(const char *a, const char *b, size_t c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_vsnprintf,(SDL_OUT_Z_CAP(b) char *a, size_t b, const char *c, va_list d),(a,b,c,d),return)
SDL_DYNAPI_PROC(double,SDL_acos,(double a),(a),return)
SDL_DYNAPI_PROC(double,SDL_asin,(double a),(a),return)
SDL_DYNAPI_PROC(double,SDL_atan,(double a),(a),return)
SDL_DYNAPI_PROC(double,SDL_atan2,(double a, double b),(a,b),return)
SDL_DYNAPI_PROC(double,SDL_ceil,(double a),(a),return)
SDL_DYNAPI_PROC(double,SDL_copysign,(double a, double b),(a,b),return)
SDL_DYNAPI_PROC(double,SDL_cos,(double a),(a),return)
SDL_DYNAPI_PROC(float,SDL_cosf,(float a),(a),return)
SDL_DYNAPI_PROC(double,SDL_fabs,(double a),(a),return)
SDL_DYNAPI_PROC(double,SDL_floor,(double a),(a),return)
SDL_DYNAPI_PROC(double,SDL_log,(double a),(a),return)
SDL_DYNAPI_PROC(double,SDL_pow,(double a, double b),(a,b),return)
SDL_DYNAPI_PROC(double,SDL_scalbn,(double a, int b),(a,b),return)
SDL_DYNAPI_PROC(double,SDL_sin,(double a),(a),return)
SDL_DYNAPI_PROC(float,SDL_sinf,(float a),(a),return)
SDL_DYNAPI_PROC(double,SDL_sqrt,(double a),(a),return)
SDL_DYNAPI_PROC(SDL_iconv_t,SDL_iconv_open,(const char *a, const char *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_iconv_close,(SDL_iconv_t a),(a),return)
SDL_DYNAPI_PROC(size_t,SDL_iconv,(SDL_iconv_t a, const char **b, size_t *c, char **d, size_t *e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(char*,SDL_iconv_string,(const char *a, const char *b, const char *c, size_t d),(a,b,c,d),return)
SDL_DYNAPI_PROC(SDL_Surface*,SDL_CreateRGBSurface,(Uint32 a, int b, int c, int d, Uint32 e, Uint32 f, Uint32 g, Uint32 h),(a,b,c,d,e,f,g,h),return)
SDL_DYNAPI_PROC(SDL_Surface*,SDL_CreateRGBSurfaceFrom,(void *a, int b, int c, int d, int e, Uint32 f, Uint32 g, Uint32 h, Uint32 i),(a,b,c,d,e,f,g,h,i),return)
SDL_DYNAPI_PROC(void,SDL_FreeSurface,(SDL_Surface *a),(a),)
SDL_DYNAPI_PROC(int,SDL_SetSurfacePalette,(SDL_Surface *a, SDL_Palette *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_LockSurface,(SDL_Surface *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_UnlockSurface,(SDL_Surface *a),(a),)
SDL_DYNAPI_PROC(SDL_Surface*,SDL_LoadBMP_RW,(SDL_RWops *a, int b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_SaveBMP_RW,(SDL_Surface *a, SDL_RWops *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_SetSurfaceRLE,(SDL_Surface *a, int b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_SetColorKey,(SDL_Surface *a, int b, Uint32 c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_GetColorKey,(SDL_Surface *a, Uint32 *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_SetSurfaceColorMod,(SDL_Surface *a, Uint8 b, Uint8 c, Uint8 d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_GetSurfaceColorMod,(SDL_Surface *a, Uint8 *b, Uint8 *c, Uint8 *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_SetSurfaceAlphaMod,(SDL_Surface *a, Uint8 b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GetSurfaceAlphaMod,(SDL_Surface *a, Uint8 *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_SetSurfaceBlendMode,(SDL_Surface *a, SDL_BlendMode b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GetSurfaceBlendMode,(SDL_Surface *a, SDL_BlendMode *b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_SetClipRect,(SDL_Surface *a, const SDL_Rect *b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_GetClipRect,(SDL_Surface *a, SDL_Rect *b),(a,b),)
SDL_DYNAPI_PROC(SDL_Surface*,SDL_ConvertSurface,(SDL_Surface *a, const SDL_PixelFormat *b, Uint32 c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_Surface*,SDL_ConvertSurfaceFormat,(SDL_Surface *a, Uint32 b, Uint32 c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_ConvertPixels,(int a, int b, Uint32 c, const void *d, int e, Uint32 f, void *g, int h),(a,b,c,d,e,f,g,h),return)
SDL_DYNAPI_PROC(int,SDL_FillRect,(SDL_Surface *a, const SDL_Rect *b, Uint32 c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_FillRects,(SDL_Surface *a, const SDL_Rect *b, int c, Uint32 d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_UpperBlit,(SDL_Surface *a, const SDL_Rect *b, SDL_Surface *c, SDL_Rect *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_LowerBlit,(SDL_Surface *a, SDL_Rect *b, SDL_Surface *c, SDL_Rect *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_SoftStretch,(SDL_Surface *a, const SDL_Rect *b, SDL_Surface *c, const SDL_Rect *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_UpperBlitScaled,(SDL_Surface *a, const SDL_Rect *b, SDL_Surface *c, SDL_Rect *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_LowerBlitScaled,(SDL_Surface *a, SDL_Rect *b, SDL_Surface *c, SDL_Rect *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_GetWindowWMInfo,(SDL_Window *a, SDL_SysWMinfo *b),(a,b),return)
SDL_DYNAPI_PROC(const char*,SDL_GetThreadName,(SDL_Thread *a),(a),return)
SDL_DYNAPI_PROC(SDL_threadID,SDL_ThreadID,(void),(),return)
SDL_DYNAPI_PROC(SDL_threadID,SDL_GetThreadID,(SDL_Thread *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SetThreadPriority,(SDL_ThreadPriority a),(a),return)
SDL_DYNAPI_PROC(void,SDL_WaitThread,(SDL_Thread *a, int *b),(a,b),)
SDL_DYNAPI_PROC(void,SDL_DetachThread,(SDL_Thread *a),(a),)
SDL_DYNAPI_PROC(SDL_TLSID,SDL_TLSCreate,(void),(),return)
SDL_DYNAPI_PROC(void*,SDL_TLSGet,(SDL_TLSID a),(a),return)
SDL_DYNAPI_PROC(int,SDL_TLSSet,(SDL_TLSID a, const void *b, void (*c)(void*)),(a,b,c),return)
SDL_DYNAPI_PROC(Uint32,SDL_GetTicks,(void),(),return)
SDL_DYNAPI_PROC(Uint64,SDL_GetPerformanceCounter,(void),(),return)
SDL_DYNAPI_PROC(Uint64,SDL_GetPerformanceFrequency,(void),(),return)
SDL_DYNAPI_PROC(void,SDL_Delay,(Uint32 a),(a),)
SDL_DYNAPI_PROC(SDL_TimerID,SDL_AddTimer,(Uint32 a, SDL_TimerCallback b, void *c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_RemoveTimer,(SDL_TimerID a),(a),return)
SDL_DYNAPI_PROC(int,SDL_GetNumTouchDevices,(void),(),return)
SDL_DYNAPI_PROC(SDL_TouchID,SDL_GetTouchDevice,(int a),(a),return)
SDL_DYNAPI_PROC(int,SDL_GetNumTouchFingers,(SDL_TouchID a),(a),return)
SDL_DYNAPI_PROC(SDL_Finger*,SDL_GetTouchFinger,(SDL_TouchID a, int b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_GetVersion,(SDL_version *a),(a),)
SDL_DYNAPI_PROC(const char*,SDL_GetRevision,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_GetRevisionNumber,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_GetNumVideoDrivers,(void),(),return)
SDL_DYNAPI_PROC(const char*,SDL_GetVideoDriver,(int a),(a),return)
SDL_DYNAPI_PROC(int,SDL_VideoInit,(const char *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_VideoQuit,(void),(),)
SDL_DYNAPI_PROC(const char*,SDL_GetCurrentVideoDriver,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_GetNumVideoDisplays,(void),(),return)
SDL_DYNAPI_PROC(const char*,SDL_GetDisplayName,(int a),(a),return)
SDL_DYNAPI_PROC(int,SDL_GetDisplayBounds,(int a, SDL_Rect *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GetNumDisplayModes,(int a),(a),return)
SDL_DYNAPI_PROC(int,SDL_GetDisplayMode,(int a, int b, SDL_DisplayMode *c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_GetDesktopDisplayMode,(int a, SDL_DisplayMode *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GetCurrentDisplayMode,(int a, SDL_DisplayMode *b),(a,b),return)
SDL_DYNAPI_PROC(SDL_DisplayMode*,SDL_GetClosestDisplayMode,(int a, const SDL_DisplayMode *b, SDL_DisplayMode *c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_GetWindowDisplayIndex,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SetWindowDisplayMode,(SDL_Window *a, const SDL_DisplayMode *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GetWindowDisplayMode,(SDL_Window *a, SDL_DisplayMode *b),(a,b),return)
SDL_DYNAPI_PROC(Uint32,SDL_GetWindowPixelFormat,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(SDL_Window*,SDL_CreateWindow,(const char *a, int b, int c, int d, int e, Uint32 f),(a,b,c,d,e,f),return)
SDL_DYNAPI_PROC(SDL_Window*,SDL_CreateWindowFrom,(const void *a),(a),return)
SDL_DYNAPI_PROC(Uint32,SDL_GetWindowID,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(SDL_Window*,SDL_GetWindowFromID,(Uint32 a),(a),return)
SDL_DYNAPI_PROC(Uint32,SDL_GetWindowFlags,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_SetWindowTitle,(SDL_Window *a, const char *b),(a,b),)
SDL_DYNAPI_PROC(const char*,SDL_GetWindowTitle,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_SetWindowIcon,(SDL_Window *a, SDL_Surface *b),(a,b),)
SDL_DYNAPI_PROC(void*,SDL_SetWindowData,(SDL_Window *a, const char *b, void *c),(a,b,c),return)
SDL_DYNAPI_PROC(void*,SDL_GetWindowData,(SDL_Window *a, const char *b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_SetWindowPosition,(SDL_Window *a, int b, int c),(a,b,c),)
SDL_DYNAPI_PROC(void,SDL_GetWindowPosition,(SDL_Window *a, int *b, int *c),(a,b,c),)
SDL_DYNAPI_PROC(void,SDL_SetWindowSize,(SDL_Window *a, int b, int c),(a,b,c),)
SDL_DYNAPI_PROC(void,SDL_GetWindowSize,(SDL_Window *a, int *b, int *c),(a,b,c),)
SDL_DYNAPI_PROC(void,SDL_SetWindowMinimumSize,(SDL_Window *a, int b, int c),(a,b,c),)
SDL_DYNAPI_PROC(void,SDL_GetWindowMinimumSize,(SDL_Window *a, int *b, int *c),(a,b,c),)
SDL_DYNAPI_PROC(void,SDL_SetWindowMaximumSize,(SDL_Window *a, int b, int c),(a,b,c),)
SDL_DYNAPI_PROC(void,SDL_GetWindowMaximumSize,(SDL_Window *a, int *b, int *c),(a,b,c),)
SDL_DYNAPI_PROC(void,SDL_SetWindowBordered,(SDL_Window *a, SDL_bool b),(a,b),)
SDL_DYNAPI_PROC(void,SDL_ShowWindow,(SDL_Window *a),(a),)
SDL_DYNAPI_PROC(void,SDL_HideWindow,(SDL_Window *a),(a),)
SDL_DYNAPI_PROC(void,SDL_RaiseWindow,(SDL_Window *a),(a),)
SDL_DYNAPI_PROC(void,SDL_MaximizeWindow,(SDL_Window *a),(a),)
SDL_DYNAPI_PROC(void,SDL_MinimizeWindow,(SDL_Window *a),(a),)
SDL_DYNAPI_PROC(void,SDL_RestoreWindow,(SDL_Window *a),(a),)
SDL_DYNAPI_PROC(int,SDL_SetWindowFullscreen,(SDL_Window *a, Uint32 b),(a,b),return)
SDL_DYNAPI_PROC(SDL_Surface*,SDL_GetWindowSurface,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_UpdateWindowSurface,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_UpdateWindowSurfaceRects,(SDL_Window *a, const SDL_Rect *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(void,SDL_SetWindowGrab,(SDL_Window *a, SDL_bool b),(a,b),)
SDL_DYNAPI_PROC(SDL_bool,SDL_GetWindowGrab,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SetWindowBrightness,(SDL_Window *a, float b),(a,b),return)
SDL_DYNAPI_PROC(float,SDL_GetWindowBrightness,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SetWindowGammaRamp,(SDL_Window *a, const Uint16 *b, const Uint16 *c, const Uint16 *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_GetWindowGammaRamp,(SDL_Window *a, Uint16 *b, Uint16 *c, Uint16 *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(void,SDL_DestroyWindow,(SDL_Window *a),(a),)
SDL_DYNAPI_PROC(SDL_bool,SDL_IsScreenSaverEnabled,(void),(),return)
SDL_DYNAPI_PROC(void,SDL_EnableScreenSaver,(void),(),)
SDL_DYNAPI_PROC(void,SDL_DisableScreenSaver,(void),(),)
SDL_DYNAPI_PROC(int,SDL_GL_LoadLibrary,(const char *a),(a),return)
SDL_DYNAPI_PROC(void*,SDL_GL_GetProcAddress,(const char *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_GL_UnloadLibrary,(void),(),)
SDL_DYNAPI_PROC(SDL_bool,SDL_GL_ExtensionSupported,(const char *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_GL_SetAttribute,(SDL_GLattr a, int b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GL_GetAttribute,(SDL_GLattr a, int *b),(a,b),return)
SDL_DYNAPI_PROC(SDL_GLContext,SDL_GL_CreateContext,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_GL_MakeCurrent,(SDL_Window *a, SDL_GLContext b),(a,b),return)
SDL_DYNAPI_PROC(SDL_Window*,SDL_GL_GetCurrentWindow,(void),(),return)
SDL_DYNAPI_PROC(SDL_GLContext,SDL_GL_GetCurrentContext,(void),(),return)
SDL_DYNAPI_PROC(void,SDL_GL_GetDrawableSize,(SDL_Window *a, int *b, int *c),(a,b,c),)
SDL_DYNAPI_PROC(int,SDL_GL_SetSwapInterval,(int a),(a),return)
SDL_DYNAPI_PROC(int,SDL_GL_GetSwapInterval,(void),(),return)
SDL_DYNAPI_PROC(void,SDL_GL_SwapWindow,(SDL_Window *a),(a),)
SDL_DYNAPI_PROC(void,SDL_GL_DeleteContext,(SDL_GLContext a),(a),)
SDL_DYNAPI_PROC(int,SDL_vsscanf,(const char *a, const char *b, va_list c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_GameControllerAddMappingsFromRW,(SDL_RWops *a, int b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_GL_ResetAttributes,(void),(),)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasAVX,(void),(),return)
SDL_DYNAPI_PROC(SDL_AssertionHandler,SDL_GetDefaultAssertionHandler,(void),(),return)
SDL_DYNAPI_PROC(SDL_AssertionHandler,SDL_GetAssertionHandler,(void **a),(a),return)
#ifdef __WIN32__
SDL_DYNAPI_PROC(SDL_bool,SDL_DXGIGetOutputInfo,(int a,int *b, int *c),(a,b,c),return)
#endif
SDL_DYNAPI_PROC(SDL_bool,SDL_RenderIsClipEnabled,(SDL_Renderer *a),(a),return)
#ifdef __WINRT__
SDL_DYNAPI_PROC(int,SDL_WinRTRunApp,(int a, char **b, void *c),(a,b,c),return)
SDL_DYNAPI_PROC(const wchar_t*,SDL_WinRTGetFSPathUNICODE,(SDL_WinRT_Path a),(a),return)
SDL_DYNAPI_PROC(const char*,SDL_WinRTGetFSPathUTF8,(SDL_WinRT_Path a),(a),return)
#endif
SDL_DYNAPI_PROC(void,SDL_WarpMouseGlobal,(int a, int b),(a,b),)
SDL_DYNAPI_PROC(float,SDL_sqrtf,(float a),(a),return)
SDL_DYNAPI_PROC(double,SDL_tan,(double a),(a),return)
SDL_DYNAPI_PROC(float,SDL_tanf,(float a),(a),return)
SDL_DYNAPI_PROC(int,SDL_CaptureMouse,(SDL_bool a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SetWindowHitTest,(SDL_Window *a, SDL_HitTest b, void *c),(a,b,c),return)
SDL_DYNAPI_PROC(Uint32,SDL_GetGlobalMouseState,(int *a, int *b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasAVX2,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_QueueAudio,(SDL_AudioDeviceID a, const void *b, Uint32 c),(a,b,c),return)
SDL_DYNAPI_PROC(Uint32,SDL_GetQueuedAudioSize,(SDL_AudioDeviceID a),(a),return)
SDL_DYNAPI_PROC(void,SDL_ClearQueuedAudio,(SDL_AudioDeviceID a),(a),)
SDL_DYNAPI_PROC(SDL_Window*,SDL_GetGrabbedWindow,(void),(),return)

141
src/dynapi/gendynapi.pl Executable file
View File

@@ -0,0 +1,141 @@
#!/usr/bin/perl -w
# Simple DirectMedia Layer
# Copyright (C) 1997-2014 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.
# WHAT IS THIS?
# When you add a public API to SDL, please run this script, make sure the
# output looks sane (hg diff, it adds to existing files), and commit it.
# It keeps the dynamic API jump table operating correctly.
# If you wanted this to be readable, you shouldn't have used perl.
use warnings;
use strict;
use File::Basename;
chdir(dirname(__FILE__) . '/../..');
my $sdl_dynapi_procs_h = "src/dynapi/SDL_dynapi_procs.h";
my $sdl_dynapi_overrides_h = "src/dynapi/SDL_dynapi_overrides.h";
my %existing = ();
if (-f $sdl_dynapi_procs_h) {
open(SDL_DYNAPI_PROCS_H, '<', $sdl_dynapi_procs_h) or die("Can't open $sdl_dynapi_procs_h: $!\n");
while (<SDL_DYNAPI_PROCS_H>) {
if (/\ASDL_DYNAPI_PROC\(.*?,(.*?),/) {
$existing{$1} = 1;
}
}
close(SDL_DYNAPI_PROCS_H)
}
open(SDL_DYNAPI_PROCS_H, '>>', $sdl_dynapi_procs_h) or die("Can't open $sdl_dynapi_procs_h: $!\n");
open(SDL_DYNAPI_OVERRIDES_H, '>>', $sdl_dynapi_overrides_h) or die("Can't open $sdl_dynapi_overrides_h: $!\n");
opendir(HEADERS, 'include') or die("Can't open include dir: $!\n");
while (readdir(HEADERS)) {
next if not /\.h\Z/;
my $header = "include/$_";
open(HEADER, '<', $header) or die("Can't open $header: $!\n");
while (<HEADER>) {
chomp;
next if not /\A\s*extern\s+DECLSPEC/;
my $decl = "$_ ";
if (not $decl =~ /\)\s*;/) {
while (<HEADER>) {
chomp;
s/\A\s+//;
s/\s+\Z//;
$decl .= "$_ ";
last if /\)\s*;/;
}
}
$decl =~ s/\s+\Z//;
#print("DECL: [$decl]\n");
if ($decl =~ /\A\s*extern\s+DECLSPEC\s+(const\s+|)(unsigned\s+|)(.*?)\s*(\*?)\s*SDLCALL\s+(.*?)\s*\((.*?)\);/) {
my $rc = "$1$2$3$4";
my $fn = $5;
next if $existing{$fn}; # already slotted into the jump table.
my @params = split(',', $6);
#print("rc == '$rc', fn == '$fn', params == '$params'\n");
my $retstr = ($rc eq 'void') ? '' : 'return';
my $paramstr = '(';
my $argstr = '(';
my $i = 0;
foreach (@params) {
my $str = $_;
$str =~ s/\A\s+//;
$str =~ s/\s+\Z//;
#print("1PARAM: $str\n");
if ($str eq 'void') {
$paramstr .= 'void';
} elsif ($str eq '...') {
if ($i > 0) {
$paramstr .= ', ';
}
$paramstr .= $str;
} elsif ($str =~ /\A\s*((const\s+|)(unsigned\s+|)([a-zA-Z0-9_]*)\s*([\*\s]*))\s*(.*?)\Z/) {
#print("PARSED: [$1], [$2], [$3], [$4], [$5]\n");
my $type = $1;
my $var = $6;
$type =~ s/\A\s+//;
$type =~ s/\s+\Z//;
$var =~ s/\A\s+//;
$var =~ s/\s+\Z//;
$type =~ s/\s*\*\Z/*/g;
$type =~ s/\s*(\*+)\Z/ $1/;
#print("SPLIT: ($type, $var)\n");
my $name = chr(ord('a') + $i);
if ($i > 0) {
$paramstr .= ', ';
$argstr .= ',';
}
my $spc = ($type =~ /\*\Z/) ? '' : ' ';
$paramstr .= "$type$spc$name";
$argstr .= "$name";
}
$i++;
}
$paramstr = '(void' if ($i == 0); # Just to make this consistent.
$paramstr .= ')';
$argstr .= ')';
print("NEW: $decl\n");
print SDL_DYNAPI_PROCS_H "SDL_DYNAPI_PROC($rc,$fn,$paramstr,$argstr,$retstr)\n";
print SDL_DYNAPI_OVERRIDES_H "#define $fn ${fn}_REAL\n";
} else {
print("Failed to parse decl [$decl]!\n");
}
}
close(HEADER);
}
closedir(HEADERS);
close(SDL_DYNAPI_PROCS_H);
close(SDL_DYNAPI_OVERRIDES_H);
# vi: set ts=4 sw=4 expandtab:

View File

@@ -0,0 +1,46 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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"
/* Clipboard event handling code for SDL */
#include "SDL_events.h"
#include "SDL_events_c.h"
#include "SDL_clipboardevents_c.h"
int
SDL_SendClipboardUpdate(void)
{
int posted;
/* Post the event, if desired */
posted = 0;
if (SDL_GetEventState(SDL_CLIPBOARDUPDATE) == SDL_ENABLE) {
SDL_Event event;
event.type = SDL_CLIPBOARDUPDATE;
posted = (SDL_PushEvent(&event) > 0);
}
return (posted);
}
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,30 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_clipboardevents_c_h
#define _SDL_clipboardevents_c_h
extern int SDL_SendClipboardUpdate(void);
#endif /* _SDL_clipboardevents_c_h */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,46 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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"
/* Drag and drop event handling code for SDL */
#include "SDL_events.h"
#include "SDL_events_c.h"
#include "SDL_dropevents_c.h"
int
SDL_SendDropFile(const char *file)
{
int posted;
/* Post the event, if desired */
posted = 0;
if (SDL_GetEventState(SDL_DROPFILE) == SDL_ENABLE) {
SDL_Event event;
event.type = SDL_DROPFILE;
event.drop.file = SDL_strdup(file);
posted = (SDL_PushEvent(&event) > 0);
}
return (posted);
}
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,30 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 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_dropevents_c_h
#define _SDL_dropevents_c_h
extern int SDL_SendDropFile(const char *file);
#endif /* _SDL_dropevents_c_h */
/* vi: set ts=4 sw=4 expandtab: */

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