mirror of
https://github.com/encounter/SDL.git
synced 2025-12-13 15:16:13 +00:00
the last parameter of XChangeProperty is the number of elements.. and when the element format is 32.. the element is "long" so we have 5 long elements here.
Yes this seems confusing as on mac+linux Long is either 32 or 64bits depending on the architecture, but this is how the X11 protocol is defined. Thus 5 is the correct value for the nelts here. Not 5 or 10 depending on the architecture. More info on the confusion https://bugs.freedesktop.org/show_bug.cgi?id=16802
This commit is contained in:
477
src/SDL.c
Normal file
477
src/SDL.c
Normal 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
384
src/SDL_assert.c
Normal 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
24
src/SDL_assert_c.h
Normal 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
275
src/SDL_error.c
Normal 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
64
src/SDL_error_c.h
Normal 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
223
src/SDL_hints.c
Normal 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
38
src/SDL_internal.h
Normal 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
440
src/SDL_log.c
Normal 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
246
src/atomic/SDL_atomic.c
Normal 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
135
src/atomic/SDL_spinlock.c
Normal 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
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
55
src/audio/SDL_audio_c.h
Normal 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
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
123
src/audio/SDL_audiodev.c
Normal 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: */
|
||||
38
src/audio/SDL_audiodev_c.h
Normal file
38
src/audio/SDL_audiodev_c.h
Normal 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
25
src/audio/SDL_audiomem.h
Normal 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
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
321
src/audio/SDL_mixer.c
Normal 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
199
src/audio/SDL_sysaudio.h
Normal 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
624
src/audio/SDL_wave.c
Normal 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
67
src/audio/SDL_wave.h
Normal 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: */
|
||||
685
src/audio/alsa/SDL_alsa_audio.c
Normal file
685
src/audio/alsa/SDL_alsa_audio.c
Normal 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: */
|
||||
45
src/audio/alsa/SDL_alsa_audio.h
Normal file
45
src/audio/alsa/SDL_alsa_audio.h
Normal 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: */
|
||||
185
src/audio/android/SDL_androidaudio.c
Normal file
185
src/audio/android/SDL_androidaudio.c
Normal 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: */
|
||||
|
||||
41
src/audio/android/SDL_androidaudio.h
Normal file
41
src/audio/android/SDL_androidaudio.h
Normal 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: */
|
||||
384
src/audio/arts/SDL_artsaudio.c
Normal file
384
src/audio/arts/SDL_artsaudio.c
Normal 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: */
|
||||
52
src/audio/arts/SDL_artsaudio.h
Normal file
52
src/audio/arts/SDL_artsaudio.h
Normal 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: */
|
||||
363
src/audio/bsd/SDL_bsdaudio.c
Normal file
363
src/audio/bsd/SDL_bsdaudio.c
Normal 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: */
|
||||
51
src/audio/bsd/SDL_bsdaudio.h
Normal file
51
src/audio/bsd/SDL_bsdaudio.h
Normal 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: */
|
||||
698
src/audio/coreaudio/SDL_coreaudio.c
Normal file
698
src/audio/coreaudio/SDL_coreaudio.c
Normal 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: */
|
||||
57
src/audio/coreaudio/SDL_coreaudio.h
Normal file
57
src/audio/coreaudio/SDL_coreaudio.h
Normal 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: */
|
||||
517
src/audio/directsound/SDL_directsound.c
Normal file
517
src/audio/directsound/SDL_directsound.c
Normal 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: */
|
||||
46
src/audio/directsound/SDL_directsound.h
Normal file
46
src/audio/directsound/SDL_directsound.h
Normal 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: */
|
||||
165
src/audio/disk/SDL_diskaudio.c
Normal file
165
src/audio/disk/SDL_diskaudio.c
Normal 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: */
|
||||
42
src/audio/disk/SDL_diskaudio.h
Normal file
42
src/audio/disk/SDL_diskaudio.h
Normal 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: */
|
||||
308
src/audio/dsp/SDL_dspaudio.c
Normal file
308
src/audio/dsp/SDL_dspaudio.c
Normal 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: */
|
||||
43
src/audio/dsp/SDL_dspaudio.h
Normal file
43
src/audio/dsp/SDL_dspaudio.h
Normal 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: */
|
||||
48
src/audio/dummy/SDL_dummyaudio.c
Normal file
48
src/audio/dummy/SDL_dummyaudio.c
Normal 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: */
|
||||
41
src/audio/dummy/SDL_dummyaudio.h
Normal file
41
src/audio/dummy/SDL_dummyaudio.h
Normal 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: */
|
||||
275
src/audio/emscripten/SDL_emscriptenaudio.c
Normal file
275
src/audio/emscripten/SDL_emscriptenaudio.c
Normal 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: */
|
||||
42
src/audio/emscripten/SDL_emscriptenaudio.h
Normal file
42
src/audio/emscripten/SDL_emscriptenaudio.h
Normal 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: */
|
||||
345
src/audio/esd/SDL_esdaudio.c
Normal file
345
src/audio/esd/SDL_esdaudio.c
Normal 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: */
|
||||
50
src/audio/esd/SDL_esdaudio.h
Normal file
50
src/audio/esd/SDL_esdaudio.h
Normal 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: */
|
||||
345
src/audio/fusionsound/SDL_fsaudio.c
Normal file
345
src/audio/fusionsound/SDL_fsaudio.c
Normal 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: */
|
||||
49
src/audio/fusionsound/SDL_fsaudio.h
Normal file
49
src/audio/fusionsound/SDL_fsaudio.h
Normal 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: */
|
||||
240
src/audio/haiku/SDL_haikuaudio.cc
Normal file
240
src/audio/haiku/SDL_haikuaudio.cc
Normal 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: */
|
||||
38
src/audio/haiku/SDL_haikuaudio.h
Normal file
38
src/audio/haiku/SDL_haikuaudio.h
Normal 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: */
|
||||
152
src/audio/nacl/SDL_naclaudio.c
Normal file
152
src/audio/nacl/SDL_naclaudio.c
Normal 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: */
|
||||
41
src/audio/nacl/SDL_naclaudio.h
Normal file
41
src/audio/nacl/SDL_naclaudio.h
Normal 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 */
|
||||
397
src/audio/nas/SDL_nasaudio.c
Normal file
397
src/audio/nas/SDL_nasaudio.c
Normal 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: */
|
||||
56
src/audio/nas/SDL_nasaudio.h
Normal file
56
src/audio/nas/SDL_nasaudio.h
Normal 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: */
|
||||
541
src/audio/paudio/SDL_paudio.c
Normal file
541
src/audio/paudio/SDL_paudio.c
Normal 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: */
|
||||
47
src/audio/paudio/SDL_paudio.h
Normal file
47
src/audio/paudio/SDL_paudio.h
Normal 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: */
|
||||
199
src/audio/psp/SDL_pspaudio.c
Normal file
199
src/audio/psp/SDL_pspaudio.c
Normal 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: */
|
||||
45
src/audio/psp/SDL_pspaudio.h
Normal file
45
src/audio/psp/SDL_pspaudio.h
Normal 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
|
||||
*/
|
||||
699
src/audio/pulseaudio/SDL_pulseaudio.c
Normal file
699
src/audio/pulseaudio/SDL_pulseaudio.c
Normal 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: */
|
||||
49
src/audio/pulseaudio/SDL_pulseaudio.h
Normal file
49
src/audio/pulseaudio/SDL_pulseaudio.h
Normal 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: */
|
||||
809
src/audio/qsa/SDL_qsa_audio.c
Normal file
809
src/audio/qsa/SDL_qsa_audio.c
Normal 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, ¶m);
|
||||
param.sched_priority = param.sched_curpriority + 15;
|
||||
status = SchedSet(0, 0, SCHED_NOCHANGE, ¶m);
|
||||
}
|
||||
|
||||
/* 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: */
|
||||
57
src/audio/qsa/SDL_qsa_audio.h
Normal file
57
src/audio/qsa/SDL_qsa_audio.h
Normal 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
761
src/audio/sdlgenaudiocvt.pl
Executable 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 ...
|
||||
|
||||
332
src/audio/sndio/SDL_sndioaudio.c
Normal file
332
src/audio/sndio/SDL_sndioaudio.c
Normal 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: */
|
||||
45
src/audio/sndio/SDL_sndioaudio.h
Normal file
45
src/audio/sndio/SDL_sndioaudio.h
Normal 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: */
|
||||
428
src/audio/sun/SDL_sunaudio.c
Normal file
428
src/audio/sun/SDL_sunaudio.c
Normal 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: */
|
||||
47
src/audio/sun/SDL_sunaudio.h
Normal file
47
src/audio/sun/SDL_sunaudio.h
Normal 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
365
src/audio/winmm/SDL_winmm.c
Normal 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: */
|
||||
45
src/audio/winmm/SDL_winmm.h
Normal file
45
src/audio/winmm/SDL_winmm.h
Normal 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: */
|
||||
526
src/audio/xaudio2/SDL_xaudio2.c
Normal file
526
src/audio/xaudio2/SDL_xaudio2.c
Normal 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: */
|
||||
90
src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp
Normal file
90
src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp
Normal 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
|
||||
}
|
||||
70
src/audio/xaudio2/SDL_xaudio2_winrthelpers.h
Normal file
70
src/audio/xaudio2/SDL_xaudio2_winrthelpers.h
Normal 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
|
||||
1621
src/core/android/SDL_android.c
Normal file
1621
src/core/android/SDL_android.c
Normal file
File diff suppressed because it is too large
Load Diff
93
src/core/android/SDL_android.h
Normal file
93
src/core/android/SDL_android.h
Normal 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
238
src/core/linux/SDL_dbus.c
Normal 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
80
src/core/linux/SDL_dbus.h
Normal 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
809
src/core/linux/SDL_evdev.c
Normal 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: */
|
||||
|
||||
59
src/core/linux/SDL_evdev.h
Normal file
59
src/core/linux/SDL_evdev.h
Normal 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: */
|
||||
674
src/core/linux/SDL_ibus.c
Normal file
674
src/core/linux/SDL_ibus.c
Normal file
@@ -0,0 +1,674 @@
|
||||
/*
|
||||
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);
|
||||
|
||||
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
58
src/core/linux/SDL_ibus.h
Normal 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
529
src/core/linux/SDL_udev.c
Normal 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
117
src/core/linux/SDL_udev.h
Normal 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 */
|
||||
111
src/core/windows/SDL_directx.h
Normal file
111
src/core/windows/SDL_directx.h
Normal 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: */
|
||||
129
src/core/windows/SDL_windows.c
Normal file
129
src/core/windows/SDL_windows.c
Normal 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: */
|
||||
64
src/core/windows/SDL_windows.h
Normal file
64
src/core/windows/SDL_windows.h
Normal 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: */
|
||||
129
src/core/windows/SDL_xinput.c
Normal file
129
src/core/windows/SDL_xinput.c
Normal 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: */
|
||||
134
src/core/windows/SDL_xinput.h
Normal file
134
src/core/windows/SDL_xinput.h
Normal 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: */
|
||||
37
src/core/winrt/SDL_winrtapp_common.cpp
Normal file
37
src/core/winrt/SDL_winrtapp_common.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
31
src/core/winrt/SDL_winrtapp_common.h
Normal file
31
src/core/winrt/SDL_winrtapp_common.h
Normal 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
|
||||
738
src/core/winrt/SDL_winrtapp_direct3d.cpp
Normal file
738
src/core/winrt/SDL_winrtapp_direct3d.cpp
Normal 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
|
||||
|
||||
83
src/core/winrt/SDL_winrtapp_direct3d.h
Normal file
83
src/core/winrt/SDL_winrtapp_direct3d.h
Normal 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;
|
||||
160
src/core/winrt/SDL_winrtapp_xaml.cpp
Normal file
160
src/core/winrt/SDL_winrtapp_xaml.cpp
Normal 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
|
||||
}
|
||||
33
src/core/winrt/SDL_winrtapp_xaml.h
Normal file
33
src/core/winrt/SDL_winrtapp_xaml.h
Normal 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
799
src/cpuinfo/SDL_cpuinfo.c
Normal 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
319
src/dynapi/SDL_dynapi.c
Normal 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
61
src/dynapi/SDL_dynapi.h
Normal 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: */
|
||||
594
src/dynapi/SDL_dynapi_overrides.h
Normal file
594
src/dynapi/SDL_dynapi_overrides.h
Normal 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
|
||||
626
src/dynapi/SDL_dynapi_procs.h
Normal file
626
src/dynapi/SDL_dynapi_procs.h
Normal 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
141
src/dynapi/gendynapi.pl
Executable 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:
|
||||
46
src/events/SDL_clipboardevents.c
Normal file
46
src/events/SDL_clipboardevents.c
Normal 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: */
|
||||
30
src/events/SDL_clipboardevents_c.h
Normal file
30
src/events/SDL_clipboardevents_c.h
Normal 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: */
|
||||
46
src/events/SDL_dropevents.c
Normal file
46
src/events/SDL_dropevents.c
Normal 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: */
|
||||
30
src/events/SDL_dropevents_c.h
Normal file
30
src/events/SDL_dropevents_c.h
Normal 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
Reference in New Issue
Block a user