mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-12 07:04:36 +00:00
sdl 2.0.8 update
This commit is contained in:
parent
7f674a59c6
commit
bfb08f9482
894 changed files with 66879 additions and 43299 deletions
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -36,10 +36,7 @@
|
|||
|
||||
/* 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);
|
||||
# include "timer/SDL_timer_c.h"
|
||||
#endif
|
||||
#if SDL_VIDEO_DRIVER_WINDOWS
|
||||
extern int SDL_HelperWindowCreate(void);
|
||||
|
|
@ -81,7 +78,7 @@ SDL_PrivateShouldInitSubsystem(Uint32 subsystem)
|
|||
{
|
||||
int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
|
||||
SDL_assert(SDL_SubsystemRefCount[subsystem_index] < 255);
|
||||
return (SDL_SubsystemRefCount[subsystem_index] == 0);
|
||||
return (SDL_SubsystemRefCount[subsystem_index] == 0) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Private helper to check if a system needs to be quit. */
|
||||
|
|
@ -95,7 +92,7 @@ SDL_PrivateShouldQuitSubsystem(Uint32 subsystem) {
|
|||
/* 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;
|
||||
return (SDL_SubsystemRefCount[subsystem_index] == 1 || SDL_bInMainQuit) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -456,7 +453,7 @@ SDL_GetPlatform()
|
|||
|
||||
#if defined(__WIN32__)
|
||||
|
||||
#if !defined(HAVE_LIBC) || (defined(__WATCOMC__) && defined(BUILD_DLL))
|
||||
#if (!defined(HAVE_LIBC) || defined(__WATCOMC__)) && !defined(SDL_STATIC_LIB)
|
||||
/* Need to include DllMain() on Watcom C for some reason.. */
|
||||
|
||||
BOOL APIENTRY
|
||||
|
|
@ -472,7 +469,7 @@ _DllMainCRTStartup(HANDLE hModule,
|
|||
}
|
||||
return TRUE;
|
||||
}
|
||||
#endif /* building DLL with Watcom C */
|
||||
#endif /* Building DLL */
|
||||
|
||||
#endif /* __WIN32__ */
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -44,7 +44,12 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
static SDL_assert_state
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
|
||||
static SDL_assert_state SDLCALL
|
||||
SDL_PromptAssertion(const SDL_assert_data *data, void *userdata);
|
||||
|
||||
/*
|
||||
|
|
@ -53,7 +58,10 @@ SDL_PromptAssertion(const SDL_assert_data *data, void *userdata);
|
|||
*/
|
||||
static SDL_assert_data *triggered_assertions = NULL;
|
||||
|
||||
#ifndef SDL_THREADS_DISABLED
|
||||
static SDL_mutex *assertion_mutex = NULL;
|
||||
#endif
|
||||
|
||||
static SDL_AssertionHandler assertion_handler = SDL_PromptAssertion;
|
||||
static void *assertion_userdata = NULL;
|
||||
|
||||
|
|
@ -111,23 +119,29 @@ static void SDL_GenerateAssertionReport(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void SDL_ExitProcess(int exitcode)
|
||||
|
||||
static SDL_NORETURN void SDL_ExitProcess(int exitcode)
|
||||
{
|
||||
#ifdef __WIN32__
|
||||
ExitProcess(exitcode);
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
emscripten_cancel_main_loop(); /* this should "kill" the app. */
|
||||
emscripten_force_exit(exitcode); /* this should "kill" the app. */
|
||||
exit(exitcode);
|
||||
#else
|
||||
_exit(exitcode);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void SDL_AbortAssertion(void)
|
||||
|
||||
static SDL_NORETURN void SDL_AbortAssertion(void)
|
||||
{
|
||||
SDL_Quit();
|
||||
SDL_ExitProcess(42);
|
||||
}
|
||||
|
||||
|
||||
static SDL_assert_state
|
||||
static SDL_assert_state SDLCALL
|
||||
SDL_PromptAssertion(const SDL_assert_data *data, void *userdata)
|
||||
{
|
||||
#ifdef __WIN32__
|
||||
|
|
@ -216,9 +230,45 @@ SDL_PromptAssertion(const SDL_assert_data *data, void *userdata)
|
|||
state = (SDL_assert_state)selected;
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_STDIO_H
|
||||
|
||||
else
|
||||
{
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
/* This is nasty, but we can't block on a custom UI. */
|
||||
for ( ; ; ) {
|
||||
SDL_bool okay = SDL_TRUE;
|
||||
char *buf = (char *) EM_ASM_INT({
|
||||
var str =
|
||||
Pointer_stringify($0) + '\n\n' +
|
||||
'Abort/Retry/Ignore/AlwaysIgnore? [ariA] :';
|
||||
var reply = window.prompt(str, "i");
|
||||
if (reply === null) {
|
||||
reply = "i";
|
||||
}
|
||||
return allocate(intArrayFromString(reply), 'i8', ALLOC_NORMAL);
|
||||
}, message);
|
||||
|
||||
if (SDL_strcmp(buf, "a") == 0) {
|
||||
state = SDL_ASSERTION_ABORT;
|
||||
/* (currently) no break functionality on Emscripten
|
||||
} else if (SDL_strcmp(buf, "b") == 0) {
|
||||
state = SDL_ASSERTION_BREAK; */
|
||||
} else if (SDL_strcmp(buf, "r") == 0) {
|
||||
state = SDL_ASSERTION_RETRY;
|
||||
} else if (SDL_strcmp(buf, "i") == 0) {
|
||||
state = SDL_ASSERTION_IGNORE;
|
||||
} else if (SDL_strcmp(buf, "A") == 0) {
|
||||
state = SDL_ASSERTION_ALWAYS_IGNORE;
|
||||
} else {
|
||||
okay = SDL_FALSE;
|
||||
}
|
||||
free(buf);
|
||||
|
||||
if (okay) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#elif defined(HAVE_STDIO_H)
|
||||
/* this is a little hacky. */
|
||||
for ( ; ; ) {
|
||||
char buf[32];
|
||||
|
|
@ -228,25 +278,25 @@ SDL_PromptAssertion(const SDL_assert_data *data, void *userdata)
|
|||
break;
|
||||
}
|
||||
|
||||
if (SDL_strcmp(buf, "a") == 0) {
|
||||
if (SDL_strncmp(buf, "a", 1) == 0) {
|
||||
state = SDL_ASSERTION_ABORT;
|
||||
break;
|
||||
} else if (SDL_strcmp(buf, "b") == 0) {
|
||||
} else if (SDL_strncmp(buf, "b", 1) == 0) {
|
||||
state = SDL_ASSERTION_BREAK;
|
||||
break;
|
||||
} else if (SDL_strcmp(buf, "r") == 0) {
|
||||
} else if (SDL_strncmp(buf, "r", 1) == 0) {
|
||||
state = SDL_ASSERTION_RETRY;
|
||||
break;
|
||||
} else if (SDL_strcmp(buf, "i") == 0) {
|
||||
} else if (SDL_strncmp(buf, "i", 1) == 0) {
|
||||
state = SDL_ASSERTION_IGNORE;
|
||||
break;
|
||||
} else if (SDL_strcmp(buf, "A") == 0) {
|
||||
} else if (SDL_strncmp(buf, "A", 1) == 0) {
|
||||
state = SDL_ASSERTION_ALWAYS_IGNORE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_STDIO_H */
|
||||
}
|
||||
|
||||
/* Re-enter fullscreen mode */
|
||||
if (window) {
|
||||
|
|
@ -263,10 +313,11 @@ 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;
|
||||
static int assertion_running = 0;
|
||||
|
||||
#ifndef SDL_THREADS_DISABLED
|
||||
static SDL_SpinLock spinlock = 0;
|
||||
SDL_AtomicLock(&spinlock);
|
||||
if (assertion_mutex == NULL) { /* never called SDL_Init()? */
|
||||
assertion_mutex = SDL_CreateMutex();
|
||||
|
|
@ -280,6 +331,7 @@ SDL_ReportAssertion(SDL_assert_data *data, const char *func, const char *file,
|
|||
if (SDL_LockMutex(assertion_mutex) < 0) {
|
||||
return SDL_ASSERTION_IGNORE; /* oh well, I guess. */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* doing this because Visual C is upset over assigning in the macro. */
|
||||
if (data->trigger_count == 0) {
|
||||
|
|
@ -323,7 +375,10 @@ SDL_ReportAssertion(SDL_assert_data *data, const char *func, const char *file,
|
|||
}
|
||||
|
||||
assertion_running--;
|
||||
|
||||
#ifndef SDL_THREADS_DISABLED
|
||||
SDL_UnlockMutex(assertion_mutex);
|
||||
#endif
|
||||
|
||||
return state;
|
||||
}
|
||||
|
|
@ -332,10 +387,12 @@ SDL_ReportAssertion(SDL_assert_data *data, const char *func, const char *file,
|
|||
void SDL_AssertionsQuit(void)
|
||||
{
|
||||
SDL_GenerateAssertionReport();
|
||||
#ifndef SDL_THREADS_DISABLED
|
||||
if (assertion_mutex != NULL) {
|
||||
SDL_DestroyMutex(assertion_mutex);
|
||||
assertion_mutex = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SDL_SetAssertionHandler(SDL_AssertionHandler handler, void *userdata)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
|||
339
Engine/lib/sdl/src/SDL_dataqueue.c
Normal file
339
Engine/lib/sdl/src/SDL_dataqueue.c
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "./SDL_internal.h"
|
||||
#include "SDL.h"
|
||||
#include "./SDL_dataqueue.h"
|
||||
#include "SDL_assert.h"
|
||||
|
||||
typedef struct SDL_DataQueuePacket
|
||||
{
|
||||
size_t datalen; /* bytes currently in use in this packet. */
|
||||
size_t startpos; /* bytes currently consumed in this packet. */
|
||||
struct SDL_DataQueuePacket *next; /* next item in linked list. */
|
||||
Uint8 data[SDL_VARIABLE_LENGTH_ARRAY]; /* packet data */
|
||||
} SDL_DataQueuePacket;
|
||||
|
||||
struct SDL_DataQueue
|
||||
{
|
||||
SDL_DataQueuePacket *head; /* device fed from here. */
|
||||
SDL_DataQueuePacket *tail; /* queue fills to here. */
|
||||
SDL_DataQueuePacket *pool; /* these are unused packets. */
|
||||
size_t packet_size; /* size of new packets */
|
||||
size_t queued_bytes; /* number of bytes of data in the queue. */
|
||||
};
|
||||
|
||||
static void
|
||||
SDL_FreeDataQueueList(SDL_DataQueuePacket *packet)
|
||||
{
|
||||
while (packet) {
|
||||
SDL_DataQueuePacket *next = packet->next;
|
||||
SDL_free(packet);
|
||||
packet = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* this all expects that you managed thread safety elsewhere. */
|
||||
|
||||
SDL_DataQueue *
|
||||
SDL_NewDataQueue(const size_t _packetlen, const size_t initialslack)
|
||||
{
|
||||
SDL_DataQueue *queue = (SDL_DataQueue *) SDL_malloc(sizeof (SDL_DataQueue));
|
||||
|
||||
if (!queue) {
|
||||
SDL_OutOfMemory();
|
||||
return NULL;
|
||||
} else {
|
||||
const size_t packetlen = _packetlen ? _packetlen : 1024;
|
||||
const size_t wantpackets = (initialslack + (packetlen - 1)) / packetlen;
|
||||
size_t i;
|
||||
|
||||
SDL_zerop(queue);
|
||||
queue->packet_size = packetlen;
|
||||
|
||||
for (i = 0; i < wantpackets; i++) {
|
||||
SDL_DataQueuePacket *packet = (SDL_DataQueuePacket *) SDL_malloc(sizeof (SDL_DataQueuePacket) + packetlen);
|
||||
if (packet) { /* don't care if this fails, we'll deal later. */
|
||||
packet->datalen = 0;
|
||||
packet->startpos = 0;
|
||||
packet->next = queue->pool;
|
||||
queue->pool = packet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_FreeDataQueue(SDL_DataQueue *queue)
|
||||
{
|
||||
if (queue) {
|
||||
SDL_FreeDataQueueList(queue->head);
|
||||
SDL_FreeDataQueueList(queue->pool);
|
||||
SDL_free(queue);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack)
|
||||
{
|
||||
const size_t packet_size = queue ? queue->packet_size : 1;
|
||||
const size_t slackpackets = (slack + (packet_size-1)) / packet_size;
|
||||
SDL_DataQueuePacket *packet;
|
||||
SDL_DataQueuePacket *prev = NULL;
|
||||
size_t i;
|
||||
|
||||
if (!queue) {
|
||||
return;
|
||||
}
|
||||
|
||||
packet = queue->head;
|
||||
|
||||
/* merge the available pool and the current queue into one list. */
|
||||
if (packet) {
|
||||
queue->tail->next = queue->pool;
|
||||
} else {
|
||||
packet = queue->pool;
|
||||
}
|
||||
|
||||
/* Remove the queued packets from the device. */
|
||||
queue->tail = NULL;
|
||||
queue->head = NULL;
|
||||
queue->queued_bytes = 0;
|
||||
queue->pool = packet;
|
||||
|
||||
/* Optionally keep some slack in the pool to reduce malloc pressure. */
|
||||
for (i = 0; packet && (i < slackpackets); i++) {
|
||||
prev = packet;
|
||||
packet = packet->next;
|
||||
}
|
||||
|
||||
if (prev) {
|
||||
prev->next = NULL;
|
||||
} else {
|
||||
queue->pool = NULL;
|
||||
}
|
||||
|
||||
SDL_FreeDataQueueList(packet); /* free extra packets */
|
||||
}
|
||||
|
||||
static SDL_DataQueuePacket *
|
||||
AllocateDataQueuePacket(SDL_DataQueue *queue)
|
||||
{
|
||||
SDL_DataQueuePacket *packet;
|
||||
|
||||
SDL_assert(queue != NULL);
|
||||
|
||||
packet = queue->pool;
|
||||
if (packet != NULL) {
|
||||
/* we have one available in the pool. */
|
||||
queue->pool = packet->next;
|
||||
} else {
|
||||
/* Have to allocate a new one! */
|
||||
packet = (SDL_DataQueuePacket *) SDL_malloc(sizeof (SDL_DataQueuePacket) + queue->packet_size);
|
||||
if (packet == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
packet->datalen = 0;
|
||||
packet->startpos = 0;
|
||||
packet->next = NULL;
|
||||
|
||||
SDL_assert((queue->head != NULL) == (queue->queued_bytes != 0));
|
||||
if (queue->tail == NULL) {
|
||||
queue->head = packet;
|
||||
} else {
|
||||
queue->tail->next = packet;
|
||||
}
|
||||
queue->tail = packet;
|
||||
return packet;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *_data, const size_t _len)
|
||||
{
|
||||
size_t len = _len;
|
||||
const Uint8 *data = (const Uint8 *) _data;
|
||||
const size_t packet_size = queue ? queue->packet_size : 0;
|
||||
SDL_DataQueuePacket *orighead;
|
||||
SDL_DataQueuePacket *origtail;
|
||||
size_t origlen;
|
||||
size_t datalen;
|
||||
|
||||
if (!queue) {
|
||||
return SDL_InvalidParamError("queue");
|
||||
}
|
||||
|
||||
orighead = queue->head;
|
||||
origtail = queue->tail;
|
||||
origlen = origtail ? origtail->datalen : 0;
|
||||
|
||||
while (len > 0) {
|
||||
SDL_DataQueuePacket *packet = queue->tail;
|
||||
SDL_assert(!packet || (packet->datalen <= packet_size));
|
||||
if (!packet || (packet->datalen >= packet_size)) {
|
||||
/* tail packet missing or completely full; we need a new packet. */
|
||||
packet = AllocateDataQueuePacket(queue);
|
||||
if (!packet) {
|
||||
/* uhoh, reset so we've queued nothing new, free what we can. */
|
||||
if (!origtail) {
|
||||
packet = queue->head; /* whole queue. */
|
||||
} else {
|
||||
packet = origtail->next; /* what we added to existing queue. */
|
||||
origtail->next = NULL;
|
||||
origtail->datalen = origlen;
|
||||
}
|
||||
queue->head = orighead;
|
||||
queue->tail = origtail;
|
||||
queue->pool = NULL;
|
||||
|
||||
SDL_FreeDataQueueList(packet); /* give back what we can. */
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
}
|
||||
|
||||
datalen = SDL_min(len, packet_size - packet->datalen);
|
||||
SDL_memcpy(packet->data + packet->datalen, data, datalen);
|
||||
data += datalen;
|
||||
len -= datalen;
|
||||
packet->datalen += datalen;
|
||||
queue->queued_bytes += datalen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
SDL_PeekIntoDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
|
||||
{
|
||||
size_t len = _len;
|
||||
Uint8 *buf = (Uint8 *) _buf;
|
||||
Uint8 *ptr = buf;
|
||||
SDL_DataQueuePacket *packet;
|
||||
|
||||
if (!queue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (packet = queue->head; len && packet; packet = packet->next) {
|
||||
const size_t avail = packet->datalen - packet->startpos;
|
||||
const size_t cpy = SDL_min(len, avail);
|
||||
SDL_assert(queue->queued_bytes >= avail);
|
||||
|
||||
SDL_memcpy(ptr, packet->data + packet->startpos, cpy);
|
||||
ptr += cpy;
|
||||
len -= cpy;
|
||||
}
|
||||
|
||||
return (size_t) (ptr - buf);
|
||||
}
|
||||
|
||||
size_t
|
||||
SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
|
||||
{
|
||||
size_t len = _len;
|
||||
Uint8 *buf = (Uint8 *) _buf;
|
||||
Uint8 *ptr = buf;
|
||||
SDL_DataQueuePacket *packet;
|
||||
|
||||
if (!queue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((len > 0) && ((packet = queue->head) != NULL)) {
|
||||
const size_t avail = packet->datalen - packet->startpos;
|
||||
const size_t cpy = SDL_min(len, avail);
|
||||
SDL_assert(queue->queued_bytes >= avail);
|
||||
|
||||
SDL_memcpy(ptr, packet->data + packet->startpos, cpy);
|
||||
packet->startpos += cpy;
|
||||
ptr += cpy;
|
||||
queue->queued_bytes -= cpy;
|
||||
len -= cpy;
|
||||
|
||||
if (packet->startpos == packet->datalen) { /* packet is done, put it in the pool. */
|
||||
queue->head = packet->next;
|
||||
SDL_assert((packet->next != NULL) || (packet == queue->tail));
|
||||
packet->next = queue->pool;
|
||||
queue->pool = packet;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_assert((queue->head != NULL) == (queue->queued_bytes != 0));
|
||||
|
||||
if (queue->head == NULL) {
|
||||
queue->tail = NULL; /* in case we drained the queue entirely. */
|
||||
}
|
||||
|
||||
return (size_t) (ptr - buf);
|
||||
}
|
||||
|
||||
size_t
|
||||
SDL_CountDataQueue(SDL_DataQueue *queue)
|
||||
{
|
||||
return queue ? queue->queued_bytes : 0;
|
||||
}
|
||||
|
||||
void *
|
||||
SDL_ReserveSpaceInDataQueue(SDL_DataQueue *queue, const size_t len)
|
||||
{
|
||||
SDL_DataQueuePacket *packet;
|
||||
|
||||
if (!queue) {
|
||||
SDL_InvalidParamError("queue");
|
||||
return NULL;
|
||||
} else if (len == 0) {
|
||||
SDL_InvalidParamError("len");
|
||||
return NULL;
|
||||
} else if (len > queue->packet_size) {
|
||||
SDL_SetError("len is larger than packet size");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
packet = queue->head;
|
||||
if (packet) {
|
||||
const size_t avail = queue->packet_size - packet->datalen;
|
||||
if (len <= avail) { /* we can use the space at end of this packet. */
|
||||
void *retval = packet->data + packet->datalen;
|
||||
packet->datalen += len;
|
||||
queue->queued_bytes += len;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
/* Need a fresh packet. */
|
||||
packet = AllocateDataQueuePacket(queue);
|
||||
if (!packet) {
|
||||
SDL_OutOfMemory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
packet->datalen = len;
|
||||
queue->queued_bytes += len;
|
||||
return packet->data;
|
||||
}
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
55
Engine/lib/sdl/src/SDL_dataqueue.h
Normal file
55
Engine/lib/sdl/src/SDL_dataqueue.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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_dataqueue_h_
|
||||
#define SDL_dataqueue_h_
|
||||
|
||||
/* this is not (currently) a public API. But maybe it should be! */
|
||||
|
||||
struct SDL_DataQueue;
|
||||
typedef struct SDL_DataQueue SDL_DataQueue;
|
||||
|
||||
SDL_DataQueue *SDL_NewDataQueue(const size_t packetlen, const size_t initialslack);
|
||||
void SDL_FreeDataQueue(SDL_DataQueue *queue);
|
||||
void SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack);
|
||||
int SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *data, const size_t len);
|
||||
size_t SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *buf, const size_t len);
|
||||
size_t SDL_PeekIntoDataQueue(SDL_DataQueue *queue, void *buf, const size_t len);
|
||||
size_t SDL_CountDataQueue(SDL_DataQueue *queue);
|
||||
|
||||
/* this sets a section of the data queue aside (possibly allocating memory for it)
|
||||
as if it's been written to, but returns a pointer to that space. You may write
|
||||
to this space until a read would consume it. Writes (and other calls to this
|
||||
function) will safely append their data after this reserved space and can
|
||||
be in flight at the same time. There is no thread safety.
|
||||
If there isn't an existing block of memory that can contain the reserved
|
||||
space, one will be allocated for it. You can not (currently) allocate
|
||||
a space larger than the packetlen requested in SDL_NewDataQueue.
|
||||
Returned buffer is uninitialized.
|
||||
This lets you avoid an extra copy in some cases, but it's safer to use
|
||||
SDL_WriteToDataQueue() unless you know what you're doing.
|
||||
Returns pointer to buffer of at least (len) bytes, NULL on error.
|
||||
*/
|
||||
void *SDL_ReserveSpaceInDataQueue(SDL_DataQueue *queue, const size_t len);
|
||||
|
||||
#endif /* SDL_dataqueue_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -49,6 +49,8 @@ SDL_LookupString(const char *key)
|
|||
|
||||
/* Public functions */
|
||||
|
||||
static char *SDL_GetErrorMsg(char *errstr, int maxlen);
|
||||
|
||||
int
|
||||
SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
|
||||
{
|
||||
|
|
@ -74,6 +76,16 @@ SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
|
|||
case 0: /* Malformed format string.. */
|
||||
--fmt;
|
||||
break;
|
||||
case 'l':
|
||||
switch (*fmt++) {
|
||||
case 0: /* Malformed format string.. */
|
||||
--fmt;
|
||||
break;
|
||||
case 'i': case 'd': case 'u':
|
||||
error->args[error->argc++].value_l = va_arg(ap, long);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
case 'i':
|
||||
case 'd':
|
||||
|
|
@ -110,16 +122,83 @@ SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
|
|||
}
|
||||
va_end(ap);
|
||||
|
||||
/* If we are in debug mode, print out an error message */
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_ERROR, "%s", SDL_GetError());
|
||||
|
||||
if (SDL_LogGetPriority(SDL_LOG_CATEGORY_ERROR) <= SDL_LOG_PRIORITY_DEBUG) {
|
||||
/* If we are in debug mode, print out an error message
|
||||
* Avoid stomping on the static buffer in GetError, just
|
||||
* in case this is called while processing a ShowMessageBox to
|
||||
* show an error already in that static buffer.
|
||||
*/
|
||||
char errmsg[SDL_ERRBUFIZE];
|
||||
SDL_GetErrorMsg(errmsg, sizeof(errmsg));
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_ERROR, "%s", errmsg);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
/* 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
|
||||
|
||||
|
||||
/* keep this at the end of the file so it works with GCC builds that don't
|
||||
support "#pragma GCC diagnostic push" ... we'll just leave the warning
|
||||
disabled after this. */
|
||||
/* this pragma arrived in GCC 4.2 and causes a warning on older GCCs! Sigh. */
|
||||
#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 2))))
|
||||
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||
#endif
|
||||
|
||||
/* This function has a bit more overhead than most error functions
|
||||
so that it supports internationalization and thread-safe errors.
|
||||
*/
|
||||
|
|
@ -150,6 +229,22 @@ SDL_GetErrorMsg(char *errstr, int maxlen)
|
|||
&& spot < (tmp + SDL_arraysize(tmp) - 2)) {
|
||||
*spot++ = *fmt++;
|
||||
}
|
||||
if (*fmt == 'l') {
|
||||
*spot++ = *fmt++;
|
||||
*spot++ = *fmt++;
|
||||
*spot++ = '\0';
|
||||
switch (spot[-2]) {
|
||||
case 'i': case 'd': case 'u':
|
||||
len = SDL_snprintf(msg, maxlen, tmp,
|
||||
error->args[argi++].value_l);
|
||||
if (len > 0) {
|
||||
msg += len;
|
||||
maxlen -= len;
|
||||
}
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
*spot++ = *fmt++;
|
||||
*spot++ = '\0';
|
||||
switch (spot[-2]) {
|
||||
|
|
@ -220,63 +315,5 @@ SDL_GetErrorMsg(char *errstr, int maxlen)
|
|||
}
|
||||
return (errstr);
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
/* 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: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -24,8 +24,8 @@
|
|||
error messages
|
||||
*/
|
||||
|
||||
#ifndef _SDL_error_c_h
|
||||
#define _SDL_error_c_h
|
||||
#ifndef SDL_error_c_h_
|
||||
#define SDL_error_c_h_
|
||||
|
||||
#define ERR_MAX_STRLEN 128
|
||||
#define ERR_MAX_ARGS 5
|
||||
|
|
@ -51,6 +51,7 @@ typedef struct SDL_error
|
|||
unsigned char value_c;
|
||||
#endif
|
||||
int value_i;
|
||||
long value_l;
|
||||
double value_f;
|
||||
char buf[ERR_MAX_STRLEN];
|
||||
} args[ERR_MAX_ARGS];
|
||||
|
|
@ -59,6 +60,6 @@ typedef struct SDL_error
|
|||
/* Defined in SDL_thread.c */
|
||||
extern SDL_error *SDL_GetErrBuf(void);
|
||||
|
||||
#endif /* _SDL_error_c_h */
|
||||
#endif /* SDL_error_c_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -122,7 +122,7 @@ SDL_bool
|
|||
SDL_GetHintBoolean(const char *name, SDL_bool default_value)
|
||||
{
|
||||
const char *hint = SDL_GetHint(name);
|
||||
if (!hint) {
|
||||
if (!hint || !*hint) {
|
||||
return default_value;
|
||||
}
|
||||
if (*hint == '0' || SDL_strcasecmp(hint, "false") == 0) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -18,8 +18,22 @@
|
|||
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
|
||||
#ifndef SDL_internal_h_
|
||||
#define SDL_internal_h_
|
||||
|
||||
/* Many of SDL's features require _GNU_SOURCE on various platforms */
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
/* This is for a variable-length array at the end of a struct:
|
||||
struct x { int y; char z[SDL_VARIABLE_LENGTH_ARRAY]; };
|
||||
Use this because GCC 2 needs different magic than other compilers. */
|
||||
#if (defined(__GNUC__) && (__GNUC__ <= 2)) || defined(__CC_ARM) || defined(__cplusplus)
|
||||
#define SDL_VARIABLE_LENGTH_ARRAY 1
|
||||
#else
|
||||
#define SDL_VARIABLE_LENGTH_ARRAY
|
||||
#endif
|
||||
|
||||
#include "dynapi/SDL_dynapi.h"
|
||||
|
||||
|
|
@ -33,6 +47,6 @@
|
|||
|
||||
#include "SDL_config.h"
|
||||
|
||||
#endif
|
||||
#endif /* SDL_internal_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -50,9 +50,7 @@ typedef struct SDL_LogLevel
|
|||
} SDL_LogLevel;
|
||||
|
||||
/* The default log output function */
|
||||
static void SDL_LogOutput(void *userdata,
|
||||
int category, SDL_LogPriority priority,
|
||||
const char *message);
|
||||
static void SDLCALL 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;
|
||||
|
|
@ -304,15 +302,15 @@ SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list
|
|||
SDL_stack_free(message);
|
||||
}
|
||||
|
||||
#if defined(__WIN32__)
|
||||
/* Flag tracking the attachment of the console: 0=unattached, 1=attached, -1=error */
|
||||
#if defined(__WIN32__) && !defined(HAVE_STDIO_H) && !defined(__WINRT__)
|
||||
/* Flag tracking the attachment of the console: 0=unattached, 1=attached to a console, 2=attached to a file, -1=error */
|
||||
static int consoleAttached = 0;
|
||||
|
||||
/* Handle to stderr output of console. */
|
||||
static HANDLE stderrHandle = NULL;
|
||||
#endif
|
||||
|
||||
static void
|
||||
static void SDLCALL
|
||||
SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
|
||||
const char *message)
|
||||
{
|
||||
|
|
@ -328,6 +326,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
|
|||
BOOL attachResult;
|
||||
DWORD attachError;
|
||||
unsigned long charsWritten;
|
||||
DWORD consoleMode;
|
||||
|
||||
/* Maybe attach console and get stderr handle */
|
||||
if (consoleAttached == 0) {
|
||||
|
|
@ -335,7 +334,8 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
|
|||
if (!attachResult) {
|
||||
attachError = GetLastError();
|
||||
if (attachError == ERROR_INVALID_HANDLE) {
|
||||
OutputDebugString(TEXT("Parent process has no console\r\n"));
|
||||
/* This is expected when running from Visual Studio */
|
||||
/*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"));
|
||||
|
|
@ -351,9 +351,14 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
|
|||
/* Newly attached */
|
||||
consoleAttached = 1;
|
||||
}
|
||||
|
||||
|
||||
if (consoleAttached == 1) {
|
||||
stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
if (GetConsoleMode(stderrHandle, &consoleMode) == 0) {
|
||||
/* WriteConsole fails if the output is redirected to a file. Must use WriteFile instead. */
|
||||
consoleAttached = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* !defined(HAVE_STDIO_H) && !defined(__WINRT__) */
|
||||
|
|
@ -375,6 +380,11 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
|
|||
OutputDebugString(TEXT("Insufficient heap memory to write message\r\n"));
|
||||
}
|
||||
}
|
||||
|
||||
} else if (consoleAttached == 2) {
|
||||
if (!WriteFile(stderrHandle, output, lstrlenA(output), &charsWritten, NULL)) {
|
||||
OutputDebugString(TEXT("Error calling WriteFile\r\n"));
|
||||
}
|
||||
}
|
||||
#endif /* !defined(HAVE_STDIO_H) && !defined(__WINRT__) */
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -35,6 +35,48 @@
|
|||
#include <atomic.h>
|
||||
#endif
|
||||
|
||||
/* The __atomic_load_n() intrinsic showed up in different times for different compilers. */
|
||||
#if defined(HAVE_GCC_ATOMICS)
|
||||
# if defined(__clang__)
|
||||
# if __has_builtin(__atomic_load_n)
|
||||
/* !!! FIXME: this advertises as available in the NDK but uses an external symbol we don't have.
|
||||
It might be in a later NDK or we might need an extra library? --ryan. */
|
||||
# if !defined(__ANDROID__)
|
||||
# define HAVE_ATOMIC_LOAD_N 1
|
||||
# endif
|
||||
# endif
|
||||
# elif defined(__GNUC__)
|
||||
# if (__GNUC__ >= 5)
|
||||
# define HAVE_ATOMIC_LOAD_N 1
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__WATCOMC__) && defined(__386__)
|
||||
#define HAVE_WATCOM_ATOMICS
|
||||
extern _inline int _SDL_xchg_watcom(volatile int *a, int v);
|
||||
#pragma aux _SDL_xchg_watcom = \
|
||||
"xchg [ecx], eax" \
|
||||
parm [ecx] [eax] \
|
||||
value [eax] \
|
||||
modify exact [eax];
|
||||
|
||||
extern _inline unsigned char _SDL_cmpxchg_watcom(volatile int *a, int newval, int oldval);
|
||||
#pragma aux _SDL_cmpxchg_watcom = \
|
||||
"lock cmpxchg [edx], ecx" \
|
||||
"setz al" \
|
||||
parm [edx] [ecx] [eax] \
|
||||
value [al] \
|
||||
modify exact [eax];
|
||||
|
||||
extern _inline int _SDL_xadd_watcom(volatile int *a, int v);
|
||||
#pragma aux _SDL_xadd_watcom = \
|
||||
"lock xadd [ecx], eax" \
|
||||
parm [ecx] [eax] \
|
||||
value [eax] \
|
||||
modify exact [eax];
|
||||
#endif /* __WATCOMC__ && __386__ */
|
||||
|
||||
/*
|
||||
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
|
||||
|
|
@ -58,7 +100,7 @@
|
|||
Contributed by Bob Pendleton, bob@pendleton.com
|
||||
*/
|
||||
|
||||
#if !defined(HAVE_MSC_ATOMICS) && !defined(HAVE_GCC_ATOMICS) && !defined(__MACOSX__) && !defined(__SOLARIS__)
|
||||
#if !defined(HAVE_MSC_ATOMICS) && !defined(HAVE_GCC_ATOMICS) && !defined(__MACOSX__) && !defined(__SOLARIS__) && !defined(HAVE_WATCOM_ATOMICS)
|
||||
#define EMULATE_CAS 1
|
||||
#endif
|
||||
|
||||
|
|
@ -88,10 +130,12 @@ 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_WATCOM_ATOMICS)
|
||||
return (SDL_bool) _SDL_cmpxchg_watcom(&a->value, newval, oldval);
|
||||
#elif defined(HAVE_GCC_ATOMICS)
|
||||
return (SDL_bool) __sync_bool_compare_and_swap(&a->value, oldval, newval);
|
||||
#elif defined(__MACOSX__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
|
||||
return (SDL_bool) OSAtomicCompareAndSwap32Barrier(oldval, newval, &a->value);
|
||||
#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)
|
||||
|
|
@ -119,12 +163,14 @@ SDL_AtomicCASPtr(void **a, void *oldval, void *newval)
|
|||
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_WATCOM_ATOMICS)
|
||||
return (SDL_bool) _SDL_cmpxchg_watcom((int *)a, (long)newval, (long)oldval);
|
||||
#elif defined(HAVE_GCC_ATOMICS)
|
||||
return __sync_bool_compare_and_swap(a, oldval, newval);
|
||||
#elif defined(__MACOSX__) && defined(__LP64__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
|
||||
return (SDL_bool) OSAtomicCompareAndSwap64Barrier((int64_t)oldval, (int64_t)newval, (int64_t*) a);
|
||||
#elif defined(__MACOSX__) && !defined(__LP64__) /* this is deprecated in 10.12 sdk; favor gcc atomics. */
|
||||
return (SDL_bool) OSAtomicCompareAndSwap32Barrier((int32_t)oldval, (int32_t)newval, (int32_t*) a);
|
||||
#elif defined(__SOLARIS__)
|
||||
return (SDL_bool) (atomic_cas_ptr(a, oldval, newval) == oldval);
|
||||
#elif EMULATE_CAS
|
||||
|
|
@ -148,6 +194,8 @@ SDL_AtomicSet(SDL_atomic_t *a, int v)
|
|||
{
|
||||
#ifdef HAVE_MSC_ATOMICS
|
||||
return _InterlockedExchange((long*)&a->value, v);
|
||||
#elif defined(HAVE_WATCOM_ATOMICS)
|
||||
return _SDL_xchg_watcom(&a->value, v);
|
||||
#elif defined(HAVE_GCC_ATOMICS)
|
||||
return __sync_lock_test_and_set(&a->value, v);
|
||||
#elif defined(__SOLARIS__) && defined(_LP64)
|
||||
|
|
@ -170,6 +218,8 @@ SDL_AtomicSetPtr(void **a, void *v)
|
|||
return (void *) _InterlockedExchange((long *)a, (long) v);
|
||||
#elif defined(HAVE_MSC_ATOMICS) && (!_M_IX86)
|
||||
return _InterlockedExchangePointer(a, v);
|
||||
#elif defined(HAVE_WATCOM_ATOMICS)
|
||||
return (void *) _SDL_xchg_watcom((int *)a, (long)v);
|
||||
#elif defined(HAVE_GCC_ATOMICS)
|
||||
return __sync_lock_test_and_set(a, v);
|
||||
#elif defined(__SOLARIS__)
|
||||
|
|
@ -188,6 +238,8 @@ SDL_AtomicAdd(SDL_atomic_t *a, int v)
|
|||
{
|
||||
#ifdef HAVE_MSC_ATOMICS
|
||||
return _InterlockedExchangeAdd((long*)&a->value, v);
|
||||
#elif defined(HAVE_WATCOM_ATOMICS)
|
||||
return _SDL_xadd_watcom(&a->value, v);
|
||||
#elif defined(HAVE_GCC_ATOMICS)
|
||||
return __sync_fetch_and_add(&a->value, v);
|
||||
#elif defined(__SOLARIS__)
|
||||
|
|
@ -211,36 +263,41 @@ SDL_AtomicAdd(SDL_atomic_t *a, int v)
|
|||
int
|
||||
SDL_AtomicGet(SDL_atomic_t *a)
|
||||
{
|
||||
#ifdef HAVE_ATOMIC_LOAD_N
|
||||
return __atomic_load_n(&a->value, __ATOMIC_SEQ_CST);
|
||||
#else
|
||||
int value;
|
||||
do {
|
||||
value = a->value;
|
||||
} while (!SDL_AtomicCAS(a, value, value));
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
|
||||
void *
|
||||
SDL_AtomicGetPtr(void **a)
|
||||
{
|
||||
#ifdef HAVE_ATOMIC_LOAD_N
|
||||
return __atomic_load_n(a, __ATOMIC_SEQ_CST);
|
||||
#else
|
||||
void *value;
|
||||
do {
|
||||
value = *a;
|
||||
} while (!SDL_AtomicCASPtr(a, value, value));
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
|
||||
#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
|
||||
void
|
||||
SDL_MemoryBarrierReleaseFunction(void)
|
||||
{
|
||||
SDL_MemoryBarrierRelease();
|
||||
}
|
||||
|
||||
void
|
||||
SDL_MemoryBarrierAcquireFunction(void)
|
||||
{
|
||||
SDL_MemoryBarrierAcquire();
|
||||
}
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -32,6 +32,16 @@
|
|||
#include <atomic.h>
|
||||
#endif
|
||||
|
||||
#if defined(__WATCOMC__) && defined(__386__)
|
||||
SDL_COMPILE_TIME_ASSERT(locksize, 4==sizeof(SDL_SpinLock));
|
||||
extern _inline int _SDL_xchg_watcom(volatile int *a, int v);
|
||||
#pragma aux _SDL_xchg_watcom = \
|
||||
"xchg [ecx], eax" \
|
||||
parm [ecx] [eax] \
|
||||
value [eax] \
|
||||
modify exact [eax];
|
||||
#endif /* __WATCOMC__ && __386__ */
|
||||
|
||||
/* This function is where all the magic happens... */
|
||||
SDL_bool
|
||||
SDL_AtomicTryLock(SDL_SpinLock *lock)
|
||||
|
|
@ -58,6 +68,9 @@ SDL_AtomicTryLock(SDL_SpinLock *lock)
|
|||
SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long));
|
||||
return (InterlockedExchange((long*)lock, 1) == 0);
|
||||
|
||||
#elif defined(__WATCOMC__) && defined(__386__)
|
||||
return _SDL_xchg_watcom(lock, 1) == 0;
|
||||
|
||||
#elif HAVE_GCC_ATOMICS || HAVE_GCC_SYNC_LOCK_TEST_AND_SET
|
||||
return (__sync_lock_test_and_set(lock, 1) == 0);
|
||||
|
||||
|
|
@ -119,6 +132,10 @@ SDL_AtomicUnlock(SDL_SpinLock *lock)
|
|||
_ReadWriteBarrier();
|
||||
*lock = 0;
|
||||
|
||||
#elif defined(__WATCOMC__) && defined(__386__)
|
||||
SDL_CompilerBarrier ();
|
||||
*lock = 0;
|
||||
|
||||
#elif HAVE_GCC_ATOMICS || HAVE_GCC_SYNC_LOCK_TEST_AND_SET
|
||||
__sync_lock_release(lock);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -33,36 +33,6 @@
|
|||
static SDL_AudioDriver current_audio;
|
||||
static SDL_AudioDevice *open_devices[16];
|
||||
|
||||
/*
|
||||
* Not all of these will be compiled and linked in, but it's convenient
|
||||
* to have a complete list here and saves yet-another block of #ifdefs...
|
||||
* Please see bootstrap[], below, for the actual #ifdef mess.
|
||||
*/
|
||||
extern AudioBootStrap PULSEAUDIO_bootstrap;
|
||||
extern AudioBootStrap ALSA_bootstrap;
|
||||
extern AudioBootStrap SNDIO_bootstrap;
|
||||
extern AudioBootStrap BSD_AUDIO_bootstrap;
|
||||
extern AudioBootStrap DSP_bootstrap;
|
||||
extern AudioBootStrap QSAAUDIO_bootstrap;
|
||||
extern AudioBootStrap SUNAUDIO_bootstrap;
|
||||
extern AudioBootStrap ARTS_bootstrap;
|
||||
extern AudioBootStrap ESD_bootstrap;
|
||||
extern AudioBootStrap NACLAUDIO_bootstrap;
|
||||
extern AudioBootStrap NAS_bootstrap;
|
||||
extern AudioBootStrap XAUDIO2_bootstrap;
|
||||
extern AudioBootStrap DSOUND_bootstrap;
|
||||
extern AudioBootStrap WINMM_bootstrap;
|
||||
extern AudioBootStrap PAUDIO_bootstrap;
|
||||
extern AudioBootStrap HAIKUAUDIO_bootstrap;
|
||||
extern AudioBootStrap COREAUDIO_bootstrap;
|
||||
extern AudioBootStrap DISKAUDIO_bootstrap;
|
||||
extern AudioBootStrap DUMMYAUDIO_bootstrap;
|
||||
extern AudioBootStrap FUSIONSOUND_bootstrap;
|
||||
extern AudioBootStrap ANDROIDAUDIO_bootstrap;
|
||||
extern AudioBootStrap PSPAUDIO_bootstrap;
|
||||
extern AudioBootStrap SNDIO_bootstrap;
|
||||
extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
|
||||
|
||||
/* Available audio drivers */
|
||||
static const AudioBootStrap *const bootstrap[] = {
|
||||
#if SDL_AUDIO_DRIVER_PULSEAUDIO
|
||||
|
|
@ -74,8 +44,8 @@ static const AudioBootStrap *const bootstrap[] = {
|
|||
#if SDL_AUDIO_DRIVER_SNDIO
|
||||
&SNDIO_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_BSD
|
||||
&BSD_AUDIO_bootstrap,
|
||||
#if SDL_AUDIO_DRIVER_NETBSD
|
||||
&NETBSDAUDIO_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_OSS
|
||||
&DSP_bootstrap,
|
||||
|
|
@ -98,8 +68,8 @@ static const AudioBootStrap *const bootstrap[] = {
|
|||
#if SDL_AUDIO_DRIVER_NAS
|
||||
&NAS_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_XAUDIO2
|
||||
&XAUDIO2_bootstrap,
|
||||
#if SDL_AUDIO_DRIVER_WASAPI
|
||||
&WASAPI_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_DSOUND
|
||||
&DSOUND_bootstrap,
|
||||
|
|
@ -116,12 +86,6 @@ static const AudioBootStrap *const bootstrap[] = {
|
|||
#if SDL_AUDIO_DRIVER_COREAUDIO
|
||||
&COREAUDIO_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_DISK
|
||||
&DISKAUDIO_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_DUMMY
|
||||
&DUMMYAUDIO_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_FUSIONSOUND
|
||||
&FUSIONSOUND_bootstrap,
|
||||
#endif
|
||||
|
|
@ -133,10 +97,102 @@ static const AudioBootStrap *const bootstrap[] = {
|
|||
#endif
|
||||
#if SDL_AUDIO_DRIVER_EMSCRIPTEN
|
||||
&EMSCRIPTENAUDIO_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_JACK
|
||||
&JACK_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_DISK
|
||||
&DISKAUDIO_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_DUMMY
|
||||
&DUMMYAUDIO_bootstrap,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
#ifdef HAVE_LIBSAMPLERATE_H
|
||||
#ifdef SDL_LIBSAMPLERATE_DYNAMIC
|
||||
static void *SRC_lib = NULL;
|
||||
#endif
|
||||
SDL_bool SRC_available = SDL_FALSE;
|
||||
int SRC_converter = 0;
|
||||
SRC_STATE* (*SRC_src_new)(int converter_type, int channels, int *error) = NULL;
|
||||
int (*SRC_src_process)(SRC_STATE *state, SRC_DATA *data) = NULL;
|
||||
int (*SRC_src_reset)(SRC_STATE *state) = NULL;
|
||||
SRC_STATE* (*SRC_src_delete)(SRC_STATE *state) = NULL;
|
||||
const char* (*SRC_src_strerror)(int error) = NULL;
|
||||
|
||||
static SDL_bool
|
||||
LoadLibSampleRate(void)
|
||||
{
|
||||
const char *hint = SDL_GetHint(SDL_HINT_AUDIO_RESAMPLING_MODE);
|
||||
|
||||
SRC_available = SDL_FALSE;
|
||||
SRC_converter = 0;
|
||||
|
||||
if (!hint || *hint == '0' || SDL_strcasecmp(hint, "default") == 0) {
|
||||
return SDL_FALSE; /* don't load anything. */
|
||||
} else if (*hint == '1' || SDL_strcasecmp(hint, "fast") == 0) {
|
||||
SRC_converter = SRC_SINC_FASTEST;
|
||||
} else if (*hint == '2' || SDL_strcasecmp(hint, "medium") == 0) {
|
||||
SRC_converter = SRC_SINC_MEDIUM_QUALITY;
|
||||
} else if (*hint == '3' || SDL_strcasecmp(hint, "best") == 0) {
|
||||
SRC_converter = SRC_SINC_BEST_QUALITY;
|
||||
} else {
|
||||
return SDL_FALSE; /* treat it like "default", don't load anything. */
|
||||
}
|
||||
|
||||
#ifdef SDL_LIBSAMPLERATE_DYNAMIC
|
||||
SDL_assert(SRC_lib == NULL);
|
||||
SRC_lib = SDL_LoadObject(SDL_LIBSAMPLERATE_DYNAMIC);
|
||||
if (!SRC_lib) {
|
||||
SDL_ClearError();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
SRC_src_new = (SRC_STATE* (*)(int converter_type, int channels, int *error))SDL_LoadFunction(SRC_lib, "src_new");
|
||||
SRC_src_process = (int (*)(SRC_STATE *state, SRC_DATA *data))SDL_LoadFunction(SRC_lib, "src_process");
|
||||
SRC_src_reset = (int(*)(SRC_STATE *state))SDL_LoadFunction(SRC_lib, "src_reset");
|
||||
SRC_src_delete = (SRC_STATE* (*)(SRC_STATE *state))SDL_LoadFunction(SRC_lib, "src_delete");
|
||||
SRC_src_strerror = (const char* (*)(int error))SDL_LoadFunction(SRC_lib, "src_strerror");
|
||||
|
||||
if (!SRC_src_new || !SRC_src_process || !SRC_src_reset || !SRC_src_delete || !SRC_src_strerror) {
|
||||
SDL_UnloadObject(SRC_lib);
|
||||
SRC_lib = NULL;
|
||||
return SDL_FALSE;
|
||||
}
|
||||
#else
|
||||
SRC_src_new = src_new;
|
||||
SRC_src_process = src_process;
|
||||
SRC_src_reset = src_reset;
|
||||
SRC_src_delete = src_delete;
|
||||
SRC_src_strerror = src_strerror;
|
||||
#endif
|
||||
|
||||
SRC_available = SDL_TRUE;
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
UnloadLibSampleRate(void)
|
||||
{
|
||||
#ifdef SDL_LIBSAMPLERATE_DYNAMIC
|
||||
if (SRC_lib != NULL) {
|
||||
SDL_UnloadObject(SRC_lib);
|
||||
}
|
||||
SRC_lib = NULL;
|
||||
#endif
|
||||
|
||||
SRC_available = SDL_FALSE;
|
||||
SRC_src_new = NULL;
|
||||
SRC_src_process = NULL;
|
||||
SRC_src_reset = NULL;
|
||||
SRC_src_delete = NULL;
|
||||
SRC_src_strerror = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SDL_AudioDevice *
|
||||
get_audio_device(SDL_AudioDeviceID id)
|
||||
{
|
||||
|
|
@ -169,6 +225,16 @@ SDL_AudioThreadInit_Default(_THIS)
|
|||
{ /* no-op. */
|
||||
}
|
||||
|
||||
static void
|
||||
SDL_AudioThreadDeinit_Default(_THIS)
|
||||
{ /* no-op. */
|
||||
}
|
||||
|
||||
static void
|
||||
SDL_AudioBeginLoopIteration_Default(_THIS)
|
||||
{ /* no-op. */
|
||||
}
|
||||
|
||||
static void
|
||||
SDL_AudioWaitDevice_Default(_THIS)
|
||||
{ /* no-op. */
|
||||
|
|
@ -288,6 +354,8 @@ finish_audio_entry_points_init(void)
|
|||
FILL_STUB(DetectDevices);
|
||||
FILL_STUB(OpenDevice);
|
||||
FILL_STUB(ThreadInit);
|
||||
FILL_STUB(ThreadDeinit);
|
||||
FILL_STUB(BeginLoopIteration);
|
||||
FILL_STUB(WaitDevice);
|
||||
FILL_STUB(PlayDevice);
|
||||
FILL_STUB(GetPendingBytes);
|
||||
|
|
@ -448,136 +516,23 @@ SDL_RemoveAudioDevice(const int iscapture, void *handle)
|
|||
|
||||
/* buffer queueing support... */
|
||||
|
||||
/* this expects that you managed thread safety elsewhere. */
|
||||
static void
|
||||
free_audio_queue(SDL_AudioBufferQueue *packet)
|
||||
{
|
||||
while (packet) {
|
||||
SDL_AudioBufferQueue *next = packet->next;
|
||||
SDL_free(packet);
|
||||
packet = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE: This assumes you'll hold the mixer lock before calling! */
|
||||
static int
|
||||
queue_audio_to_device(SDL_AudioDevice *device, const Uint8 *data, Uint32 len)
|
||||
{
|
||||
SDL_AudioBufferQueue *orighead;
|
||||
SDL_AudioBufferQueue *origtail;
|
||||
Uint32 origlen;
|
||||
Uint32 datalen;
|
||||
|
||||
orighead = device->buffer_queue_head;
|
||||
origtail = device->buffer_queue_tail;
|
||||
origlen = origtail ? origtail->datalen : 0;
|
||||
|
||||
while (len > 0) {
|
||||
SDL_AudioBufferQueue *packet = device->buffer_queue_tail;
|
||||
SDL_assert(!packet || (packet->datalen <= SDL_AUDIOBUFFERQUEUE_PACKETLEN));
|
||||
if (!packet || (packet->datalen >= SDL_AUDIOBUFFERQUEUE_PACKETLEN)) {
|
||||
/* tail packet missing or completely full; we need a new packet. */
|
||||
packet = device->buffer_queue_pool;
|
||||
if (packet != NULL) {
|
||||
/* we have one available in the pool. */
|
||||
device->buffer_queue_pool = packet->next;
|
||||
} else {
|
||||
/* Have to allocate a new one! */
|
||||
packet = (SDL_AudioBufferQueue *) SDL_malloc(sizeof (SDL_AudioBufferQueue));
|
||||
if (packet == NULL) {
|
||||
/* uhoh, reset so we've queued nothing new, free what we can. */
|
||||
if (!origtail) {
|
||||
packet = device->buffer_queue_head; /* whole queue. */
|
||||
} else {
|
||||
packet = origtail->next; /* what we added to existing queue. */
|
||||
origtail->next = NULL;
|
||||
origtail->datalen = origlen;
|
||||
}
|
||||
device->buffer_queue_head = orighead;
|
||||
device->buffer_queue_tail = origtail;
|
||||
device->buffer_queue_pool = NULL;
|
||||
|
||||
free_audio_queue(packet); /* give back what we can. */
|
||||
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
}
|
||||
packet->datalen = 0;
|
||||
packet->startpos = 0;
|
||||
packet->next = NULL;
|
||||
|
||||
SDL_assert((device->buffer_queue_head != NULL) == (device->queued_bytes != 0));
|
||||
if (device->buffer_queue_tail == NULL) {
|
||||
device->buffer_queue_head = packet;
|
||||
} else {
|
||||
device->buffer_queue_tail->next = packet;
|
||||
}
|
||||
device->buffer_queue_tail = packet;
|
||||
}
|
||||
|
||||
datalen = SDL_min(len, SDL_AUDIOBUFFERQUEUE_PACKETLEN - packet->datalen);
|
||||
SDL_memcpy(packet->data + packet->datalen, data, datalen);
|
||||
data += datalen;
|
||||
len -= datalen;
|
||||
packet->datalen += datalen;
|
||||
device->queued_bytes += datalen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NOTE: This assumes you'll hold the mixer lock before calling! */
|
||||
static Uint32
|
||||
dequeue_audio_from_device(SDL_AudioDevice *device, Uint8 *stream, Uint32 len)
|
||||
{
|
||||
SDL_AudioBufferQueue *packet;
|
||||
Uint8 *ptr = stream;
|
||||
|
||||
while ((len > 0) && ((packet = device->buffer_queue_head) != NULL)) {
|
||||
const Uint32 avail = packet->datalen - packet->startpos;
|
||||
const Uint32 cpy = SDL_min(len, avail);
|
||||
SDL_assert(device->queued_bytes >= avail);
|
||||
|
||||
SDL_memcpy(ptr, packet->data + packet->startpos, cpy);
|
||||
packet->startpos += cpy;
|
||||
ptr += cpy;
|
||||
device->queued_bytes -= cpy;
|
||||
len -= cpy;
|
||||
|
||||
if (packet->startpos == packet->datalen) { /* packet is done, put it in the pool. */
|
||||
device->buffer_queue_head = packet->next;
|
||||
SDL_assert((packet->next != NULL) || (packet == device->buffer_queue_tail));
|
||||
packet->next = device->buffer_queue_pool;
|
||||
device->buffer_queue_pool = packet;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_assert((device->buffer_queue_head != NULL) == (device->queued_bytes != 0));
|
||||
|
||||
if (device->buffer_queue_head == NULL) {
|
||||
device->buffer_queue_tail = NULL; /* in case we drained the queue entirely. */
|
||||
}
|
||||
|
||||
return (Uint32) (ptr - stream);
|
||||
}
|
||||
|
||||
static void SDLCALL
|
||||
SDL_BufferQueueDrainCallback(void *userdata, Uint8 *stream, int len)
|
||||
{
|
||||
/* this function always holds the mixer lock before being called. */
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
|
||||
Uint32 written;
|
||||
size_t dequeued;
|
||||
|
||||
SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */
|
||||
SDL_assert(!device->iscapture); /* this shouldn't ever happen, right?! */
|
||||
SDL_assert(len >= 0); /* this shouldn't ever happen, right?! */
|
||||
|
||||
written = dequeue_audio_from_device(device, stream, (Uint32) len);
|
||||
stream += written;
|
||||
len -= (int) written;
|
||||
dequeued = SDL_ReadFromDataQueue(device->buffer_queue, stream, len);
|
||||
stream += dequeued;
|
||||
len -= (int) dequeued;
|
||||
|
||||
if (len > 0) { /* fill any remaining space in the stream with silence. */
|
||||
SDL_assert(device->buffer_queue_head == NULL);
|
||||
SDL_assert(SDL_CountDataQueue(device->buffer_queue) == 0);
|
||||
SDL_memset(stream, device->spec.silence, len);
|
||||
}
|
||||
}
|
||||
|
|
@ -595,7 +550,7 @@ SDL_BufferQueueFillCallback(void *userdata, Uint8 *stream, int len)
|
|||
/* note that if this needs to allocate more space and run out of memory,
|
||||
we have no choice but to quietly drop the data and hope it works out
|
||||
later, but you probably have bigger problems in this case anyhow. */
|
||||
queue_audio_to_device(device, stream, (Uint32) len);
|
||||
SDL_WriteToDataQueue(device->buffer_queue, stream, len);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -608,13 +563,13 @@ SDL_QueueAudio(SDL_AudioDeviceID devid, const void *data, Uint32 len)
|
|||
return -1; /* get_audio_device() will have set the error state */
|
||||
} else if (device->iscapture) {
|
||||
return SDL_SetError("This is a capture device, queueing not allowed");
|
||||
} else if (device->spec.callback != SDL_BufferQueueDrainCallback) {
|
||||
} else if (device->callbackspec.callback != SDL_BufferQueueDrainCallback) {
|
||||
return SDL_SetError("Audio device has a callback, queueing not allowed");
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
current_audio.impl.LockDevice(device);
|
||||
rc = queue_audio_to_device(device, data, len);
|
||||
rc = SDL_WriteToDataQueue(device->buffer_queue, data, len);
|
||||
current_audio.impl.UnlockDevice(device);
|
||||
}
|
||||
|
||||
|
|
@ -630,12 +585,12 @@ SDL_DequeueAudio(SDL_AudioDeviceID devid, void *data, Uint32 len)
|
|||
if ( (len == 0) || /* nothing to do? */
|
||||
(!device) || /* called with bogus device id */
|
||||
(!device->iscapture) || /* playback devices can't dequeue */
|
||||
(device->spec.callback != SDL_BufferQueueFillCallback) ) { /* not set for queueing */
|
||||
(device->callbackspec.callback != SDL_BufferQueueFillCallback) ) { /* not set for queueing */
|
||||
return 0; /* just report zero bytes dequeued. */
|
||||
}
|
||||
|
||||
current_audio.impl.LockDevice(device);
|
||||
rc = dequeue_audio_from_device(device, data, len);
|
||||
rc = (Uint32) SDL_ReadFromDataQueue(device->buffer_queue, data, len);
|
||||
current_audio.impl.UnlockDevice(device);
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -651,13 +606,13 @@ SDL_GetQueuedAudioSize(SDL_AudioDeviceID devid)
|
|||
}
|
||||
|
||||
/* Nothing to do unless we're set up for queueing. */
|
||||
if (device->spec.callback == SDL_BufferQueueDrainCallback) {
|
||||
if (device->callbackspec.callback == SDL_BufferQueueDrainCallback) {
|
||||
current_audio.impl.LockDevice(device);
|
||||
retval = device->queued_bytes + current_audio.impl.GetPendingBytes(device);
|
||||
retval = ((Uint32) SDL_CountDataQueue(device->buffer_queue)) + current_audio.impl.GetPendingBytes(device);
|
||||
current_audio.impl.UnlockDevice(device);
|
||||
} else if (device->spec.callback == SDL_BufferQueueFillCallback) {
|
||||
} else if (device->callbackspec.callback == SDL_BufferQueueFillCallback) {
|
||||
current_audio.impl.LockDevice(device);
|
||||
retval = device->queued_bytes;
|
||||
retval = (Uint32) SDL_CountDataQueue(device->buffer_queue);
|
||||
current_audio.impl.UnlockDevice(device);
|
||||
}
|
||||
|
||||
|
|
@ -668,7 +623,6 @@ void
|
|||
SDL_ClearQueuedAudio(SDL_AudioDeviceID devid)
|
||||
{
|
||||
SDL_AudioDevice *device = get_audio_device(devid);
|
||||
SDL_AudioBufferQueue *packet;
|
||||
|
||||
if (!device) {
|
||||
return; /* nothing to do. */
|
||||
|
|
@ -677,35 +631,10 @@ SDL_ClearQueuedAudio(SDL_AudioDeviceID devid)
|
|||
/* Blank out the device and release the mutex. Free it afterwards. */
|
||||
current_audio.impl.LockDevice(device);
|
||||
|
||||
/* merge the available pool and the current queue into one list. */
|
||||
packet = device->buffer_queue_head;
|
||||
if (packet) {
|
||||
device->buffer_queue_tail->next = device->buffer_queue_pool;
|
||||
} else {
|
||||
packet = device->buffer_queue_pool;
|
||||
}
|
||||
|
||||
/* Remove the queued packets from the device. */
|
||||
device->buffer_queue_tail = NULL;
|
||||
device->buffer_queue_head = NULL;
|
||||
device->queued_bytes = 0;
|
||||
device->buffer_queue_pool = packet;
|
||||
|
||||
/* Keep up to two packets in the pool to reduce future malloc pressure. */
|
||||
if (packet) {
|
||||
if (!packet->next) {
|
||||
packet = NULL; /* one packet (the only one) for the pool. */
|
||||
} else {
|
||||
SDL_AudioBufferQueue *next = packet->next->next;
|
||||
packet->next->next = NULL; /* two packets for the pool. */
|
||||
packet = next; /* rest will be freed. */
|
||||
}
|
||||
}
|
||||
SDL_ClearDataQueue(device->buffer_queue, SDL_AUDIOBUFFERQUEUE_PACKETLEN * 2);
|
||||
|
||||
current_audio.impl.UnlockDevice(device);
|
||||
|
||||
/* free any extra packets we didn't keep in the pool. */
|
||||
free_audio_queue(packet);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -714,12 +643,10 @@ static int SDLCALL
|
|||
SDL_RunAudio(void *devicep)
|
||||
{
|
||||
SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
|
||||
const int silence = (int) device->spec.silence;
|
||||
const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq);
|
||||
const int stream_len = (device->convert.needed) ? device->convert.len : device->spec.size;
|
||||
Uint8 *stream;
|
||||
void *udata = device->spec.userdata;
|
||||
void (SDLCALL *callback) (void *, Uint8 *, int) = device->spec.callback;
|
||||
void *udata = device->callbackspec.userdata;
|
||||
SDL_AudioCallback callback = device->callbackspec.callback;
|
||||
int data_len = 0;
|
||||
Uint8 *data;
|
||||
|
||||
SDL_assert(!device->iscapture);
|
||||
|
||||
|
|
@ -732,51 +659,64 @@ SDL_RunAudio(void *devicep)
|
|||
|
||||
/* Loop, filling the audio buffers */
|
||||
while (!SDL_AtomicGet(&device->shutdown)) {
|
||||
current_audio.impl.BeginLoopIteration(device);
|
||||
data_len = device->callbackspec.size;
|
||||
|
||||
/* Fill the current buffer with sound */
|
||||
if (device->convert.needed) {
|
||||
stream = device->convert.buf;
|
||||
} else if (SDL_AtomicGet(&device->enabled)) {
|
||||
stream = current_audio.impl.GetDeviceBuf(device);
|
||||
if (!device->stream && SDL_AtomicGet(&device->enabled)) {
|
||||
SDL_assert(data_len == device->spec.size);
|
||||
data = current_audio.impl.GetDeviceBuf(device);
|
||||
} else {
|
||||
/* if the device isn't enabled, we still write to the
|
||||
fake_stream, so the app's callback will fire with
|
||||
work_buffer, so the app's callback will fire with
|
||||
a regular frequency, in case they depend on that
|
||||
for timing or progress. They can use hotplug
|
||||
now to know if the device failed. */
|
||||
stream = NULL;
|
||||
now to know if the device failed.
|
||||
Streaming playback uses work_buffer, too. */
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
if (stream == NULL) {
|
||||
stream = device->fake_stream;
|
||||
if (data == NULL) {
|
||||
data = device->work_buffer;
|
||||
}
|
||||
|
||||
/* !!! FIXME: this should be LockDevice. */
|
||||
if ( SDL_AtomicGet(&device->enabled) ) {
|
||||
SDL_LockMutex(device->mixer_lock);
|
||||
if (SDL_AtomicGet(&device->paused)) {
|
||||
SDL_memset(stream, silence, stream_len);
|
||||
} else {
|
||||
(*callback) (udata, stream, stream_len);
|
||||
}
|
||||
SDL_UnlockMutex(device->mixer_lock);
|
||||
}
|
||||
|
||||
/* Convert the audio if necessary */
|
||||
if (device->convert.needed && SDL_AtomicGet(&device->enabled)) {
|
||||
SDL_ConvertAudio(&device->convert);
|
||||
stream = current_audio.impl.GetDeviceBuf(device);
|
||||
if (stream == NULL) {
|
||||
stream = device->fake_stream;
|
||||
} else {
|
||||
SDL_memcpy(stream, device->convert.buf,
|
||||
device->convert.len_cvt);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ready current buffer for play and change current buffer */
|
||||
if (stream == device->fake_stream) {
|
||||
SDL_Delay(delay);
|
||||
SDL_LockMutex(device->mixer_lock);
|
||||
if (SDL_AtomicGet(&device->paused)) {
|
||||
SDL_memset(data, device->spec.silence, data_len);
|
||||
} else {
|
||||
callback(udata, data, data_len);
|
||||
}
|
||||
SDL_UnlockMutex(device->mixer_lock);
|
||||
|
||||
if (device->stream) {
|
||||
/* Stream available audio to device, converting/resampling. */
|
||||
/* if this fails...oh well. We'll play silence here. */
|
||||
SDL_AudioStreamPut(device->stream, data, data_len);
|
||||
|
||||
while (SDL_AudioStreamAvailable(device->stream) >= ((int) device->spec.size)) {
|
||||
int got;
|
||||
data = SDL_AtomicGet(&device->enabled) ? current_audio.impl.GetDeviceBuf(device) : NULL;
|
||||
got = SDL_AudioStreamGet(device->stream, data ? data : device->work_buffer, device->spec.size);
|
||||
SDL_assert((got < 0) || (got == device->spec.size));
|
||||
|
||||
if (data == NULL) { /* device is having issues... */
|
||||
const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq);
|
||||
SDL_Delay(delay); /* wait for as long as this buffer would have played. Maybe device recovers later? */
|
||||
} else {
|
||||
if (got != device->spec.size) {
|
||||
SDL_memset(data, device->spec.silence, device->spec.size);
|
||||
}
|
||||
current_audio.impl.PlayDevice(device);
|
||||
current_audio.impl.WaitDevice(device);
|
||||
}
|
||||
}
|
||||
} else if (data == device->work_buffer) {
|
||||
/* nothing to do; pause like we queued a buffer to play. */
|
||||
const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq);
|
||||
SDL_Delay(delay);
|
||||
} else { /* writing directly to the device. */
|
||||
/* queue this buffer and wait for it to finish playing. */
|
||||
current_audio.impl.PlayDevice(device);
|
||||
current_audio.impl.WaitDevice(device);
|
||||
}
|
||||
|
|
@ -787,9 +727,12 @@ SDL_RunAudio(void *devicep)
|
|||
/* Wait for the audio to drain. */
|
||||
SDL_Delay(((device->spec.samples * 1000) / device->spec.freq) * 2);
|
||||
|
||||
current_audio.impl.ThreadDeinit(device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* !!! FIXME: this needs to deal with device spec changes. */
|
||||
/* The general capture thread function */
|
||||
static int SDLCALL
|
||||
SDL_CaptureAudio(void *devicep)
|
||||
|
|
@ -797,10 +740,10 @@ SDL_CaptureAudio(void *devicep)
|
|||
SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
|
||||
const int silence = (int) device->spec.silence;
|
||||
const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq);
|
||||
const int stream_len = (device->convert.needed) ? device->convert.len : device->spec.size;
|
||||
Uint8 *stream;
|
||||
void *udata = device->spec.userdata;
|
||||
void (SDLCALL *callback) (void *, Uint8 *, int) = device->spec.callback;
|
||||
const int data_len = device->spec.size;
|
||||
Uint8 *data;
|
||||
void *udata = device->callbackspec.userdata;
|
||||
SDL_AudioCallback callback = device->callbackspec.callback;
|
||||
|
||||
SDL_assert(device->iscapture);
|
||||
|
||||
|
|
@ -816,34 +759,43 @@ SDL_CaptureAudio(void *devicep)
|
|||
int still_need;
|
||||
Uint8 *ptr;
|
||||
|
||||
if (!SDL_AtomicGet(&device->enabled) || SDL_AtomicGet(&device->paused)) {
|
||||
current_audio.impl.BeginLoopIteration(device);
|
||||
|
||||
if (SDL_AtomicGet(&device->paused)) {
|
||||
SDL_Delay(delay); /* just so we don't cook the CPU. */
|
||||
if (device->stream) {
|
||||
SDL_AudioStreamClear(device->stream);
|
||||
}
|
||||
current_audio.impl.FlushCapture(device); /* dump anything pending. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Fill the current buffer with sound */
|
||||
still_need = stream_len;
|
||||
if (device->convert.needed) {
|
||||
ptr = stream = device->convert.buf;
|
||||
} else {
|
||||
/* just use the "fake" stream to hold data read from the device. */
|
||||
ptr = stream = device->fake_stream;
|
||||
}
|
||||
still_need = data_len;
|
||||
|
||||
/* Use the work_buffer to hold data read from the device. */
|
||||
data = device->work_buffer;
|
||||
SDL_assert(data != NULL);
|
||||
|
||||
ptr = data;
|
||||
|
||||
/* We still read from the device when "paused" to keep the state sane,
|
||||
and block when there isn't data so this thread isn't eating CPU.
|
||||
But we don't process it further or call the app's callback. */
|
||||
|
||||
while (still_need > 0) {
|
||||
const int rc = current_audio.impl.CaptureFromDevice(device, ptr, still_need);
|
||||
SDL_assert(rc <= still_need); /* device should not overflow buffer. :) */
|
||||
if (rc > 0) {
|
||||
still_need -= rc;
|
||||
ptr += rc;
|
||||
} else { /* uhoh, device failed for some reason! */
|
||||
SDL_OpenedAudioDeviceDisconnected(device);
|
||||
break;
|
||||
if (!SDL_AtomicGet(&device->enabled)) {
|
||||
SDL_Delay(delay); /* try to keep callback firing at normal pace. */
|
||||
} else {
|
||||
while (still_need > 0) {
|
||||
const int rc = current_audio.impl.CaptureFromDevice(device, ptr, still_need);
|
||||
SDL_assert(rc <= still_need); /* device should not overflow buffer. :) */
|
||||
if (rc > 0) {
|
||||
still_need -= rc;
|
||||
ptr += rc;
|
||||
} else { /* uhoh, device failed for some reason! */
|
||||
SDL_OpenedAudioDeviceDisconnected(device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -852,22 +804,38 @@ SDL_CaptureAudio(void *devicep)
|
|||
SDL_memset(ptr, silence, still_need);
|
||||
}
|
||||
|
||||
if (device->convert.needed) {
|
||||
SDL_ConvertAudio(&device->convert);
|
||||
}
|
||||
if (device->stream) {
|
||||
/* if this fails...oh well. */
|
||||
SDL_AudioStreamPut(device->stream, data, data_len);
|
||||
|
||||
/* !!! FIXME: this should be LockDevice. */
|
||||
SDL_LockMutex(device->mixer_lock);
|
||||
if (SDL_AtomicGet(&device->paused)) {
|
||||
current_audio.impl.FlushCapture(device); /* one snuck in! */
|
||||
} else {
|
||||
(*callback)(udata, stream, stream_len);
|
||||
while (SDL_AudioStreamAvailable(device->stream) >= ((int) device->callbackspec.size)) {
|
||||
const int got = SDL_AudioStreamGet(device->stream, device->work_buffer, device->callbackspec.size);
|
||||
SDL_assert((got < 0) || (got == device->callbackspec.size));
|
||||
if (got != device->callbackspec.size) {
|
||||
SDL_memset(device->work_buffer, device->spec.silence, device->callbackspec.size);
|
||||
}
|
||||
|
||||
/* !!! FIXME: this should be LockDevice. */
|
||||
SDL_LockMutex(device->mixer_lock);
|
||||
if (!SDL_AtomicGet(&device->paused)) {
|
||||
callback(udata, device->work_buffer, device->callbackspec.size);
|
||||
}
|
||||
SDL_UnlockMutex(device->mixer_lock);
|
||||
}
|
||||
} else { /* feeding user callback directly without streaming. */
|
||||
/* !!! FIXME: this should be LockDevice. */
|
||||
SDL_LockMutex(device->mixer_lock);
|
||||
if (!SDL_AtomicGet(&device->paused)) {
|
||||
callback(udata, data, device->callbackspec.size);
|
||||
}
|
||||
SDL_UnlockMutex(device->mixer_lock);
|
||||
}
|
||||
SDL_UnlockMutex(device->mixer_lock);
|
||||
}
|
||||
|
||||
current_audio.impl.FlushCapture(device);
|
||||
|
||||
current_audio.impl.ThreadDeinit(device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -968,6 +936,10 @@ SDL_AudioInit(const char *driver_name)
|
|||
/* Make sure we have a list of devices available at startup. */
|
||||
current_audio.impl.DetectDevices();
|
||||
|
||||
#ifdef HAVE_LIBSAMPLERATE_H
|
||||
LoadLibSampleRate();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1098,16 +1070,15 @@ close_audio_device(SDL_AudioDevice * device)
|
|||
if (device->mixer_lock != NULL) {
|
||||
SDL_DestroyMutex(device->mixer_lock);
|
||||
}
|
||||
SDL_free(device->fake_stream);
|
||||
if (device->convert.needed) {
|
||||
SDL_free(device->convert.buf);
|
||||
}
|
||||
|
||||
SDL_free(device->work_buffer);
|
||||
SDL_FreeAudioStream(device->stream);
|
||||
|
||||
if (device->hidden != NULL) {
|
||||
current_audio.impl.CloseDevice(device);
|
||||
}
|
||||
|
||||
free_audio_queue(device->buffer_queue_head);
|
||||
free_audio_queue(device->buffer_queue_pool);
|
||||
SDL_FreeDataQueue(device->buffer_queue);
|
||||
|
||||
SDL_free(device);
|
||||
}
|
||||
|
|
@ -1180,11 +1151,11 @@ open_audio_device(const char *devname, int iscapture,
|
|||
const SDL_AudioSpec * desired, SDL_AudioSpec * obtained,
|
||||
int allowed_changes, int min_id)
|
||||
{
|
||||
const SDL_bool is_internal_thread = (desired->callback != NULL);
|
||||
const SDL_bool is_internal_thread = (desired->callback == NULL);
|
||||
SDL_AudioDeviceID id = 0;
|
||||
SDL_AudioSpec _obtained;
|
||||
SDL_AudioDevice *device;
|
||||
SDL_bool build_cvt;
|
||||
SDL_bool build_stream;
|
||||
void *handle = NULL;
|
||||
int i = 0;
|
||||
|
||||
|
|
@ -1319,84 +1290,87 @@ open_audio_device(const char *devname, int iscapture,
|
|||
SDL_assert(device->hidden != NULL);
|
||||
|
||||
/* See if we need to do any conversion */
|
||||
build_cvt = SDL_FALSE;
|
||||
build_stream = SDL_FALSE;
|
||||
if (obtained->freq != device->spec.freq) {
|
||||
if (allowed_changes & SDL_AUDIO_ALLOW_FREQUENCY_CHANGE) {
|
||||
obtained->freq = device->spec.freq;
|
||||
} else {
|
||||
build_cvt = SDL_TRUE;
|
||||
build_stream = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
if (obtained->format != device->spec.format) {
|
||||
if (allowed_changes & SDL_AUDIO_ALLOW_FORMAT_CHANGE) {
|
||||
obtained->format = device->spec.format;
|
||||
} else {
|
||||
build_cvt = SDL_TRUE;
|
||||
build_stream = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
if (obtained->channels != device->spec.channels) {
|
||||
if (allowed_changes & SDL_AUDIO_ALLOW_CHANNELS_CHANGE) {
|
||||
obtained->channels = device->spec.channels;
|
||||
} else {
|
||||
build_cvt = SDL_TRUE;
|
||||
build_stream = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the audio driver changes the buffer size, accept it.
|
||||
This needs to be done after the format is modified above,
|
||||
otherwise it might not have the correct buffer size.
|
||||
/* !!! FIXME in 2.1: add SDL_AUDIO_ALLOW_SAMPLES_CHANGE flag?
|
||||
As of 2.0.6, we will build a stream to buffer the difference between
|
||||
what the app wants to feed and the device wants to eat, so everyone
|
||||
gets their way. In prior releases, SDL would force the callback to
|
||||
feed at the rate the device requested, adjusted for resampling.
|
||||
*/
|
||||
if (device->spec.samples != obtained->samples) {
|
||||
obtained->samples = device->spec.samples;
|
||||
SDL_CalculateAudioSpec(obtained);
|
||||
build_stream = SDL_TRUE;
|
||||
}
|
||||
|
||||
if (build_cvt) {
|
||||
/* Build an audio conversion block */
|
||||
if (SDL_BuildAudioCVT(&device->convert,
|
||||
obtained->format, obtained->channels,
|
||||
obtained->freq,
|
||||
device->spec.format, device->spec.channels,
|
||||
device->spec.freq) < 0) {
|
||||
SDL_CalculateAudioSpec(obtained); /* recalc after possible changes. */
|
||||
|
||||
device->callbackspec = *obtained;
|
||||
|
||||
if (build_stream) {
|
||||
if (iscapture) {
|
||||
device->stream = SDL_NewAudioStream(device->spec.format,
|
||||
device->spec.channels, device->spec.freq,
|
||||
obtained->format, obtained->channels, obtained->freq);
|
||||
} else {
|
||||
device->stream = SDL_NewAudioStream(obtained->format, obtained->channels,
|
||||
obtained->freq, device->spec.format,
|
||||
device->spec.channels, device->spec.freq);
|
||||
}
|
||||
|
||||
if (!device->stream) {
|
||||
close_audio_device(device);
|
||||
return 0;
|
||||
}
|
||||
if (device->convert.needed) {
|
||||
device->convert.len = (int) (((double) device->spec.size) /
|
||||
device->convert.len_ratio);
|
||||
|
||||
device->convert.buf =
|
||||
(Uint8 *) SDL_malloc(device->convert.len *
|
||||
device->convert.len_mult);
|
||||
if (device->convert.buf == NULL) {
|
||||
close_audio_device(device);
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (device->spec.callback == NULL) { /* use buffer queueing? */
|
||||
/* pool a few packets to start. Enough for two callbacks. */
|
||||
const int packetlen = SDL_AUDIOBUFFERQUEUE_PACKETLEN;
|
||||
const int wantbytes = ((device->convert.needed) ? device->convert.len : device->spec.size) * 2;
|
||||
const int wantpackets = (wantbytes / packetlen) + ((wantbytes % packetlen) ? packetlen : 0);
|
||||
for (i = 0; i < wantpackets; i++) {
|
||||
SDL_AudioBufferQueue *packet = (SDL_AudioBufferQueue *) SDL_malloc(sizeof (SDL_AudioBufferQueue));
|
||||
if (packet) { /* don't care if this fails, we'll deal later. */
|
||||
packet->datalen = 0;
|
||||
packet->startpos = 0;
|
||||
packet->next = device->buffer_queue_pool;
|
||||
device->buffer_queue_pool = packet;
|
||||
}
|
||||
device->buffer_queue = SDL_NewDataQueue(SDL_AUDIOBUFFERQUEUE_PACKETLEN, obtained->size * 2);
|
||||
if (!device->buffer_queue) {
|
||||
close_audio_device(device);
|
||||
SDL_SetError("Couldn't create audio buffer queue");
|
||||
return 0;
|
||||
}
|
||||
|
||||
device->spec.callback = iscapture ? SDL_BufferQueueFillCallback : SDL_BufferQueueDrainCallback;
|
||||
device->spec.userdata = device;
|
||||
device->callbackspec.callback = iscapture ? SDL_BufferQueueFillCallback : SDL_BufferQueueDrainCallback;
|
||||
device->callbackspec.userdata = device;
|
||||
}
|
||||
|
||||
/* add it to our list of open devices. */
|
||||
open_devices[id] = device;
|
||||
/* Allocate a scratch audio buffer */
|
||||
device->work_buffer_len = build_stream ? device->callbackspec.size : 0;
|
||||
if (device->spec.size > device->work_buffer_len) {
|
||||
device->work_buffer_len = device->spec.size;
|
||||
}
|
||||
SDL_assert(device->work_buffer_len > 0);
|
||||
|
||||
device->work_buffer = (Uint8 *) SDL_malloc(device->work_buffer_len);
|
||||
if (device->work_buffer == NULL) {
|
||||
close_audio_device(device);
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
|
||||
open_devices[id] = device; /* add it to our list of open devices. */
|
||||
|
||||
/* Start the audio thread if necessary */
|
||||
if (!current_audio.impl.ProvidesOwnCallbackThread) {
|
||||
|
|
@ -1406,21 +1380,7 @@ open_audio_device(const char *devname, int iscapture,
|
|||
const size_t stacksize = is_internal_thread ? 64 * 1024 : 0;
|
||||
char threadname[64];
|
||||
|
||||
/* Allocate a fake audio buffer; only used by our internal threads. */
|
||||
Uint32 stream_len = (device->convert.needed) ? device->convert.len_cvt : 0;
|
||||
if (device->spec.size > stream_len) {
|
||||
stream_len = device->spec.size;
|
||||
}
|
||||
SDL_assert(stream_len > 0);
|
||||
|
||||
device->fake_stream = (Uint8 *) SDL_malloc(stream_len);
|
||||
if (device->fake_stream == NULL) {
|
||||
close_audio_device(device);
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_snprintf(threadname, sizeof (threadname), "SDLAudioDev%d", (int) device->id);
|
||||
SDL_snprintf(threadname, sizeof (threadname), "SDLAudio%c%d", (iscapture) ? 'C' : 'P', (int) device->id);
|
||||
device->thread = SDL_CreateThreadInternal(iscapture ? SDL_CaptureAudio : SDL_RunAudio, threadname, stacksize, device);
|
||||
|
||||
if (device->thread == NULL) {
|
||||
|
|
@ -1456,7 +1416,14 @@ SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained)
|
|||
id = open_audio_device(NULL, 0, desired, obtained,
|
||||
SDL_AUDIO_ALLOW_ANY_CHANGE, 1);
|
||||
} else {
|
||||
id = open_audio_device(NULL, 0, desired, NULL, 0, 1);
|
||||
SDL_AudioSpec _obtained;
|
||||
SDL_zero(_obtained);
|
||||
id = open_audio_device(NULL, 0, desired, &_obtained, 0, 1);
|
||||
/* On successful open, copy calculated values into 'desired'. */
|
||||
if (id > 0) {
|
||||
desired->size = _obtained.size;
|
||||
desired->silence = _obtained.silence;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_assert((id == 0) || (id == 1));
|
||||
|
|
@ -1579,6 +1546,12 @@ SDL_AudioQuit(void)
|
|||
|
||||
SDL_zero(current_audio);
|
||||
SDL_zero(open_devices);
|
||||
|
||||
#ifdef HAVE_LIBSAMPLERATE_H
|
||||
UnloadLibSampleRate();
|
||||
#endif
|
||||
|
||||
SDL_FreeResampleFilter();
|
||||
}
|
||||
|
||||
#define NUM_FORMATS 10
|
||||
|
|
@ -1655,13 +1628,7 @@ SDL_MixAudio(Uint8 * dst, const Uint8 * src, Uint32 len, int volume)
|
|||
/* Mix the user-level audio format */
|
||||
SDL_AudioDevice *device = get_audio_device(1);
|
||||
if (device != NULL) {
|
||||
SDL_AudioFormat format;
|
||||
if (device->convert.needed) {
|
||||
format = device->convert.src_format;
|
||||
} else {
|
||||
format = device->spec.format;
|
||||
}
|
||||
SDL_MixAudioFormat(dst, src, format, len, volume);
|
||||
SDL_MixAudioFormat(dst, src, device->callbackspec.format, len, volume);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -18,10 +18,35 @@
|
|||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_audio_c_h_
|
||||
#define SDL_audio_c_h_
|
||||
|
||||
#include "../SDL_internal.h"
|
||||
|
||||
#ifndef DEBUG_CONVERT
|
||||
#define DEBUG_CONVERT 0
|
||||
#endif
|
||||
|
||||
#if DEBUG_CONVERT
|
||||
#define LOG_DEBUG_CONVERT(from, to) fprintf(stderr, "Converting %s to %s.\n", from, to);
|
||||
#else
|
||||
#define LOG_DEBUG_CONVERT(from, to)
|
||||
#endif
|
||||
|
||||
/* Functions and variables exported from SDL_audio.c for SDL_sysaudio.c */
|
||||
|
||||
#ifdef HAVE_LIBSAMPLERATE_H
|
||||
#include "samplerate.h"
|
||||
extern SDL_bool SRC_available;
|
||||
extern int SRC_converter;
|
||||
extern SRC_STATE* (*SRC_src_new)(int converter_type, int channels, int *error);
|
||||
extern int (*SRC_src_process)(SRC_STATE *state, SRC_DATA *data);
|
||||
extern int (*SRC_src_reset)(SRC_STATE *state);
|
||||
extern SRC_STATE* (*SRC_src_delete)(SRC_STATE *state);
|
||||
extern const char* (*SRC_src_strerror)(int error);
|
||||
#endif
|
||||
|
||||
/* Functions to get a list of "close" audio formats */
|
||||
extern SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format);
|
||||
extern SDL_AudioFormat SDL_NextAudioFormat(void);
|
||||
|
|
@ -29,24 +54,26 @@ extern SDL_AudioFormat SDL_NextAudioFormat(void);
|
|||
/* Function to calculate the size and silence for a SDL_AudioSpec */
|
||||
extern void SDL_CalculateAudioSpec(SDL_AudioSpec * spec);
|
||||
|
||||
/* 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[];
|
||||
/* Choose the audio filter functions below */
|
||||
extern void SDL_ChooseAudioConverters(void);
|
||||
|
||||
/* 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[];
|
||||
/* These pointers get set during SDL_ChooseAudioConverters() to various SIMD implementations. */
|
||||
extern SDL_AudioFilter SDL_Convert_S8_to_F32;
|
||||
extern SDL_AudioFilter SDL_Convert_U8_to_F32;
|
||||
extern SDL_AudioFilter SDL_Convert_S16_to_F32;
|
||||
extern SDL_AudioFilter SDL_Convert_U16_to_F32;
|
||||
extern SDL_AudioFilter SDL_Convert_S32_to_F32;
|
||||
extern SDL_AudioFilter SDL_Convert_F32_to_S8;
|
||||
extern SDL_AudioFilter SDL_Convert_F32_to_U8;
|
||||
extern SDL_AudioFilter SDL_Convert_F32_to_S16;
|
||||
extern SDL_AudioFilter SDL_Convert_F32_to_U16;
|
||||
extern SDL_AudioFilter SDL_Convert_F32_to_S32;
|
||||
|
||||
/* You need to call SDL_PrepareResampleFilter() before using the internal resampler.
|
||||
SDL_AudioQuit() calls SDL_FreeResamplerFilter(), you should never call it yourself. */
|
||||
extern int SDL_PrepareResampleFilter(void);
|
||||
extern void SDL_FreeResampleFilter(void);
|
||||
|
||||
#endif /* SDL_audio_c_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
/* Get the name of the audio device we use for output */
|
||||
|
||||
#if SDL_AUDIO_DRIVER_BSD || SDL_AUDIO_DRIVER_OSS || SDL_AUDIO_DRIVER_SUNAUDIO
|
||||
#if SDL_AUDIO_DRIVER_NETBSD || SDL_AUDIO_DRIVER_OSS || SDL_AUDIO_DRIVER_SUNAUDIO
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
|
|
@ -103,9 +103,10 @@ SDL_EnumUnixAudioDevices_Internal(const int iscapture, const int classic, int (*
|
|||
|
||||
if (SDL_strlen(audiodev) < (sizeof(audiopath) - 3)) {
|
||||
int instance = 0;
|
||||
while (instance++ <= 64) {
|
||||
while (instance <= 64) {
|
||||
SDL_snprintf(audiopath, SDL_arraysize(audiopath),
|
||||
"%s%d", audiodev, instance);
|
||||
instance++;
|
||||
test_device(iscapture, audiopath, flags, test);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,11 +20,13 @@
|
|||
*/
|
||||
#include "../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_sysaudio_h
|
||||
#define _SDL_sysaudio_h
|
||||
#ifndef SDL_sysaudio_h_
|
||||
#define SDL_sysaudio_h_
|
||||
|
||||
#include "SDL_mutex.h"
|
||||
#include "SDL_thread.h"
|
||||
#include "../SDL_dataqueue.h"
|
||||
#include "./SDL_audio_c.h"
|
||||
|
||||
/* !!! FIXME: These are wordy and unlocalized... */
|
||||
#define DEFAULT_OUTPUT_DEVNAME "System audio output device"
|
||||
|
|
@ -49,7 +51,6 @@ extern void SDL_RemoveAudioDevice(const int iscapture, void *handle);
|
|||
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
|
||||
|
|
@ -61,20 +62,13 @@ extern void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device);
|
|||
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 (*ThreadDeinit) (_THIS); /* Called by audio thread at end */
|
||||
void (*BeginLoopIteration)(_THIS); /* Called by audio thread at top of loop */
|
||||
void (*WaitDevice) (_THIS);
|
||||
void (*PlayDevice) (_THIS);
|
||||
int (*GetPendingBytes) (_THIS);
|
||||
|
|
@ -105,11 +99,7 @@ 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
|
||||
char name[SDL_VARIABLE_LENGTH_ARRAY];
|
||||
} SDL_AudioDeviceItem;
|
||||
|
||||
|
||||
|
|
@ -136,15 +126,6 @@ typedef struct SDL_AudioDriver
|
|||
} 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
|
||||
{
|
||||
|
|
@ -152,15 +133,14 @@ struct SDL_AudioDevice
|
|||
/* Data common to all devices */
|
||||
SDL_AudioDeviceID id;
|
||||
|
||||
/* The current audio specification (shared with audio thread) */
|
||||
/* The device's current audio specification */
|
||||
SDL_AudioSpec spec;
|
||||
|
||||
/* An audio conversion block for audio format emulation */
|
||||
SDL_AudioCVT convert;
|
||||
/* The callback's expected audio specification (converted vs device's spec). */
|
||||
SDL_AudioSpec callbackspec;
|
||||
|
||||
/* The streamer, if sample rate conversion necessitates it */
|
||||
int use_streamer;
|
||||
SDL_AudioStreamer streamer;
|
||||
/* Stream that converts and resamples. NULL if not needed. */
|
||||
SDL_AudioStream *stream;
|
||||
|
||||
/* Current state flags */
|
||||
SDL_atomic_t shutdown; /* true if we are signaling the play thread to end. */
|
||||
|
|
@ -168,8 +148,11 @@ struct SDL_AudioDevice
|
|||
SDL_atomic_t paused;
|
||||
SDL_bool iscapture;
|
||||
|
||||
/* Fake audio buffer for when the audio hardware is busy */
|
||||
Uint8 *fake_stream;
|
||||
/* Scratch buffer used in the bridge between SDL and the user callback. */
|
||||
Uint8 *work_buffer;
|
||||
|
||||
/* Size, in bytes, of work_buffer. */
|
||||
Uint32 work_buffer_len;
|
||||
|
||||
/* A mutex for locking the mixing buffers */
|
||||
SDL_mutex *mixer_lock;
|
||||
|
|
@ -179,10 +162,7 @@ struct SDL_AudioDevice
|
|||
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. */
|
||||
SDL_DataQueue *buffer_queue;
|
||||
|
||||
/* * * */
|
||||
/* Data private to this driver */
|
||||
|
|
@ -200,6 +180,32 @@ typedef struct AudioBootStrap
|
|||
int demand_only; /* 1==request explicitly, or it won't be available. */
|
||||
} AudioBootStrap;
|
||||
|
||||
#endif /* _SDL_sysaudio_h */
|
||||
/* Not all of these are available in a given build. Use #ifdefs, etc. */
|
||||
extern AudioBootStrap PULSEAUDIO_bootstrap;
|
||||
extern AudioBootStrap ALSA_bootstrap;
|
||||
extern AudioBootStrap JACK_bootstrap;
|
||||
extern AudioBootStrap SNDIO_bootstrap;
|
||||
extern AudioBootStrap NETBSDAUDIO_bootstrap;
|
||||
extern AudioBootStrap DSP_bootstrap;
|
||||
extern AudioBootStrap QSAAUDIO_bootstrap;
|
||||
extern AudioBootStrap SUNAUDIO_bootstrap;
|
||||
extern AudioBootStrap ARTS_bootstrap;
|
||||
extern AudioBootStrap ESD_bootstrap;
|
||||
extern AudioBootStrap NACLAUDIO_bootstrap;
|
||||
extern AudioBootStrap NAS_bootstrap;
|
||||
extern AudioBootStrap WASAPI_bootstrap;
|
||||
extern AudioBootStrap DSOUND_bootstrap;
|
||||
extern AudioBootStrap WINMM_bootstrap;
|
||||
extern AudioBootStrap PAUDIO_bootstrap;
|
||||
extern AudioBootStrap HAIKUAUDIO_bootstrap;
|
||||
extern AudioBootStrap COREAUDIO_bootstrap;
|
||||
extern AudioBootStrap DISKAUDIO_bootstrap;
|
||||
extern AudioBootStrap DUMMYAUDIO_bootstrap;
|
||||
extern AudioBootStrap FUSIONSOUND_bootstrap;
|
||||
extern AudioBootStrap ANDROIDAUDIO_bootstrap;
|
||||
extern AudioBootStrap PSPAUDIO_bootstrap;
|
||||
extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
|
||||
|
||||
#endif /* SDL_sysaudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -403,6 +403,47 @@ IMA_ADPCM_decode(Uint8 ** audio_buf, Uint32 * audio_len)
|
|||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ConvertSint24ToSint32(Uint8 ** audio_buf, Uint32 * audio_len)
|
||||
{
|
||||
const double DIVBY8388608 = 0.00000011920928955078125;
|
||||
const Uint32 original_len = *audio_len;
|
||||
const Uint32 samples = original_len / 3;
|
||||
const Uint32 expanded_len = samples * sizeof (Uint32);
|
||||
Uint8 *ptr = (Uint8 *) SDL_realloc(*audio_buf, expanded_len);
|
||||
const Uint8 *src;
|
||||
Uint32 *dst;
|
||||
Uint32 i;
|
||||
|
||||
if (!ptr) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
*audio_buf = ptr;
|
||||
*audio_len = expanded_len;
|
||||
|
||||
/* work from end to start, since we're expanding in-place. */
|
||||
src = (ptr + original_len) - 3;
|
||||
dst = ((Uint32 *) (ptr + expanded_len)) - 1;
|
||||
for (i = 0; i < samples; i++) {
|
||||
/* There's probably a faster way to do all this. */
|
||||
const Sint32 converted = ((Sint32) ( (((Uint32) src[2]) << 24) |
|
||||
(((Uint32) src[1]) << 16) |
|
||||
(((Uint32) src[0]) << 8) )) >> 8;
|
||||
const double scaled = (((double) converted) * DIVBY8388608);
|
||||
src -= 3;
|
||||
*(dst--) = (Sint32) (scaled * 2147483647.0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* GUIDs that are used by WAVE_FORMAT_EXTENSIBLE */
|
||||
static const Uint8 extensible_pcm_guid[16] = { 1, 0, 0, 0, 0, 0, 16, 0, 128, 0, 0, 170, 0, 56, 155, 113 };
|
||||
static const Uint8 extensible_ieee_guid[16] = { 3, 0, 0, 0, 0, 0, 16, 0, 128, 0, 0, 170, 0, 56, 155, 113 };
|
||||
|
||||
SDL_AudioSpec *
|
||||
SDL_LoadWAV_RW(SDL_RWops * src, int freesrc,
|
||||
SDL_AudioSpec * spec, Uint8 ** audio_buf, Uint32 * audio_len)
|
||||
|
|
@ -421,6 +462,7 @@ SDL_LoadWAV_RW(SDL_RWops * src, int freesrc,
|
|||
|
||||
/* FMT chunk */
|
||||
WaveFMT *format = NULL;
|
||||
WaveExtensibleFMT *ext = NULL;
|
||||
|
||||
SDL_zero(chunk);
|
||||
|
||||
|
|
@ -494,6 +536,24 @@ SDL_LoadWAV_RW(SDL_RWops * src, int freesrc,
|
|||
}
|
||||
IMA_ADPCM_encoded = 1;
|
||||
break;
|
||||
case EXTENSIBLE_CODE:
|
||||
/* note that this ignores channel masks, smaller valid bit counts
|
||||
inside a larger container, and most subtypes. This is just enough
|
||||
to get things that didn't really _need_ WAVE_FORMAT_EXTENSIBLE
|
||||
to be useful working when they use this format flag. */
|
||||
ext = (WaveExtensibleFMT *) format;
|
||||
if (SDL_SwapLE16(ext->size) < 22) {
|
||||
SDL_SetError("bogus extended .wav header");
|
||||
was_error = 1;
|
||||
goto done;
|
||||
}
|
||||
if (SDL_memcmp(ext->subformat, extensible_pcm_guid, 16) == 0) {
|
||||
break; /* cool. */
|
||||
} else if (SDL_memcmp(ext->subformat, extensible_ieee_guid, 16) == 0) {
|
||||
IEEE_float_encoded = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MP3_CODE:
|
||||
SDL_SetError("MPEG Layer 3 data not supported");
|
||||
was_error = 1;
|
||||
|
|
@ -528,6 +588,9 @@ SDL_LoadWAV_RW(SDL_RWops * src, int freesrc,
|
|||
case 16:
|
||||
spec->format = AUDIO_S16;
|
||||
break;
|
||||
case 24: /* convert this. */
|
||||
spec->format = AUDIO_S32;
|
||||
break;
|
||||
case 32:
|
||||
spec->format = AUDIO_S32;
|
||||
break;
|
||||
|
|
@ -575,6 +638,13 @@ SDL_LoadWAV_RW(SDL_RWops * src, int freesrc,
|
|||
}
|
||||
}
|
||||
|
||||
if (SDL_SwapLE16(format->bitspersample) == 24) {
|
||||
if (ConvertSint24ToSint32(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);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -38,6 +38,7 @@
|
|||
#define IEEE_FLOAT_CODE 0x0003
|
||||
#define IMA_ADPCM_CODE 0x0011
|
||||
#define MP3_CODE 0x0055
|
||||
#define EXTENSIBLE_CODE 0xFFFE
|
||||
#define WAVE_MONO 1
|
||||
#define WAVE_STEREO 2
|
||||
|
||||
|
|
@ -64,4 +65,13 @@ typedef struct Chunk
|
|||
Uint8 *data;
|
||||
} Chunk;
|
||||
|
||||
typedef struct WaveExtensibleFMT
|
||||
{
|
||||
WaveFMT format;
|
||||
Uint16 size;
|
||||
Uint16 validbits;
|
||||
Uint32 channelmask;
|
||||
Uint8 subformat[16]; /* a GUID. */
|
||||
} WaveExtensibleFMT;
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -26,7 +26,6 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
#include <signal.h> /* For kill() */
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "SDL_assert.h"
|
||||
|
|
@ -91,6 +90,10 @@ static int (*ALSA_snd_pcm_reset)(snd_pcm_t *);
|
|||
static int (*ALSA_snd_device_name_hint) (int, const char *, void ***);
|
||||
static char* (*ALSA_snd_device_name_get_hint) (const void *, const char *);
|
||||
static int (*ALSA_snd_device_name_free_hint) (void **);
|
||||
#ifdef SND_CHMAP_API_VERSION
|
||||
static snd_pcm_chmap_t* (*ALSA_snd_pcm_get_chmap) (snd_pcm_t *);
|
||||
static int (*ALSA_snd_pcm_chmap_print) (const snd_pcm_chmap_t *map, size_t maxlen, char *buf);
|
||||
#endif
|
||||
|
||||
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
|
||||
#define snd_pcm_hw_params_sizeof ALSA_snd_pcm_hw_params_sizeof
|
||||
|
|
@ -155,6 +158,10 @@ load_alsa_syms(void)
|
|||
SDL_ALSA_SYM(snd_device_name_hint);
|
||||
SDL_ALSA_SYM(snd_device_name_get_hint);
|
||||
SDL_ALSA_SYM(snd_device_name_free_hint);
|
||||
#ifdef SND_CHMAP_API_VERSION
|
||||
SDL_ALSA_SYM(snd_pcm_get_chmap);
|
||||
SDL_ALSA_SYM(snd_pcm_chmap_print);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -255,25 +262,25 @@ ALSA_WaitDevice(_THIS)
|
|||
tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \
|
||||
}
|
||||
|
||||
static SDL_INLINE void
|
||||
static void
|
||||
swizzle_alsa_channels_6_64bit(void *buffer, Uint32 bufferlen)
|
||||
{
|
||||
SWIZ6(Uint64, buffer, bufferlen);
|
||||
}
|
||||
|
||||
static SDL_INLINE void
|
||||
static void
|
||||
swizzle_alsa_channels_6_32bit(void *buffer, Uint32 bufferlen)
|
||||
{
|
||||
SWIZ6(Uint32, buffer, bufferlen);
|
||||
}
|
||||
|
||||
static SDL_INLINE void
|
||||
static void
|
||||
swizzle_alsa_channels_6_16bit(void *buffer, Uint32 bufferlen)
|
||||
{
|
||||
SWIZ6(Uint16, buffer, bufferlen);
|
||||
}
|
||||
|
||||
static SDL_INLINE void
|
||||
static void
|
||||
swizzle_alsa_channels_6_8bit(void *buffer, Uint32 bufferlen)
|
||||
{
|
||||
SWIZ6(Uint8, buffer, bufferlen);
|
||||
|
|
@ -286,7 +293,7 @@ swizzle_alsa_channels_6_8bit(void *buffer, Uint32 bufferlen)
|
|||
* 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
|
||||
static void
|
||||
swizzle_alsa_channels(_THIS, void *buffer, Uint32 bufferlen)
|
||||
{
|
||||
if (this->spec.channels == 6) {
|
||||
|
|
@ -302,6 +309,15 @@ swizzle_alsa_channels(_THIS, void *buffer, Uint32 bufferlen)
|
|||
/* !!! FIXME: update this for 7.1 if needed, later. */
|
||||
}
|
||||
|
||||
#ifdef SND_CHMAP_API_VERSION
|
||||
/* Some devices have the right channel map, no swizzling necessary */
|
||||
static void
|
||||
no_swizzle(_THIS, void *buffer, Uint32 bufferlen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* SND_CHMAP_API_VERSION */
|
||||
|
||||
|
||||
static void
|
||||
ALSA_PlayDevice(_THIS)
|
||||
|
|
@ -311,23 +327,10 @@ ALSA_PlayDevice(_THIS)
|
|||
this->spec.channels;
|
||||
snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples);
|
||||
|
||||
swizzle_alsa_channels(this, this->hidden->mixbuf, frames_left);
|
||||
this->hidden->swizzle_func(this, this->hidden->mixbuf, frames_left);
|
||||
|
||||
while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
|
||||
int status;
|
||||
|
||||
/* This wait is a work-around for a hang when USB devices are
|
||||
unplugged. Normally it should not result in any waiting,
|
||||
but in the case of a USB unplug, it serves as a way to
|
||||
join the playback thread after the timeout occurs */
|
||||
status = ALSA_snd_pcm_wait(this->hidden->pcm_handle, 1000);
|
||||
if (status == 0) {
|
||||
/*fprintf(stderr, "ALSA timeout waiting for available buffer space\n");*/
|
||||
SDL_OpenedAudioDeviceDisconnected(this);
|
||||
return;
|
||||
}
|
||||
|
||||
status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
|
||||
int status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
|
||||
sample_buf, frames_left);
|
||||
|
||||
if (status < 0) {
|
||||
|
|
@ -347,6 +350,13 @@ ALSA_PlayDevice(_THIS)
|
|||
}
|
||||
continue;
|
||||
}
|
||||
else if (status == 0) {
|
||||
/* No frames were written (no available space in pcm device).
|
||||
Allow other threads to catch up. */
|
||||
Uint32 delay = (frames_left / 2 * 1000) / this->spec.freq;
|
||||
SDL_Delay(delay);
|
||||
}
|
||||
|
||||
sample_buf += status * frame_size;
|
||||
frames_left -= status;
|
||||
}
|
||||
|
|
@ -366,23 +376,22 @@ ALSA_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
|||
this->spec.channels;
|
||||
const int total_frames = buflen / frame_size;
|
||||
snd_pcm_uframes_t frames_left = total_frames;
|
||||
snd_pcm_uframes_t wait_time = frame_size / 2;
|
||||
|
||||
SDL_assert((buflen % frame_size) == 0);
|
||||
|
||||
while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
|
||||
/* !!! FIXME: This works, but needs more testing before going live */
|
||||
/* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */
|
||||
int status = ALSA_snd_pcm_readi(this->hidden->pcm_handle,
|
||||
int status;
|
||||
|
||||
status = ALSA_snd_pcm_readi(this->hidden->pcm_handle,
|
||||
sample_buf, frames_left);
|
||||
|
||||
if (status < 0) {
|
||||
if (status == -EAGAIN) {
|
||||
ALSA_snd_pcm_wait(this->hidden->pcm_handle, wait_time);
|
||||
status = 0;
|
||||
}
|
||||
else if (status < 0) {
|
||||
/*printf("ALSA: capture error %d\n", status);*/
|
||||
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 */
|
||||
|
|
@ -398,7 +407,7 @@ ALSA_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
|||
frames_left -= status;
|
||||
}
|
||||
|
||||
swizzle_alsa_channels(this, buffer, total_frames - frames_left);
|
||||
this->hidden->swizzle_func(this, buffer, total_frames - frames_left);
|
||||
|
||||
return (total_frames - frames_left) * frame_size;
|
||||
}
|
||||
|
|
@ -548,6 +557,10 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
SDL_AudioFormat test_format = 0;
|
||||
unsigned int rate = 0;
|
||||
unsigned int channels = 0;
|
||||
#ifdef SND_CHMAP_API_VERSION
|
||||
snd_pcm_chmap_t *chmap;
|
||||
char chmap_str[64];
|
||||
#endif
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
|
|
@ -640,6 +653,22 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
}
|
||||
this->spec.format = test_format;
|
||||
|
||||
/* Validate number of channels and determine if swizzling is necessary
|
||||
* Assume original swizzling, until proven otherwise.
|
||||
*/
|
||||
this->hidden->swizzle_func = swizzle_alsa_channels;
|
||||
#ifdef SND_CHMAP_API_VERSION
|
||||
chmap = ALSA_snd_pcm_get_chmap(pcm_handle);
|
||||
if (chmap) {
|
||||
ALSA_snd_pcm_chmap_print(chmap, sizeof(chmap_str), chmap_str);
|
||||
if (SDL_strcmp("FL FR FC LFE RL RR", chmap_str) == 0 ||
|
||||
SDL_strcmp("FL FR FC LFE SL SR", chmap_str) == 0) {
|
||||
this->hidden->swizzle_func = no_swizzle;
|
||||
}
|
||||
free(chmap);
|
||||
}
|
||||
#endif /* SND_CHMAP_API_VERSION */
|
||||
|
||||
/* Set the number of channels */
|
||||
status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
|
||||
this->spec.channels);
|
||||
|
|
@ -708,8 +737,9 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
|
||||
}
|
||||
|
||||
/* Switch to blocking mode for playback */
|
||||
ALSA_snd_pcm_nonblock(pcm_handle, 0);
|
||||
if (!iscapture) {
|
||||
ALSA_snd_pcm_nonblock(pcm_handle, 0);
|
||||
}
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return 0;
|
||||
|
|
@ -726,18 +756,28 @@ static void
|
|||
add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSeen)
|
||||
{
|
||||
ALSA_Device *dev = SDL_malloc(sizeof (ALSA_Device));
|
||||
char *desc = ALSA_snd_device_name_get_hint(hint, "DESC");
|
||||
char *desc;
|
||||
char *handle = NULL;
|
||||
char *ptr;
|
||||
|
||||
if (!desc) {
|
||||
SDL_free(dev);
|
||||
return;
|
||||
} else if (!dev) {
|
||||
free(desc);
|
||||
if (!dev) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Not all alsa devices are enumerable via snd_device_name_get_hint
|
||||
(i.e. bluetooth devices). Therefore if hint is passed in to this
|
||||
function as NULL, assume name contains desc.
|
||||
Make sure not to free the storage associated with desc in this case */
|
||||
if (hint) {
|
||||
desc = ALSA_snd_device_name_get_hint(hint, "DESC");
|
||||
if (!desc) {
|
||||
SDL_free(dev);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
desc = (char *) name;
|
||||
}
|
||||
|
||||
SDL_assert(name != NULL);
|
||||
|
||||
/* some strings have newlines, like "HDA NVidia, HDMI 0\nHDMI Audio Output".
|
||||
|
|
@ -751,14 +791,16 @@ add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSee
|
|||
|
||||
handle = SDL_strdup(name);
|
||||
if (!handle) {
|
||||
free(desc);
|
||||
if (hint) {
|
||||
free(desc);
|
||||
}
|
||||
SDL_free(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_AddAudioDevice(iscapture, desc, handle);
|
||||
free(desc);
|
||||
|
||||
if (hint)
|
||||
free(desc);
|
||||
dev->name = handle;
|
||||
dev->iscapture = iscapture;
|
||||
dev->next = *pSeen;
|
||||
|
|
@ -778,12 +820,15 @@ ALSA_HotplugThread(void *arg)
|
|||
ALSA_Device *dev;
|
||||
Uint32 ticks;
|
||||
|
||||
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_LOW);
|
||||
|
||||
while (!SDL_AtomicGet(&ALSA_hotplug_shutdown)) {
|
||||
void **hints = NULL;
|
||||
ALSA_Device *unseen;
|
||||
ALSA_Device *seen;
|
||||
ALSA_Device *prev;
|
||||
|
||||
if (ALSA_snd_device_name_hint(-1, "pcm", &hints) != -1) {
|
||||
ALSA_Device *unseen = devices;
|
||||
ALSA_Device *seen = NULL;
|
||||
ALSA_Device *prev;
|
||||
int i, j;
|
||||
const char *match = NULL;
|
||||
int bestmatch = 0xFFFF;
|
||||
|
|
@ -793,6 +838,8 @@ ALSA_HotplugThread(void *arg)
|
|||
"hw:", "sysdefault:", "default:", NULL
|
||||
};
|
||||
|
||||
unseen = devices;
|
||||
seen = NULL;
|
||||
/* Apparently there are several different ways that ALSA lists
|
||||
actual hardware. It could be prefixed with "hw:" or "default:"
|
||||
or "sysdefault:" and maybe others. Go through the list and see
|
||||
|
|
@ -887,7 +934,7 @@ ALSA_HotplugThread(void *arg)
|
|||
|
||||
/* report anything still in unseen as removed. */
|
||||
for (dev = unseen; dev; dev = next) {
|
||||
/*printf("ALSA: removing %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
|
||||
/*printf("ALSA: removing usb %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
|
||||
next = dev->next;
|
||||
SDL_RemoveAudioDevice(dev->iscapture, dev->name);
|
||||
SDL_free(dev->name);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_ALSA_audio_h
|
||||
#define _SDL_ALSA_audio_h
|
||||
#ifndef SDL_ALSA_audio_h_
|
||||
#define SDL_ALSA_audio_h_
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
|
|
@ -38,8 +38,11 @@ struct SDL_PrivateAudioData
|
|||
/* Raw mixing buffer */
|
||||
Uint8 *mixbuf;
|
||||
int mixlen;
|
||||
|
||||
/* swizzle function */
|
||||
void (*swizzle_func)(_THIS, void *buffer, Uint32 bufferlen);
|
||||
};
|
||||
|
||||
#endif /* _SDL_ALSA_audio_h */
|
||||
#endif /* SDL_ALSA_audio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -215,6 +215,10 @@ void ANDROIDAUDIO_ResumeDevices(void)
|
|||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void ANDROIDAUDIO_ResumeDevices(void) {}
|
||||
void ANDROIDAUDIO_PauseDevices(void) {}
|
||||
|
||||
#endif /* SDL_AUDIO_DRIVER_ANDROID */
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_androidaudio_h
|
||||
#define _SDL_androidaudio_h
|
||||
#ifndef SDL_androidaudio_h_
|
||||
#define SDL_androidaudio_h_
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
|
|
@ -34,6 +34,9 @@ struct SDL_PrivateAudioData
|
|||
int resume;
|
||||
};
|
||||
|
||||
#endif /* _SDL_androidaudio_h */
|
||||
void ANDROIDAUDIO_ResumeDevices(void);
|
||||
void ANDROIDAUDIO_PauseDevices(void);
|
||||
|
||||
#endif /* SDL_androidaudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_artscaudio_h
|
||||
#define _SDL_artscaudio_h
|
||||
#ifndef SDL_artsaudio_h_
|
||||
#define SDL_artsaudio_h_
|
||||
|
||||
#include <artsc.h>
|
||||
|
||||
|
|
@ -42,11 +42,12 @@ struct SDL_PrivateAudioData
|
|||
Uint8 *mixbuf;
|
||||
int mixlen;
|
||||
|
||||
/* Support for audio timing using a timer, in addition to select() */
|
||||
/* Support for audio timing using a timer, in addition to SDL_IOReady() */
|
||||
float frame_ticks;
|
||||
float next_frame;
|
||||
};
|
||||
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
|
||||
|
||||
#endif /* _SDL_artscaudio_h */
|
||||
#endif /* SDL_artsaudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_coreaudio_h
|
||||
#define _SDL_coreaudio_h
|
||||
#ifndef SDL_coreaudio_h_
|
||||
#define SDL_coreaudio_h_
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ struct SDL_PrivateAudioData
|
|||
{
|
||||
SDL_Thread *thread;
|
||||
AudioQueueRef audioQueue;
|
||||
AudioQueueBufferRef audioBuffer[2];
|
||||
AudioQueueBufferRef *audioBuffer;
|
||||
void *buffer;
|
||||
UInt32 bufferOffset;
|
||||
UInt32 bufferSize;
|
||||
|
|
@ -63,5 +63,6 @@ struct SDL_PrivateAudioData
|
|||
#endif
|
||||
};
|
||||
|
||||
#endif /* _SDL_coreaudio_h */
|
||||
#endif /* SDL_coreaudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
/* !!! FIXME: clean out some of the macro salsa in here. */
|
||||
|
||||
#include "SDL_audio.h"
|
||||
#include "SDL_hints.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_sysaudio.h"
|
||||
#include "SDL_coreaudio.h"
|
||||
|
|
@ -285,9 +286,9 @@ static void interruption_begin(_THIS)
|
|||
static void interruption_end(_THIS)
|
||||
{
|
||||
if (this != NULL && this->hidden != NULL && this->hidden->audioQueue != NULL
|
||||
&& this->hidden->interrupted) {
|
||||
&& this->hidden->interrupted
|
||||
&& AudioQueueStart(this->hidden->audioQueue, NULL) == AVAudioSessionErrorCodeNone) {
|
||||
this->hidden->interrupted = SDL_FALSE;
|
||||
AudioQueueStart(this->hidden->audioQueue, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -325,7 +326,8 @@ static BOOL update_audio_session(_THIS, SDL_bool open)
|
|||
@autoreleasepool {
|
||||
AVAudioSession *session = [AVAudioSession sharedInstance];
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
NSString *category;
|
||||
/* Set category to ambient by default so that other music continues playing. */
|
||||
NSString *category = AVAudioSessionCategoryAmbient;
|
||||
NSError *err = nil;
|
||||
|
||||
if (open_playback_devices && open_capture_devices) {
|
||||
|
|
@ -333,10 +335,17 @@ static BOOL update_audio_session(_THIS, SDL_bool open)
|
|||
} else if (open_capture_devices) {
|
||||
category = AVAudioSessionCategoryRecord;
|
||||
} else {
|
||||
/* Set category to ambient 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. */
|
||||
category = AVAudioSessionCategoryAmbient;
|
||||
const char *hint = SDL_GetHint(SDL_HINT_AUDIO_CATEGORY);
|
||||
if (hint) {
|
||||
if (SDL_strcasecmp(hint, "AVAudioSessionCategoryAmbient") == 0) {
|
||||
category = AVAudioSessionCategoryAmbient;
|
||||
} else if (SDL_strcasecmp(hint, "AVAudioSessionCategorySoloAmbient") == 0) {
|
||||
category = AVAudioSessionCategorySoloAmbient;
|
||||
} else if (SDL_strcasecmp(hint, "AVAudioSessionCategoryPlayback") == 0 ||
|
||||
SDL_strcasecmp(hint, "playback") == 0) {
|
||||
category = AVAudioSessionCategoryPlayback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (![session setCategory:category error:&err]) {
|
||||
|
|
@ -400,8 +409,12 @@ static void
|
|||
outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
|
||||
{
|
||||
SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
|
||||
if (SDL_AtomicGet(&this->hidden->shutdown)) {
|
||||
return; /* don't do anything. */
|
||||
}
|
||||
|
||||
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
|
||||
/* Supply silence if audio is enabled and not paused */
|
||||
/* Supply silence if audio is not enabled or paused */
|
||||
SDL_memset(inBuffer->mAudioData, this->spec.silence, inBuffer->mAudioDataBytesCapacity);
|
||||
} else {
|
||||
UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
|
||||
|
|
@ -412,7 +425,7 @@ outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffe
|
|||
if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
|
||||
/* Generate the data */
|
||||
SDL_LockMutex(this->mixer_lock);
|
||||
(*this->spec.callback)(this->spec.userdata,
|
||||
(*this->callbackspec.callback)(this->callbackspec.userdata,
|
||||
this->hidden->buffer, this->hidden->bufferSize);
|
||||
SDL_UnlockMutex(this->mixer_lock);
|
||||
this->hidden->bufferOffset = 0;
|
||||
|
|
@ -430,9 +443,7 @@ outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffe
|
|||
}
|
||||
}
|
||||
|
||||
if (!SDL_AtomicGet(&this->hidden->shutdown)) {
|
||||
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
|
||||
}
|
||||
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
|
||||
|
||||
inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity;
|
||||
}
|
||||
|
|
@ -443,7 +454,13 @@ inputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer
|
|||
const AudioStreamPacketDescription *inPacketDescs )
|
||||
{
|
||||
SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
|
||||
if (SDL_AtomicGet(&this->enabled) && !SDL_AtomicGet(&this->paused)) { /* ignore unless we're active. */
|
||||
|
||||
if (SDL_AtomicGet(&this->shutdown)) {
|
||||
return; /* don't do anything. */
|
||||
}
|
||||
|
||||
/* ignore unless we're active. */
|
||||
if (!SDL_AtomicGet(&this->paused) && SDL_AtomicGet(&this->enabled) && !SDL_AtomicGet(&this->paused)) {
|
||||
const Uint8 *ptr = (const Uint8 *) inBuffer->mAudioData;
|
||||
UInt32 remaining = inBuffer->mAudioDataByteSize;
|
||||
while (remaining > 0) {
|
||||
|
|
@ -459,16 +476,14 @@ inputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer
|
|||
|
||||
if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
|
||||
SDL_LockMutex(this->mixer_lock);
|
||||
(*this->spec.callback)(this->spec.userdata, this->hidden->buffer, this->hidden->bufferSize);
|
||||
(*this->callbackspec.callback)(this->callbackspec.userdata, this->hidden->buffer, this->hidden->bufferSize);
|
||||
SDL_UnlockMutex(this->mixer_lock);
|
||||
this->hidden->bufferOffset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!SDL_AtomicGet(&this->hidden->shutdown)) {
|
||||
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
|
||||
}
|
||||
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -514,7 +529,6 @@ static void
|
|||
COREAUDIO_CloseDevice(_THIS)
|
||||
{
|
||||
const SDL_bool iscapture = this->iscapture;
|
||||
int i;
|
||||
|
||||
/* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */
|
||||
/* !!! FIXME: (we only do a "default" device on iOS right now...can we do more?) */
|
||||
|
|
@ -527,24 +541,24 @@ COREAUDIO_CloseDevice(_THIS)
|
|||
update_audio_session(this, SDL_FALSE);
|
||||
#endif
|
||||
|
||||
/* if callback fires again, feed silence; don't call into the app. */
|
||||
SDL_AtomicSet(&this->paused, 1);
|
||||
|
||||
if (this->hidden->audioQueue) {
|
||||
AudioQueueDispose(this->hidden->audioQueue, 1);
|
||||
}
|
||||
|
||||
if (this->hidden->thread) {
|
||||
SDL_AtomicSet(&this->hidden->shutdown, 1);
|
||||
SDL_WaitThread(this->hidden->thread, NULL);
|
||||
}
|
||||
|
||||
if (this->hidden->audioQueue) {
|
||||
for (i = 0; i < SDL_arraysize(this->hidden->audioBuffer); i++) {
|
||||
if (this->hidden->audioBuffer[i]) {
|
||||
AudioQueueFreeBuffer(this->hidden->audioQueue, this->hidden->audioBuffer[i]);
|
||||
}
|
||||
}
|
||||
AudioQueueDispose(this->hidden->audioQueue, 1);
|
||||
}
|
||||
|
||||
if (this->hidden->ready_semaphore) {
|
||||
SDL_DestroySemaphore(this->hidden->ready_semaphore);
|
||||
}
|
||||
|
||||
/* AudioQueueDispose() frees the actual buffer objects. */
|
||||
SDL_free(this->hidden->audioBuffer);
|
||||
SDL_free(this->hidden->thread_error);
|
||||
SDL_free(this->hidden->buffer);
|
||||
SDL_free(this->hidden);
|
||||
|
|
@ -663,7 +677,31 @@ prepare_audioqueue(_THIS)
|
|||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < SDL_arraysize(this->hidden->audioBuffer); i++) {
|
||||
/* Make sure we can feed the device a minimum amount of time */
|
||||
double MINIMUM_AUDIO_BUFFER_TIME_MS = 15.0;
|
||||
#if defined(__IPHONEOS__)
|
||||
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1) {
|
||||
/* Older iOS hardware, use 40 ms as a minimum time */
|
||||
MINIMUM_AUDIO_BUFFER_TIME_MS = 40.0;
|
||||
}
|
||||
#endif
|
||||
const double msecs = (this->spec.samples / ((double) this->spec.freq)) * 1000.0;
|
||||
int numAudioBuffers = 2;
|
||||
if (msecs < MINIMUM_AUDIO_BUFFER_TIME_MS) { /* use more buffers if we have a VERY small sample set. */
|
||||
numAudioBuffers = ((int)SDL_ceil(MINIMUM_AUDIO_BUFFER_TIME_MS / msecs) * 2);
|
||||
}
|
||||
|
||||
this->hidden->audioBuffer = SDL_calloc(1, sizeof (AudioQueueBufferRef) * numAudioBuffers);
|
||||
if (this->hidden->audioBuffer == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if DEBUG_COREAUDIO
|
||||
printf("COREAUDIO: numAudioBuffers == %d\n", numAudioBuffers);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < numAudioBuffers; i++) {
|
||||
result = AudioQueueAllocateBuffer(this->hidden->audioQueue, this->spec.size, &this->hidden->audioBuffer[i]);
|
||||
CHECK_RESULT("AudioQueueAllocateBuffer");
|
||||
SDL_memset(this->hidden->audioBuffer[i]->mAudioData, this->spec.silence, this->hidden->audioBuffer[i]->mAudioDataBytesCapacity);
|
||||
|
|
@ -696,10 +734,7 @@ audioqueue_thread(void *arg)
|
|||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
|
||||
}
|
||||
|
||||
if (this->iscapture) { /* just stop immediately for capture devices. */
|
||||
AudioQueueStop(this->hidden->audioQueue, 1);
|
||||
} else { /* Drain off any pending playback. */
|
||||
AudioQueueStop(this->hidden->audioQueue, 0);
|
||||
if (!this->iscapture) { /* Drain off any pending playback. */
|
||||
const CFTimeInterval secs = (((this->spec.size / (SDL_AUDIO_BITSIZE(this->spec.format) / 8)) / this->spec.channels) / ((CFTimeInterval) this->spec.freq)) * 2.0;
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, secs, 0);
|
||||
}
|
||||
|
|
@ -734,6 +769,13 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
if (!update_audio_session(this, SDL_TRUE)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Stop CoreAudio from doing expensive audio rate conversion */
|
||||
@autoreleasepool {
|
||||
AVAudioSession* session = [AVAudioSession sharedInstance];
|
||||
[session setPreferredSampleRate:this->spec.freq error:nil];
|
||||
this->spec.freq = (int)session.sampleRate;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setup a AudioStreamBasicDescription with the requested format */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -434,7 +434,6 @@ CreateCaptureBuffer(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
|
|||
LPDIRECTSOUNDCAPTURE capture = this->hidden->capture;
|
||||
LPDIRECTSOUNDCAPTUREBUFFER *capturebuf = &this->hidden->capturebuf;
|
||||
DSCBUFFERDESC format;
|
||||
// DWORD junk, cursor;
|
||||
HRESULT result;
|
||||
|
||||
SDL_zero(format);
|
||||
|
|
@ -523,8 +522,8 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
bufsize = numchunks * this->spec.size;
|
||||
if ((bufsize < DSBSIZE_MIN) || (bufsize > DSBSIZE_MAX)) {
|
||||
SDL_SetError("Sound buffer size must be between %d and %d",
|
||||
(DSBSIZE_MIN < numchunks) ? 1 : DSBSIZE_MIN / numchunks,
|
||||
DSBSIZE_MAX / numchunks);
|
||||
(int) ((DSBSIZE_MIN < numchunks) ? 1 : DSBSIZE_MIN / numchunks),
|
||||
(int) (DSBSIZE_MAX / numchunks));
|
||||
} else {
|
||||
int rc;
|
||||
WAVEFORMATEX wfmt;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_directsound_h
|
||||
#define _SDL_directsound_h
|
||||
#ifndef SDL_directsound_h_
|
||||
#define SDL_directsound_h_
|
||||
|
||||
#include "../../core/windows/SDL_directx.h"
|
||||
|
||||
|
|
@ -42,6 +42,6 @@ struct SDL_PrivateAudioData
|
|||
Uint8 *locked_buf;
|
||||
};
|
||||
|
||||
#endif /* _SDL_directsound_h */
|
||||
#endif /* SDL_directsound_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -33,6 +33,7 @@
|
|||
#include "SDL_audio.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "SDL_diskaudio.h"
|
||||
#include "SDL_log.h"
|
||||
|
||||
/* !!! FIXME: these should be SDL hints, not environment variables. */
|
||||
/* environment variables and defaults. */
|
||||
|
|
@ -160,12 +161,11 @@ DISKAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||
}
|
||||
|
||||
#if HAVE_STDIO_H
|
||||
fprintf(stderr,
|
||||
"WARNING: You are using the SDL disk i/o audio driver!\n"
|
||||
" %s file [%s].\n", iscapture ? "Reading from" : "Writing to",
|
||||
fname);
|
||||
#endif
|
||||
SDL_LogCritical(SDL_LOG_CATEGORY_AUDIO,
|
||||
"You are using the SDL disk i/o audio driver!\n");
|
||||
SDL_LogCritical(SDL_LOG_CATEGORY_AUDIO,
|
||||
" %s file [%s].\n", iscapture ? "Reading from" : "Writing to",
|
||||
fname);
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_diskaudio_h
|
||||
#define _SDL_diskaudio_h
|
||||
#ifndef SDL_diskaudio_h_
|
||||
#define SDL_diskaudio_h_
|
||||
|
||||
#include "SDL_rwops.h"
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
|
@ -37,5 +37,5 @@ struct SDL_PrivateAudioData
|
|||
Uint8 *mixbuf;
|
||||
};
|
||||
|
||||
#endif /* _SDL_diskaudio_h */
|
||||
#endif /* SDL_diskaudio_h_ */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_dspaudio_h
|
||||
#define _SDL_dspaudio_h
|
||||
#ifndef SDL_dspaudio_h_
|
||||
#define SDL_dspaudio_h_
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
|
|
@ -39,5 +39,5 @@ struct SDL_PrivateAudioData
|
|||
};
|
||||
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
|
||||
|
||||
#endif /* _SDL_dspaudio_h */
|
||||
#endif /* SDL_dspaudio_h_ */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_dummyaudio_h
|
||||
#define _SDL_dummyaudio_h
|
||||
#ifndef SDL_dummyaudio_h_
|
||||
#define SDL_dummyaudio_h_
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
|
|
@ -37,5 +37,5 @@ struct SDL_PrivateAudioData
|
|||
Uint32 initial_calls;
|
||||
};
|
||||
|
||||
#endif /* _SDL_dummyaudio_h */
|
||||
#endif /* SDL_dummyaudio_h_ */
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -26,175 +26,121 @@
|
|||
#include "SDL_log.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "SDL_emscriptenaudio.h"
|
||||
#include "SDL_assert.h"
|
||||
|
||||
#include <emscripten/emscripten.h>
|
||||
|
||||
static int
|
||||
copyData(_THIS)
|
||||
static void
|
||||
FeedAudioDevice(_THIS, const void *buf, const int buflen)
|
||||
{
|
||||
int byte_len;
|
||||
const int framelen = (SDL_AUDIO_BITSIZE(this->spec.format) / 8) * this->spec.channels;
|
||||
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!';
|
||||
}
|
||||
|
||||
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;
|
||||
for (var j = 0; j < $1; ++j) {
|
||||
channelData[j] = HEAPF32[$0 + ((j*numChannels + c) << 2) >> 2]; /* !!! FIXME: why are these shifts here? */
|
||||
}
|
||||
}
|
||||
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;
|
||||
}, buf, buflen / framelen);
|
||||
}
|
||||
|
||||
static void
|
||||
HandleAudioProcess(_THIS)
|
||||
{
|
||||
Uint8 *buf = NULL;
|
||||
int byte_len = 0;
|
||||
int bytes = SDL_AUDIO_BITSIZE(this->spec.format) / 8;
|
||||
SDL_AudioCallback callback = this->callbackspec.callback;
|
||||
const int stream_len = this->callbackspec.size;
|
||||
|
||||
/* Only do something if audio is enabled */
|
||||
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
|
||||
if (this->stream) {
|
||||
SDL_AudioStreamClear(this->stream);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->convert.needed) {
|
||||
const int bytes_in = SDL_AUDIO_BITSIZE(this->convert.src_format) / 8;
|
||||
|
||||
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);
|
||||
if (this->stream == NULL) { /* no conversion necessary. */
|
||||
SDL_assert(this->spec.size == stream_len);
|
||||
callback(this->callbackspec.userdata, this->work_buffer, stream_len);
|
||||
} else { /* streaming/converting */
|
||||
int got;
|
||||
while (SDL_AudioStreamAvailable(this->stream) < ((int) this->spec.size)) {
|
||||
callback(this->callbackspec.userdata, this->work_buffer, stream_len);
|
||||
if (SDL_AudioStreamPut(this->stream, this->work_buffer, stream_len) == -1) {
|
||||
SDL_AudioStreamClear(this->stream);
|
||||
SDL_AtomicSet(&this->enabled, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
got = SDL_AudioStreamGet(this->stream, this->work_buffer, this->spec.size);
|
||||
SDL_assert((got < 0) || (got == this->spec.size));
|
||||
if (got != this->spec.size) {
|
||||
SDL_memset(this->work_buffer, this->spec.silence, this->spec.size);
|
||||
}
|
||||
(*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] = HEAPF32[$0 + ((j*numChannels + c) << 2) >> 2];
|
||||
}
|
||||
}
|
||||
}, buf, byte_len / bytes / this->spec.channels);
|
||||
}
|
||||
FeedAudioDevice(this, this->work_buffer, this->spec.size);
|
||||
}
|
||||
|
||||
static void
|
||||
HandleCaptureProcess(_THIS)
|
||||
{
|
||||
Uint8 *buf;
|
||||
int buflen;
|
||||
SDL_AudioCallback callback = this->callbackspec.callback;
|
||||
const int stream_len = this->callbackspec.size;
|
||||
|
||||
/* Only do something if audio is enabled */
|
||||
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
|
||||
SDL_AudioStreamClear(this->stream);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->convert.needed) {
|
||||
buf = this->convert.buf;
|
||||
buflen = this->convert.len_cvt;
|
||||
} else {
|
||||
if (!this->hidden->mixbuf) {
|
||||
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size);
|
||||
if (!this->hidden->mixbuf) {
|
||||
return; /* oh well. */
|
||||
}
|
||||
}
|
||||
buf = this->hidden->mixbuf;
|
||||
buflen = this->spec.size;
|
||||
}
|
||||
|
||||
EM_ASM_ARGS({
|
||||
var numChannels = SDL2.capture.currentCaptureBuffer.numberOfChannels;
|
||||
if (numChannels == 1) { /* fastpath this a little for the common (mono) case. */
|
||||
var channelData = SDL2.capture.currentCaptureBuffer.getChannelData(0);
|
||||
for (var c = 0; c < numChannels; ++c) {
|
||||
var channelData = SDL2.capture.currentCaptureBuffer.getChannelData(c);
|
||||
if (channelData.length != $1) {
|
||||
throw 'Web Audio capture buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!';
|
||||
}
|
||||
for (var j = 0; j < $1; ++j) {
|
||||
setValue($0 + (j * 4), channelData[j], 'float');
|
||||
}
|
||||
} else {
|
||||
for (var c = 0; c < numChannels; ++c) {
|
||||
var channelData = SDL2.capture.currentCaptureBuffer.getChannelData(c);
|
||||
if (channelData.length != $1) {
|
||||
throw 'Web Audio capture buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!';
|
||||
}
|
||||
|
||||
if (numChannels == 1) { /* fastpath this a little for the common (mono) case. */
|
||||
for (var j = 0; j < $1; ++j) {
|
||||
setValue($0 + (j * 4), channelData[j], 'float');
|
||||
}
|
||||
} else {
|
||||
for (var j = 0; j < $1; ++j) {
|
||||
setValue($0 + (((j * numChannels) + c) * 4), channelData[j], 'float');
|
||||
}
|
||||
}
|
||||
}
|
||||
}, buf, (this->spec.size / sizeof (float)) / this->spec.channels);
|
||||
}, this->work_buffer, (this->spec.size / sizeof (float)) / this->spec.channels);
|
||||
|
||||
/* okay, we've got an interleaved float32 array in C now. */
|
||||
|
||||
if (this->convert.needed) {
|
||||
SDL_ConvertAudio(&this->convert);
|
||||
if (this->stream == NULL) { /* no conversion necessary. */
|
||||
SDL_assert(this->spec.size == stream_len);
|
||||
callback(this->callbackspec.userdata, this->work_buffer, stream_len);
|
||||
} else { /* streaming/converting */
|
||||
if (SDL_AudioStreamPut(this->stream, this->work_buffer, this->spec.size) == -1) {
|
||||
SDL_AtomicSet(&this->enabled, 0);
|
||||
}
|
||||
|
||||
while (SDL_AudioStreamAvailable(this->stream) >= stream_len) {
|
||||
const int got = SDL_AudioStreamGet(this->stream, this->work_buffer, stream_len);
|
||||
SDL_assert((got < 0) || (got == stream_len));
|
||||
if (got != stream_len) {
|
||||
SDL_memset(this->work_buffer, this->callbackspec.silence, stream_len);
|
||||
}
|
||||
callback(this->callbackspec.userdata, this->work_buffer, stream_len); /* Send it to the app. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Send it to the app. */
|
||||
(*this->spec.callback) (this->spec.userdata, buf, buflen);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
EMSCRIPTENAUDIO_CloseDevice(_THIS)
|
||||
{
|
||||
|
|
@ -236,8 +182,9 @@ EMSCRIPTENAUDIO_CloseDevice(_THIS)
|
|||
}
|
||||
}, this->iscapture);
|
||||
|
||||
SDL_free(this->hidden->mixbuf);
|
||||
#if 0 /* !!! FIXME: currently not used. Can we move some stuff off the SDL2 namespace? --ryan. */
|
||||
SDL_free(this->hidden);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -245,8 +192,6 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscaptu
|
|||
{
|
||||
SDL_bool valid_format = SDL_FALSE;
|
||||
SDL_AudioFormat test_format;
|
||||
int i;
|
||||
float f;
|
||||
int result;
|
||||
|
||||
/* based on parts of library_sdl.js */
|
||||
|
|
@ -293,29 +238,17 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscaptu
|
|||
}
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
#if 0 /* !!! FIXME: currently not used. Can we move some stuff off the SDL2 namespace? --ryan. */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
SDL_malloc((sizeof *this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
SDL_zerop(this->hidden);
|
||||
#endif
|
||||
|
||||
/* limit to native freq */
|
||||
const 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;
|
||||
}
|
||||
this->spec.freq = EM_ASM_INT_V({ return SDL2.audioContext.sampleRate; });
|
||||
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
|
|
@ -395,6 +328,9 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscaptu
|
|||
static int
|
||||
EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl * impl)
|
||||
{
|
||||
int available;
|
||||
int capture_available;
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = EMSCRIPTENAUDIO_OpenDevice;
|
||||
impl->CloseDevice = EMSCRIPTENAUDIO_CloseDevice;
|
||||
|
|
@ -406,7 +342,7 @@ EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl * impl)
|
|||
impl->ProvidesOwnCallbackThread = 1;
|
||||
|
||||
/* check availability */
|
||||
const int available = EM_ASM_INT_V({
|
||||
available = EM_ASM_INT_V({
|
||||
if (typeof(AudioContext) !== 'undefined') {
|
||||
return 1;
|
||||
} else if (typeof(webkitAudioContext) !== 'undefined') {
|
||||
|
|
@ -419,7 +355,7 @@ EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl * impl)
|
|||
SDL_SetError("No audio context available");
|
||||
}
|
||||
|
||||
const int capture_available = available && EM_ASM_INT_V({
|
||||
capture_available = available && EM_ASM_INT_V({
|
||||
if ((typeof(navigator.mediaDevices) !== 'undefined') && (typeof(navigator.mediaDevices.getUserMedia) !== 'undefined')) {
|
||||
return 1;
|
||||
} else if (typeof(navigator.webkitGetUserMedia) !== 'undefined') {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_emscriptenaudio_h
|
||||
#define _SDL_emscriptenaudio_h
|
||||
#ifndef SDL_emscriptenaudio_h_
|
||||
#define SDL_emscriptenaudio_h_
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
|
|
@ -30,13 +30,9 @@
|
|||
|
||||
struct SDL_PrivateAudioData
|
||||
{
|
||||
Uint8 *mixbuf;
|
||||
Uint32 mixlen;
|
||||
|
||||
Uint32 conv_in_len;
|
||||
|
||||
Uint32 write_off, read_off;
|
||||
int unused;
|
||||
};
|
||||
|
||||
#endif /* _SDL_emscriptenaudio_h */
|
||||
#endif /* SDL_emscriptenaudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_esdaudio_h
|
||||
#define _SDL_esdaudio_h
|
||||
#ifndef SDL_esdaudio_h_
|
||||
#define SDL_esdaudio_h_
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
|
|
@ -46,5 +46,6 @@ struct SDL_PrivateAudioData
|
|||
};
|
||||
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
|
||||
|
||||
#endif /* _SDL_esdaudio_h */
|
||||
#endif /* SDL_esdaudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_fsaudio_h
|
||||
#define _SDL_fsaudio_h
|
||||
#ifndef SDL_fsaudio_h_
|
||||
#define SDL_fsaudio_h_
|
||||
|
||||
#include <fusionsound/fusionsound.h>
|
||||
|
||||
|
|
@ -45,5 +45,6 @@ struct SDL_PrivateAudioData
|
|||
|
||||
};
|
||||
|
||||
#endif /* _SDL_fsaudio_h */
|
||||
#endif /* SDL_fsaudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -36,6 +36,7 @@ extern "C"
|
|||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_sysaudio.h"
|
||||
#include "SDL_haikuaudio.h"
|
||||
#include "SDL_assert.h"
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -47,26 +48,39 @@ FillSound(void *device, void *stream, size_t len,
|
|||
const media_raw_audio_format & format)
|
||||
{
|
||||
SDL_AudioDevice *audio = (SDL_AudioDevice *) device;
|
||||
SDL_AudioCallback callback = audio->callbackspec.callback;
|
||||
|
||||
/* Only do soemthing if audio is enabled */
|
||||
if (!SDL_AtomicGet(&audio->enabled)) {
|
||||
/* Only do something if audio is enabled */
|
||||
if (!SDL_AtomicGet(&audio->enabled) || SDL_AtomicGet(&audio->paused)) {
|
||||
if (audio->stream) {
|
||||
SDL_AudioStreamClear(audio->stream);
|
||||
}
|
||||
SDL_memset(stream, audio->spec.silence, len);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SDL_AtomicGet(&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);
|
||||
SDL_assert(audio->spec.size == len);
|
||||
|
||||
if (audio->stream == NULL) { /* no conversion necessary. */
|
||||
SDL_LockMutex(audio->mixer_lock);
|
||||
callback(audio->callbackspec.userdata, (Uint8 *) stream, len);
|
||||
SDL_UnlockMutex(audio->mixer_lock);
|
||||
} else { /* streaming/converting */
|
||||
const int stream_len = audio->callbackspec.size;
|
||||
const int ilen = (int) len;
|
||||
while (SDL_AudioStreamAvailable(audio->stream) < ilen) {
|
||||
callback(audio->callbackspec.userdata, audio->work_buffer, stream_len);
|
||||
if (SDL_AudioStreamPut(audio->stream, audio->work_buffer, stream_len) == -1) {
|
||||
SDL_AudioStreamClear(audio->stream);
|
||||
SDL_AtomicSet(&audio->enabled, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const int got = SDL_AudioStreamGet(audio->stream, stream, ilen);
|
||||
SDL_assert((got < 0) || (got == ilen));
|
||||
if (got != ilen) {
|
||||
SDL_memset(stream, audio->spec.silence, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_beaudio_h
|
||||
#define _SDL_beaudio_h
|
||||
#ifndef SDL_haikuaudio_h_
|
||||
#define SDL_haikuaudio_h_
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
|
|
@ -33,6 +33,6 @@ struct SDL_PrivateAudioData
|
|||
BSoundPlayer *audio_obj;
|
||||
};
|
||||
|
||||
#endif /* _SDL_beaudio_h */
|
||||
#endif /* SDL_haikuaudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
429
Engine/lib/sdl/src/audio/jack/SDL_jackaudio.c
Normal file
429
Engine/lib/sdl/src/audio/jack/SDL_jackaudio.c
Normal file
|
|
@ -0,0 +1,429 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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_JACK
|
||||
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "SDL_jackaudio.h"
|
||||
#include "SDL_loadso.h"
|
||||
#include "../../thread/SDL_systhread.h"
|
||||
|
||||
|
||||
static jack_client_t * (*JACK_jack_client_open) (const char *, jack_options_t, jack_status_t *, ...);
|
||||
static int (*JACK_jack_client_close) (jack_client_t *);
|
||||
static void (*JACK_jack_on_shutdown) (jack_client_t *, JackShutdownCallback, void *);
|
||||
static int (*JACK_jack_activate) (jack_client_t *);
|
||||
static int (*JACK_jack_deactivate) (jack_client_t *);
|
||||
static void * (*JACK_jack_port_get_buffer) (jack_port_t *, jack_nframes_t);
|
||||
static int (*JACK_jack_port_unregister) (jack_client_t *, jack_port_t *);
|
||||
static void (*JACK_jack_free) (void *);
|
||||
static const char ** (*JACK_jack_get_ports) (jack_client_t *, const char *, const char *, unsigned long);
|
||||
static jack_nframes_t (*JACK_jack_get_sample_rate) (jack_client_t *);
|
||||
static jack_nframes_t (*JACK_jack_get_buffer_size) (jack_client_t *);
|
||||
static jack_port_t * (*JACK_jack_port_register) (jack_client_t *, const char *, const char *, unsigned long, unsigned long);
|
||||
static const char * (*JACK_jack_port_name) (const jack_port_t *);
|
||||
static int (*JACK_jack_connect) (jack_client_t *, const char *, const char *);
|
||||
static int (*JACK_jack_set_process_callback) (jack_client_t *, JackProcessCallback, void *);
|
||||
|
||||
static int load_jack_syms(void);
|
||||
|
||||
|
||||
#ifdef SDL_AUDIO_DRIVER_JACK_DYNAMIC
|
||||
|
||||
static const char *jack_library = SDL_AUDIO_DRIVER_JACK_DYNAMIC;
|
||||
static void *jack_handle = NULL;
|
||||
|
||||
/* !!! FIXME: this is copy/pasted in several places now */
|
||||
static int
|
||||
load_jack_sym(const char *fn, void **addr)
|
||||
{
|
||||
*addr = SDL_LoadFunction(jack_handle, fn);
|
||||
if (*addr == NULL) {
|
||||
/* Don't call SDL_SetError(): SDL_LoadFunction already did. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
|
||||
#define SDL_JACK_SYM(x) \
|
||||
if (!load_jack_sym(#x, (void **) (char *) &JACK_##x)) return -1
|
||||
|
||||
static void
|
||||
UnloadJackLibrary(void)
|
||||
{
|
||||
if (jack_handle != NULL) {
|
||||
SDL_UnloadObject(jack_handle);
|
||||
jack_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
LoadJackLibrary(void)
|
||||
{
|
||||
int retval = 0;
|
||||
if (jack_handle == NULL) {
|
||||
jack_handle = SDL_LoadObject(jack_library);
|
||||
if (jack_handle == NULL) {
|
||||
retval = -1;
|
||||
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
|
||||
} else {
|
||||
retval = load_jack_syms();
|
||||
if (retval < 0) {
|
||||
UnloadJackLibrary();
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define SDL_JACK_SYM(x) JACK_##x = x
|
||||
|
||||
static void
|
||||
UnloadJackLibrary(void)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
LoadJackLibrary(void)
|
||||
{
|
||||
load_jack_syms();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* SDL_AUDIO_DRIVER_JACK_DYNAMIC */
|
||||
|
||||
|
||||
static int
|
||||
load_jack_syms(void)
|
||||
{
|
||||
SDL_JACK_SYM(jack_client_open);
|
||||
SDL_JACK_SYM(jack_client_close);
|
||||
SDL_JACK_SYM(jack_on_shutdown);
|
||||
SDL_JACK_SYM(jack_activate);
|
||||
SDL_JACK_SYM(jack_deactivate);
|
||||
SDL_JACK_SYM(jack_port_get_buffer);
|
||||
SDL_JACK_SYM(jack_port_unregister);
|
||||
SDL_JACK_SYM(jack_free);
|
||||
SDL_JACK_SYM(jack_get_ports);
|
||||
SDL_JACK_SYM(jack_get_sample_rate);
|
||||
SDL_JACK_SYM(jack_get_buffer_size);
|
||||
SDL_JACK_SYM(jack_port_register);
|
||||
SDL_JACK_SYM(jack_port_name);
|
||||
SDL_JACK_SYM(jack_connect);
|
||||
SDL_JACK_SYM(jack_set_process_callback);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
jackShutdownCallback(void *arg) /* JACK went away; device is lost. */
|
||||
{
|
||||
SDL_AudioDevice *this = (SDL_AudioDevice *) arg;
|
||||
SDL_OpenedAudioDeviceDisconnected(this);
|
||||
SDL_SemPost(this->hidden->iosem); /* unblock the SDL thread. */
|
||||
}
|
||||
|
||||
// !!! FIXME: implement and register these!
|
||||
//typedef int(* JackSampleRateCallback)(jack_nframes_t nframes, void *arg)
|
||||
//typedef int(* JackBufferSizeCallback)(jack_nframes_t nframes, void *arg)
|
||||
|
||||
static int
|
||||
jackProcessPlaybackCallback(jack_nframes_t nframes, void *arg)
|
||||
{
|
||||
SDL_AudioDevice *this = (SDL_AudioDevice *) arg;
|
||||
jack_port_t **ports = this->hidden->sdlports;
|
||||
const int total_channels = this->spec.channels;
|
||||
const int total_frames = this->spec.samples;
|
||||
int channelsi;
|
||||
|
||||
if (!SDL_AtomicGet(&this->enabled)) {
|
||||
/* silence the buffer to avoid repeats and corruption. */
|
||||
SDL_memset(this->hidden->iobuffer, '\0', this->spec.size);
|
||||
}
|
||||
|
||||
for (channelsi = 0; channelsi < total_channels; channelsi++) {
|
||||
float *dst = (float *) JACK_jack_port_get_buffer(ports[channelsi], nframes);
|
||||
if (dst) {
|
||||
const float *src = ((float *) this->hidden->iobuffer) + channelsi;
|
||||
int framesi;
|
||||
for (framesi = 0; framesi < total_frames; framesi++) {
|
||||
*(dst++) = *src;
|
||||
src += total_channels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SemPost(this->hidden->iosem); /* tell SDL thread we're done; refill the buffer. */
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
static void
|
||||
JACK_WaitDevice(_THIS)
|
||||
{
|
||||
if (SDL_AtomicGet(&this->enabled)) {
|
||||
if (SDL_SemWait(this->hidden->iosem) == -1) {
|
||||
SDL_OpenedAudioDeviceDisconnected(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
JACK_GetDeviceBuf(_THIS)
|
||||
{
|
||||
return (Uint8 *) this->hidden->iobuffer;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
jackProcessCaptureCallback(jack_nframes_t nframes, void *arg)
|
||||
{
|
||||
SDL_AudioDevice *this = (SDL_AudioDevice *) arg;
|
||||
if (SDL_AtomicGet(&this->enabled)) {
|
||||
jack_port_t **ports = this->hidden->sdlports;
|
||||
const int total_channels = this->spec.channels;
|
||||
const int total_frames = this->spec.samples;
|
||||
int channelsi;
|
||||
|
||||
for (channelsi = 0; channelsi < total_channels; channelsi++) {
|
||||
const float *src = (const float *) JACK_jack_port_get_buffer(ports[channelsi], nframes);
|
||||
if (src) {
|
||||
float *dst = ((float *) this->hidden->iobuffer) + channelsi;
|
||||
int framesi;
|
||||
for (framesi = 0; framesi < total_frames; framesi++) {
|
||||
*dst = *(src++);
|
||||
dst += total_channels;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SemPost(this->hidden->iosem); /* tell SDL thread we're done; new buffer is ready! */
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
static int
|
||||
JACK_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||
{
|
||||
SDL_assert(buflen == this->spec.size); /* we always fill a full buffer. */
|
||||
|
||||
/* Wait for JACK to fill the iobuffer */
|
||||
if (SDL_SemWait(this->hidden->iosem) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_memcpy(buffer, this->hidden->iobuffer, buflen);
|
||||
return buflen;
|
||||
}
|
||||
|
||||
static void
|
||||
JACK_FlushCapture(_THIS)
|
||||
{
|
||||
SDL_SemWait(this->hidden->iosem);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
JACK_CloseDevice(_THIS)
|
||||
{
|
||||
if (this->hidden->client) {
|
||||
JACK_jack_deactivate(this->hidden->client);
|
||||
|
||||
if (this->hidden->sdlports) {
|
||||
const int channels = this->spec.channels;
|
||||
int i;
|
||||
for (i = 0; i < channels; i++) {
|
||||
JACK_jack_port_unregister(this->hidden->client, this->hidden->sdlports[i]);
|
||||
}
|
||||
SDL_free(this->hidden->sdlports);
|
||||
}
|
||||
|
||||
JACK_jack_client_close(this->hidden->client);
|
||||
}
|
||||
|
||||
if (this->hidden->iosem) {
|
||||
SDL_DestroySemaphore(this->hidden->iosem);
|
||||
}
|
||||
|
||||
if (this->hidden->devports) {
|
||||
JACK_jack_free(this->hidden->devports);
|
||||
}
|
||||
|
||||
SDL_free(this->hidden->iobuffer);
|
||||
}
|
||||
|
||||
static int
|
||||
JACK_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
{
|
||||
/* Note that JACK uses "output" for capture devices (they output audio
|
||||
data to us) and "input" for playback (we input audio data to them).
|
||||
Likewise, SDL's playback port will be "output" (we write data out)
|
||||
and capture will be "input" (we read data in). */
|
||||
const unsigned long sysportflags = iscapture ? JackPortIsOutput : JackPortIsInput;
|
||||
const unsigned long sdlportflags = iscapture ? JackPortIsInput : JackPortIsOutput;
|
||||
const JackProcessCallback callback = iscapture ? jackProcessCaptureCallback : jackProcessPlaybackCallback;
|
||||
const char *sdlportstr = iscapture ? "input" : "output";
|
||||
const char **devports = NULL;
|
||||
jack_client_t *client = NULL;
|
||||
jack_status_t status;
|
||||
int channels = 0;
|
||||
int i;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, sizeof (*this->hidden));
|
||||
if (this->hidden == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
/* !!! FIXME: we _still_ need an API to specify an app name */
|
||||
client = JACK_jack_client_open("SDL", JackNoStartServer, &status, NULL);
|
||||
this->hidden->client = client;
|
||||
if (client == NULL) {
|
||||
return SDL_SetError("Can't open JACK client");
|
||||
}
|
||||
|
||||
devports = JACK_jack_get_ports(client, NULL, NULL, JackPortIsPhysical | sysportflags);
|
||||
this->hidden->devports = devports;
|
||||
if (!devports || !devports[0]) {
|
||||
return SDL_SetError("No physical JACK ports available");
|
||||
}
|
||||
|
||||
while (devports[++channels]) {
|
||||
/* spin to count devports */
|
||||
}
|
||||
|
||||
/* !!! FIXME: docs say about buffer size: "This size may change, clients that depend on it must register a bufsize_callback so they will be notified if it does." */
|
||||
|
||||
/* Jack pretty much demands what it wants. */
|
||||
this->spec.format = AUDIO_F32SYS;
|
||||
this->spec.freq = JACK_jack_get_sample_rate(client);
|
||||
this->spec.channels = channels;
|
||||
this->spec.samples = JACK_jack_get_buffer_size(client);
|
||||
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
this->hidden->iosem = SDL_CreateSemaphore(0);
|
||||
if (!this->hidden->iosem) {
|
||||
return -1; /* error was set by SDL_CreateSemaphore */
|
||||
}
|
||||
|
||||
this->hidden->iobuffer = (float *) SDL_calloc(1, this->spec.size);
|
||||
if (!this->hidden->iobuffer) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
/* Build SDL's ports, which we will connect to the device ports. */
|
||||
this->hidden->sdlports = (jack_port_t **) SDL_calloc(channels, sizeof (jack_port_t *));
|
||||
if (this->hidden->sdlports == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
for (i = 0; i < channels; i++) {
|
||||
char portname[32];
|
||||
SDL_snprintf(portname, sizeof (portname), "sdl_jack_%s_%d", sdlportstr, i);
|
||||
this->hidden->sdlports[i] = JACK_jack_port_register(client, portname, JACK_DEFAULT_AUDIO_TYPE, sdlportflags, 0);
|
||||
if (this->hidden->sdlports[i] == NULL) {
|
||||
return SDL_SetError("jack_port_register failed");
|
||||
}
|
||||
}
|
||||
|
||||
if (JACK_jack_set_process_callback(client, callback, this) != 0) {
|
||||
return SDL_SetError("JACK: Couldn't set process callback");
|
||||
}
|
||||
|
||||
JACK_jack_on_shutdown(client, jackShutdownCallback, this);
|
||||
|
||||
if (JACK_jack_activate(client) != 0) {
|
||||
return SDL_SetError("Failed to activate JACK client");
|
||||
}
|
||||
|
||||
/* once activated, we can connect all the ports. */
|
||||
for (i = 0; i < channels; i++) {
|
||||
const char *sdlport = JACK_jack_port_name(this->hidden->sdlports[i]);
|
||||
const char *srcport = iscapture ? devports[i] : sdlport;
|
||||
const char *dstport = iscapture ? sdlport : devports[i];
|
||||
if (JACK_jack_connect(client, srcport, dstport) != 0) {
|
||||
return SDL_SetError("Couldn't connect JACK ports: %s => %s", srcport, dstport);
|
||||
}
|
||||
}
|
||||
|
||||
/* don't need these anymore. */
|
||||
this->hidden->devports = NULL;
|
||||
JACK_jack_free(devports);
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
JACK_Deinitialize(void)
|
||||
{
|
||||
UnloadJackLibrary();
|
||||
}
|
||||
|
||||
static int
|
||||
JACK_Init(SDL_AudioDriverImpl * impl)
|
||||
{
|
||||
if (LoadJackLibrary() < 0) {
|
||||
return 0;
|
||||
} else {
|
||||
/* Make sure a JACK server is running and available. */
|
||||
jack_status_t status;
|
||||
jack_client_t *client = JACK_jack_client_open("SDL", JackNoStartServer, &status, NULL);
|
||||
if (client == NULL) {
|
||||
UnloadJackLibrary();
|
||||
return 0;
|
||||
}
|
||||
JACK_jack_client_close(client);
|
||||
}
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->OpenDevice = JACK_OpenDevice;
|
||||
impl->WaitDevice = JACK_WaitDevice;
|
||||
impl->GetDeviceBuf = JACK_GetDeviceBuf;
|
||||
impl->CloseDevice = JACK_CloseDevice;
|
||||
impl->Deinitialize = JACK_Deinitialize;
|
||||
impl->CaptureFromDevice = JACK_CaptureFromDevice;
|
||||
impl->FlushCapture = JACK_FlushCapture;
|
||||
impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
|
||||
impl->OnlyHasDefaultCaptureDevice = SDL_TRUE;
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
|
||||
return 1; /* this audio target is available. */
|
||||
}
|
||||
|
||||
AudioBootStrap JACK_bootstrap = {
|
||||
"jack", "JACK Audio Connection Kit", JACK_Init, 0
|
||||
};
|
||||
|
||||
#endif /* SDL_AUDIO_DRIVER_JACK */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
42
Engine/lib/sdl/src/audio/jack/SDL_jackaudio.h
Normal file
42
Engine/lib/sdl/src/audio/jack/SDL_jackaudio.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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_jackaudio_h_
|
||||
#define SDL_jackaudio_h_
|
||||
|
||||
#include <jack/jack.h>
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
{
|
||||
jack_client_t *client;
|
||||
SDL_sem *iosem;
|
||||
float *iobuffer;
|
||||
const char **devports;
|
||||
jack_port_t **sdlports;
|
||||
};
|
||||
|
||||
#endif /* SDL_jackaudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -45,29 +45,46 @@
|
|||
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) {
|
||||
static void nacl_audio_callback(void* stream, uint32_t buffer_size, PP_TimeDelta latency, void* data) {
|
||||
const int len = (int) buffer_size;
|
||||
SDL_AudioDevice* _this = (SDL_AudioDevice*) data;
|
||||
SDL_AudioCallback callback = _this->callbackspec.callback;
|
||||
|
||||
SDL_LockMutex(private->mutex); /* !!! FIXME: is this mutex necessary? */
|
||||
|
||||
if (SDL_AtomicGet(&_this->enabled) && !SDL_AtomicGet(&_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);
|
||||
/* Only do something if audio is enabled */
|
||||
if (!SDL_AtomicGet(&_this->enabled) || SDL_AtomicGet(&_this->paused)) {
|
||||
if (_this->stream) {
|
||||
SDL_AudioStreamClear(_this->stream);
|
||||
}
|
||||
} else {
|
||||
SDL_memset(samples, _this->spec.silence, buffer_size);
|
||||
SDL_memset(stream, _this->spec.silence, len);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SDL_assert(_this->spec.size == len);
|
||||
|
||||
if (_this->stream == NULL) { /* no conversion necessary. */
|
||||
SDL_LockMutex(_this->mixer_lock);
|
||||
callback(_this->callbackspec.userdata, stream, len);
|
||||
SDL_UnlockMutex(_this->mixer_lock);
|
||||
} else { /* streaming/converting */
|
||||
const int stream_len = _this->callbackspec.size;
|
||||
while (SDL_AudioStreamAvailable(_this->stream) < len) {
|
||||
callback(_this->callbackspec.userdata, _this->work_buffer, stream_len);
|
||||
if (SDL_AudioStreamPut(_this->stream, _this->work_buffer, stream_len) == -1) {
|
||||
SDL_AudioStreamClear(_this->stream);
|
||||
SDL_AtomicSet(&_this->enabled, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const int got = SDL_AudioStreamGet(_this->stream, stream, len);
|
||||
SDL_assert((got < 0) || (got == len));
|
||||
if (got != len) {
|
||||
SDL_memset(stream, _this->spec.silence, len);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(private->mutex);
|
||||
}
|
||||
|
||||
|
|
@ -89,8 +106,7 @@ NACLAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) {
|
|||
|
||||
private = (SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *private));
|
||||
if (private == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
return 0;
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
private->mutex = SDL_CreateMutex();
|
||||
|
|
@ -114,7 +130,7 @@ NACLAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) {
|
|||
/* Start audio playback while we are still on the main thread. */
|
||||
ppb_audio->StartPlayback(private->audio);
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_naclaudio_h
|
||||
#define _SDL_naclaudio_h
|
||||
#ifndef SDL_naclaudio_h_
|
||||
#define SDL_naclaudio_h_
|
||||
|
||||
#include "SDL_audio.h"
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
|
@ -38,4 +38,6 @@ typedef struct SDL_PrivateAudioData {
|
|||
PP_Resource audio;
|
||||
} SDL_PrivateAudioData;
|
||||
|
||||
#endif /* _SDL_naclaudio_h */
|
||||
#endif /* SDL_naclaudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -116,7 +116,7 @@ LoadNASLibrary(void)
|
|||
char *err = (char *) alloca(len);
|
||||
SDL_strlcpy(err, origerr, len);
|
||||
retval = -1;
|
||||
SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s\n",
|
||||
SDL_SetError("NAS: SDL_LoadObject('%s') failed: %s",
|
||||
nas_library, err);
|
||||
} else {
|
||||
retval = load_nas_syms();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_nasaudio_h
|
||||
#define _SDL_nasaudio_h
|
||||
#ifndef SDL_nasaudio_h_
|
||||
#define SDL_nasaudio_h_
|
||||
|
||||
#ifdef __sgi
|
||||
#include <nas/audiolib.h>
|
||||
|
|
@ -51,6 +51,6 @@ struct SDL_PrivateAudioData
|
|||
struct timeval last_tv;
|
||||
int buf_free;
|
||||
};
|
||||
#endif /* _SDL_nasaudio_h */
|
||||
#endif /* SDL_nasaudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,10 +20,10 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#if SDL_AUDIO_DRIVER_BSD
|
||||
#if SDL_AUDIO_DRIVER_NETBSD
|
||||
|
||||
/*
|
||||
* Driver for native OpenBSD/NetBSD audio(4).
|
||||
* Driver for native NetBSD audio(4).
|
||||
* vedge@vedge.com.ar.
|
||||
*/
|
||||
|
||||
|
|
@ -38,9 +38,10 @@
|
|||
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "../../core/unix/SDL_poll.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_audiodev_c.h"
|
||||
#include "SDL_bsdaudio.h"
|
||||
#include "SDL_netbsdaudio.h"
|
||||
|
||||
/* Use timer for synchronization */
|
||||
/* #define USE_TIMER_SYNC */
|
||||
|
|
@ -50,14 +51,14 @@
|
|||
|
||||
|
||||
static void
|
||||
BSDAUDIO_DetectDevices(void)
|
||||
NETBSDAUDIO_DetectDevices(void)
|
||||
{
|
||||
SDL_EnumUnixAudioDevices(0, NULL);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
BSDAUDIO_Status(_THIS)
|
||||
NETBSDAUDIO_Status(_THIS)
|
||||
{
|
||||
#ifdef DEBUG_AUDIO
|
||||
/* *INDENT-OFF* */
|
||||
|
|
@ -121,7 +122,7 @@ BSDAUDIO_Status(_THIS)
|
|||
|
||||
/* This function waits until it is possible to write a full sound buffer */
|
||||
static void
|
||||
BSDAUDIO_WaitDevice(_THIS)
|
||||
NETBSDAUDIO_WaitDevice(_THIS)
|
||||
{
|
||||
#ifndef USE_BLOCKING_WRITES /* Not necessary when using blocking writes */
|
||||
/* See if we need to use timed audio synchronization */
|
||||
|
|
@ -134,18 +135,11 @@ BSDAUDIO_WaitDevice(_THIS)
|
|||
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;
|
||||
/* Use SDL_IOReady() for audio synchronization */
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr, "Waiting for audio to get ready\n");
|
||||
#endif
|
||||
if (select(this->hidden->audio_fd + 1, NULL, &fdset, NULL, &timeout)
|
||||
if (SDL_IOReady(this->hidden->audio_fd, SDL_TRUE, 10 * 1000)
|
||||
<= 0) {
|
||||
const char *message =
|
||||
"Audio timeout - buggy audio driver? (disabled)";
|
||||
|
|
@ -169,7 +163,7 @@ BSDAUDIO_WaitDevice(_THIS)
|
|||
}
|
||||
|
||||
static void
|
||||
BSDAUDIO_PlayDevice(_THIS)
|
||||
NETBSDAUDIO_PlayDevice(_THIS)
|
||||
{
|
||||
int written, p = 0;
|
||||
|
||||
|
|
@ -208,19 +202,19 @@ BSDAUDIO_PlayDevice(_THIS)
|
|||
}
|
||||
|
||||
static Uint8 *
|
||||
BSDAUDIO_GetDeviceBuf(_THIS)
|
||||
NETBSDAUDIO_GetDeviceBuf(_THIS)
|
||||
{
|
||||
return (this->hidden->mixbuf);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
BSDAUDIO_CaptureFromDevice(_THIS, void *_buffer, int buflen)
|
||||
NETBSDAUDIO_CaptureFromDevice(_THIS, void *_buffer, int buflen)
|
||||
{
|
||||
Uint8 *buffer = (Uint8 *) _buffer;
|
||||
int br, p = 0;
|
||||
|
||||
/* Write the audio data, checking for EAGAIN on broken audio drivers */
|
||||
/* Capture the audio data, checking for EAGAIN on broken audio drivers */
|
||||
do {
|
||||
br = read(this->hidden->audio_fd, buffer + p, buflen - p);
|
||||
if (br > 0)
|
||||
|
|
@ -243,7 +237,7 @@ BSDAUDIO_CaptureFromDevice(_THIS, void *_buffer, int buflen)
|
|||
}
|
||||
|
||||
static void
|
||||
BSDAUDIO_FlushCapture(_THIS)
|
||||
NETBSDAUDIO_FlushCapture(_THIS)
|
||||
{
|
||||
audio_info_t info;
|
||||
size_t remain;
|
||||
|
|
@ -265,7 +259,7 @@ BSDAUDIO_FlushCapture(_THIS)
|
|||
}
|
||||
|
||||
static void
|
||||
BSDAUDIO_CloseDevice(_THIS)
|
||||
NETBSDAUDIO_CloseDevice(_THIS)
|
||||
{
|
||||
if (this->hidden->audio_fd >= 0) {
|
||||
close(this->hidden->audio_fd);
|
||||
|
|
@ -275,7 +269,7 @@ BSDAUDIO_CloseDevice(_THIS)
|
|||
}
|
||||
|
||||
static int
|
||||
BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
{
|
||||
const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT;
|
||||
SDL_AudioFormat format = 0;
|
||||
|
|
@ -383,24 +377,24 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
|
||||
}
|
||||
|
||||
BSDAUDIO_Status(this);
|
||||
NETBSDAUDIO_Status(this);
|
||||
|
||||
/* We're ready to rock and roll. :-) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
BSDAUDIO_Init(SDL_AudioDriverImpl * impl)
|
||||
NETBSDAUDIO_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->CaptureFromDevice = BSDAUDIO_CaptureFromDevice;
|
||||
impl->FlushCapture = BSDAUDIO_FlushCapture;
|
||||
impl->DetectDevices = NETBSDAUDIO_DetectDevices;
|
||||
impl->OpenDevice = NETBSDAUDIO_OpenDevice;
|
||||
impl->PlayDevice = NETBSDAUDIO_PlayDevice;
|
||||
impl->WaitDevice = NETBSDAUDIO_WaitDevice;
|
||||
impl->GetDeviceBuf = NETBSDAUDIO_GetDeviceBuf;
|
||||
impl->CloseDevice = NETBSDAUDIO_CloseDevice;
|
||||
impl->CaptureFromDevice = NETBSDAUDIO_CaptureFromDevice;
|
||||
impl->FlushCapture = NETBSDAUDIO_FlushCapture;
|
||||
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
impl->AllowsArbitraryDeviceNames = 1;
|
||||
|
|
@ -409,10 +403,10 @@ BSDAUDIO_Init(SDL_AudioDriverImpl * impl)
|
|||
}
|
||||
|
||||
|
||||
AudioBootStrap BSD_AUDIO_bootstrap = {
|
||||
"bsd", "BSD audio", BSDAUDIO_Init, 0
|
||||
AudioBootStrap NETBSDAUDIO_bootstrap = {
|
||||
"netbsd", "NetBSD audio", NETBSDAUDIO_Init, 0
|
||||
};
|
||||
|
||||
#endif /* SDL_AUDIO_DRIVER_BSD */
|
||||
#endif /* SDL_AUDIO_DRIVER_NETBSD */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_bsdaudio_h
|
||||
#define _SDL_bsdaudio_h
|
||||
#ifndef SDL_netbsdaudio_h_
|
||||
#define SDL_netbsdaudio_h_
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
|
|
@ -32,20 +32,17 @@ 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() */
|
||||
/* Support for audio timing using a timer, in addition to SDL_IOReady() */
|
||||
float frame_ticks;
|
||||
float next_frame;
|
||||
};
|
||||
|
||||
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
|
||||
|
||||
#endif /* _SDL_bsdaudio_h */
|
||||
#endif /* SDL_netbsdaudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -36,9 +36,10 @@
|
|||
#include "SDL_audio.h"
|
||||
#include "SDL_stdinc.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../../core/unix/SDL_poll.h"
|
||||
#include "SDL_paudio.h"
|
||||
|
||||
#define DEBUG_AUDIO 0
|
||||
/* #define DEBUG_AUDIO */
|
||||
|
||||
/* 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. */
|
||||
|
|
@ -137,44 +138,31 @@ PAUDIO_WaitDevice(_THIS)
|
|||
SDL_Delay(ticks);
|
||||
}
|
||||
} else {
|
||||
int timeoutMS;
|
||||
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;
|
||||
timeoutMS = 10 * 1000;
|
||||
} 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;
|
||||
timeoutMS = paud_bufinfo.write_buf_time;
|
||||
#ifdef DEBUG_AUDIO
|
||||
fprintf(stderr,
|
||||
"Waiting for write_buf_time=%ld,%ld\n",
|
||||
timeout.tv_sec, timeout.tv_usec);
|
||||
fprintf(stderr, "Waiting for write_buf_time=%d ms\n", timeoutMS);
|
||||
#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)";
|
||||
if (SDL_IOReady(this->hidden->audio_fd, SDL_TRUE, timeoutMS) <= 0) {
|
||||
/*
|
||||
* 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);
|
||||
fprintf(stderr, "SDL: %s - Audio timeout - buggy audio driver? (disabled)\n", strerror(errno));
|
||||
SDL_OpenedAudioDeviceDisconnected(this);
|
||||
/* Don't try to close - may hang */
|
||||
this->hidden->audio_fd = -1;
|
||||
|
|
@ -245,7 +233,6 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
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;
|
||||
|
|
@ -487,7 +474,7 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
return SDL_SetError("Can't start audio play");
|
||||
}
|
||||
|
||||
/* Check to see if we need to use select() workaround */
|
||||
/* Check to see if we need to use SDL_IOReady() workaround */
|
||||
if (workaround != NULL) {
|
||||
this->hidden->frame_ticks = (float) (this->spec.samples * 1000) /
|
||||
this->spec.freq;
|
||||
|
|
@ -510,11 +497,11 @@ PAUDIO_Init(SDL_AudioDriverImpl * impl)
|
|||
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->OpenDevice = PAUDIO_OpenDevice;
|
||||
impl->PlayDevice = PAUDIO_PlayDevice;
|
||||
impl->PlayDevice = PAUDIO_WaitDevice;
|
||||
impl->GetDeviceBuf = PAUDIO_GetDeviceBuf;
|
||||
impl->CloseDevice = PAUDIO_CloseDevice;
|
||||
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: add device enum! */
|
||||
|
||||
return 1; /* this audio target is available. */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_paudaudio_h
|
||||
#define _SDL_paudaudio_h
|
||||
#ifndef SDL_paudio_h_
|
||||
#define SDL_paudio_h_
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
|
|
@ -37,11 +37,12 @@ struct SDL_PrivateAudioData
|
|||
Uint8 *mixbuf;
|
||||
int mixlen;
|
||||
|
||||
/* Support for audio timing using a timer, in addition to select() */
|
||||
/* Support for audio timing using a timer, in addition to SDL_IOReady() */
|
||||
float frame_ticks;
|
||||
float next_frame;
|
||||
};
|
||||
#define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */
|
||||
|
||||
#endif /* _SDL_paudaudio_h */
|
||||
#endif /* SDL_paudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -80,6 +80,7 @@ PSPAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
if (this->spec.channels == 1) {
|
||||
format = PSP_AUDIO_FORMAT_MONO;
|
||||
} else {
|
||||
this->spec.channels = 2;
|
||||
format = PSP_AUDIO_FORMAT_STEREO;
|
||||
}
|
||||
this->hidden->channel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, this->spec.samples, format);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -19,8 +19,8 @@
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef _SDL_pspaudio_h
|
||||
#define _SDL_pspaudio_h
|
||||
#ifndef SDL_pspaudio_h_
|
||||
#define SDL_pspaudio_h_
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
|
|
@ -40,6 +40,6 @@ struct SDL_PrivateAudioData {
|
|||
int next_buffer;
|
||||
};
|
||||
|
||||
#endif /* _SDL_pspaudio_h */
|
||||
/* vim: ts=4 sw=4
|
||||
*/
|
||||
#endif /* SDL_pspaudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -37,7 +37,6 @@
|
|||
#endif
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <pulse/pulseaudio.h>
|
||||
|
||||
#include "SDL_timer.h"
|
||||
|
|
@ -250,12 +249,6 @@ getAppName(void)
|
|||
return "SDL Application"; /* oh well. */
|
||||
}
|
||||
|
||||
static void
|
||||
stream_operation_complete_no_op(pa_stream *s, int success, void *userdata)
|
||||
{
|
||||
/* no-op for pa_stream_drain(), etc, to use for callback. */
|
||||
}
|
||||
|
||||
static void
|
||||
WaitForPulseOperation(pa_mainloop *mainloop, pa_operation *o)
|
||||
{
|
||||
|
|
@ -427,6 +420,8 @@ static void
|
|||
PULSEAUDIO_FlushCapture(_THIS)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = this->hidden;
|
||||
const void *data = NULL;
|
||||
size_t nbytes = 0;
|
||||
|
||||
if (h->capturebuf != NULL) {
|
||||
PULSEAUDIO_pa_stream_drop(h->stream);
|
||||
|
|
@ -434,7 +429,22 @@ PULSEAUDIO_FlushCapture(_THIS)
|
|||
h->capturelen = 0;
|
||||
}
|
||||
|
||||
WaitForPulseOperation(h->mainloop, PULSEAUDIO_pa_stream_flush(h->stream, stream_operation_complete_no_op, NULL));
|
||||
while (SDL_TRUE) {
|
||||
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; /* uhoh, pulse failed! */
|
||||
}
|
||||
|
||||
if (PULSEAUDIO_pa_stream_readable_size(h->stream) == 0) {
|
||||
break; /* no data available, so we're done. */
|
||||
}
|
||||
|
||||
/* a new fragment is available! Just dump it. */
|
||||
PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes);
|
||||
PULSEAUDIO_pa_stream_drop(h->stream); /* drop this fragment. */
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_pulseaudio_h
|
||||
#define _SDL_pulseaudio_h
|
||||
#ifndef SDL_pulseaudio_h_
|
||||
#define SDL_pulseaudio_h_
|
||||
|
||||
#include <pulse/simple.h>
|
||||
|
||||
|
|
@ -47,6 +47,6 @@ struct SDL_PrivateAudioData
|
|||
int capturelen;
|
||||
};
|
||||
|
||||
#endif /* _SDL_pulseaudio_h */
|
||||
#endif /* SDL_pulseaudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -45,6 +45,7 @@
|
|||
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "../../core/unix/SDL_poll.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "SDL_qsa_audio.h"
|
||||
|
||||
|
|
@ -56,24 +57,6 @@
|
|||
#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 */
|
||||
|
|
@ -97,40 +80,16 @@ 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);
|
||||
struct sched_param param;
|
||||
if (SchedGet(0, 0, ¶m) != -1) {
|
||||
param.sched_priority = param.sched_curpriority + 15;
|
||||
SchedSet(0, 0, SCHED_NOCHANGE, ¶m);
|
||||
}
|
||||
}
|
||||
|
||||
/* PCM channel parameters initialize function */
|
||||
|
|
@ -155,67 +114,25 @@ QSA_InitAudioParams(snd_pcm_channel_params_t * cpars)
|
|||
static void
|
||||
QSA_WaitDevice(_THIS)
|
||||
{
|
||||
fd_set wfds;
|
||||
fd_set rfds;
|
||||
int selectret;
|
||||
struct timeval timeout;
|
||||
int result;
|
||||
|
||||
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;
|
||||
/* 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 ! */
|
||||
result = SDL_IOReady(this->hidden->audio_fd, !this->hidden->iscapture, 2 * 1000);
|
||||
switch (result) {
|
||||
case -1:
|
||||
SDL_SetError("QSA: SDL_IOReady() failed: %s", strerror(errno));
|
||||
break;
|
||||
case 0:
|
||||
SDL_SetError("QSA: timeout on buffer waiting occured");
|
||||
this->hidden->timeout_on_wait = 1;
|
||||
break;
|
||||
default:
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -357,7 +274,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
if (this->hidden == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
SDL_zerop(this->hidden);
|
||||
|
||||
/* Initialize channel transfer parameters to default */
|
||||
QSA_InitAudioParams(&cparams);
|
||||
|
|
@ -371,13 +287,13 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
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);
|
||||
iscapture ? SND_PCM_OPEN_CAPTURE : SND_PCM_OPEN_PLAYBACK);
|
||||
} 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);
|
||||
iscapture ? SND_PCM_OPEN_CAPTURE : SND_PCM_OPEN_PLAYBACK);
|
||||
}
|
||||
|
||||
/* Check if requested device is opened */
|
||||
|
|
@ -386,16 +302,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
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) {
|
||||
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 */
|
||||
|
|
@ -494,7 +400,7 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
/* Setup the transfer parameters according to cparams */
|
||||
status = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams);
|
||||
if (status < 0) {
|
||||
return QSA_SetError("snd_pcm_channel_params", status);
|
||||
return QSA_SetError("snd_pcm_plugin_params", status);
|
||||
}
|
||||
|
||||
/* Make sure channel is setup right one last time */
|
||||
|
|
@ -722,9 +628,6 @@ QSA_Deinitialize(void)
|
|||
static int
|
||||
QSA_Init(SDL_AudioDriverImpl * impl)
|
||||
{
|
||||
snd_pcm_t *handle = NULL;
|
||||
int32_t status = 0;
|
||||
|
||||
/* Clear devices array */
|
||||
SDL_zero(qsa_playback_device);
|
||||
SDL_zero(qsa_capture_device);
|
||||
|
|
@ -745,20 +648,12 @@ QSA_Init(SDL_AudioDriverImpl * impl)
|
|||
impl->LockDevice = NULL;
|
||||
impl->UnlockDevice = NULL;
|
||||
|
||||
impl->OnlyHasDefaultOutputDevice = 0;
|
||||
impl->ProvidesOwnCallbackThread = 0;
|
||||
impl->SkipMixerLock = 0;
|
||||
impl->HasCaptureSupport = 1;
|
||||
impl->OnlyHasDefaultOutputDevice = 0;
|
||||
impl->OnlyHasDefaultCaptureDevice = 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. */
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
|
|||
|
|
@ -1,761 +0,0 @@
|
|||
#!/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-2016 Sam Lantinga <slouken\@libsdl.org>
|
||||
|
||||
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 ...
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -33,6 +33,7 @@
|
|||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "SDL_audio.h"
|
||||
|
|
@ -43,6 +44,14 @@
|
|||
#include "SDL_loadso.h"
|
||||
#endif
|
||||
|
||||
#ifndef INFTIM
|
||||
#define INFTIM -1
|
||||
#endif
|
||||
|
||||
#ifndef SIO_DEVANY
|
||||
#define SIO_DEVANY "default"
|
||||
#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 *);
|
||||
|
|
@ -51,6 +60,10 @@ 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 int (*SNDIO_sio_nfds)(struct sio_hdl *);
|
||||
static int (*SNDIO_sio_pollfd)(struct sio_hdl *, struct pollfd *, int);
|
||||
static int (*SNDIO_sio_revents)(struct sio_hdl *, struct pollfd *);
|
||||
static int (*SNDIO_sio_eof)(struct sio_hdl *);
|
||||
static void (*SNDIO_sio_initpar)(struct sio_par *);
|
||||
|
||||
#ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
|
||||
|
|
@ -87,6 +100,10 @@ load_sndio_syms(void)
|
|||
SDL_SNDIO_SYM(sio_stop);
|
||||
SDL_SNDIO_SYM(sio_read);
|
||||
SDL_SNDIO_SYM(sio_write);
|
||||
SDL_SNDIO_SYM(sio_nfds);
|
||||
SDL_SNDIO_SYM(sio_pollfd);
|
||||
SDL_SNDIO_SYM(sio_revents);
|
||||
SDL_SNDIO_SYM(sio_eof);
|
||||
SDL_SNDIO_SYM(sio_initpar);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -164,6 +181,41 @@ SNDIO_PlayDevice(_THIS)
|
|||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
SNDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||
{
|
||||
size_t r;
|
||||
int revents;
|
||||
int nfds;
|
||||
|
||||
/* Emulate a blocking read */
|
||||
r = SNDIO_sio_read(this->hidden->dev, buffer, buflen);
|
||||
while (r == 0 && !SNDIO_sio_eof(this->hidden->dev)) {
|
||||
if ((nfds = SNDIO_sio_pollfd(this->hidden->dev, this->hidden->pfd, POLLIN)) <= 0
|
||||
|| poll(this->hidden->pfd, nfds, INFTIM) < 0) {
|
||||
return -1;
|
||||
}
|
||||
revents = SNDIO_sio_revents(this->hidden->dev, this->hidden->pfd);
|
||||
if (revents & POLLIN) {
|
||||
r = SNDIO_sio_read(this->hidden->dev, buffer, buflen);
|
||||
}
|
||||
if (revents & POLLHUP) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (int) r;
|
||||
}
|
||||
|
||||
static void
|
||||
SNDIO_FlushCapture(_THIS)
|
||||
{
|
||||
char buf[512];
|
||||
|
||||
while (SNDIO_sio_read(this->hidden->dev, buf, sizeof(buf)) != 0) {
|
||||
/* do nothing */;
|
||||
}
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
SNDIO_GetDeviceBuf(_THIS)
|
||||
{
|
||||
|
|
@ -173,6 +225,9 @@ SNDIO_GetDeviceBuf(_THIS)
|
|||
static void
|
||||
SNDIO_CloseDevice(_THIS)
|
||||
{
|
||||
if ( this->hidden->pfd != NULL ) {
|
||||
SDL_free(this->hidden->pfd);
|
||||
}
|
||||
if ( this->hidden->dev != NULL ) {
|
||||
SNDIO_sio_stop(this->hidden->dev);
|
||||
SNDIO_sio_close(this->hidden->dev);
|
||||
|
|
@ -197,11 +252,19 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
|
||||
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) {
|
||||
/* Capture devices must be non-blocking for SNDIO_FlushCapture */
|
||||
if ((this->hidden->dev =
|
||||
SNDIO_sio_open(devname != NULL ? devname : SIO_DEVANY,
|
||||
iscapture ? SIO_REC : SIO_PLAY, iscapture)) == NULL) {
|
||||
return SDL_SetError("sio_open() failed");
|
||||
}
|
||||
|
||||
/* Allocate the pollfd array for capture devices */
|
||||
if (iscapture && (this->hidden->pfd =
|
||||
SDL_malloc(sizeof(struct pollfd) * SNDIO_sio_nfds(this->hidden->dev))) == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
SNDIO_sio_initpar(&par);
|
||||
|
||||
par.rate = this->spec.freq;
|
||||
|
|
@ -300,8 +363,12 @@ SNDIO_Init(SDL_AudioDriverImpl * impl)
|
|||
impl->PlayDevice = SNDIO_PlayDevice;
|
||||
impl->GetDeviceBuf = SNDIO_GetDeviceBuf;
|
||||
impl->CloseDevice = SNDIO_CloseDevice;
|
||||
impl->CaptureFromDevice = SNDIO_CaptureFromDevice;
|
||||
impl->FlushCapture = SNDIO_FlushCapture;
|
||||
impl->Deinitialize = SNDIO_Deinitialize;
|
||||
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: sndio can handle multiple devices. */
|
||||
|
||||
impl->AllowsArbitraryDeviceNames = 1;
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
|
||||
return 1; /* this audio target is available. */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,9 +20,10 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_sndioaudio_h
|
||||
#define _SDL_sndioaudio_h
|
||||
#ifndef SDL_sndioaudio_h_
|
||||
#define SDL_sndioaudio_h_
|
||||
|
||||
#include <poll.h>
|
||||
#include <sndio.h>
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
|
@ -38,8 +39,11 @@ struct SDL_PrivateAudioData
|
|||
/* Raw mixing buffer */
|
||||
Uint8 *mixbuf;
|
||||
int mixlen;
|
||||
|
||||
/* Polling structures for non-blocking sndio devices */
|
||||
struct pollfd *pfd;
|
||||
};
|
||||
|
||||
#endif /* _SDL_sndioaudio_h */
|
||||
#endif /* SDL_sndioaudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "../../core/unix/SDL_poll.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_audiodev_c.h"
|
||||
#include "SDL_sunaudio.h"
|
||||
|
|
@ -97,11 +98,7 @@ SUNAUDIO_WaitDevice(_THIS)
|
|||
}
|
||||
}
|
||||
#else
|
||||
fd_set fdset;
|
||||
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(this->hidden->audio_fd, &fdset);
|
||||
select(this->hidden->audio_fd + 1, NULL, &fdset, NULL, NULL);
|
||||
SDL_IOReady(this->hidden->audio_fd, SDL_TRUE, -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -193,6 +190,10 @@ SUNAUDIO_CloseDevice(_THIS)
|
|||
static int
|
||||
SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
{
|
||||
#ifdef AUDIO_SETINFO
|
||||
int enc;
|
||||
#endif
|
||||
int desired_freq = 0;
|
||||
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
|
||||
SDL_AudioFormat format = 0;
|
||||
audio_info_t info;
|
||||
|
|
@ -220,10 +221,7 @@ SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
|||
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
|
||||
}
|
||||
|
||||
#ifdef AUDIO_SETINFO
|
||||
int enc;
|
||||
#endif
|
||||
int desired_freq = this->spec.freq;
|
||||
desired_freq = this->spec.freq;
|
||||
|
||||
/* Determine the audio parameters from the AudioSpec */
|
||||
switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_sunaudio_h
|
||||
#define _SDL_sunaudio_h
|
||||
#ifndef SDL_sunaudio_h_
|
||||
#define SDL_sunaudio_h_
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
|
|
@ -42,6 +42,6 @@ struct SDL_PrivateAudioData
|
|||
int frequency; /* The audio frequency in KHz */
|
||||
};
|
||||
|
||||
#endif /* _SDL_sunaudio_h */
|
||||
#endif /* SDL_sunaudio_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
779
Engine/lib/sdl/src/audio/wasapi/SDL_wasapi.c
Normal file
779
Engine/lib/sdl/src/audio/wasapi/SDL_wasapi.c
Normal file
|
|
@ -0,0 +1,779 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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_WASAPI
|
||||
|
||||
#include "../../core/windows/SDL_windows.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_sysaudio.h"
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_log.h"
|
||||
|
||||
#define COBJMACROS
|
||||
#include <mmdeviceapi.h>
|
||||
#include <audioclient.h>
|
||||
|
||||
#include "SDL_wasapi.h"
|
||||
|
||||
/* This constant isn't available on MinGW-w64 */
|
||||
#ifndef AUDCLNT_STREAMFLAGS_RATEADJUST
|
||||
#define AUDCLNT_STREAMFLAGS_RATEADJUST 0x00100000
|
||||
#endif
|
||||
|
||||
/* these increment as default devices change. Opened default devices pick up changes in their threads. */
|
||||
SDL_atomic_t WASAPI_DefaultPlaybackGeneration;
|
||||
SDL_atomic_t WASAPI_DefaultCaptureGeneration;
|
||||
|
||||
/* This is a list of device id strings we have inflight, so we have consistent pointers to the same device. */
|
||||
typedef struct DevIdList
|
||||
{
|
||||
WCHAR *str;
|
||||
struct DevIdList *next;
|
||||
} DevIdList;
|
||||
|
||||
static DevIdList *deviceid_list = NULL;
|
||||
|
||||
/* Some GUIDs we need to know without linking to libraries that aren't available before Vista. */
|
||||
static const IID SDL_IID_IAudioRenderClient = { 0xf294acfc, 0x3146, 0x4483,{ 0xa7, 0xbf, 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2 } };
|
||||
static const IID SDL_IID_IAudioCaptureClient = { 0xc8adbd64, 0xe71e, 0x48a0,{ 0xa4, 0xde, 0x18, 0x5c, 0x39, 0x5c, 0xd3, 0x17 } };
|
||||
static const GUID SDL_KSDATAFORMAT_SUBTYPE_PCM = { 0x00000001, 0x0000, 0x0010,{ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
|
||||
static const GUID SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { 0x00000003, 0x0000, 0x0010,{ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
|
||||
|
||||
static SDL_bool
|
||||
WStrEqual(const WCHAR *a, const WCHAR *b)
|
||||
{
|
||||
while (*a) {
|
||||
if (*a != *b) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
return *b == 0;
|
||||
}
|
||||
|
||||
static size_t
|
||||
WStrLen(const WCHAR *wstr)
|
||||
{
|
||||
size_t retval = 0;
|
||||
if (wstr) {
|
||||
while (*(wstr++)) {
|
||||
retval++;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static WCHAR *
|
||||
WStrDupe(const WCHAR *wstr)
|
||||
{
|
||||
const size_t len = (WStrLen(wstr) + 1) * sizeof (WCHAR);
|
||||
WCHAR *retval = (WCHAR *) SDL_malloc(len);
|
||||
if (retval) {
|
||||
SDL_memcpy(retval, wstr, len);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WASAPI_RemoveDevice(const SDL_bool iscapture, LPCWSTR devid)
|
||||
{
|
||||
DevIdList *i;
|
||||
DevIdList *next;
|
||||
DevIdList *prev = NULL;
|
||||
for (i = deviceid_list; i; i = next) {
|
||||
next = i->next;
|
||||
if (WStrEqual(i->str, devid)) {
|
||||
if (prev) {
|
||||
prev->next = next;
|
||||
} else {
|
||||
deviceid_list = next;
|
||||
}
|
||||
SDL_RemoveAudioDevice(iscapture, i->str);
|
||||
SDL_free(i->str);
|
||||
SDL_free(i);
|
||||
}
|
||||
prev = i;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, LPCWSTR devid)
|
||||
{
|
||||
DevIdList *devidlist;
|
||||
|
||||
/* You can have multiple endpoints on a device that are mutually exclusive ("Speakers" vs "Line Out" or whatever).
|
||||
In a perfect world, things that are unplugged won't be in this collection. The only gotcha is probably for
|
||||
phones and tablets, where you might have an internal speaker and a headphone jack and expect both to be
|
||||
available and switch automatically. (!!! FIXME...?) */
|
||||
|
||||
/* see if we already have this one. */
|
||||
for (devidlist = deviceid_list; devidlist; devidlist = devidlist->next) {
|
||||
if (WStrEqual(devidlist->str, devid)) {
|
||||
return; /* we already have this. */
|
||||
}
|
||||
}
|
||||
|
||||
devidlist = (DevIdList *) SDL_malloc(sizeof (*devidlist));
|
||||
if (!devidlist) {
|
||||
return; /* oh well. */
|
||||
}
|
||||
|
||||
devid = WStrDupe(devid);
|
||||
if (!devid) {
|
||||
SDL_free(devidlist);
|
||||
return; /* oh well. */
|
||||
}
|
||||
|
||||
devidlist->str = (WCHAR *) devid;
|
||||
devidlist->next = deviceid_list;
|
||||
deviceid_list = devidlist;
|
||||
|
||||
SDL_AddAudioDevice(iscapture, devname, (void *) devid);
|
||||
}
|
||||
|
||||
static void
|
||||
WASAPI_DetectDevices(void)
|
||||
{
|
||||
WASAPI_EnumerateEndpoints();
|
||||
}
|
||||
|
||||
static int
|
||||
WASAPI_GetPendingBytes(_THIS)
|
||||
{
|
||||
UINT32 frames = 0;
|
||||
|
||||
/* it's okay to fail here; we'll deal with failures in the audio thread. */
|
||||
/* FIXME: need a lock around checking this->hidden->client */
|
||||
if (this->hidden->client != NULL) { /* definitely activated? */
|
||||
if (FAILED(IAudioClient_GetCurrentPadding(this->hidden->client, &frames))) {
|
||||
return 0; /* oh well. */
|
||||
}
|
||||
}
|
||||
return ((int) frames) * this->hidden->framesize;
|
||||
}
|
||||
|
||||
static SDL_INLINE SDL_bool
|
||||
WasapiFailed(_THIS, const HRESULT err)
|
||||
{
|
||||
if (err == S_OK) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (err == AUDCLNT_E_DEVICE_INVALIDATED) {
|
||||
this->hidden->device_lost = SDL_TRUE;
|
||||
} else if (SDL_AtomicGet(&this->enabled)) {
|
||||
IAudioClient_Stop(this->hidden->client);
|
||||
SDL_OpenedAudioDeviceDisconnected(this);
|
||||
SDL_assert(!SDL_AtomicGet(&this->enabled));
|
||||
}
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
UpdateAudioStream(_THIS, const SDL_AudioSpec *oldspec)
|
||||
{
|
||||
/* Since WASAPI requires us to handle all audio conversion, and our
|
||||
device format might have changed, we might have to add/remove/change
|
||||
the audio stream that the higher level uses to convert data, so
|
||||
SDL keeps firing the callback as if nothing happened here. */
|
||||
|
||||
if ( (this->callbackspec.channels == this->spec.channels) &&
|
||||
(this->callbackspec.format == this->spec.format) &&
|
||||
(this->callbackspec.freq == this->spec.freq) &&
|
||||
(this->callbackspec.samples == this->spec.samples) ) {
|
||||
/* no need to buffer/convert in an AudioStream! */
|
||||
SDL_FreeAudioStream(this->stream);
|
||||
this->stream = NULL;
|
||||
} else if ( (oldspec->channels == this->spec.channels) &&
|
||||
(oldspec->format == this->spec.format) &&
|
||||
(oldspec->freq == this->spec.freq) ) {
|
||||
/* The existing audio stream is okay to keep using. */
|
||||
} else {
|
||||
/* replace the audiostream for new format */
|
||||
SDL_FreeAudioStream(this->stream);
|
||||
if (this->iscapture) {
|
||||
this->stream = SDL_NewAudioStream(this->spec.format,
|
||||
this->spec.channels, this->spec.freq,
|
||||
this->callbackspec.format,
|
||||
this->callbackspec.channels,
|
||||
this->callbackspec.freq);
|
||||
} else {
|
||||
this->stream = SDL_NewAudioStream(this->callbackspec.format,
|
||||
this->callbackspec.channels,
|
||||
this->callbackspec.freq, this->spec.format,
|
||||
this->spec.channels, this->spec.freq);
|
||||
}
|
||||
|
||||
if (!this->stream) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* make sure our scratch buffer can cover the new device spec. */
|
||||
if (this->spec.size > this->work_buffer_len) {
|
||||
Uint8 *ptr = (Uint8 *) SDL_realloc(this->work_buffer, this->spec.size);
|
||||
if (ptr == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
this->work_buffer = ptr;
|
||||
this->work_buffer_len = this->spec.size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void ReleaseWasapiDevice(_THIS);
|
||||
|
||||
static SDL_bool
|
||||
RecoverWasapiDevice(_THIS)
|
||||
{
|
||||
ReleaseWasapiDevice(this); /* dump the lost device's handles. */
|
||||
|
||||
if (this->hidden->default_device_generation) {
|
||||
this->hidden->default_device_generation = SDL_AtomicGet(this->iscapture ? &WASAPI_DefaultCaptureGeneration : &WASAPI_DefaultPlaybackGeneration);
|
||||
}
|
||||
|
||||
/* this can fail for lots of reasons, but the most likely is we had a
|
||||
non-default device that was disconnected, so we can't recover. Default
|
||||
devices try to reinitialize whatever the new default is, so it's more
|
||||
likely to carry on here, but this handles a non-default device that
|
||||
simply had its format changed in the Windows Control Panel. */
|
||||
if (WASAPI_ActivateDevice(this, SDL_TRUE) == -1) {
|
||||
SDL_OpenedAudioDeviceDisconnected(this);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
this->hidden->device_lost = SDL_FALSE;
|
||||
|
||||
return SDL_TRUE; /* okay, carry on with new device details! */
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
RecoverWasapiIfLost(_THIS)
|
||||
{
|
||||
const int generation = this->hidden->default_device_generation;
|
||||
SDL_bool lost = this->hidden->device_lost;
|
||||
|
||||
if (!SDL_AtomicGet(&this->enabled)) {
|
||||
return SDL_FALSE; /* already failed. */
|
||||
}
|
||||
|
||||
if (!this->hidden->client) {
|
||||
return SDL_TRUE; /* still waiting for activation. */
|
||||
}
|
||||
|
||||
if (!lost && (generation > 0)) { /* is a default device? */
|
||||
const int newgen = SDL_AtomicGet(this->iscapture ? &WASAPI_DefaultCaptureGeneration : &WASAPI_DefaultPlaybackGeneration);
|
||||
if (generation != newgen) { /* the desired default device was changed, jump over to it. */
|
||||
lost = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return lost ? RecoverWasapiDevice(this) : SDL_TRUE;
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
WASAPI_GetDeviceBuf(_THIS)
|
||||
{
|
||||
/* get an endpoint buffer from WASAPI. */
|
||||
BYTE *buffer = NULL;
|
||||
|
||||
while (RecoverWasapiIfLost(this) && this->hidden->render) {
|
||||
if (!WasapiFailed(this, IAudioRenderClient_GetBuffer(this->hidden->render, this->spec.samples, &buffer))) {
|
||||
return (Uint8 *) buffer;
|
||||
}
|
||||
SDL_assert(buffer == NULL);
|
||||
}
|
||||
|
||||
return (Uint8 *) buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
WASAPI_PlayDevice(_THIS)
|
||||
{
|
||||
if (this->hidden->render != NULL) { /* definitely activated? */
|
||||
/* WasapiFailed() will mark the device for reacquisition or removal elsewhere. */
|
||||
WasapiFailed(this, IAudioRenderClient_ReleaseBuffer(this->hidden->render, this->spec.samples, 0));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
WASAPI_WaitDevice(_THIS)
|
||||
{
|
||||
while (RecoverWasapiIfLost(this) && this->hidden->client && this->hidden->event) {
|
||||
/*SDL_Log("WAITDEVICE");*/
|
||||
if (WaitForSingleObjectEx(this->hidden->event, INFINITE, FALSE) == WAIT_OBJECT_0) {
|
||||
const UINT32 maxpadding = this->spec.samples;
|
||||
UINT32 padding = 0;
|
||||
if (!WasapiFailed(this, IAudioClient_GetCurrentPadding(this->hidden->client, &padding))) {
|
||||
/*SDL_Log("WASAPI EVENT! padding=%u maxpadding=%u", (unsigned int)padding, (unsigned int)maxpadding);*/
|
||||
if (padding <= maxpadding) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*SDL_Log("WASAPI FAILED EVENT!");*/
|
||||
IAudioClient_Stop(this->hidden->client);
|
||||
SDL_OpenedAudioDeviceDisconnected(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
WASAPI_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||
{
|
||||
SDL_AudioStream *stream = this->hidden->capturestream;
|
||||
const int avail = SDL_AudioStreamAvailable(stream);
|
||||
if (avail > 0) {
|
||||
const int cpy = SDL_min(buflen, avail);
|
||||
SDL_AudioStreamGet(stream, buffer, cpy);
|
||||
return cpy;
|
||||
}
|
||||
|
||||
while (RecoverWasapiIfLost(this)) {
|
||||
HRESULT ret;
|
||||
BYTE *ptr = NULL;
|
||||
UINT32 frames = 0;
|
||||
DWORD flags = 0;
|
||||
|
||||
/* uhoh, client isn't activated yet, just return silence. */
|
||||
if (!this->hidden->capture) {
|
||||
/* Delay so we run at about the speed that audio would be arriving. */
|
||||
SDL_Delay(((this->spec.samples * 1000) / this->spec.freq));
|
||||
SDL_memset(buffer, this->spec.silence, buflen);
|
||||
return buflen;
|
||||
}
|
||||
|
||||
ret = IAudioCaptureClient_GetBuffer(this->hidden->capture, &ptr, &frames, &flags, NULL, NULL);
|
||||
if (ret != AUDCLNT_S_BUFFER_EMPTY) {
|
||||
WasapiFailed(this, ret); /* mark device lost/failed if necessary. */
|
||||
}
|
||||
|
||||
if ((ret == AUDCLNT_S_BUFFER_EMPTY) || !frames) {
|
||||
WASAPI_WaitDevice(this);
|
||||
} else if (ret == S_OK) {
|
||||
const int total = ((int) frames) * this->hidden->framesize;
|
||||
const int cpy = SDL_min(buflen, total);
|
||||
const int leftover = total - cpy;
|
||||
const SDL_bool silent = (flags & AUDCLNT_BUFFERFLAGS_SILENT) ? SDL_TRUE : SDL_FALSE;
|
||||
|
||||
if (silent) {
|
||||
SDL_memset(buffer, this->spec.silence, cpy);
|
||||
} else {
|
||||
SDL_memcpy(buffer, ptr, cpy);
|
||||
}
|
||||
|
||||
if (leftover > 0) {
|
||||
ptr += cpy;
|
||||
if (silent) {
|
||||
SDL_memset(ptr, this->spec.silence, leftover); /* I guess this is safe? */
|
||||
}
|
||||
|
||||
if (SDL_AudioStreamPut(stream, ptr, leftover) == -1) {
|
||||
return -1; /* uhoh, out of memory, etc. Kill device. :( */
|
||||
}
|
||||
}
|
||||
|
||||
ret = IAudioCaptureClient_ReleaseBuffer(this->hidden->capture, frames);
|
||||
WasapiFailed(this, ret); /* mark device lost/failed if necessary. */
|
||||
|
||||
return cpy;
|
||||
}
|
||||
}
|
||||
|
||||
return -1; /* unrecoverable error. */
|
||||
}
|
||||
|
||||
static void
|
||||
WASAPI_FlushCapture(_THIS)
|
||||
{
|
||||
BYTE *ptr = NULL;
|
||||
UINT32 frames = 0;
|
||||
DWORD flags = 0;
|
||||
|
||||
if (!this->hidden->capture) {
|
||||
return; /* not activated yet? */
|
||||
}
|
||||
|
||||
/* just read until we stop getting packets, throwing them away. */
|
||||
while (SDL_TRUE) {
|
||||
const HRESULT ret = IAudioCaptureClient_GetBuffer(this->hidden->capture, &ptr, &frames, &flags, NULL, NULL);
|
||||
if (ret == AUDCLNT_S_BUFFER_EMPTY) {
|
||||
break; /* no more buffered data; we're done. */
|
||||
} else if (WasapiFailed(this, ret)) {
|
||||
break; /* failed for some other reason, abort. */
|
||||
} else if (WasapiFailed(this, IAudioCaptureClient_ReleaseBuffer(this->hidden->capture, frames))) {
|
||||
break; /* something broke. */
|
||||
}
|
||||
}
|
||||
SDL_AudioStreamClear(this->hidden->capturestream);
|
||||
}
|
||||
|
||||
static void
|
||||
ReleaseWasapiDevice(_THIS)
|
||||
{
|
||||
if (this->hidden->client) {
|
||||
IAudioClient_Stop(this->hidden->client);
|
||||
IAudioClient_SetEventHandle(this->hidden->client, NULL);
|
||||
IAudioClient_Release(this->hidden->client);
|
||||
this->hidden->client = NULL;
|
||||
}
|
||||
|
||||
if (this->hidden->render) {
|
||||
IAudioRenderClient_Release(this->hidden->render);
|
||||
this->hidden->render = NULL;
|
||||
}
|
||||
|
||||
if (this->hidden->capture) {
|
||||
IAudioCaptureClient_Release(this->hidden->capture);
|
||||
this->hidden->capture = NULL;
|
||||
}
|
||||
|
||||
if (this->hidden->waveformat) {
|
||||
CoTaskMemFree(this->hidden->waveformat);
|
||||
this->hidden->waveformat = NULL;
|
||||
}
|
||||
|
||||
if (this->hidden->capturestream) {
|
||||
SDL_FreeAudioStream(this->hidden->capturestream);
|
||||
this->hidden->capturestream = NULL;
|
||||
}
|
||||
|
||||
if (this->hidden->activation_handler) {
|
||||
WASAPI_PlatformDeleteActivationHandler(this->hidden->activation_handler);
|
||||
this->hidden->activation_handler = NULL;
|
||||
}
|
||||
|
||||
if (this->hidden->event) {
|
||||
CloseHandle(this->hidden->event);
|
||||
this->hidden->event = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
WASAPI_CloseDevice(_THIS)
|
||||
{
|
||||
WASAPI_UnrefDevice(this);
|
||||
}
|
||||
|
||||
void
|
||||
WASAPI_RefDevice(_THIS)
|
||||
{
|
||||
SDL_AtomicIncRef(&this->hidden->refcount);
|
||||
}
|
||||
|
||||
void
|
||||
WASAPI_UnrefDevice(_THIS)
|
||||
{
|
||||
if (!SDL_AtomicDecRef(&this->hidden->refcount)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* actual closing happens here. */
|
||||
|
||||
/* don't touch this->hidden->task in here; it has to be reverted from
|
||||
our callback thread. We do that in WASAPI_ThreadDeinit().
|
||||
(likewise for this->hidden->coinitialized). */
|
||||
ReleaseWasapiDevice(this);
|
||||
SDL_free(this->hidden->devid);
|
||||
SDL_free(this->hidden);
|
||||
}
|
||||
|
||||
/* This is called once a device is activated, possibly asynchronously. */
|
||||
int
|
||||
WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
|
||||
{
|
||||
/* !!! FIXME: we could request an exclusive mode stream, which is lower latency;
|
||||
!!! it will write into the kernel's audio buffer directly instead of
|
||||
!!! shared memory that a user-mode mixer then writes to the kernel with
|
||||
!!! everything else. Doing this means any other sound using this device will
|
||||
!!! stop playing, including the user's MP3 player and system notification
|
||||
!!! sounds. You'd probably need to release the device when the app isn't in
|
||||
!!! the foreground, to be a good citizen of the system. It's doable, but it's
|
||||
!!! more work and causes some annoyances, and I don't know what the latency
|
||||
!!! wins actually look like. Maybe add a hint to force exclusive mode at
|
||||
!!! some point. To be sure, defaulting to shared mode is the right thing to
|
||||
!!! do in any case. */
|
||||
const SDL_AudioSpec oldspec = this->spec;
|
||||
const AUDCLNT_SHAREMODE sharemode = AUDCLNT_SHAREMODE_SHARED;
|
||||
UINT32 bufsize = 0; /* this is in sample frames, not samples, not bytes. */
|
||||
REFERENCE_TIME duration = 0;
|
||||
IAudioClient *client = this->hidden->client;
|
||||
IAudioRenderClient *render = NULL;
|
||||
IAudioCaptureClient *capture = NULL;
|
||||
WAVEFORMATEX *waveformat = NULL;
|
||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
SDL_AudioFormat wasapi_format = 0;
|
||||
SDL_bool valid_format = SDL_FALSE;
|
||||
HRESULT ret = S_OK;
|
||||
DWORD streamflags = 0;
|
||||
|
||||
SDL_assert(client != NULL);
|
||||
|
||||
#ifdef __WINRT__ /* CreateEventEx() arrived in Vista, so we need an #ifdef for XP. */
|
||||
this->hidden->event = CreateEventEx(NULL, NULL, 0, EVENT_ALL_ACCESS);
|
||||
#else
|
||||
this->hidden->event = CreateEventW(NULL, 0, 0, NULL);
|
||||
#endif
|
||||
|
||||
if (this->hidden->event == NULL) {
|
||||
return WIN_SetError("WASAPI can't create an event handle");
|
||||
}
|
||||
|
||||
ret = IAudioClient_GetMixFormat(client, &waveformat);
|
||||
if (FAILED(ret)) {
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't determine mix format", ret);
|
||||
}
|
||||
|
||||
SDL_assert(waveformat != NULL);
|
||||
this->hidden->waveformat = waveformat;
|
||||
|
||||
this->spec.channels = (Uint8) waveformat->nChannels;
|
||||
|
||||
/* Make sure we have a valid format that we can convert to whatever WASAPI wants. */
|
||||
if ((waveformat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) && (waveformat->wBitsPerSample == 32)) {
|
||||
wasapi_format = AUDIO_F32SYS;
|
||||
} else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 16)) {
|
||||
wasapi_format = AUDIO_S16SYS;
|
||||
} else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 32)) {
|
||||
wasapi_format = AUDIO_S32SYS;
|
||||
} else if (waveformat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
||||
const WAVEFORMATEXTENSIBLE *ext = (const WAVEFORMATEXTENSIBLE *) waveformat;
|
||||
if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
|
||||
wasapi_format = AUDIO_F32SYS;
|
||||
} else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 16)) {
|
||||
wasapi_format = AUDIO_S16SYS;
|
||||
} else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof (GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
|
||||
wasapi_format = AUDIO_S32SYS;
|
||||
}
|
||||
}
|
||||
|
||||
while ((!valid_format) && (test_format)) {
|
||||
if (test_format == wasapi_format) {
|
||||
this->spec.format = test_format;
|
||||
valid_format = SDL_TRUE;
|
||||
break;
|
||||
}
|
||||
test_format = SDL_NextAudioFormat();
|
||||
}
|
||||
|
||||
if (!valid_format) {
|
||||
return SDL_SetError("WASAPI: Unsupported audio format");
|
||||
}
|
||||
|
||||
ret = IAudioClient_GetDevicePeriod(client, NULL, &duration);
|
||||
if (FAILED(ret)) {
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't determine minimum device period", ret);
|
||||
}
|
||||
|
||||
/* favor WASAPI's resampler over our own, in Win7+. */
|
||||
if (this->spec.freq != waveformat->nSamplesPerSec) {
|
||||
/* RATEADJUST only works with output devices in share mode, and is available in Win7 and later.*/
|
||||
if (WIN_IsWindows7OrGreater() && !this->iscapture && (sharemode == AUDCLNT_SHAREMODE_SHARED)) {
|
||||
streamflags |= AUDCLNT_STREAMFLAGS_RATEADJUST;
|
||||
waveformat->nSamplesPerSec = this->spec.freq;
|
||||
waveformat->nAvgBytesPerSec = waveformat->nSamplesPerSec * waveformat->nChannels * (waveformat->wBitsPerSample / 8);
|
||||
}
|
||||
else {
|
||||
this->spec.freq = waveformat->nSamplesPerSec; /* force sampling rate so our resampler kicks in. */
|
||||
}
|
||||
}
|
||||
|
||||
streamflags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
|
||||
ret = IAudioClient_Initialize(client, sharemode, streamflags, duration, sharemode == AUDCLNT_SHAREMODE_SHARED ? 0 : duration, waveformat, NULL);
|
||||
if (FAILED(ret)) {
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't initialize audio client", ret);
|
||||
}
|
||||
|
||||
ret = IAudioClient_SetEventHandle(client, this->hidden->event);
|
||||
if (FAILED(ret)) {
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't set event handle", ret);
|
||||
}
|
||||
|
||||
ret = IAudioClient_GetBufferSize(client, &bufsize);
|
||||
if (FAILED(ret)) {
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't determine buffer size", ret);
|
||||
}
|
||||
|
||||
this->spec.samples = (Uint16) bufsize;
|
||||
if (!this->iscapture) {
|
||||
this->spec.samples /= 2; /* fill half of the DMA buffer on each run. */
|
||||
}
|
||||
|
||||
/* Update the fragment size as size in bytes */
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
this->hidden->framesize = (SDL_AUDIO_BITSIZE(this->spec.format) / 8) * this->spec.channels;
|
||||
|
||||
if (this->iscapture) {
|
||||
this->hidden->capturestream = SDL_NewAudioStream(this->spec.format, this->spec.channels, this->spec.freq, this->spec.format, this->spec.channels, this->spec.freq);
|
||||
if (!this->hidden->capturestream) {
|
||||
return -1; /* already set SDL_Error */
|
||||
}
|
||||
|
||||
ret = IAudioClient_GetService(client, &SDL_IID_IAudioCaptureClient, (void**) &capture);
|
||||
if (FAILED(ret)) {
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't get capture client service", ret);
|
||||
}
|
||||
|
||||
SDL_assert(capture != NULL);
|
||||
this->hidden->capture = capture;
|
||||
ret = IAudioClient_Start(client);
|
||||
if (FAILED(ret)) {
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't start capture", ret);
|
||||
}
|
||||
|
||||
WASAPI_FlushCapture(this); /* MSDN says you should flush capture endpoint right after startup. */
|
||||
} else {
|
||||
ret = IAudioClient_GetService(client, &SDL_IID_IAudioRenderClient, (void**) &render);
|
||||
if (FAILED(ret)) {
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't get render client service", ret);
|
||||
}
|
||||
|
||||
SDL_assert(render != NULL);
|
||||
this->hidden->render = render;
|
||||
ret = IAudioClient_Start(client);
|
||||
if (FAILED(ret)) {
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't start playback", ret);
|
||||
}
|
||||
}
|
||||
|
||||
if (updatestream) {
|
||||
if (UpdateAudioStream(this, &oldspec) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0; /* good to go. */
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
WASAPI_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
{
|
||||
LPCWSTR devid = (LPCWSTR) 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_zerop(this->hidden);
|
||||
|
||||
WASAPI_RefDevice(this); /* so CloseDevice() will unref to zero. */
|
||||
|
||||
if (!devid) { /* is default device? */
|
||||
this->hidden->default_device_generation = SDL_AtomicGet(iscapture ? &WASAPI_DefaultCaptureGeneration : &WASAPI_DefaultPlaybackGeneration);
|
||||
} else {
|
||||
this->hidden->devid = WStrDupe(devid);
|
||||
if (!this->hidden->devid) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
}
|
||||
|
||||
if (WASAPI_ActivateDevice(this, SDL_FALSE) == -1) {
|
||||
return -1; /* already set error. */
|
||||
}
|
||||
|
||||
/* Ready, but waiting for async device activation.
|
||||
Until activation is successful, we will report silence from capture
|
||||
devices and ignore data on playback devices.
|
||||
Also, since we don't know the _actual_ device format until after
|
||||
activation, we let the app have whatever it asks for. We set up
|
||||
an SDL_AudioStream to convert, if necessary, once the activation
|
||||
completes. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
WASAPI_ThreadInit(_THIS)
|
||||
{
|
||||
WASAPI_PlatformThreadInit(this);
|
||||
}
|
||||
|
||||
static void
|
||||
WASAPI_ThreadDeinit(_THIS)
|
||||
{
|
||||
WASAPI_PlatformThreadDeinit(this);
|
||||
}
|
||||
|
||||
static void
|
||||
WASAPI_Deinitialize(void)
|
||||
{
|
||||
DevIdList *devidlist;
|
||||
DevIdList *next;
|
||||
|
||||
WASAPI_PlatformDeinit();
|
||||
|
||||
for (devidlist = deviceid_list; devidlist; devidlist = next) {
|
||||
next = devidlist->next;
|
||||
SDL_free(devidlist->str);
|
||||
SDL_free(devidlist);
|
||||
}
|
||||
deviceid_list = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
WASAPI_Init(SDL_AudioDriverImpl * impl)
|
||||
{
|
||||
SDL_AtomicSet(&WASAPI_DefaultPlaybackGeneration, 1);
|
||||
SDL_AtomicSet(&WASAPI_DefaultCaptureGeneration, 1);
|
||||
|
||||
if (WASAPI_PlatformInit() == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->DetectDevices = WASAPI_DetectDevices;
|
||||
impl->ThreadInit = WASAPI_ThreadInit;
|
||||
impl->ThreadDeinit = WASAPI_ThreadDeinit;
|
||||
impl->BeginLoopIteration = WASAPI_BeginLoopIteration;
|
||||
impl->OpenDevice = WASAPI_OpenDevice;
|
||||
impl->PlayDevice = WASAPI_PlayDevice;
|
||||
impl->WaitDevice = WASAPI_WaitDevice;
|
||||
impl->GetPendingBytes = WASAPI_GetPendingBytes;
|
||||
impl->GetDeviceBuf = WASAPI_GetDeviceBuf;
|
||||
impl->CaptureFromDevice = WASAPI_CaptureFromDevice;
|
||||
impl->FlushCapture = WASAPI_FlushCapture;
|
||||
impl->CloseDevice = WASAPI_CloseDevice;
|
||||
impl->Deinitialize = WASAPI_Deinitialize;
|
||||
impl->HasCaptureSupport = 1;
|
||||
|
||||
return 1; /* this audio target is available. */
|
||||
}
|
||||
|
||||
AudioBootStrap WASAPI_bootstrap = {
|
||||
"wasapi", "WASAPI", WASAPI_Init, 0
|
||||
};
|
||||
|
||||
#endif /* SDL_AUDIO_DRIVER_WASAPI */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
85
Engine/lib/sdl/src/audio/wasapi/SDL_wasapi.h
Normal file
85
Engine/lib/sdl/src/audio/wasapi/SDL_wasapi.h
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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_wasapi_h_
|
||||
#define SDL_wasapi_h_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#ifdef __cplusplus
|
||||
#define _THIS SDL_AudioDevice *_this
|
||||
#else
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
#endif
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
{
|
||||
SDL_atomic_t refcount;
|
||||
WCHAR *devid;
|
||||
WAVEFORMATEX *waveformat;
|
||||
IAudioClient *client;
|
||||
IAudioRenderClient *render;
|
||||
IAudioCaptureClient *capture;
|
||||
SDL_AudioStream *capturestream;
|
||||
HANDLE event;
|
||||
HANDLE task;
|
||||
SDL_bool coinitialized;
|
||||
int framesize;
|
||||
int default_device_generation;
|
||||
SDL_bool device_lost;
|
||||
void *activation_handler;
|
||||
SDL_atomic_t just_activated;
|
||||
};
|
||||
|
||||
/* these increment as default devices change. Opened default devices pick up changes in their threads. */
|
||||
extern SDL_atomic_t WASAPI_DefaultPlaybackGeneration;
|
||||
extern SDL_atomic_t WASAPI_DefaultCaptureGeneration;
|
||||
|
||||
/* win32 and winrt implementations call into these. */
|
||||
int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream);
|
||||
void WASAPI_RefDevice(_THIS);
|
||||
void WASAPI_UnrefDevice(_THIS);
|
||||
void WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, LPCWSTR devid);
|
||||
void WASAPI_RemoveDevice(const SDL_bool iscapture, LPCWSTR devid);
|
||||
|
||||
/* These are functions that are implemented differently for Windows vs WinRT. */
|
||||
int WASAPI_PlatformInit(void);
|
||||
void WASAPI_PlatformDeinit(void);
|
||||
void WASAPI_EnumerateEndpoints(void);
|
||||
int WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery);
|
||||
void WASAPI_PlatformThreadInit(_THIS);
|
||||
void WASAPI_PlatformThreadDeinit(_THIS);
|
||||
void WASAPI_PlatformDeleteActivationHandler(void *handler);
|
||||
void WASAPI_BeginLoopIteration(_THIS);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SDL_wasapi_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
417
Engine/lib/sdl/src/audio/wasapi/SDL_wasapi_win32.c
Normal file
417
Engine/lib/sdl/src/audio/wasapi/SDL_wasapi_win32.c
Normal file
|
|
@ -0,0 +1,417 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 is code that Windows uses to talk to WASAPI-related system APIs.
|
||||
This is for non-WinRT desktop apps. The C++/CX implementation of these
|
||||
functions, exclusive to WinRT, are in SDL_wasapi_winrt.cpp.
|
||||
The code in SDL_wasapi.c is used by both standard Windows and WinRT builds
|
||||
to deal with audio and calls into these functions. */
|
||||
|
||||
#if SDL_AUDIO_DRIVER_WASAPI && !defined(__WINRT__)
|
||||
|
||||
#include "../../core/windows/SDL_windows.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_sysaudio.h"
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_log.h"
|
||||
|
||||
#define COBJMACROS
|
||||
#include <mmdeviceapi.h>
|
||||
#include <audioclient.h>
|
||||
|
||||
#include "SDL_wasapi.h"
|
||||
|
||||
static const ERole SDL_WASAPI_role = eConsole; /* !!! FIXME: should this be eMultimedia? Should be a hint? */
|
||||
|
||||
/* This is global to the WASAPI target, to handle hotplug and default device lookup. */
|
||||
static IMMDeviceEnumerator *enumerator = NULL;
|
||||
|
||||
/* PropVariantInit() is an inline function/macro in PropIdl.h that calls the C runtime's memset() directly. Use ours instead, to avoid dependency. */
|
||||
#ifdef PropVariantInit
|
||||
#undef PropVariantInit
|
||||
#endif
|
||||
#define PropVariantInit(p) SDL_zerop(p)
|
||||
|
||||
/* handle to Avrt.dll--Vista and later!--for flagging the callback thread as "Pro Audio" (low latency). */
|
||||
static HMODULE libavrt = NULL;
|
||||
typedef HANDLE(WINAPI *pfnAvSetMmThreadCharacteristicsW)(LPWSTR, LPDWORD);
|
||||
typedef BOOL(WINAPI *pfnAvRevertMmThreadCharacteristics)(HANDLE);
|
||||
static pfnAvSetMmThreadCharacteristicsW pAvSetMmThreadCharacteristicsW = NULL;
|
||||
static pfnAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL;
|
||||
|
||||
/* Some GUIDs we need to know without linking to libraries that aren't available before Vista. */
|
||||
static const CLSID SDL_CLSID_MMDeviceEnumerator = { 0xbcde0395, 0xe52f, 0x467c,{ 0x8e, 0x3d, 0xc4, 0x57, 0x92, 0x91, 0x69, 0x2e } };
|
||||
static const IID SDL_IID_IMMDeviceEnumerator = { 0xa95664d2, 0x9614, 0x4f35,{ 0xa7, 0x46, 0xde, 0x8d, 0xb6, 0x36, 0x17, 0xe6 } };
|
||||
static const IID SDL_IID_IMMNotificationClient = { 0x7991eec9, 0x7e89, 0x4d85,{ 0x83, 0x90, 0x6c, 0x70, 0x3c, 0xec, 0x60, 0xc0 } };
|
||||
static const IID SDL_IID_IMMEndpoint = { 0x1be09788, 0x6894, 0x4089,{ 0x85, 0x86, 0x9a, 0x2a, 0x6c, 0x26, 0x5a, 0xc5 } };
|
||||
static const IID SDL_IID_IAudioClient = { 0x1cb9ad4c, 0xdbfa, 0x4c32,{ 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2 } };
|
||||
static const PROPERTYKEY SDL_PKEY_Device_FriendlyName = { { 0xa45c254e, 0xdf1c, 0x4efd,{ 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, } }, 14 };
|
||||
|
||||
|
||||
static char *
|
||||
GetWasapiDeviceName(IMMDevice *device)
|
||||
{
|
||||
/* PKEY_Device_FriendlyName gives you "Speakers (SoundBlaster Pro)" which drives me nuts. I'd rather it be
|
||||
"SoundBlaster Pro (Speakers)" but I guess that's developers vs users. Windows uses the FriendlyName in
|
||||
its own UIs, like Volume Control, etc. */
|
||||
char *utf8dev = NULL;
|
||||
IPropertyStore *props = NULL;
|
||||
if (SUCCEEDED(IMMDevice_OpenPropertyStore(device, STGM_READ, &props))) {
|
||||
PROPVARIANT var;
|
||||
PropVariantInit(&var);
|
||||
if (SUCCEEDED(IPropertyStore_GetValue(props, &SDL_PKEY_Device_FriendlyName, &var))) {
|
||||
utf8dev = WIN_StringToUTF8(var.pwszVal);
|
||||
}
|
||||
PropVariantClear(&var);
|
||||
IPropertyStore_Release(props);
|
||||
}
|
||||
return utf8dev;
|
||||
}
|
||||
|
||||
|
||||
/* We need a COM subclass of IMMNotificationClient for hotplug support, which is
|
||||
easy in C++, but we have to tapdance more to make work in C.
|
||||
Thanks to this page for coaching on how to make this work:
|
||||
https://www.codeproject.com/Articles/13601/COM-in-plain-C */
|
||||
|
||||
typedef struct SDLMMNotificationClient
|
||||
{
|
||||
const IMMNotificationClientVtbl *lpVtbl;
|
||||
SDL_atomic_t refcount;
|
||||
} SDLMMNotificationClient;
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
SDLMMNotificationClient_QueryInterface(IMMNotificationClient *this, REFIID iid, void **ppv)
|
||||
{
|
||||
if ((WIN_IsEqualIID(iid, &IID_IUnknown)) || (WIN_IsEqualIID(iid, &SDL_IID_IMMNotificationClient)))
|
||||
{
|
||||
*ppv = this;
|
||||
this->lpVtbl->AddRef(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE
|
||||
SDLMMNotificationClient_AddRef(IMMNotificationClient *ithis)
|
||||
{
|
||||
SDLMMNotificationClient *this = (SDLMMNotificationClient *) ithis;
|
||||
return (ULONG) (SDL_AtomicIncRef(&this->refcount) + 1);
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE
|
||||
SDLMMNotificationClient_Release(IMMNotificationClient *ithis)
|
||||
{
|
||||
/* this is a static object; we don't ever free it. */
|
||||
SDLMMNotificationClient *this = (SDLMMNotificationClient *) ithis;
|
||||
const ULONG retval = SDL_AtomicDecRef(&this->refcount);
|
||||
if (retval == 0) {
|
||||
SDL_AtomicSet(&this->refcount, 0); /* uhh... */
|
||||
return 0;
|
||||
}
|
||||
return retval - 1;
|
||||
}
|
||||
|
||||
/* These are the entry points called when WASAPI device endpoints change. */
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
SDLMMNotificationClient_OnDefaultDeviceChanged(IMMNotificationClient *ithis, EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId)
|
||||
{
|
||||
if (role != SDL_WASAPI_role) {
|
||||
return S_OK; /* ignore it. */
|
||||
}
|
||||
|
||||
/* Increment the "generation," so opened devices will pick this up in their threads. */
|
||||
switch (flow) {
|
||||
case eRender:
|
||||
SDL_AtomicAdd(&WASAPI_DefaultPlaybackGeneration, 1);
|
||||
break;
|
||||
|
||||
case eCapture:
|
||||
SDL_AtomicAdd(&WASAPI_DefaultCaptureGeneration, 1);
|
||||
break;
|
||||
|
||||
case eAll:
|
||||
SDL_AtomicAdd(&WASAPI_DefaultPlaybackGeneration, 1);
|
||||
SDL_AtomicAdd(&WASAPI_DefaultCaptureGeneration, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
SDL_assert(!"uhoh, unexpected OnDefaultDeviceChange flow!");
|
||||
break;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
SDLMMNotificationClient_OnDeviceAdded(IMMNotificationClient *ithis, LPCWSTR pwstrDeviceId)
|
||||
{
|
||||
/* we ignore this; devices added here then progress to ACTIVE, if appropriate, in
|
||||
OnDeviceStateChange, making that a better place to deal with device adds. More
|
||||
importantly: the first time you plug in a USB audio device, this callback will
|
||||
fire, but when you unplug it, it isn't removed (it's state changes to NOTPRESENT).
|
||||
Plugging it back in won't fire this callback again. */
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
SDLMMNotificationClient_OnDeviceRemoved(IMMNotificationClient *ithis, LPCWSTR pwstrDeviceId)
|
||||
{
|
||||
/* See notes in OnDeviceAdded handler about why we ignore this. */
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
SDLMMNotificationClient_OnDeviceStateChanged(IMMNotificationClient *ithis, LPCWSTR pwstrDeviceId, DWORD dwNewState)
|
||||
{
|
||||
IMMDevice *device = NULL;
|
||||
|
||||
if (SUCCEEDED(IMMDeviceEnumerator_GetDevice(enumerator, pwstrDeviceId, &device))) {
|
||||
IMMEndpoint *endpoint = NULL;
|
||||
if (SUCCEEDED(IMMDevice_QueryInterface(device, &SDL_IID_IMMEndpoint, (void **) &endpoint))) {
|
||||
EDataFlow flow;
|
||||
if (SUCCEEDED(IMMEndpoint_GetDataFlow(endpoint, &flow))) {
|
||||
const SDL_bool iscapture = (flow == eCapture);
|
||||
if (dwNewState == DEVICE_STATE_ACTIVE) {
|
||||
char *utf8dev = GetWasapiDeviceName(device);
|
||||
if (utf8dev) {
|
||||
WASAPI_AddDevice(iscapture, utf8dev, pwstrDeviceId);
|
||||
SDL_free(utf8dev);
|
||||
}
|
||||
} else {
|
||||
WASAPI_RemoveDevice(iscapture, pwstrDeviceId);
|
||||
}
|
||||
}
|
||||
IMMEndpoint_Release(endpoint);
|
||||
}
|
||||
IMMDevice_Release(device);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE
|
||||
SDLMMNotificationClient_OnPropertyValueChanged(IMMNotificationClient *this, LPCWSTR pwstrDeviceId, const PROPERTYKEY key)
|
||||
{
|
||||
return S_OK; /* we don't care about these. */
|
||||
}
|
||||
|
||||
static const IMMNotificationClientVtbl notification_client_vtbl = {
|
||||
SDLMMNotificationClient_QueryInterface,
|
||||
SDLMMNotificationClient_AddRef,
|
||||
SDLMMNotificationClient_Release,
|
||||
SDLMMNotificationClient_OnDeviceStateChanged,
|
||||
SDLMMNotificationClient_OnDeviceAdded,
|
||||
SDLMMNotificationClient_OnDeviceRemoved,
|
||||
SDLMMNotificationClient_OnDefaultDeviceChanged,
|
||||
SDLMMNotificationClient_OnPropertyValueChanged
|
||||
};
|
||||
|
||||
static SDLMMNotificationClient notification_client = { ¬ification_client_vtbl, { 1 } };
|
||||
|
||||
|
||||
int
|
||||
WASAPI_PlatformInit(void)
|
||||
{
|
||||
HRESULT ret;
|
||||
|
||||
/* just skip the discussion with COM here. */
|
||||
if (!WIN_IsWindowsVistaOrGreater()) {
|
||||
return SDL_SetError("WASAPI support requires Windows Vista or later");
|
||||
}
|
||||
|
||||
if (FAILED(WIN_CoInitialize())) {
|
||||
return SDL_SetError("WASAPI: CoInitialize() failed");
|
||||
}
|
||||
|
||||
ret = CoCreateInstance(&SDL_CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &SDL_IID_IMMDeviceEnumerator, (LPVOID) &enumerator);
|
||||
if (FAILED(ret)) {
|
||||
WIN_CoUninitialize();
|
||||
return WIN_SetErrorFromHRESULT("WASAPI CoCreateInstance(MMDeviceEnumerator)", ret);
|
||||
}
|
||||
|
||||
libavrt = LoadLibraryW(L"avrt.dll"); /* this library is available in Vista and later. No WinXP, so have to LoadLibrary to use it for now! */
|
||||
if (libavrt) {
|
||||
pAvSetMmThreadCharacteristicsW = (pfnAvSetMmThreadCharacteristicsW) GetProcAddress(libavrt, "AvSetMmThreadCharacteristicsW");
|
||||
pAvRevertMmThreadCharacteristics = (pfnAvRevertMmThreadCharacteristics) GetProcAddress(libavrt, "AvRevertMmThreadCharacteristics");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
WASAPI_PlatformDeinit(void)
|
||||
{
|
||||
if (enumerator) {
|
||||
IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(enumerator, (IMMNotificationClient *) ¬ification_client);
|
||||
IMMDeviceEnumerator_Release(enumerator);
|
||||
enumerator = NULL;
|
||||
}
|
||||
|
||||
if (libavrt) {
|
||||
FreeLibrary(libavrt);
|
||||
libavrt = NULL;
|
||||
}
|
||||
|
||||
pAvSetMmThreadCharacteristicsW = NULL;
|
||||
pAvRevertMmThreadCharacteristics = NULL;
|
||||
|
||||
WIN_CoUninitialize();
|
||||
}
|
||||
|
||||
void
|
||||
WASAPI_PlatformThreadInit(_THIS)
|
||||
{
|
||||
/* this thread uses COM. */
|
||||
if (SUCCEEDED(WIN_CoInitialize())) { /* can't report errors, hope it worked! */
|
||||
this->hidden->coinitialized = SDL_TRUE;
|
||||
}
|
||||
|
||||
/* Set this thread to very high "Pro Audio" priority. */
|
||||
if (pAvSetMmThreadCharacteristicsW) {
|
||||
DWORD idx = 0;
|
||||
this->hidden->task = pAvSetMmThreadCharacteristicsW(TEXT("Pro Audio"), &idx);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WASAPI_PlatformThreadDeinit(_THIS)
|
||||
{
|
||||
/* Set this thread back to normal priority. */
|
||||
if (this->hidden->task && pAvRevertMmThreadCharacteristics) {
|
||||
pAvRevertMmThreadCharacteristics(this->hidden->task);
|
||||
this->hidden->task = NULL;
|
||||
}
|
||||
|
||||
if (this->hidden->coinitialized) {
|
||||
WIN_CoUninitialize();
|
||||
this->hidden->coinitialized = SDL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery)
|
||||
{
|
||||
LPCWSTR devid = this->hidden->devid;
|
||||
IMMDevice *device = NULL;
|
||||
HRESULT ret;
|
||||
|
||||
if (devid == NULL) {
|
||||
const EDataFlow dataflow = this->iscapture ? eCapture : eRender;
|
||||
ret = IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, dataflow, SDL_WASAPI_role, &device);
|
||||
} else {
|
||||
ret = IMMDeviceEnumerator_GetDevice(enumerator, devid, &device);
|
||||
}
|
||||
|
||||
if (FAILED(ret)) {
|
||||
SDL_assert(device == NULL);
|
||||
this->hidden->client = NULL;
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't find requested audio endpoint", ret);
|
||||
}
|
||||
|
||||
/* this is not async in standard win32, yay! */
|
||||
ret = IMMDevice_Activate(device, &SDL_IID_IAudioClient, CLSCTX_ALL, NULL, (void **) &this->hidden->client);
|
||||
IMMDevice_Release(device);
|
||||
|
||||
if (FAILED(ret)) {
|
||||
SDL_assert(this->hidden->client == NULL);
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't activate audio endpoint", ret);
|
||||
}
|
||||
|
||||
SDL_assert(this->hidden->client != NULL);
|
||||
if (WASAPI_PrepDevice(this, isrecovery) == -1) { /* not async, fire it right away. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0; /* good to go. */
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
WASAPI_EnumerateEndpointsForFlow(const SDL_bool iscapture)
|
||||
{
|
||||
IMMDeviceCollection *collection = NULL;
|
||||
UINT i, total;
|
||||
|
||||
/* Note that WASAPI separates "adapter devices" from "audio endpoint devices"
|
||||
...one adapter device ("SoundBlaster Pro") might have multiple endpoint devices ("Speakers", "Line-Out"). */
|
||||
|
||||
if (FAILED(IMMDeviceEnumerator_EnumAudioEndpoints(enumerator, iscapture ? eCapture : eRender, DEVICE_STATE_ACTIVE, &collection))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (FAILED(IMMDeviceCollection_GetCount(collection, &total))) {
|
||||
IMMDeviceCollection_Release(collection);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < total; i++) {
|
||||
IMMDevice *device = NULL;
|
||||
if (SUCCEEDED(IMMDeviceCollection_Item(collection, i, &device))) {
|
||||
LPWSTR devid = NULL;
|
||||
if (SUCCEEDED(IMMDevice_GetId(device, &devid))) {
|
||||
char *devname = GetWasapiDeviceName(device);
|
||||
if (devname) {
|
||||
WASAPI_AddDevice(iscapture, devname, devid);
|
||||
SDL_free(devname);
|
||||
}
|
||||
CoTaskMemFree(devid);
|
||||
}
|
||||
IMMDevice_Release(device);
|
||||
}
|
||||
}
|
||||
|
||||
IMMDeviceCollection_Release(collection);
|
||||
}
|
||||
|
||||
void
|
||||
WASAPI_EnumerateEndpoints(void)
|
||||
{
|
||||
WASAPI_EnumerateEndpointsForFlow(SDL_FALSE); /* playback */
|
||||
WASAPI_EnumerateEndpointsForFlow(SDL_TRUE); /* capture */
|
||||
|
||||
/* if this fails, we just won't get hotplug events. Carry on anyhow. */
|
||||
IMMDeviceEnumerator_RegisterEndpointNotificationCallback(enumerator, (IMMNotificationClient *) ¬ification_client);
|
||||
}
|
||||
|
||||
void
|
||||
WASAPI_PlatformDeleteActivationHandler(void *handler)
|
||||
{
|
||||
/* not asynchronous. */
|
||||
SDL_assert(!"This function should have only been called on WinRT.");
|
||||
}
|
||||
|
||||
void
|
||||
WASAPI_BeginLoopIteration(_THIS)
|
||||
{
|
||||
/* no-op. */
|
||||
}
|
||||
|
||||
#endif /* SDL_AUDIO_DRIVER_WASAPI && !defined(__WINRT__) */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
276
Engine/lib/sdl/src/audio/wasapi/SDL_wasapi_winrt.cpp
Normal file
276
Engine/lib/sdl/src/audio/wasapi/SDL_wasapi_winrt.cpp
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 is C++/CX code that the WinRT port uses to talk to WASAPI-related
|
||||
// system APIs. The C implementation of these functions, for non-WinRT apps,
|
||||
// is in SDL_wasapi_win32.c. The code in SDL_wasapi.c is used by both standard
|
||||
// Windows and WinRT builds to deal with audio and calls into these functions.
|
||||
|
||||
#if SDL_AUDIO_DRIVER_WASAPI && defined(__WINRT__)
|
||||
|
||||
#include <Windows.h>
|
||||
#include <windows.ui.core.h>
|
||||
#include <windows.devices.enumeration.h>
|
||||
#include <windows.media.devices.h>
|
||||
#include <wrl/implements.h>
|
||||
|
||||
extern "C" {
|
||||
#include "../../core/windows/SDL_windows.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_sysaudio.h"
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_log.h"
|
||||
}
|
||||
|
||||
#define COBJMACROS
|
||||
#include <mmdeviceapi.h>
|
||||
#include <audioclient.h>
|
||||
|
||||
#include "SDL_wasapi.h"
|
||||
|
||||
using namespace Windows::Devices::Enumeration;
|
||||
using namespace Windows::Media::Devices;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
class SDL_WasapiDeviceEventHandler
|
||||
{
|
||||
public:
|
||||
SDL_WasapiDeviceEventHandler(const SDL_bool _iscapture);
|
||||
~SDL_WasapiDeviceEventHandler();
|
||||
void OnDeviceAdded(DeviceWatcher^ sender, DeviceInformation^ args);
|
||||
void OnDeviceRemoved(DeviceWatcher^ sender, DeviceInformationUpdate^ args);
|
||||
void OnDeviceUpdated(DeviceWatcher^ sender, DeviceInformationUpdate^ args);
|
||||
void OnDefaultRenderDeviceChanged(Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args);
|
||||
void OnDefaultCaptureDeviceChanged(Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args);
|
||||
|
||||
private:
|
||||
const SDL_bool iscapture;
|
||||
DeviceWatcher^ watcher;
|
||||
Windows::Foundation::EventRegistrationToken added_handler;
|
||||
Windows::Foundation::EventRegistrationToken removed_handler;
|
||||
Windows::Foundation::EventRegistrationToken updated_handler;
|
||||
Windows::Foundation::EventRegistrationToken default_changed_handler;
|
||||
};
|
||||
|
||||
SDL_WasapiDeviceEventHandler::SDL_WasapiDeviceEventHandler(const SDL_bool _iscapture)
|
||||
: iscapture(_iscapture)
|
||||
, watcher(DeviceInformation::CreateWatcher(_iscapture ? DeviceClass::AudioCapture : DeviceClass::AudioRender))
|
||||
{
|
||||
if (!watcher)
|
||||
return; // uhoh.
|
||||
|
||||
// !!! FIXME: this doesn't need a lambda here, I think, if I make SDL_WasapiDeviceEventHandler a proper C++/CX class. --ryan.
|
||||
added_handler = watcher->Added += ref new TypedEventHandler<DeviceWatcher^, DeviceInformation^>([this](DeviceWatcher^ sender, DeviceInformation^ args) { OnDeviceAdded(sender, args); } );
|
||||
removed_handler = watcher->Removed += ref new TypedEventHandler<DeviceWatcher^, DeviceInformationUpdate^>([this](DeviceWatcher^ sender, DeviceInformationUpdate^ args) { OnDeviceRemoved(sender, args); } );
|
||||
updated_handler = watcher->Updated += ref new TypedEventHandler<DeviceWatcher^, DeviceInformationUpdate^>([this](DeviceWatcher^ sender, DeviceInformationUpdate^ args) { OnDeviceUpdated(sender, args); } );
|
||||
if (iscapture) {
|
||||
default_changed_handler = MediaDevice::DefaultAudioCaptureDeviceChanged += ref new TypedEventHandler<Platform::Object^, DefaultAudioCaptureDeviceChangedEventArgs^>([this](Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args) { OnDefaultCaptureDeviceChanged(sender, args); } );
|
||||
} else {
|
||||
default_changed_handler = MediaDevice::DefaultAudioRenderDeviceChanged += ref new TypedEventHandler<Platform::Object^, DefaultAudioRenderDeviceChangedEventArgs^>([this](Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args) { OnDefaultRenderDeviceChanged(sender, args); } );
|
||||
}
|
||||
watcher->Start();
|
||||
}
|
||||
|
||||
SDL_WasapiDeviceEventHandler::~SDL_WasapiDeviceEventHandler()
|
||||
{
|
||||
if (watcher) {
|
||||
watcher->Added -= added_handler;
|
||||
watcher->Removed -= removed_handler;
|
||||
watcher->Updated -= updated_handler;
|
||||
watcher->Stop();
|
||||
watcher = nullptr;
|
||||
}
|
||||
|
||||
if (iscapture) {
|
||||
MediaDevice::DefaultAudioCaptureDeviceChanged -= default_changed_handler;
|
||||
} else {
|
||||
MediaDevice::DefaultAudioRenderDeviceChanged -= default_changed_handler;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SDL_WasapiDeviceEventHandler::OnDeviceAdded(DeviceWatcher^ sender, DeviceInformation^ info)
|
||||
{
|
||||
SDL_assert(sender == this->watcher);
|
||||
char *utf8dev = WIN_StringToUTF8(info->Name->Data());
|
||||
if (utf8dev) {
|
||||
WASAPI_AddDevice(this->iscapture, utf8dev, info->Id->Data());
|
||||
SDL_free(utf8dev);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SDL_WasapiDeviceEventHandler::OnDeviceRemoved(DeviceWatcher^ sender, DeviceInformationUpdate^ info)
|
||||
{
|
||||
SDL_assert(sender == this->watcher);
|
||||
WASAPI_RemoveDevice(this->iscapture, info->Id->Data());
|
||||
}
|
||||
|
||||
void
|
||||
SDL_WasapiDeviceEventHandler::OnDeviceUpdated(DeviceWatcher^ sender, DeviceInformationUpdate^ args)
|
||||
{
|
||||
SDL_assert(sender == this->watcher);
|
||||
}
|
||||
|
||||
void
|
||||
SDL_WasapiDeviceEventHandler::OnDefaultRenderDeviceChanged(Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args)
|
||||
{
|
||||
SDL_assert(this->iscapture);
|
||||
SDL_AtomicAdd(&WASAPI_DefaultPlaybackGeneration, 1);
|
||||
}
|
||||
|
||||
void
|
||||
SDL_WasapiDeviceEventHandler::OnDefaultCaptureDeviceChanged(Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args)
|
||||
{
|
||||
SDL_assert(!this->iscapture);
|
||||
SDL_AtomicAdd(&WASAPI_DefaultCaptureGeneration, 1);
|
||||
}
|
||||
|
||||
|
||||
static SDL_WasapiDeviceEventHandler *playback_device_event_handler;
|
||||
static SDL_WasapiDeviceEventHandler *capture_device_event_handler;
|
||||
|
||||
int WASAPI_PlatformInit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WASAPI_PlatformDeinit(void)
|
||||
{
|
||||
delete playback_device_event_handler;
|
||||
playback_device_event_handler = nullptr;
|
||||
delete capture_device_event_handler;
|
||||
capture_device_event_handler = nullptr;
|
||||
}
|
||||
|
||||
void WASAPI_EnumerateEndpoints(void)
|
||||
{
|
||||
// DeviceWatchers will fire an Added event for each existing device at
|
||||
// startup, so we don't need to enumerate them separately before
|
||||
// listening for updates.
|
||||
playback_device_event_handler = new SDL_WasapiDeviceEventHandler(SDL_FALSE);
|
||||
capture_device_event_handler = new SDL_WasapiDeviceEventHandler(SDL_TRUE);
|
||||
}
|
||||
|
||||
struct SDL_WasapiActivationHandler : public RuntimeClass< RuntimeClassFlags< ClassicCom >, FtmBase, IActivateAudioInterfaceCompletionHandler >
|
||||
{
|
||||
SDL_WasapiActivationHandler() : device(nullptr) {}
|
||||
STDMETHOD(ActivateCompleted)(IActivateAudioInterfaceAsyncOperation *operation);
|
||||
SDL_AudioDevice *device;
|
||||
};
|
||||
|
||||
HRESULT
|
||||
SDL_WasapiActivationHandler::ActivateCompleted(IActivateAudioInterfaceAsyncOperation *async)
|
||||
{
|
||||
HRESULT result = S_OK;
|
||||
IUnknown *iunknown = nullptr;
|
||||
const HRESULT ret = async->GetActivateResult(&result, &iunknown);
|
||||
|
||||
if (SUCCEEDED(ret) && SUCCEEDED(result)) {
|
||||
iunknown->QueryInterface(IID_PPV_ARGS(&device->hidden->client));
|
||||
if (device->hidden->client) {
|
||||
// Just set a flag, since we're probably in a different thread. We'll pick it up and init everything on our own thread to prevent races.
|
||||
SDL_AtomicSet(&device->hidden->just_activated, 1);
|
||||
}
|
||||
}
|
||||
|
||||
WASAPI_UnrefDevice(device);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void
|
||||
WASAPI_PlatformDeleteActivationHandler(void *handler)
|
||||
{
|
||||
((SDL_WasapiActivationHandler *) handler)->Release();
|
||||
}
|
||||
|
||||
int
|
||||
WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery)
|
||||
{
|
||||
LPCWSTR devid = _this->hidden->devid;
|
||||
Platform::String^ defdevid;
|
||||
|
||||
if (devid == nullptr) {
|
||||
defdevid = _this->iscapture ? MediaDevice::GetDefaultAudioCaptureId(AudioDeviceRole::Default) : MediaDevice::GetDefaultAudioRenderId(AudioDeviceRole::Default);
|
||||
if (defdevid) {
|
||||
devid = defdevid->Data();
|
||||
}
|
||||
}
|
||||
|
||||
SDL_AtomicSet(&_this->hidden->just_activated, 0);
|
||||
|
||||
ComPtr<SDL_WasapiActivationHandler> handler = Make<SDL_WasapiActivationHandler>();
|
||||
if (handler == nullptr) {
|
||||
return SDL_SetError("Failed to allocate WASAPI activation handler");
|
||||
}
|
||||
|
||||
handler.Get()->AddRef(); // we hold a reference after ComPtr destructs on return, causing a Release, and Release ourselves in WASAPI_PlatformDeleteActivationHandler(), etc.
|
||||
handler.Get()->device = _this;
|
||||
_this->hidden->activation_handler = handler.Get();
|
||||
|
||||
WASAPI_RefDevice(_this); /* completion handler will unref it. */
|
||||
IActivateAudioInterfaceAsyncOperation *async = nullptr;
|
||||
const HRESULT ret = ActivateAudioInterfaceAsync(devid, __uuidof(IAudioClient), nullptr, handler.Get(), &async);
|
||||
|
||||
if (async != nullptr) {
|
||||
async->Release();
|
||||
}
|
||||
|
||||
if (FAILED(ret)) {
|
||||
handler.Get()->Release();
|
||||
WASAPI_UnrefDevice(_this);
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't activate requested audio endpoint", ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
WASAPI_BeginLoopIteration(_THIS)
|
||||
{
|
||||
if (SDL_AtomicCAS(&_this->hidden->just_activated, 1, 0)) {
|
||||
if (WASAPI_PrepDevice(_this, SDL_TRUE) == -1) {
|
||||
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WASAPI_PlatformThreadInit(_THIS)
|
||||
{
|
||||
// !!! FIXME: set this thread to "Pro Audio" priority.
|
||||
}
|
||||
|
||||
void
|
||||
WASAPI_PlatformThreadDeinit(_THIS)
|
||||
{
|
||||
// !!! FIXME: set this thread to "Pro Audio" priority.
|
||||
}
|
||||
|
||||
#endif // SDL_AUDIO_DRIVER_WASAPI && defined(__WINRT__)
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -33,6 +33,40 @@
|
|||
#include "../SDL_audio_c.h"
|
||||
#include "SDL_winmm.h"
|
||||
|
||||
/* MinGW32 mmsystem.h doesn't include these structures */
|
||||
#if defined(__MINGW32__) && defined(_MMSYSTEM_H)
|
||||
|
||||
typedef struct tagWAVEINCAPS2W
|
||||
{
|
||||
WORD wMid;
|
||||
WORD wPid;
|
||||
MMVERSION vDriverVersion;
|
||||
WCHAR szPname[MAXPNAMELEN];
|
||||
DWORD dwFormats;
|
||||
WORD wChannels;
|
||||
WORD wReserved1;
|
||||
GUID ManufacturerGuid;
|
||||
GUID ProductGuid;
|
||||
GUID NameGuid;
|
||||
} WAVEINCAPS2W,*PWAVEINCAPS2W,*NPWAVEINCAPS2W,*LPWAVEINCAPS2W;
|
||||
|
||||
typedef struct tagWAVEOUTCAPS2W
|
||||
{
|
||||
WORD wMid;
|
||||
WORD wPid;
|
||||
MMVERSION vDriverVersion;
|
||||
WCHAR szPname[MAXPNAMELEN];
|
||||
DWORD dwFormats;
|
||||
WORD wChannels;
|
||||
WORD wReserved1;
|
||||
DWORD dwSupport;
|
||||
GUID ManufacturerGuid;
|
||||
GUID ProductGuid;
|
||||
GUID NameGuid;
|
||||
} WAVEOUTCAPS2W,*PWAVEOUTCAPS2W,*NPWAVEOUTCAPS2W,*LPWAVEOUTCAPS2W;
|
||||
|
||||
#endif /* defined(__MINGW32__) && defined(_MMSYSTEM_H) */
|
||||
|
||||
#ifndef WAVE_FORMAT_IEEE_FLOAT
|
||||
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_winmm_h
|
||||
#define _SDL_winmm_h
|
||||
#ifndef SDL_winmm_h_
|
||||
#define SDL_winmm_h_
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
|
|
@ -40,6 +40,6 @@ struct SDL_PrivateAudioData
|
|||
int next_buffer;
|
||||
};
|
||||
|
||||
#endif /* _SDL_winmm_h */
|
||||
#endif /* SDL_winmm_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,503 +0,0 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 (albeit with a header file
|
||||
that doesn't compile as C code).
|
||||
*/
|
||||
# define SDL_XAUDIO2_HAS_SDK
|
||||
#include "SDL_xaudio2.h" /* ... compiles as C code, in contrast to XAudio2 headers
|
||||
in the Windows SDK, v.10.0.10240.0 (Win 10's initial SDK)
|
||||
*/
|
||||
#else
|
||||
/* XAudio2 exists in the last DirectX SDK as well as the latest Windows SDK.
|
||||
To enable XAudio2 support, you will need to add the location of your DirectX SDK headers to
|
||||
the SDL projects additional include directories and then set SDL_XAUDIO2_HAS_SDK=1 as a
|
||||
preprocessor define
|
||||
*/
|
||||
#if 0 /* See comment above */
|
||||
#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
|
||||
#endif /* 0 */
|
||||
|
||||
#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
|
||||
|
||||
#if !defined(_SDL_XAUDIO2_H)
|
||||
#define INITGUID 1
|
||||
#include <xaudio2.h>
|
||||
#endif
|
||||
|
||||
/* 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 (!SDL_AtomicGet(&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 (SDL_AtomicGet(&this->enabled)) {
|
||||
SDL_SemWait(this->hidden->semaphore);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
XAUDIO2_PrepareToClose(_THIS)
|
||||
{
|
||||
IXAudio2SourceVoice *source = this->hidden->source;
|
||||
if (source) {
|
||||
IXAudio2SourceVoice_Discontinuity(source);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
XAUDIO2_CloseDevice(_THIS)
|
||||
{
|
||||
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);
|
||||
}
|
||||
if (this->hidden->semaphore != NULL) {
|
||||
SDL_DestroySemaphore(this->hidden->semaphore);
|
||||
}
|
||||
|
||||
SDL_free(this->hidden->mixbuf);
|
||||
SDL_free(this->hidden);
|
||||
}
|
||||
|
||||
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_zerop(this->hidden);
|
||||
|
||||
this->hidden->ixa2 = ixa2;
|
||||
this->hidden->semaphore = SDL_CreateSemaphore(1);
|
||||
if (this->hidden->semaphore == NULL) {
|
||||
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) {
|
||||
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) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
this->hidden->nextbuf = this->hidden->mixbuf;
|
||||
SDL_memset(this->hidden->mixbuf, this->spec.silence, 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) {
|
||||
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) {
|
||||
return SDL_SetError("XAudio2: Couldn't create source voice");
|
||||
}
|
||||
this->hidden->source = source;
|
||||
|
||||
/* Start everything playing! */
|
||||
result = IXAudio2_StartEngine(ixa2);
|
||||
if (result != S_OK) {
|
||||
return SDL_SetError("XAudio2: Couldn't start engine");
|
||||
}
|
||||
|
||||
result = IXAudio2SourceVoice_Start(source, 0, XAUDIO2_COMMIT_NOW);
|
||||
if (result != S_OK) {
|
||||
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->PrepareToClose = XAUDIO2_PrepareToClose;
|
||||
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: */
|
||||
|
|
@ -1,386 +0,0 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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_XAUDIO2_H
|
||||
#define _SDL_XAUDIO2_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmreg.h>
|
||||
#include <objbase.h>
|
||||
|
||||
/* XAudio2 packs its structure members together as tightly as possible.
|
||||
This pragma is needed to ensure compatibility with XAudio2 on 64-bit
|
||||
platforms.
|
||||
*/
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef interface IXAudio2 IXAudio2;
|
||||
typedef interface IXAudio2SourceVoice IXAudio2SourceVoice;
|
||||
typedef interface IXAudio2MasteringVoice IXAudio2MasteringVoice;
|
||||
typedef interface IXAudio2EngineCallback IXAudio2EngineCallback;
|
||||
typedef interface IXAudio2VoiceCallback IXAudio2VoiceCallback;
|
||||
typedef interface IXAudio2Voice IXAudio2Voice;
|
||||
typedef interface IXAudio2SubmixVoice IXAudio2SubmixVoice;
|
||||
|
||||
typedef enum _AUDIO_STREAM_CATEGORY {
|
||||
AudioCategory_Other = 0,
|
||||
AudioCategory_ForegroundOnlyMedia,
|
||||
AudioCategory_BackgroundCapableMedia,
|
||||
AudioCategory_Communications,
|
||||
AudioCategory_Alerts,
|
||||
AudioCategory_SoundEffects,
|
||||
AudioCategory_GameEffects,
|
||||
AudioCategory_GameMedia,
|
||||
AudioCategory_GameChat,
|
||||
AudioCategory_Movie,
|
||||
AudioCategory_Media
|
||||
} AUDIO_STREAM_CATEGORY;
|
||||
|
||||
typedef struct XAUDIO2_BUFFER {
|
||||
UINT32 Flags;
|
||||
UINT32 AudioBytes;
|
||||
const BYTE *pAudioData;
|
||||
UINT32 PlayBegin;
|
||||
UINT32 PlayLength;
|
||||
UINT32 LoopBegin;
|
||||
UINT32 LoopLength;
|
||||
UINT32 LoopCount;
|
||||
void *pContext;
|
||||
} XAUDIO2_BUFFER;
|
||||
|
||||
typedef struct XAUDIO2_BUFFER_WMA {
|
||||
const UINT32 *pDecodedPacketCumulativeBytes;
|
||||
UINT32 PacketCount;
|
||||
} XAUDIO2_BUFFER_WMA;
|
||||
|
||||
typedef struct XAUDIO2_SEND_DESCRIPTOR {
|
||||
UINT32 Flags;
|
||||
IXAudio2Voice *pOutputVoice;
|
||||
} XAUDIO2_SEND_DESCRIPTOR;
|
||||
|
||||
typedef struct XAUDIO2_VOICE_SENDS {
|
||||
UINT32 SendCount;
|
||||
XAUDIO2_SEND_DESCRIPTOR *pSends;
|
||||
} XAUDIO2_VOICE_SENDS;
|
||||
|
||||
typedef struct XAUDIO2_EFFECT_DESCRIPTOR {
|
||||
IUnknown *pEffect;
|
||||
BOOL InitialState;
|
||||
UINT32 OutputChannels;
|
||||
} XAUDIO2_EFFECT_DESCRIPTOR;
|
||||
|
||||
typedef struct XAUDIO2_EFFECT_CHAIN {
|
||||
UINT32 EffectCount;
|
||||
XAUDIO2_EFFECT_DESCRIPTOR *pEffectDescriptors;
|
||||
} XAUDIO2_EFFECT_CHAIN;
|
||||
|
||||
typedef struct XAUDIO2_PERFORMANCE_DATA {
|
||||
UINT64 AudioCyclesSinceLastQuery;
|
||||
UINT64 TotalCyclesSinceLastQuery;
|
||||
UINT32 MinimumCyclesPerQuantum;
|
||||
UINT32 MaximumCyclesPerQuantum;
|
||||
UINT32 MemoryUsageInBytes;
|
||||
UINT32 CurrentLatencyInSamples;
|
||||
UINT32 GlitchesSinceEngineStarted;
|
||||
UINT32 ActiveSourceVoiceCount;
|
||||
UINT32 TotalSourceVoiceCount;
|
||||
UINT32 ActiveSubmixVoiceCount;
|
||||
UINT32 ActiveResamplerCount;
|
||||
UINT32 ActiveMatrixMixCount;
|
||||
UINT32 ActiveXmaSourceVoices;
|
||||
UINT32 ActiveXmaStreams;
|
||||
} XAUDIO2_PERFORMANCE_DATA;
|
||||
|
||||
typedef struct XAUDIO2_DEBUG_CONFIGURATION {
|
||||
UINT32 TraceMask;
|
||||
UINT32 BreakMask;
|
||||
BOOL LogThreadID;
|
||||
BOOL LogFileline;
|
||||
BOOL LogFunctionName;
|
||||
BOOL LogTiming;
|
||||
} XAUDIO2_DEBUG_CONFIGURATION;
|
||||
|
||||
typedef struct XAUDIO2_VOICE_DETAILS {
|
||||
UINT32 CreationFlags;
|
||||
UINT32 ActiveFlags;
|
||||
UINT32 InputChannels;
|
||||
UINT32 InputSampleRate;
|
||||
} XAUDIO2_VOICE_DETAILS;
|
||||
|
||||
typedef enum XAUDIO2_FILTER_TYPE {
|
||||
LowPassFilter = 0,
|
||||
BandPassFilter = 1,
|
||||
HighPassFilter = 2,
|
||||
NotchFilter = 3,
|
||||
LowPassOnePoleFilter = 4,
|
||||
HighPassOnePoleFilter = 5
|
||||
} XAUDIO2_FILTER_TYPE;
|
||||
|
||||
typedef struct XAUDIO2_FILTER_PARAMETERS {
|
||||
XAUDIO2_FILTER_TYPE Type;
|
||||
float Frequency;
|
||||
float OneOverQ;
|
||||
} XAUDIO2_FILTER_PARAMETERS;
|
||||
|
||||
typedef struct XAUDIO2_VOICE_STATE {
|
||||
void *pCurrentBufferContext;
|
||||
UINT32 BuffersQueued;
|
||||
UINT64 SamplesPlayed;
|
||||
} XAUDIO2_VOICE_STATE;
|
||||
|
||||
|
||||
typedef UINT32 XAUDIO2_PROCESSOR;
|
||||
#define Processor1 0x00000001
|
||||
#define XAUDIO2_DEFAULT_PROCESSOR Processor1
|
||||
|
||||
#define XAUDIO2_E_DEVICE_INVALIDATED 0x88960004
|
||||
#define XAUDIO2_COMMIT_NOW 0
|
||||
#define XAUDIO2_VOICE_NOSAMPLESPLAYED 0x0100
|
||||
#define XAUDIO2_DEFAULT_CHANNELS 0
|
||||
|
||||
extern HRESULT __stdcall XAudio2Create(
|
||||
_Out_ IXAudio2 **ppXAudio2,
|
||||
_In_ UINT32 Flags,
|
||||
_In_ XAUDIO2_PROCESSOR XAudio2Processor
|
||||
);
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IXAudio2
|
||||
typedef interface IXAudio2 {
|
||||
const struct IXAudio2Vtbl FAR* lpVtbl;
|
||||
} IXAudio2;
|
||||
typedef const struct IXAudio2Vtbl IXAudio2Vtbl;
|
||||
const struct IXAudio2Vtbl
|
||||
{
|
||||
/* IUnknown */
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID *ppv) PURE;
|
||||
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
||||
|
||||
/* IXAudio2 */
|
||||
STDMETHOD_(HRESULT, RegisterForCallbacks)(THIS, IXAudio2EngineCallback *pCallback) PURE;
|
||||
STDMETHOD_(VOID, UnregisterForCallbacks)(THIS, IXAudio2EngineCallback *pCallback) PURE;
|
||||
STDMETHOD_(HRESULT, CreateSourceVoice)(THIS, IXAudio2SourceVoice **ppSourceVoice,
|
||||
const WAVEFORMATEX *pSourceFormat,
|
||||
UINT32 Flags,
|
||||
float MaxFrequencyRatio,
|
||||
IXAudio2VoiceCallback *pCallback,
|
||||
const XAUDIO2_VOICE_SENDS *pSendList,
|
||||
const XAUDIO2_EFFECT_CHAIN *pEffectChain) PURE;
|
||||
STDMETHOD_(HRESULT, CreateSubmixVoice)(THIS, IXAudio2SubmixVoice **ppSubmixVoice,
|
||||
UINT32 InputChannels,
|
||||
UINT32 InputSampleRate,
|
||||
UINT32 Flags,
|
||||
UINT32 ProcessingStage,
|
||||
const XAUDIO2_VOICE_SENDS *pSendList,
|
||||
const XAUDIO2_EFFECT_CHAIN *pEffectChain) PURE;
|
||||
STDMETHOD_(HRESULT, CreateMasteringVoice)(THIS, IXAudio2MasteringVoice **ppMasteringVoice,
|
||||
UINT32 InputChannels,
|
||||
UINT32 InputSampleRate,
|
||||
UINT32 Flags,
|
||||
LPCWSTR szDeviceId,
|
||||
const XAUDIO2_EFFECT_CHAIN *pEffectChain,
|
||||
AUDIO_STREAM_CATEGORY StreamCategory) PURE;
|
||||
STDMETHOD_(HRESULT, StartEngine)(THIS) PURE;
|
||||
STDMETHOD_(VOID, StopEngine)(THIS) PURE;
|
||||
STDMETHOD_(HRESULT, CommitChanges)(THIS, UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(HRESULT, GetPerformanceData)(THIS, XAUDIO2_PERFORMANCE_DATA *pPerfData) PURE;
|
||||
STDMETHOD_(HRESULT, SetDebugConfiguration)(THIS, XAUDIO2_DEBUG_CONFIGURATION *pDebugConfiguration,
|
||||
VOID *pReserved) PURE;
|
||||
};
|
||||
|
||||
#define IXAudio2_Release(A) ((A)->lpVtbl->Release(A))
|
||||
#define IXAudio2_CreateSourceVoice(A,B,C,D,E,F,G,H) ((A)->lpVtbl->CreateSourceVoice(A,B,C,D,E,F,G,H))
|
||||
#define IXAudio2_CreateMasteringVoice(A,B,C,D,E,F,G,H) ((A)->lpVtbl->CreateMasteringVoice(A,B,C,D,E,F,G,H))
|
||||
#define IXAudio2_StartEngine(A) ((A)->lpVtbl->StartEngine(A))
|
||||
#define IXAudio2_StopEngine(A) ((A)->lpVtbl->StopEngine(A))
|
||||
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IXAudio2SourceVoice
|
||||
typedef interface IXAudio2SourceVoice {
|
||||
const struct IXAudio2SourceVoiceVtbl FAR* lpVtbl;
|
||||
} IXAudio2SourceVoice;
|
||||
typedef const struct IXAudio2SourceVoiceVtbl IXAudio2SourceVoiceVtbl;
|
||||
const struct IXAudio2SourceVoiceVtbl
|
||||
{
|
||||
/* MSDN says that IXAudio2Voice inherits from IXAudio2, but MSVC's debugger
|
||||
* says otherwise, and that IXAudio2Voice doesn't inherit from any other
|
||||
* interface!
|
||||
*/
|
||||
|
||||
/* IXAudio2Voice */
|
||||
STDMETHOD_(VOID, GetVoiceDetails)(THIS, XAUDIO2_VOICE_DETAILS *pVoiceDetails) PURE;
|
||||
STDMETHOD_(HRESULT, SetOutputVoices)(THIS, const XAUDIO2_VOICE_SENDS *pSendList) PURE;
|
||||
STDMETHOD_(HRESULT, SetEffectChain)(THIS, const XAUDIO2_EFFECT_CHAIN *pEffectChain) PURE;
|
||||
STDMETHOD_(HRESULT, EnableEffect)(THIS, UINT32 EffectIndex, UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(HRESULT, DisableEffect)(THIS, UINT32 EffectIndex, UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(VOID, GetEffectState)(THIS, UINT32 EffectIndex, BOOL *pEnabled) PURE;
|
||||
STDMETHOD_(HRESULT, SetEffectParameters)(THIS, UINT32 EffectIndex,
|
||||
const void *pParameters,
|
||||
UINT32 ParametersByteSize,
|
||||
UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(VOID, GetEffectParameters)(THIS, UINT32 EffectIndex,
|
||||
void *pParameters,
|
||||
UINT32 ParametersByteSize) PURE;
|
||||
STDMETHOD_(HRESULT, SetFilterParameters)(THIS, const XAUDIO2_FILTER_PARAMETERS *pParameters,
|
||||
UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(VOID, GetFilterParameters)(THIS, XAUDIO2_FILTER_PARAMETERS *pParameters) PURE;
|
||||
STDMETHOD_(HRESULT, SetOutputFilterParameters)(THIS, IXAudio2Voice *pDestinationVoice,
|
||||
XAUDIO2_FILTER_PARAMETERS *pParameters,
|
||||
UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(VOID, GetOutputFilterParameters)(THIS, IXAudio2Voice *pDestinationVoice,
|
||||
XAUDIO2_FILTER_PARAMETERS *pParameters) PURE;
|
||||
STDMETHOD_(HRESULT, SetVolume)(THIS, float Volume,
|
||||
UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(VOID, GetVolume)(THIS, float *pVolume) PURE;
|
||||
STDMETHOD_(HRESULT, SetChannelVolumes)(THIS, UINT32 Channels,
|
||||
const float *pVolumes,
|
||||
UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(VOID, GetChannelVolumes)(THIS, UINT32 Channels,
|
||||
float *pVolumes) PURE;
|
||||
STDMETHOD_(HRESULT, SetOutputMatrix)(THIS, IXAudio2Voice *pDestinationVoice,
|
||||
UINT32 SourceChannels,
|
||||
UINT32 DestinationChannels,
|
||||
const float *pLevelMatrix,
|
||||
UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(VOID, GetOutputMatrix)(THIS, IXAudio2Voice *pDestinationVoice,
|
||||
UINT32 SourceChannels,
|
||||
UINT32 DestinationChannels,
|
||||
float *pLevelMatrix) PURE;
|
||||
STDMETHOD_(VOID, DestroyVoice)(THIS) PURE;
|
||||
|
||||
/* IXAudio2SourceVoice */
|
||||
STDMETHOD_(HRESULT, Start)(THIS, UINT32 Flags,
|
||||
UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(HRESULT, Stop)(THIS, UINT32 Flags,
|
||||
UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(HRESULT, SubmitSourceBuffer)(THIS, const XAUDIO2_BUFFER *pBuffer,
|
||||
const XAUDIO2_BUFFER_WMA *pBufferWMA) PURE;
|
||||
STDMETHOD_(HRESULT, FlushSourceBuffers)(THIS) PURE;
|
||||
STDMETHOD_(HRESULT, Discontinuity)(THIS) PURE;
|
||||
STDMETHOD_(HRESULT, ExitLoop)(THIS, UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(VOID, GetState)(THIS, XAUDIO2_VOICE_STATE *pVoiceState,
|
||||
UINT32 Flags) PURE;
|
||||
STDMETHOD_(HRESULT, SetFrequencyRatio)(THIS, float Ratio,
|
||||
UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(VOID, GetFrequencyRatio)(THIS, float *pRatio) PURE;
|
||||
STDMETHOD_(HRESULT, SetSourceSampleRate)(THIS, UINT32 NewSourceSampleRate) PURE;
|
||||
};
|
||||
|
||||
#define IXAudio2SourceVoice_DestroyVoice(A) ((A)->lpVtbl->DestroyVoice(A))
|
||||
#define IXAudio2SourceVoice_Start(A,B,C) ((A)->lpVtbl->Start(A,B,C))
|
||||
#define IXAudio2SourceVoice_Stop(A,B,C) ((A)->lpVtbl->Stop(A,B,C))
|
||||
#define IXAudio2SourceVoice_SubmitSourceBuffer(A,B,C) ((A)->lpVtbl->SubmitSourceBuffer(A,B,C))
|
||||
#define IXAudio2SourceVoice_FlushSourceBuffers(A) ((A)->lpVtbl->FlushSourceBuffers(A))
|
||||
#define IXAudio2SourceVoice_Discontinuity(A) ((A)->lpVtbl->Discontinuity(A))
|
||||
#define IXAudio2SourceVoice_GetState(A,B,C) ((A)->lpVtbl->GetState(A,B,C))
|
||||
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IXAudio2MasteringVoice
|
||||
typedef interface IXAudio2MasteringVoice {
|
||||
const struct IXAudio2MasteringVoiceVtbl FAR* lpVtbl;
|
||||
} IXAudio2MasteringVoice;
|
||||
typedef const struct IXAudio2MasteringVoiceVtbl IXAudio2MasteringVoiceVtbl;
|
||||
const struct IXAudio2MasteringVoiceVtbl
|
||||
{
|
||||
/* MSDN says that IXAudio2Voice inherits from IXAudio2, but MSVC's debugger
|
||||
* says otherwise, and that IXAudio2Voice doesn't inherit from any other
|
||||
* interface!
|
||||
*/
|
||||
|
||||
/* IXAudio2Voice */
|
||||
STDMETHOD_(VOID, GetVoiceDetails)(THIS, XAUDIO2_VOICE_DETAILS *pVoiceDetails) PURE;
|
||||
STDMETHOD_(HRESULT, SetOutputVoices)(THIS, const XAUDIO2_VOICE_SENDS *pSendList) PURE;
|
||||
STDMETHOD_(HRESULT, SetEffectChain)(THIS, const XAUDIO2_EFFECT_CHAIN *pEffectChain) PURE;
|
||||
STDMETHOD_(HRESULT, EnableEffect)(THIS, UINT32 EffectIndex, UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(HRESULT, DisableEffect)(THIS, UINT32 EffectIndex, UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(VOID, GetEffectState)(THIS, UINT32 EffectIndex, BOOL *pEnabled) PURE;
|
||||
STDMETHOD_(HRESULT, SetEffectParameters)(THIS, UINT32 EffectIndex,
|
||||
const void *pParameters,
|
||||
UINT32 ParametersByteSize,
|
||||
UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(VOID, GetEffectParameters)(THIS, UINT32 EffectIndex,
|
||||
void *pParameters,
|
||||
UINT32 ParametersByteSize) PURE;
|
||||
STDMETHOD_(HRESULT, SetFilterParameters)(THIS, const XAUDIO2_FILTER_PARAMETERS *pParameters,
|
||||
UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(VOID, GetFilterParameters)(THIS, XAUDIO2_FILTER_PARAMETERS *pParameters) PURE;
|
||||
STDMETHOD_(HRESULT, SetOutputFilterParameters)(THIS, IXAudio2Voice *pDestinationVoice,
|
||||
XAUDIO2_FILTER_PARAMETERS *pParameters,
|
||||
UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(VOID, GetOutputFilterParameters)(THIS, IXAudio2Voice *pDestinationVoice,
|
||||
XAUDIO2_FILTER_PARAMETERS *pParameters) PURE;
|
||||
STDMETHOD_(HRESULT, SetVolume)(THIS, float Volume,
|
||||
UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(VOID, GetVolume)(THIS, float *pVolume) PURE;
|
||||
STDMETHOD_(HRESULT, SetChannelVolumes)(THIS, UINT32 Channels,
|
||||
const float *pVolumes,
|
||||
UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(VOID, GetChannelVolumes)(THIS, UINT32 Channels,
|
||||
float *pVolumes) PURE;
|
||||
STDMETHOD_(HRESULT, SetOutputMatrix)(THIS, IXAudio2Voice *pDestinationVoice,
|
||||
UINT32 SourceChannels,
|
||||
UINT32 DestinationChannels,
|
||||
const float *pLevelMatrix,
|
||||
UINT32 OperationSet) PURE;
|
||||
STDMETHOD_(VOID, GetOutputMatrix)(THIS, IXAudio2Voice *pDestinationVoice,
|
||||
UINT32 SourceChannels,
|
||||
UINT32 DestinationChannels,
|
||||
float *pLevelMatrix) PURE;
|
||||
STDMETHOD_(VOID, DestroyVoice)(THIS) PURE;
|
||||
|
||||
/* IXAudio2SourceVoice */
|
||||
STDMETHOD_(VOID, GetChannelMask)(THIS, DWORD *pChannelMask) PURE;
|
||||
};
|
||||
|
||||
#define IXAudio2MasteringVoice_DestroyVoice(A) ((A)->lpVtbl->DestroyVoice(A))
|
||||
|
||||
|
||||
#undef INTERFACE
|
||||
#define INTERFACE IXAudio2VoiceCallback
|
||||
typedef interface IXAudio2VoiceCallback {
|
||||
const struct IXAudio2VoiceCallbackVtbl FAR* lpVtbl;
|
||||
} IXAudio2VoiceCallback;
|
||||
typedef const struct IXAudio2VoiceCallbackVtbl IXAudio2VoiceCallbackVtbl;
|
||||
const struct IXAudio2VoiceCallbackVtbl
|
||||
{
|
||||
/* MSDN says that IXAudio2VoiceCallback inherits from IXAudio2, but SDL's
|
||||
* own code says otherwise, and that IXAudio2VoiceCallback doesn't inherit
|
||||
* from any other interface!
|
||||
*/
|
||||
|
||||
/* IXAudio2VoiceCallback */
|
||||
STDMETHOD_(VOID, OnVoiceProcessingPassStart)(THIS, UINT32 BytesRequired) PURE;
|
||||
STDMETHOD_(VOID, OnVoiceProcessingPassEnd)(THIS) PURE;
|
||||
STDMETHOD_(VOID, OnStreamEnd)(THIS) PURE;
|
||||
STDMETHOD_(VOID, OnBufferStart)(THIS, void *pBufferContext) PURE;
|
||||
STDMETHOD_(VOID, OnBufferEnd)(THIS, void *pBufferContext) PURE;
|
||||
STDMETHOD_(VOID, OnLoopEnd)(THIS, void *pBufferContext) PURE;
|
||||
STDMETHOD_(VOID, OnVoiceError)(THIS, void *pBufferContext, HRESULT Error) PURE;
|
||||
};
|
||||
|
||||
#pragma pack(pop) /* Undo pragma push */
|
||||
|
||||
#endif /* _SDL_XAUDIO2_H */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
//
|
||||
// Re-implementation of methods removed from XAudio2 (in WinRT):
|
||||
//
|
||||
|
||||
typedef struct XAUDIO2_DEVICE_DETAILS
|
||||
{
|
||||
WCHAR DeviceID[256];
|
||||
WCHAR DisplayName[256];
|
||||
/* Other fields exist in the pre-Windows 8 version of this struct, however
|
||||
they weren't used by SDL, so they weren't added.
|
||||
*/
|
||||
} XAUDIO2_DEVICE_DETAILS;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HRESULT IXAudio2_GetDeviceCount(IXAudio2 * unused, UINT32 * devcount);
|
||||
HRESULT IXAudio2_GetDeviceDetails(IXAudio2 * unused, UINT32 index, XAUDIO2_DEVICE_DETAILS * details);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// C-style macros to call XAudio2's methods in C++:
|
||||
//
|
||||
#ifdef __cplusplus
|
||||
/*
|
||||
#define IXAudio2_CreateMasteringVoice(A, B, C, D, E, F, G) (A)->CreateMasteringVoice((B), (C), (D), (E), (F), (G))
|
||||
#define IXAudio2_CreateSourceVoice(A, B, C, D, E, F, G, H) (A)->CreateSourceVoice((B), (C), (D), (E), (F), (G), (H))
|
||||
#define IXAudio2_QueryInterface(A, B, C) (A)->QueryInterface((B), (C))
|
||||
#define IXAudio2_Release(A) (A)->Release()
|
||||
#define IXAudio2_StartEngine(A) (A)->StartEngine()
|
||||
#define IXAudio2_StopEngine(A) (A)->StopEngine()
|
||||
|
||||
#define IXAudio2MasteringVoice_DestroyVoice(A) (A)->DestroyVoice()
|
||||
|
||||
#define IXAudio2SourceVoice_DestroyVoice(A) (A)->DestroyVoice()
|
||||
#define IXAudio2SourceVoice_Discontinuity(A) (A)->Discontinuity()
|
||||
#define IXAudio2SourceVoice_FlushSourceBuffers(A) (A)->FlushSourceBuffers()
|
||||
#define IXAudio2SourceVoice_GetState(A, B) (A)->GetState((B))
|
||||
#define IXAudio2SourceVoice_Start(A, B, C) (A)->Start((B), (C))
|
||||
#define IXAudio2SourceVoice_Stop(A, B, C) (A)->Stop((B), (C))
|
||||
#define IXAudio2SourceVoice_SubmitSourceBuffer(A, B, C) (A)->SubmitSourceBuffer((B), (C))
|
||||
*/
|
||||
#endif // ifdef __cplusplus
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -34,11 +34,17 @@ extern "C" {
|
|||
|
||||
/* Interface from the SDL library into the Android Java activity */
|
||||
extern void Android_JNI_SetActivityTitle(const char *title);
|
||||
extern void Android_JNI_SetWindowStyle(SDL_bool fullscreen);
|
||||
extern void Android_JNI_SetOrientation(int w, int h, int resizable, const char *hint);
|
||||
|
||||
extern SDL_bool Android_JNI_GetAccelerometerValues(float values[3]);
|
||||
extern void Android_JNI_ShowTextInput(SDL_Rect *inputRect);
|
||||
extern void Android_JNI_HideTextInput(void);
|
||||
extern SDL_bool Android_JNI_IsScreenKeyboardShown(void);
|
||||
extern ANativeWindow* Android_JNI_GetNativeWindow(void);
|
||||
|
||||
extern int Android_JNI_GetDisplayDPI(float *ddpi, float *xdpi, float *ydpi);
|
||||
|
||||
/* Audio support */
|
||||
extern int Android_JNI_OpenAudioDevice(int iscapture, int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames);
|
||||
extern void* Android_JNI_GetAudioBuffer(void);
|
||||
|
|
@ -56,6 +62,9 @@ size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer, size_t size, size_t ma
|
|||
size_t Android_JNI_FileWrite(SDL_RWops* ctx, const void* buffer, size_t size, size_t num);
|
||||
int Android_JNI_FileClose(SDL_RWops* ctx);
|
||||
|
||||
/* Environment support */
|
||||
void Android_JNI_GetManifestEnvironmentVariables(void);
|
||||
|
||||
/* Clipboard support */
|
||||
int Android_JNI_SetClipboardText(const char* text);
|
||||
char* Android_JNI_GetClipboardText(void);
|
||||
|
|
@ -67,21 +76,32 @@ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seco
|
|||
/* Joystick support */
|
||||
void Android_JNI_PollInputDevices(void);
|
||||
|
||||
/* Haptic support */
|
||||
void Android_JNI_PollHapticDevices(void);
|
||||
void Android_JNI_HapticRun(int device_id, int length);
|
||||
|
||||
/* Video */
|
||||
void Android_JNI_SuspendScreenSaver(SDL_bool suspend);
|
||||
|
||||
/* Touch support */
|
||||
int Android_JNI_GetTouchDeviceIds(int **ids);
|
||||
void Android_JNI_SetSeparateMouseAndTouch(SDL_bool new_value);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Init */
|
||||
JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv* mEnv, jclass cls);
|
||||
|
||||
/* MessageBox */
|
||||
#include "SDL_messagebox.h"
|
||||
int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
/* *INDENT-OFF* */
|
||||
|
|
|
|||
175
Engine/lib/sdl/src/core/android/keyinfotable.h
Normal file
175
Engine/lib/sdl/src/core/android/keyinfotable.h
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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 _ANDROID_KeyInfo
|
||||
#define _ANDROID_KeyInfo
|
||||
|
||||
#include "SDL_scancode.h"
|
||||
#include "SDL_keycode.h"
|
||||
|
||||
/*
|
||||
This file is used by the keyboard code in SDL_uikitview.m to convert between characters
|
||||
passed in from the iPhone's virtual keyboard, and tuples of SDL_Scancode and SDL_keymods.
|
||||
For example unicharToUIKeyInfoTable['a'] would give you the scan code and keymod for lower
|
||||
case a.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SDL_Scancode code;
|
||||
uint16_t mod;
|
||||
} AndroidKeyInfo;
|
||||
|
||||
/* So far only ASCII characters here */
|
||||
static AndroidKeyInfo unicharToAndroidKeyInfoTable[] = {
|
||||
/* 0 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 1 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 2 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 3 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 4 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 5 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 6 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 7 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 8 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 9 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 10 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 11 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 12 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 13 */ { SDL_SCANCODE_RETURN, 0 },
|
||||
/* 14 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 15 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 16 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 17 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 18 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 19 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 20 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 21 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 22 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 23 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 24 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 25 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 26 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 27 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 28 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 29 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 30 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 31 */ { SDL_SCANCODE_UNKNOWN, 0 },
|
||||
/* 32 */ { SDL_SCANCODE_SPACE, 0 },
|
||||
/* 33 */ { SDL_SCANCODE_1, KMOD_SHIFT }, /* plus shift modifier '!' */
|
||||
/* 34 */ { SDL_SCANCODE_APOSTROPHE, KMOD_SHIFT }, /* plus shift modifier '"' */
|
||||
/* 35 */ { SDL_SCANCODE_3, KMOD_SHIFT }, /* plus shift modifier '#' */
|
||||
/* 36 */ { SDL_SCANCODE_4, KMOD_SHIFT }, /* plus shift modifier '$' */
|
||||
/* 37 */ { SDL_SCANCODE_5, KMOD_SHIFT }, /* plus shift modifier '%' */
|
||||
/* 38 */ { SDL_SCANCODE_7, KMOD_SHIFT }, /* plus shift modifier '&' */
|
||||
/* 39 */ { SDL_SCANCODE_APOSTROPHE, 0 }, /* ''' */
|
||||
/* 40 */ { SDL_SCANCODE_9, KMOD_SHIFT }, /* plus shift modifier '(' */
|
||||
/* 41 */ { SDL_SCANCODE_0, KMOD_SHIFT }, /* plus shift modifier ')' */
|
||||
/* 42 */ { SDL_SCANCODE_8, KMOD_SHIFT }, /* '*' */
|
||||
/* 43 */ { SDL_SCANCODE_EQUALS, KMOD_SHIFT }, /* plus shift modifier '+' */
|
||||
/* 44 */ { SDL_SCANCODE_COMMA, 0 }, /* ',' */
|
||||
/* 45 */ { SDL_SCANCODE_MINUS, 0 }, /* '-' */
|
||||
/* 46 */ { SDL_SCANCODE_PERIOD, 0 }, /* '.' */
|
||||
/* 47 */ { SDL_SCANCODE_SLASH, 0 }, /* '/' */
|
||||
/* 48 */ { SDL_SCANCODE_0, 0 },
|
||||
/* 49 */ { SDL_SCANCODE_1, 0 },
|
||||
/* 50 */ { SDL_SCANCODE_2, 0 },
|
||||
/* 51 */ { SDL_SCANCODE_3, 0 },
|
||||
/* 52 */ { SDL_SCANCODE_4, 0 },
|
||||
/* 53 */ { SDL_SCANCODE_5, 0 },
|
||||
/* 54 */ { SDL_SCANCODE_6, 0 },
|
||||
/* 55 */ { SDL_SCANCODE_7, 0 },
|
||||
/* 56 */ { SDL_SCANCODE_8, 0 },
|
||||
/* 57 */ { SDL_SCANCODE_9, 0 },
|
||||
/* 58 */ { SDL_SCANCODE_SEMICOLON, KMOD_SHIFT }, /* plus shift modifier ';' */
|
||||
/* 59 */ { SDL_SCANCODE_SEMICOLON, 0 },
|
||||
/* 60 */ { SDL_SCANCODE_COMMA, KMOD_SHIFT }, /* plus shift modifier '<' */
|
||||
/* 61 */ { SDL_SCANCODE_EQUALS, 0 },
|
||||
/* 62 */ { SDL_SCANCODE_PERIOD, KMOD_SHIFT }, /* plus shift modifier '>' */
|
||||
/* 63 */ { SDL_SCANCODE_SLASH, KMOD_SHIFT }, /* plus shift modifier '?' */
|
||||
/* 64 */ { SDL_SCANCODE_2, KMOD_SHIFT }, /* plus shift modifier '@' */
|
||||
/* 65 */ { SDL_SCANCODE_A, KMOD_SHIFT }, /* all the following need shift modifiers */
|
||||
/* 66 */ { SDL_SCANCODE_B, KMOD_SHIFT },
|
||||
/* 67 */ { SDL_SCANCODE_C, KMOD_SHIFT },
|
||||
/* 68 */ { SDL_SCANCODE_D, KMOD_SHIFT },
|
||||
/* 69 */ { SDL_SCANCODE_E, KMOD_SHIFT },
|
||||
/* 70 */ { SDL_SCANCODE_F, KMOD_SHIFT },
|
||||
/* 71 */ { SDL_SCANCODE_G, KMOD_SHIFT },
|
||||
/* 72 */ { SDL_SCANCODE_H, KMOD_SHIFT },
|
||||
/* 73 */ { SDL_SCANCODE_I, KMOD_SHIFT },
|
||||
/* 74 */ { SDL_SCANCODE_J, KMOD_SHIFT },
|
||||
/* 75 */ { SDL_SCANCODE_K, KMOD_SHIFT },
|
||||
/* 76 */ { SDL_SCANCODE_L, KMOD_SHIFT },
|
||||
/* 77 */ { SDL_SCANCODE_M, KMOD_SHIFT },
|
||||
/* 78 */ { SDL_SCANCODE_N, KMOD_SHIFT },
|
||||
/* 79 */ { SDL_SCANCODE_O, KMOD_SHIFT },
|
||||
/* 80 */ { SDL_SCANCODE_P, KMOD_SHIFT },
|
||||
/* 81 */ { SDL_SCANCODE_Q, KMOD_SHIFT },
|
||||
/* 82 */ { SDL_SCANCODE_R, KMOD_SHIFT },
|
||||
/* 83 */ { SDL_SCANCODE_S, KMOD_SHIFT },
|
||||
/* 84 */ { SDL_SCANCODE_T, KMOD_SHIFT },
|
||||
/* 85 */ { SDL_SCANCODE_U, KMOD_SHIFT },
|
||||
/* 86 */ { SDL_SCANCODE_V, KMOD_SHIFT },
|
||||
/* 87 */ { SDL_SCANCODE_W, KMOD_SHIFT },
|
||||
/* 88 */ { SDL_SCANCODE_X, KMOD_SHIFT },
|
||||
/* 89 */ { SDL_SCANCODE_Y, KMOD_SHIFT },
|
||||
/* 90 */ { SDL_SCANCODE_Z, KMOD_SHIFT },
|
||||
/* 91 */ { SDL_SCANCODE_LEFTBRACKET, 0 },
|
||||
/* 92 */ { SDL_SCANCODE_BACKSLASH, 0 },
|
||||
/* 93 */ { SDL_SCANCODE_RIGHTBRACKET, 0 },
|
||||
/* 94 */ { SDL_SCANCODE_6, KMOD_SHIFT }, /* plus shift modifier '^' */
|
||||
/* 95 */ { SDL_SCANCODE_MINUS, KMOD_SHIFT }, /* plus shift modifier '_' */
|
||||
/* 96 */ { SDL_SCANCODE_GRAVE, KMOD_SHIFT }, /* '`' */
|
||||
/* 97 */ { SDL_SCANCODE_A, 0 },
|
||||
/* 98 */ { SDL_SCANCODE_B, 0 },
|
||||
/* 99 */ { SDL_SCANCODE_C, 0 },
|
||||
/* 100 */{ SDL_SCANCODE_D, 0 },
|
||||
/* 101 */{ SDL_SCANCODE_E, 0 },
|
||||
/* 102 */{ SDL_SCANCODE_F, 0 },
|
||||
/* 103 */{ SDL_SCANCODE_G, 0 },
|
||||
/* 104 */{ SDL_SCANCODE_H, 0 },
|
||||
/* 105 */{ SDL_SCANCODE_I, 0 },
|
||||
/* 106 */{ SDL_SCANCODE_J, 0 },
|
||||
/* 107 */{ SDL_SCANCODE_K, 0 },
|
||||
/* 108 */{ SDL_SCANCODE_L, 0 },
|
||||
/* 109 */{ SDL_SCANCODE_M, 0 },
|
||||
/* 110 */{ SDL_SCANCODE_N, 0 },
|
||||
/* 111 */{ SDL_SCANCODE_O, 0 },
|
||||
/* 112 */{ SDL_SCANCODE_P, 0 },
|
||||
/* 113 */{ SDL_SCANCODE_Q, 0 },
|
||||
/* 114 */{ SDL_SCANCODE_R, 0 },
|
||||
/* 115 */{ SDL_SCANCODE_S, 0 },
|
||||
/* 116 */{ SDL_SCANCODE_T, 0 },
|
||||
/* 117 */{ SDL_SCANCODE_U, 0 },
|
||||
/* 118 */{ SDL_SCANCODE_V, 0 },
|
||||
/* 119 */{ SDL_SCANCODE_W, 0 },
|
||||
/* 120 */{ SDL_SCANCODE_X, 0 },
|
||||
/* 121 */{ SDL_SCANCODE_Y, 0 },
|
||||
/* 122 */{ SDL_SCANCODE_Z, 0 },
|
||||
/* 123 */{ SDL_SCANCODE_LEFTBRACKET, KMOD_SHIFT }, /* plus shift modifier '{' */
|
||||
/* 124 */{ SDL_SCANCODE_BACKSLASH, KMOD_SHIFT }, /* plus shift modifier '|' */
|
||||
/* 125 */{ SDL_SCANCODE_RIGHTBRACKET, KMOD_SHIFT }, /* plus shift modifier '}' */
|
||||
/* 126 */{ SDL_SCANCODE_GRAVE, KMOD_SHIFT }, /* plus shift modifier '~' */
|
||||
/* 127 */{ SDL_SCANCODE_BACKSPACE, KMOD_SHIFT }
|
||||
};
|
||||
|
||||
#endif /* _ANDROID_KeyInfo */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -56,7 +56,9 @@ LoadDBUSSyms(void)
|
|||
SDL_DBUS_SYM(message_is_signal);
|
||||
SDL_DBUS_SYM(message_new_method_call);
|
||||
SDL_DBUS_SYM(message_append_args);
|
||||
SDL_DBUS_SYM(message_append_args_valist);
|
||||
SDL_DBUS_SYM(message_get_args);
|
||||
SDL_DBUS_SYM(message_get_args_valist);
|
||||
SDL_DBUS_SYM(message_iter_init);
|
||||
SDL_DBUS_SYM(message_iter_next);
|
||||
SDL_DBUS_SYM(message_iter_get_basic);
|
||||
|
|
@ -68,6 +70,7 @@ LoadDBUSSyms(void)
|
|||
SDL_DBUS_SYM(error_free);
|
||||
SDL_DBUS_SYM(get_local_machine_id);
|
||||
SDL_DBUS_SYM(free);
|
||||
SDL_DBUS_SYM(free_string_array);
|
||||
SDL_DBUS_SYM(shutdown);
|
||||
|
||||
#undef SDL_DBUS_SYM
|
||||
|
|
@ -112,14 +115,15 @@ SDL_DBus_Init(void)
|
|||
DBusError err;
|
||||
dbus.error_init(&err);
|
||||
dbus.session_conn = dbus.bus_get_private(DBUS_BUS_SESSION, &err);
|
||||
if (!dbus.error_is_set(&err)) {
|
||||
dbus.system_conn = dbus.bus_get_private(DBUS_BUS_SYSTEM, &err);
|
||||
}
|
||||
if (dbus.error_is_set(&err)) {
|
||||
dbus.error_free(&err);
|
||||
if (dbus.session_conn) {
|
||||
dbus.connection_unref(dbus.session_conn);
|
||||
dbus.session_conn = NULL;
|
||||
}
|
||||
SDL_DBus_Quit();
|
||||
return; /* oh well */
|
||||
}
|
||||
dbus.connection_set_exit_on_disconnect(dbus.system_conn, 0);
|
||||
dbus.connection_set_exit_on_disconnect(dbus.session_conn, 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -127,12 +131,23 @@ SDL_DBus_Init(void)
|
|||
void
|
||||
SDL_DBus_Quit(void)
|
||||
{
|
||||
if (dbus.system_conn) {
|
||||
dbus.connection_close(dbus.system_conn);
|
||||
dbus.connection_unref(dbus.system_conn);
|
||||
}
|
||||
if (dbus.session_conn) {
|
||||
dbus.connection_close(dbus.session_conn);
|
||||
dbus.connection_unref(dbus.session_conn);
|
||||
dbus.shutdown();
|
||||
SDL_memset(&dbus, 0, sizeof(dbus));
|
||||
}
|
||||
/* Don't do this - bug 3950
|
||||
dbus_shutdown() is a debug feature which closes all global resources in the dbus library. Calling this should be done by the app, not a library, because if there are multiple users of dbus in the process then SDL could shut it down even though another part is using it.
|
||||
*/
|
||||
#if 0
|
||||
if (dbus.shutdown) {
|
||||
dbus.shutdown();
|
||||
}
|
||||
#endif
|
||||
SDL_zero(dbus);
|
||||
UnloadDBUSLibrary();
|
||||
}
|
||||
|
||||
|
|
@ -150,90 +165,171 @@ SDL_DBus_GetContext(void)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
SDL_DBus_ScreensaverTickle(void)
|
||||
static SDL_bool
|
||||
SDL_DBus_CallMethodInternal(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, va_list ap)
|
||||
{
|
||||
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);
|
||||
SDL_bool retval = SDL_FALSE;
|
||||
|
||||
if (conn) {
|
||||
DBusMessage *msg = dbus.message_new_method_call(node, path, interface, method);
|
||||
if (msg) {
|
||||
int firstarg = va_arg(ap, int);
|
||||
if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_append_args_valist(msg, firstarg, ap)) {
|
||||
DBusMessage *reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
|
||||
if (reply) {
|
||||
firstarg = va_arg(ap, int);
|
||||
if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_get_args_valist(reply, NULL, firstarg, ap)) {
|
||||
retval = SDL_TRUE;
|
||||
}
|
||||
dbus.message_unref(reply);
|
||||
}
|
||||
}
|
||||
dbus.message_unref(msg);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_DBus_CallMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...)
|
||||
{
|
||||
SDL_bool retval;
|
||||
va_list ap;
|
||||
va_start(ap, method);
|
||||
retval = SDL_DBus_CallMethodInternal(conn, node, path, interface, method, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_DBus_CallMethod(const char *node, const char *path, const char *interface, const char *method, ...)
|
||||
{
|
||||
SDL_bool retval;
|
||||
va_list ap;
|
||||
va_start(ap, method);
|
||||
retval = SDL_DBus_CallMethodInternal(dbus.session_conn, node, path, interface, method, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
SDL_DBus_CallVoidMethodInternal(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, va_list ap)
|
||||
{
|
||||
SDL_bool retval = SDL_FALSE;
|
||||
|
||||
if (conn) {
|
||||
DBusMessage *msg = dbus.message_new_method_call(node, path, interface, method);
|
||||
if (msg) {
|
||||
int firstarg = va_arg(ap, int);
|
||||
if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_append_args_valist(msg, firstarg, ap)) {
|
||||
if (dbus.connection_send(conn, msg, NULL)) {
|
||||
dbus.connection_flush(conn);
|
||||
retval = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
dbus.message_unref(msg);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_DBus_CallVoidMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...)
|
||||
{
|
||||
SDL_bool retval;
|
||||
va_list ap;
|
||||
va_start(ap, method);
|
||||
retval = SDL_DBus_CallVoidMethodInternal(conn, node, path, interface, method, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_DBus_CallVoidMethod(const char *node, const char *path, const char *interface, const char *method, ...)
|
||||
{
|
||||
SDL_bool retval;
|
||||
va_list ap;
|
||||
va_start(ap, method);
|
||||
retval = SDL_DBus_CallVoidMethodInternal(dbus.session_conn, node, path, interface, method, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_DBus_QueryPropertyOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result)
|
||||
{
|
||||
SDL_bool retval = SDL_FALSE;
|
||||
|
||||
if (conn) {
|
||||
DBusMessage *msg = dbus.message_new_method_call(node, path, "org.freedesktop.DBus.Properties", "Get");
|
||||
if (msg) {
|
||||
if (dbus.message_append_args(msg, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) {
|
||||
DBusMessage *reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
|
||||
if (reply) {
|
||||
DBusMessageIter iter, sub;
|
||||
dbus.message_iter_init(reply, &iter);
|
||||
if (dbus.message_iter_get_arg_type(&iter) == DBUS_TYPE_VARIANT) {
|
||||
dbus.message_iter_recurse(&iter, &sub);
|
||||
if (dbus.message_iter_get_arg_type(&sub) == expectedtype) {
|
||||
dbus.message_iter_get_basic(&sub, result);
|
||||
retval = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
dbus.message_unref(reply);
|
||||
}
|
||||
}
|
||||
dbus.message_unref(msg);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_DBus_QueryProperty(const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result)
|
||||
{
|
||||
return SDL_DBus_QueryPropertyOnConnection(dbus.session_conn, node, path, interface, property, expectedtype, result);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SDL_DBus_ScreensaverTickle(void)
|
||||
{
|
||||
SDL_DBus_CallVoidMethod("org.gnome.ScreenSaver", "/org/gnome/ScreenSaver", "org.gnome.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if ( (inhibit && (screensaver_cookie != 0)) || (!inhibit && (screensaver_cookie == 0)) ) {
|
||||
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);
|
||||
}
|
||||
const char *node = "org.freedesktop.ScreenSaver";
|
||||
const char *path = "/org/freedesktop/ScreenSaver";
|
||||
const char *interface = "org.freedesktop.ScreenSaver";
|
||||
|
||||
screensaver_cookie = 0;
|
||||
return SDL_TRUE;
|
||||
if (inhibit) {
|
||||
const char *app = "My SDL application";
|
||||
const char *reason = "Playing a game";
|
||||
if (!SDL_DBus_CallMethod(node, path, interface, "Inhibit",
|
||||
DBUS_TYPE_STRING, &app, DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID,
|
||||
DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
return (screensaver_cookie != 0) ? SDL_TRUE : SDL_FALSE;
|
||||
} else {
|
||||
if (!SDL_DBus_CallVoidMethod(node, path, interface, "UnInhibit", DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
screensaver_cookie = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_dbus_h
|
||||
#define _SDL_dbus_h
|
||||
#ifndef SDL_dbus_h_
|
||||
#define SDL_dbus_h_
|
||||
|
||||
#ifdef HAVE_DBUS_DBUS_H
|
||||
#define SDL_USE_LIBDBUS 1
|
||||
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
typedef struct SDL_DBusContext {
|
||||
DBusConnection *session_conn;
|
||||
DBusConnection *system_conn;
|
||||
|
||||
DBusConnection *(*bus_get_private)(DBusBusType, DBusError *);
|
||||
dbus_bool_t (*bus_register)(DBusConnection *, DBusError *);
|
||||
|
|
@ -53,7 +54,9 @@ typedef struct SDL_DBusContext {
|
|||
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_append_args_valist)(DBusMessage *, int, va_list);
|
||||
dbus_bool_t (*message_get_args)(DBusMessage *, DBusError *, int, ...);
|
||||
dbus_bool_t (*message_get_args_valist)(DBusMessage *, DBusError *, int, va_list);
|
||||
dbus_bool_t (*message_iter_init)(DBusMessage *, DBusMessageIter *);
|
||||
dbus_bool_t (*message_iter_next)(DBusMessageIter *);
|
||||
void (*message_iter_get_basic)(DBusMessageIter *, void *);
|
||||
|
|
@ -65,6 +68,7 @@ typedef struct SDL_DBusContext {
|
|||
void (*error_free)(DBusError *);
|
||||
char *(*get_local_machine_id)(void);
|
||||
void (*free)(void *);
|
||||
void (*free_string_array)(char **);
|
||||
void (*shutdown)(void);
|
||||
|
||||
} SDL_DBusContext;
|
||||
|
|
@ -72,11 +76,22 @@ typedef struct SDL_DBusContext {
|
|||
extern void SDL_DBus_Init(void);
|
||||
extern void SDL_DBus_Quit(void);
|
||||
extern SDL_DBusContext * SDL_DBus_GetContext(void);
|
||||
|
||||
/* These use the built-in Session connection. */
|
||||
extern SDL_bool SDL_DBus_CallMethod(const char *node, const char *path, const char *interface, const char *method, ...);
|
||||
extern SDL_bool SDL_DBus_CallVoidMethod(const char *node, const char *path, const char *interface, const char *method, ...);
|
||||
extern SDL_bool SDL_DBus_QueryProperty(const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result);
|
||||
|
||||
/* These use whatever connection you like. */
|
||||
extern SDL_bool SDL_DBus_CallMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...);
|
||||
extern SDL_bool SDL_DBus_CallVoidMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...);
|
||||
extern SDL_bool SDL_DBus_QueryPropertyOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result);
|
||||
|
||||
extern void SDL_DBus_ScreensaverTickle(void);
|
||||
extern SDL_bool SDL_DBus_ScreensaverInhibit(SDL_bool inhibit);
|
||||
|
||||
#endif /* HAVE_DBUS_DBUS_H */
|
||||
|
||||
#endif /* _SDL_dbus_h */
|
||||
#endif /* SDL_dbus_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -30,51 +30,51 @@
|
|||
*/
|
||||
|
||||
#include "SDL_evdev.h"
|
||||
#include "SDL_evdev_kbd.h"
|
||||
|
||||
#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>
|
||||
#include <linux/vt.h>
|
||||
#include <linux/tiocl.h> /* for TIOCL_GETSHIFTSTATE */
|
||||
#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"
|
||||
#include "../../events/scancodes_linux.h" /* adds linux_scancode_table */
|
||||
#include "../../core/linux/SDL_udev.h"
|
||||
|
||||
/* This isn't defined in older Linux kernel headers */
|
||||
/* These are not defined in older Linux kernel headers */
|
||||
#ifndef SYN_DROPPED
|
||||
#define SYN_DROPPED 3
|
||||
#endif
|
||||
#ifndef ABS_MT_SLOT
|
||||
#define ABS_MT_SLOT 0x2f
|
||||
#define ABS_MT_POSITION_X 0x35
|
||||
#define ABS_MT_POSITION_Y 0x36
|
||||
#define ABS_MT_TRACKING_ID 0x39
|
||||
#endif
|
||||
|
||||
typedef struct SDL_evdevlist_item
|
||||
{
|
||||
char *path;
|
||||
int fd;
|
||||
|
||||
|
||||
/* TODO: use this for every device, not just touchscreen */
|
||||
int out_of_sync;
|
||||
|
||||
|
||||
/* TODO: expand on this to have data for every possible class (mouse,
|
||||
keyboard, touchpad, etc.). Also there's probably some things in here we
|
||||
can pull out to the SDL_evdevlist_item i.e. name */
|
||||
int is_touchscreen;
|
||||
struct {
|
||||
char* name;
|
||||
|
||||
|
||||
int min_x, max_x, range_x;
|
||||
int min_y, max_y, range_y;
|
||||
|
||||
|
||||
int max_slots;
|
||||
int current_slot;
|
||||
struct {
|
||||
|
|
@ -88,18 +88,17 @@ typedef struct SDL_evdevlist_item
|
|||
int x, y;
|
||||
} * slots;
|
||||
} * touchscreen_data;
|
||||
|
||||
|
||||
struct SDL_evdevlist_item *next;
|
||||
} SDL_evdevlist_item;
|
||||
|
||||
typedef struct SDL_EVDEV_PrivateData
|
||||
{
|
||||
int ref_count;
|
||||
int num_devices;
|
||||
SDL_evdevlist_item *first;
|
||||
SDL_evdevlist_item *last;
|
||||
int num_devices;
|
||||
int ref_count;
|
||||
int console_fd;
|
||||
int kb_mode;
|
||||
SDL_EVDEV_keyboard_state *kbd;
|
||||
} SDL_EVDEV_PrivateData;
|
||||
|
||||
#define _THIS SDL_EVDEV_PrivateData *_this
|
||||
|
|
@ -111,7 +110,7 @@ static int SDL_EVDEV_device_removed(const char *dev_path);
|
|||
|
||||
#if SDL_USE_LIBUDEV
|
||||
static int SDL_EVDEV_device_added(const char *dev_path, int udev_class);
|
||||
void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class,
|
||||
static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class,
|
||||
const char *dev_path);
|
||||
#endif /* SDL_USE_LIBUDEV */
|
||||
|
||||
|
|
@ -126,93 +125,6 @@ static Uint8 EVDEV_MouseButtons[] = {
|
|||
SDL_BUTTON_X2 + 3 /* BTN_TASK 0x117 */
|
||||
};
|
||||
|
||||
static const char* EVDEV_consoles[] = {
|
||||
/* "/proc/self/fd/0",
|
||||
"/dev/tty",
|
||||
"/dev/tty0", */ /* the tty ioctl's prohibit these */
|
||||
"/dev/tty1",
|
||||
"/dev/tty2",
|
||||
"/dev/tty3",
|
||||
"/dev/tty4",
|
||||
"/dev/tty5",
|
||||
"/dev/tty6",
|
||||
"/dev/tty7", /* usually X is spawned in tty7 */
|
||||
"/dev/vc/0",
|
||||
"/dev/console"
|
||||
};
|
||||
|
||||
static int SDL_EVDEV_is_console(int fd) {
|
||||
int type;
|
||||
|
||||
return isatty(fd) && ioctl(fd, KDGKBTYPE, &type) == 0 &&
|
||||
(type == KB_101 || type == KB_84);
|
||||
}
|
||||
|
||||
/* Prevent keystrokes from reaching the tty */
|
||||
static int SDL_EVDEV_mute_keyboard(int tty_fd, int* old_kb_mode)
|
||||
{
|
||||
if (!SDL_EVDEV_is_console(tty_fd)) {
|
||||
return SDL_SetError("Tried to mute an invalid tty");
|
||||
}
|
||||
|
||||
if (ioctl(tty_fd, KDGKBMODE, old_kb_mode) < 0) {
|
||||
return SDL_SetError("Failed to get keyboard mode during muting");
|
||||
}
|
||||
|
||||
/* FIXME: atm this absolutely ruins the vt, and KDSKBMUTE isn't implemented
|
||||
in the kernel */
|
||||
/*
|
||||
if (ioctl(tty_fd, KDSKBMODE, K_OFF) < 0) {
|
||||
return SDL_SetError("Failed to set keyboard mode during muting");
|
||||
}
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Restore the keyboard mode for given tty */
|
||||
static void SDL_EVDEV_unmute_keyboard(int tty_fd, int kb_mode)
|
||||
{
|
||||
/* read above */
|
||||
/*
|
||||
if (ioctl(tty_fd, KDSKBMODE, kb_mode) < 0) {
|
||||
SDL_Log("Failed to unmute keyboard");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
static int SDL_EVDEV_get_active_tty()
|
||||
{
|
||||
int i, fd, ret, tty = 0;
|
||||
char tiocl;
|
||||
struct vt_stat vt_state;
|
||||
char path[PATH_MAX + 1];
|
||||
|
||||
for(i = 0; i < SDL_arraysize(EVDEV_consoles); i++) {
|
||||
fd = open(EVDEV_consoles[i], O_RDONLY);
|
||||
|
||||
if (fd < 0 && !SDL_EVDEV_is_console(fd))
|
||||
break;
|
||||
|
||||
tiocl = TIOCL_GETFGCONSOLE;
|
||||
if ((ret = ioctl(fd, TIOCLINUX, &tiocl)) >= 0)
|
||||
tty = ret + 1;
|
||||
else if (ioctl(fd, VT_GETSTATE, &vt_state) == 0)
|
||||
tty = vt_state.v_active;
|
||||
|
||||
close(fd);
|
||||
|
||||
if (tty) {
|
||||
sprintf(path, "/dev/tty%u", tty);
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd >= 0 && SDL_EVDEV_is_console(fd))
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
|
||||
return SDL_SetError("Failed to determine active tty");
|
||||
}
|
||||
|
||||
int
|
||||
SDL_EVDEV_Init(void)
|
||||
{
|
||||
|
|
@ -236,24 +148,18 @@ SDL_EVDEV_Init(void)
|
|||
_this = NULL;
|
||||
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_active_tty();
|
||||
|
||||
/* Mute the keyboard so keystrokes only generate evdev events and do not
|
||||
leak through to the console */
|
||||
SDL_EVDEV_mute_keyboard(_this->console_fd, &_this->kb_mode);
|
||||
|
||||
_this->kbd = SDL_EVDEV_kbd_init();
|
||||
}
|
||||
|
||||
|
||||
_this->ref_count += 1;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -263,42 +169,39 @@ 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) {
|
||||
SDL_EVDEV_unmute_keyboard(_this->console_fd, _this->kb_mode);
|
||||
close(_this->console_fd);
|
||||
}
|
||||
|
||||
|
||||
SDL_EVDEV_kbd_quit(_this->kbd);
|
||||
|
||||
/* 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->num_devices == 0);
|
||||
|
||||
|
||||
SDL_free(_this);
|
||||
_this = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if SDL_USE_LIBUDEV
|
||||
void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_class,
|
||||
static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_class,
|
||||
const char* dev_path)
|
||||
{
|
||||
if (dev_path == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switch(udev_event) {
|
||||
case SDL_UDEV_DEVICEADDED:
|
||||
if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD |
|
||||
|
|
@ -316,82 +219,6 @@ void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_class,
|
|||
}
|
||||
#endif /* SDL_USE_LIBUDEV */
|
||||
|
||||
#ifdef SDL_INPUT_LINUXKD
|
||||
/* this logic is pulled from kbd_keycode() in drivers/tty/vt/keyboard.c in the
|
||||
Linux kernel source */
|
||||
static void SDL_EVDEV_do_text_input(unsigned short keycode) {
|
||||
char shift_state;
|
||||
int locks_state;
|
||||
struct kbentry kbe;
|
||||
unsigned char type;
|
||||
char text[2] = { 0 };
|
||||
|
||||
if (_this->console_fd < 0)
|
||||
return;
|
||||
|
||||
shift_state = TIOCL_GETSHIFTSTATE;
|
||||
if (ioctl(_this->console_fd, TIOCLINUX, &shift_state) < 0) {
|
||||
/* TODO: error */
|
||||
return;
|
||||
}
|
||||
|
||||
kbe.kb_table = shift_state;
|
||||
kbe.kb_index = keycode;
|
||||
|
||||
if (ioctl(_this->console_fd, KDGKBENT, &kbe) < 0) {
|
||||
/* TODO: error */
|
||||
return;
|
||||
}
|
||||
|
||||
type = KTYP(kbe.kb_value);
|
||||
|
||||
if (type < 0xf0) {
|
||||
/*
|
||||
* FIXME: keysyms with a type below 0xf0 represent a unicode character
|
||||
* which requires special handling due to dead characters, diacritics,
|
||||
* etc. For perfect input a proper way to deal with such characters
|
||||
* should be implemented.
|
||||
*
|
||||
* For reference, the only place I was able to find out about this
|
||||
* special 0xf0 value was in an unused? couple of patches listed below.
|
||||
*
|
||||
* http://ftp.tc.edu.tw/pub/docs/Unicode/utf8/linux-2.3.12-keyboard.diff
|
||||
* http://ftp.tc.edu.tw/pub/docs/Unicode/utf8/linux-2.3.12-console.diff
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
type -= 0xf0;
|
||||
|
||||
/* if type is KT_LETTER then it can be affected by Caps Lock */
|
||||
if (type == KT_LETTER) {
|
||||
type = KT_LATIN;
|
||||
|
||||
if (ioctl(_this->console_fd, KDGKBLED, &locks_state) < 0) {
|
||||
/* TODO: error */
|
||||
return;
|
||||
}
|
||||
|
||||
if (locks_state & K_CAPSLOCK) {
|
||||
kbe.kb_table = shift_state ^ (1 << KG_SHIFT);
|
||||
|
||||
if (ioctl(_this->console_fd, KDGKBENT, &kbe) < 0) {
|
||||
/* TODO: error */
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: convert values >= 0x80 from ISO-8859-1? to UTF-8 */
|
||||
if (type != KT_LATIN || KVAL(kbe.kb_value) >= 0x80)
|
||||
return;
|
||||
|
||||
*text = KVAL(kbe.kb_value);
|
||||
SDL_SendKeyboardText(text);
|
||||
}
|
||||
#endif /* SDL_INPUT_LINUXKD */
|
||||
|
||||
void
|
||||
SDL_EVDEV_Poll(void)
|
||||
{
|
||||
|
|
@ -423,7 +250,7 @@ SDL_EVDEV_Poll(void)
|
|||
events[i].type == EV_SYN && events[i].code != SYN_REPORT) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (events[i].type) {
|
||||
case EV_KEY:
|
||||
if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) {
|
||||
|
|
@ -443,11 +270,9 @@ SDL_EVDEV_Poll(void)
|
|||
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
|
||||
SDL_EVDEV_do_text_input(events[i].code);
|
||||
#endif /* SDL_INPUT_LINUXKD */
|
||||
}
|
||||
}
|
||||
SDL_EVDEV_kbd_keycode(_this->kbd, events[i].code, events[i].value);
|
||||
break;
|
||||
case EV_ABS:
|
||||
switch(events[i].code) {
|
||||
|
|
@ -519,13 +344,13 @@ SDL_EVDEV_Poll(void)
|
|||
case SYN_REPORT:
|
||||
if (!item->is_touchscreen) /* FIXME: temp hack */
|
||||
break;
|
||||
|
||||
|
||||
for(j = 0; j < item->touchscreen_data->max_slots; j++) {
|
||||
norm_x = (float)(item->touchscreen_data->slots[j].x - item->touchscreen_data->min_x) /
|
||||
(float)item->touchscreen_data->range_x;
|
||||
norm_y = (float)(item->touchscreen_data->slots[j].y - item->touchscreen_data->min_y) /
|
||||
(float)item->touchscreen_data->range_y;
|
||||
|
||||
|
||||
switch(item->touchscreen_data->slots[j].delta) {
|
||||
case EVDEV_TOUCH_SLOTDELTA_DOWN:
|
||||
SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_TRUE, norm_x, norm_y, 1.0f);
|
||||
|
|
@ -544,7 +369,7 @@ SDL_EVDEV_Poll(void)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (item->out_of_sync)
|
||||
item->out_of_sync = 0;
|
||||
break;
|
||||
|
|
@ -573,8 +398,8 @@ SDL_EVDEV_translate_keycode(int 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);
|
||||
"get this fixed, please report this to the SDL forums/mailing list "
|
||||
"<https://discourse.libsdl.org/> EVDEV KeyCode %d", keycode);
|
||||
}
|
||||
|
||||
return scancode;
|
||||
|
|
@ -587,26 +412,26 @@ SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
|
|||
int ret, i;
|
||||
char name[64];
|
||||
struct input_absinfo abs_info;
|
||||
|
||||
|
||||
if (!item->is_touchscreen)
|
||||
return 0;
|
||||
|
||||
|
||||
item->touchscreen_data = SDL_calloc(1, sizeof(*item->touchscreen_data));
|
||||
if (item->touchscreen_data == NULL)
|
||||
return SDL_OutOfMemory();
|
||||
|
||||
|
||||
ret = ioctl(item->fd, EVIOCGNAME(sizeof(name)), name);
|
||||
if (ret < 0) {
|
||||
SDL_free(item->touchscreen_data);
|
||||
return SDL_SetError("Failed to get evdev touchscreen name");
|
||||
}
|
||||
|
||||
|
||||
item->touchscreen_data->name = SDL_strdup(name);
|
||||
if (item->touchscreen_data->name == NULL) {
|
||||
SDL_free(item->touchscreen_data);
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
|
||||
ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_X), &abs_info);
|
||||
if (ret < 0) {
|
||||
SDL_free(item->touchscreen_data->name);
|
||||
|
|
@ -616,7 +441,7 @@ SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
|
|||
item->touchscreen_data->min_x = abs_info.minimum;
|
||||
item->touchscreen_data->max_x = abs_info.maximum;
|
||||
item->touchscreen_data->range_x = abs_info.maximum - abs_info.minimum;
|
||||
|
||||
|
||||
ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_Y), &abs_info);
|
||||
if (ret < 0) {
|
||||
SDL_free(item->touchscreen_data->name);
|
||||
|
|
@ -626,7 +451,7 @@ SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
|
|||
item->touchscreen_data->min_y = abs_info.minimum;
|
||||
item->touchscreen_data->max_y = abs_info.maximum;
|
||||
item->touchscreen_data->range_y = abs_info.maximum - abs_info.minimum;
|
||||
|
||||
|
||||
ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
|
||||
if (ret < 0) {
|
||||
SDL_free(item->touchscreen_data->name);
|
||||
|
|
@ -634,7 +459,7 @@ SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
|
|||
return SDL_SetError("Failed to get evdev touchscreen limits");
|
||||
}
|
||||
item->touchscreen_data->max_slots = abs_info.maximum + 1;
|
||||
|
||||
|
||||
item->touchscreen_data->slots = SDL_calloc(
|
||||
item->touchscreen_data->max_slots,
|
||||
sizeof(*item->touchscreen_data->slots));
|
||||
|
|
@ -643,11 +468,11 @@ SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
|
|||
SDL_free(item->touchscreen_data);
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
|
||||
for(i = 0; i < item->touchscreen_data->max_slots; i++) {
|
||||
item->touchscreen_data->slots[i].tracking_id = -1;
|
||||
}
|
||||
|
||||
|
||||
ret = SDL_AddTouch(item->fd, /* I guess our fd is unique enough */
|
||||
item->touchscreen_data->name);
|
||||
if (ret < 0) {
|
||||
|
|
@ -656,7 +481,7 @@ SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
|
|||
SDL_free(item->touchscreen_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* SDL_USE_LIBUDEV */
|
||||
|
|
@ -665,7 +490,7 @@ static void
|
|||
SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) {
|
||||
if (!item->is_touchscreen)
|
||||
return;
|
||||
|
||||
|
||||
SDL_DelTouch(item->fd);
|
||||
SDL_free(item->touchscreen_data->slots);
|
||||
SDL_free(item->touchscreen_data->name);
|
||||
|
|
@ -689,21 +514,21 @@ SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
|
|||
__u32* mt_req_code;
|
||||
__s32* mt_req_values;
|
||||
size_t mt_req_size;
|
||||
|
||||
|
||||
/* TODO: sync devices other than touchscreen */
|
||||
if (!item->is_touchscreen)
|
||||
return;
|
||||
|
||||
|
||||
mt_req_size = sizeof(*mt_req_code) +
|
||||
sizeof(*mt_req_values) * item->touchscreen_data->max_slots;
|
||||
|
||||
|
||||
mt_req_code = SDL_calloc(1, mt_req_size);
|
||||
if (mt_req_code == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
mt_req_values = (__s32*)mt_req_code + 1;
|
||||
|
||||
|
||||
*mt_req_code = ABS_MT_TRACKING_ID;
|
||||
ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
|
||||
if (ret < 0) {
|
||||
|
|
@ -730,7 +555,7 @@ SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
|
|||
item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_UP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*mt_req_code = ABS_MT_POSITION_X;
|
||||
ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
|
||||
if (ret < 0) {
|
||||
|
|
@ -748,7 +573,7 @@ SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*mt_req_code = ABS_MT_POSITION_Y;
|
||||
ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
|
||||
if (ret < 0) {
|
||||
|
|
@ -766,14 +591,14 @@ SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
|
||||
if (ret < 0) {
|
||||
SDL_free(mt_req_code);
|
||||
return;
|
||||
}
|
||||
item->touchscreen_data->current_slot = abs_info.value;
|
||||
|
||||
|
||||
SDL_free(mt_req_code);
|
||||
|
||||
#endif /* EVIOCGMTSLOTS */
|
||||
|
|
@ -792,7 +617,7 @@ SDL_EVDEV_device_added(const char *dev_path, int udev_class)
|
|||
return -1; /* already have this one */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
|
||||
if (item == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
|
|
@ -803,33 +628,33 @@ SDL_EVDEV_device_added(const char *dev_path, int udev_class)
|
|||
SDL_free(item);
|
||||
return SDL_SetError("Unable to open %s", dev_path);
|
||||
}
|
||||
|
||||
|
||||
item->path = SDL_strdup(dev_path);
|
||||
if (item->path == NULL) {
|
||||
close(item->fd);
|
||||
SDL_free(item);
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
|
||||
if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) {
|
||||
item->is_touchscreen = 1;
|
||||
|
||||
|
||||
if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) {
|
||||
close(item->fd);
|
||||
SDL_free(item);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_this->last == NULL) {
|
||||
_this->first = _this->last = item;
|
||||
} else {
|
||||
_this->last->next = item;
|
||||
_this->last = item;
|
||||
}
|
||||
|
||||
|
||||
SDL_EVDEV_sync_device(item);
|
||||
|
||||
|
||||
return _this->num_devices++;
|
||||
}
|
||||
#endif /* SDL_USE_LIBUDEV */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_evdev_h
|
||||
#define _SDL_evdev_h
|
||||
#ifndef SDL_evdev_h_
|
||||
#define SDL_evdev_h_
|
||||
|
||||
#ifdef SDL_INPUT_LINUXEV
|
||||
|
||||
|
|
@ -34,6 +34,6 @@ extern void SDL_EVDEV_Poll(void);
|
|||
|
||||
#endif /* SDL_INPUT_LINUXEV */
|
||||
|
||||
#endif /* _SDL_evdev_h */
|
||||
#endif /* SDL_evdev_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
677
Engine/lib/sdl/src/core/linux/SDL_evdev_kbd.c
Normal file
677
Engine/lib/sdl/src/core/linux/SDL_evdev_kbd.c
Normal file
|
|
@ -0,0 +1,677 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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_evdev_kbd.h"
|
||||
|
||||
#ifdef SDL_INPUT_LINUXKD
|
||||
|
||||
/* This logic is adapted from drivers/tty/vt/keyboard.c in the Linux kernel source */
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/kd.h>
|
||||
#include <linux/keyboard.h>
|
||||
#include <linux/vt.h>
|
||||
#include <linux/tiocl.h> /* for TIOCL_GETSHIFTSTATE */
|
||||
|
||||
#include "../../events/SDL_events_c.h"
|
||||
#include "SDL_evdev_kbd_default_accents.h"
|
||||
#include "SDL_evdev_kbd_default_keymap.h"
|
||||
|
||||
/* These are not defined in older Linux kernel headers */
|
||||
#ifndef K_UNICODE
|
||||
#define K_UNICODE 0x03
|
||||
#endif
|
||||
#ifndef K_OFF
|
||||
#define K_OFF 0x04
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handler Tables.
|
||||
*/
|
||||
|
||||
#define K_HANDLERS\
|
||||
k_self, k_fn, k_spec, k_pad,\
|
||||
k_dead, k_cons, k_cur, k_shift,\
|
||||
k_meta, k_ascii, k_lock, k_lowercase,\
|
||||
k_slock, k_dead2, k_brl, k_ignore
|
||||
|
||||
typedef void (k_handler_fn)(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag);
|
||||
static k_handler_fn K_HANDLERS;
|
||||
static k_handler_fn *k_handler[16] = { K_HANDLERS };
|
||||
|
||||
typedef void (fn_handler_fn)(SDL_EVDEV_keyboard_state *kbd);
|
||||
static void fn_enter(SDL_EVDEV_keyboard_state *kbd);
|
||||
static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd);
|
||||
static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd);
|
||||
static void fn_num(SDL_EVDEV_keyboard_state *kbd);
|
||||
static void fn_compose(SDL_EVDEV_keyboard_state *kbd);
|
||||
|
||||
static fn_handler_fn *fn_handler[] =
|
||||
{
|
||||
NULL, fn_enter, NULL, NULL,
|
||||
NULL, NULL, NULL, fn_caps_toggle,
|
||||
fn_num, NULL, NULL, NULL,
|
||||
NULL, fn_caps_on, fn_compose, NULL,
|
||||
NULL, NULL, NULL, fn_num
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Keyboard State
|
||||
*/
|
||||
|
||||
struct SDL_EVDEV_keyboard_state
|
||||
{
|
||||
int console_fd;
|
||||
int old_kbd_mode;
|
||||
unsigned short **key_maps;
|
||||
unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */
|
||||
SDL_bool dead_key_next;
|
||||
int npadch; /* -1 or number assembled on pad */
|
||||
struct kbdiacrs *accents;
|
||||
unsigned int diacr;
|
||||
SDL_bool rep; /* flag telling character repeat */
|
||||
unsigned char lockstate;
|
||||
unsigned char slockstate;
|
||||
unsigned char ledflagstate;
|
||||
char shift_state;
|
||||
char text[128];
|
||||
unsigned int text_len;
|
||||
};
|
||||
|
||||
#ifdef DUMP_ACCENTS
|
||||
static void SDL_EVDEV_dump_accents(SDL_EVDEV_keyboard_state *kbd)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
printf("static struct kbdiacrs default_accents = {\n");
|
||||
printf(" %d,\n", kbd->accents->kb_cnt);
|
||||
printf(" {\n");
|
||||
for (i = 0; i < kbd->accents->kb_cnt; ++i) {
|
||||
struct kbdiacr *diacr = &kbd->accents->kbdiacr[i];
|
||||
printf(" { 0x%.2x, 0x%.2x, 0x%.2x },\n",
|
||||
diacr->diacr, diacr->base, diacr->result);
|
||||
}
|
||||
while (i < 256) {
|
||||
printf(" { 0x00, 0x00, 0x00 },\n");
|
||||
++i;
|
||||
}
|
||||
printf(" }\n");
|
||||
printf("};\n");
|
||||
}
|
||||
#endif /* DUMP_ACCENTS */
|
||||
|
||||
#ifdef DUMP_KEYMAP
|
||||
static void SDL_EVDEV_dump_keymap(SDL_EVDEV_keyboard_state *kbd)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
|
||||
if (kbd->key_maps[i]) {
|
||||
printf("static unsigned short default_key_map_%d[NR_KEYS] = {", i);
|
||||
for (j = 0; j < NR_KEYS; ++j) {
|
||||
if ((j%8) == 0) {
|
||||
printf("\n ");
|
||||
}
|
||||
printf("0x%.4x, ", kbd->key_maps[i][j]);
|
||||
}
|
||||
printf("\n};\n");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
printf("static unsigned short *default_key_maps[MAX_NR_KEYMAPS] = {\n");
|
||||
for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
|
||||
if (kbd->key_maps[i]) {
|
||||
printf(" default_key_map_%d,\n", i);
|
||||
} else {
|
||||
printf(" NULL,\n");
|
||||
}
|
||||
}
|
||||
printf("};\n");
|
||||
}
|
||||
#endif /* DUMP_KEYMAP */
|
||||
|
||||
static int SDL_EVDEV_kbd_load_keymaps(SDL_EVDEV_keyboard_state *kbd)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
kbd->key_maps = (unsigned short **)SDL_calloc(MAX_NR_KEYMAPS, sizeof(unsigned short *));
|
||||
if (!kbd->key_maps) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
|
||||
struct kbentry kbe;
|
||||
|
||||
kbe.kb_table = i;
|
||||
kbe.kb_index = 0;
|
||||
if (ioctl(kbd->console_fd, KDGKBENT, &kbe) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (kbe.kb_value == K_NOSUCHMAP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
kbd->key_maps[i] = (unsigned short *)SDL_malloc(NR_KEYS * sizeof(unsigned short));
|
||||
if (!kbd->key_maps[i]) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (j = 0; j < NR_KEYS; ++j) {
|
||||
kbe.kb_table = i;
|
||||
kbe.kb_index = j;
|
||||
if (ioctl(kbd->console_fd, KDGKBENT, &kbe) < 0) {
|
||||
return -1;
|
||||
}
|
||||
kbd->key_maps[i][j] = (kbe.kb_value ^ 0xf000);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_EVDEV_keyboard_state *
|
||||
SDL_EVDEV_kbd_init(void)
|
||||
{
|
||||
SDL_EVDEV_keyboard_state *kbd;
|
||||
int i;
|
||||
char flag_state;
|
||||
char shift_state[2] = {TIOCL_GETSHIFTSTATE, 0};
|
||||
|
||||
kbd = (SDL_EVDEV_keyboard_state *)SDL_calloc(1, sizeof(*kbd));
|
||||
if (!kbd) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kbd->npadch = -1;
|
||||
|
||||
/* This might fail if we're not connected to a tty (e.g. on the Steam Link) */
|
||||
kbd->console_fd = open("/dev/tty", O_RDONLY);
|
||||
|
||||
if (ioctl(kbd->console_fd, TIOCLINUX, shift_state) == 0) {
|
||||
kbd->shift_state = *shift_state;
|
||||
}
|
||||
|
||||
if (ioctl(kbd->console_fd, KDGKBLED, &flag_state) == 0) {
|
||||
kbd->ledflagstate = flag_state;
|
||||
}
|
||||
|
||||
kbd->accents = &default_accents;
|
||||
if (ioctl(kbd->console_fd, KDGKBDIACR, kbd->accents) < 0) {
|
||||
/* No worries, we'll use the default accent table */
|
||||
}
|
||||
|
||||
kbd->key_maps = default_key_maps;
|
||||
if (ioctl(kbd->console_fd, KDGKBMODE, &kbd->old_kbd_mode) == 0) {
|
||||
/* Set the keyboard in UNICODE mode and load the keymaps */
|
||||
ioctl(kbd->console_fd, KDSKBMODE, K_UNICODE);
|
||||
|
||||
if (SDL_EVDEV_kbd_load_keymaps(kbd) < 0) {
|
||||
for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
|
||||
if (kbd->key_maps[i]) {
|
||||
SDL_free(kbd->key_maps[i]);
|
||||
}
|
||||
}
|
||||
SDL_free(kbd->key_maps);
|
||||
|
||||
kbd->key_maps = default_key_maps;
|
||||
}
|
||||
|
||||
/* Mute the keyboard so keystrokes only generate evdev events
|
||||
* and do not leak through to the console
|
||||
*/
|
||||
ioctl(kbd->console_fd, KDSKBMODE, K_OFF);
|
||||
}
|
||||
|
||||
#ifdef DUMP_ACCENTS
|
||||
SDL_EVDEV_dump_accents(kbd);
|
||||
#endif
|
||||
#ifdef DUMP_KEYMAP
|
||||
SDL_EVDEV_dump_keymap(kbd);
|
||||
#endif
|
||||
return kbd;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *kbd)
|
||||
{
|
||||
if (!kbd) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (kbd->console_fd >= 0) {
|
||||
/* Restore the original keyboard mode */
|
||||
ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
|
||||
|
||||
close(kbd->console_fd);
|
||||
kbd->console_fd = -1;
|
||||
}
|
||||
|
||||
if (kbd->key_maps && kbd->key_maps != default_key_maps) {
|
||||
int i;
|
||||
for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
|
||||
if (kbd->key_maps[i]) {
|
||||
SDL_free(kbd->key_maps[i]);
|
||||
}
|
||||
}
|
||||
SDL_free(kbd->key_maps);
|
||||
}
|
||||
|
||||
SDL_free(kbd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper Functions.
|
||||
*/
|
||||
static void put_queue(SDL_EVDEV_keyboard_state *kbd, uint c)
|
||||
{
|
||||
/* c is already part of a UTF-8 sequence and safe to add as a character */
|
||||
if (kbd->text_len < (sizeof(kbd->text)-1)) {
|
||||
kbd->text[kbd->text_len++] = (char)c;
|
||||
}
|
||||
}
|
||||
|
||||
static void put_utf8(SDL_EVDEV_keyboard_state *kbd, uint c)
|
||||
{
|
||||
if (c < 0x80)
|
||||
/* 0******* */
|
||||
put_queue(kbd, c);
|
||||
else if (c < 0x800) {
|
||||
/* 110***** 10****** */
|
||||
put_queue(kbd, 0xc0 | (c >> 6));
|
||||
put_queue(kbd, 0x80 | (c & 0x3f));
|
||||
} else if (c < 0x10000) {
|
||||
if (c >= 0xD800 && c < 0xE000)
|
||||
return;
|
||||
if (c == 0xFFFF)
|
||||
return;
|
||||
/* 1110**** 10****** 10****** */
|
||||
put_queue(kbd, 0xe0 | (c >> 12));
|
||||
put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
|
||||
put_queue(kbd, 0x80 | (c & 0x3f));
|
||||
} else if (c < 0x110000) {
|
||||
/* 11110*** 10****** 10****** 10****** */
|
||||
put_queue(kbd, 0xf0 | (c >> 18));
|
||||
put_queue(kbd, 0x80 | ((c >> 12) & 0x3f));
|
||||
put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
|
||||
put_queue(kbd, 0x80 | (c & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a combining character DIACR here, followed by the character CH.
|
||||
* If the combination occurs in the table, return the corresponding value.
|
||||
* Otherwise, if CH is a space or equals DIACR, return DIACR.
|
||||
* Otherwise, conclude that DIACR was not combining after all,
|
||||
* queue it and return CH.
|
||||
*/
|
||||
static unsigned int handle_diacr(SDL_EVDEV_keyboard_state *kbd, unsigned int ch)
|
||||
{
|
||||
unsigned int d = kbd->diacr;
|
||||
unsigned int i;
|
||||
|
||||
kbd->diacr = 0;
|
||||
|
||||
for (i = 0; i < kbd->accents->kb_cnt; i++) {
|
||||
if (kbd->accents->kbdiacr[i].diacr == d &&
|
||||
kbd->accents->kbdiacr[i].base == ch) {
|
||||
return kbd->accents->kbdiacr[i].result;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch == ' ' || ch == d)
|
||||
return d;
|
||||
|
||||
put_utf8(kbd, d);
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
static int vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
|
||||
{
|
||||
return ((kbd->ledflagstate >> flag) & 1);
|
||||
}
|
||||
|
||||
static void set_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
|
||||
{
|
||||
kbd->ledflagstate |= 1 << flag;
|
||||
}
|
||||
|
||||
static void clr_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
|
||||
{
|
||||
kbd->ledflagstate &= ~(1 << flag);
|
||||
}
|
||||
|
||||
static void chg_vc_kbd_lock(SDL_EVDEV_keyboard_state *kbd, int flag)
|
||||
{
|
||||
kbd->lockstate ^= 1 << flag;
|
||||
}
|
||||
|
||||
static void chg_vc_kbd_slock(SDL_EVDEV_keyboard_state *kbd, int flag)
|
||||
{
|
||||
kbd->slockstate ^= 1 << flag;
|
||||
}
|
||||
|
||||
static void chg_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
|
||||
{
|
||||
kbd->ledflagstate ^= 1 << flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* Special function handlers
|
||||
*/
|
||||
|
||||
static void fn_enter(SDL_EVDEV_keyboard_state *kbd)
|
||||
{
|
||||
if (kbd->diacr) {
|
||||
put_utf8(kbd, kbd->diacr);
|
||||
kbd->diacr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd)
|
||||
{
|
||||
if (kbd->rep)
|
||||
return;
|
||||
|
||||
chg_vc_kbd_led(kbd, K_CAPSLOCK);
|
||||
}
|
||||
|
||||
static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd)
|
||||
{
|
||||
if (kbd->rep)
|
||||
return;
|
||||
|
||||
set_vc_kbd_led(kbd, K_CAPSLOCK);
|
||||
}
|
||||
|
||||
static void fn_num(SDL_EVDEV_keyboard_state *kbd)
|
||||
{
|
||||
if (!kbd->rep)
|
||||
chg_vc_kbd_led(kbd, K_NUMLOCK);
|
||||
}
|
||||
|
||||
static void fn_compose(SDL_EVDEV_keyboard_state *kbd)
|
||||
{
|
||||
kbd->dead_key_next = SDL_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Special key handlers
|
||||
*/
|
||||
|
||||
static void k_ignore(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
}
|
||||
|
||||
static void k_spec(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
if (up_flag)
|
||||
return;
|
||||
if (value >= SDL_arraysize(fn_handler))
|
||||
return;
|
||||
if (fn_handler[value])
|
||||
fn_handler[value](kbd);
|
||||
}
|
||||
|
||||
static void k_lowercase(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
}
|
||||
|
||||
static void k_self(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
if (up_flag)
|
||||
return; /* no action, if this is a key release */
|
||||
|
||||
if (kbd->diacr)
|
||||
value = handle_diacr(kbd, value);
|
||||
|
||||
if (kbd->dead_key_next) {
|
||||
kbd->dead_key_next = SDL_FALSE;
|
||||
kbd->diacr = value;
|
||||
return;
|
||||
}
|
||||
put_utf8(kbd, value);
|
||||
}
|
||||
|
||||
static void k_deadunicode(SDL_EVDEV_keyboard_state *kbd, unsigned int value, char up_flag)
|
||||
{
|
||||
if (up_flag)
|
||||
return;
|
||||
|
||||
kbd->diacr = (kbd->diacr ? handle_diacr(kbd, value) : value);
|
||||
}
|
||||
|
||||
static void k_dead(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
|
||||
|
||||
k_deadunicode(kbd, ret_diacr[value], up_flag);
|
||||
}
|
||||
|
||||
static void k_dead2(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
k_deadunicode(kbd, value, up_flag);
|
||||
}
|
||||
|
||||
static void k_cons(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
}
|
||||
|
||||
static void k_fn(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
}
|
||||
|
||||
static void k_cur(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
}
|
||||
|
||||
static void k_pad(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
static const char pad_chars[] = "0123456789+-*/\015,.?()#";
|
||||
|
||||
if (up_flag)
|
||||
return; /* no action, if this is a key release */
|
||||
|
||||
if (!vc_kbd_led(kbd, K_NUMLOCK)) {
|
||||
/* unprintable action */
|
||||
return;
|
||||
}
|
||||
|
||||
put_queue(kbd, pad_chars[value]);
|
||||
}
|
||||
|
||||
static void k_shift(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
int old_state = kbd->shift_state;
|
||||
|
||||
if (kbd->rep)
|
||||
return;
|
||||
/*
|
||||
* Mimic typewriter:
|
||||
* a CapsShift key acts like Shift but undoes CapsLock
|
||||
*/
|
||||
if (value == KVAL(K_CAPSSHIFT)) {
|
||||
value = KVAL(K_SHIFT);
|
||||
if (!up_flag)
|
||||
clr_vc_kbd_led(kbd, K_CAPSLOCK);
|
||||
}
|
||||
|
||||
if (up_flag) {
|
||||
/*
|
||||
* handle the case that two shift or control
|
||||
* keys are depressed simultaneously
|
||||
*/
|
||||
if (kbd->shift_down[value])
|
||||
kbd->shift_down[value]--;
|
||||
} else
|
||||
kbd->shift_down[value]++;
|
||||
|
||||
if (kbd->shift_down[value])
|
||||
kbd->shift_state |= (1 << value);
|
||||
else
|
||||
kbd->shift_state &= ~(1 << value);
|
||||
|
||||
/* kludge */
|
||||
if (up_flag && kbd->shift_state != old_state && kbd->npadch != -1) {
|
||||
put_utf8(kbd, kbd->npadch);
|
||||
kbd->npadch = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void k_meta(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
}
|
||||
|
||||
static void k_ascii(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
int base;
|
||||
|
||||
if (up_flag)
|
||||
return;
|
||||
|
||||
if (value < 10) {
|
||||
/* decimal input of code, while Alt depressed */
|
||||
base = 10;
|
||||
} else {
|
||||
/* hexadecimal input of code, while AltGr depressed */
|
||||
value -= 10;
|
||||
base = 16;
|
||||
}
|
||||
|
||||
if (kbd->npadch == -1)
|
||||
kbd->npadch = value;
|
||||
else
|
||||
kbd->npadch = kbd->npadch * base + value;
|
||||
}
|
||||
|
||||
static void k_lock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
if (up_flag || kbd->rep)
|
||||
return;
|
||||
|
||||
chg_vc_kbd_lock(kbd, value);
|
||||
}
|
||||
|
||||
static void k_slock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
k_shift(kbd, value, up_flag);
|
||||
if (up_flag || kbd->rep)
|
||||
return;
|
||||
|
||||
chg_vc_kbd_slock(kbd, value);
|
||||
/* try to make Alt, oops, AltGr and such work */
|
||||
if (!kbd->key_maps[kbd->lockstate ^ kbd->slockstate]) {
|
||||
kbd->slockstate = 0;
|
||||
chg_vc_kbd_slock(kbd, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void k_brl(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode, int down)
|
||||
{
|
||||
unsigned char shift_final;
|
||||
unsigned char type;
|
||||
unsigned short *key_map;
|
||||
unsigned short keysym;
|
||||
|
||||
if (!kbd) {
|
||||
return;
|
||||
}
|
||||
|
||||
kbd->rep = (down == 2);
|
||||
|
||||
shift_final = (kbd->shift_state | kbd->slockstate) ^ kbd->lockstate;
|
||||
key_map = kbd->key_maps[shift_final];
|
||||
if (!key_map) {
|
||||
kbd->slockstate = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (keycode < NR_KEYS) {
|
||||
keysym = key_map[keycode];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
type = KTYP(keysym);
|
||||
|
||||
if (type < 0xf0) {
|
||||
if (down) {
|
||||
put_utf8(kbd, keysym);
|
||||
}
|
||||
} else {
|
||||
type -= 0xf0;
|
||||
|
||||
/* if type is KT_LETTER then it can be affected by Caps Lock */
|
||||
if (type == KT_LETTER) {
|
||||
type = KT_LATIN;
|
||||
|
||||
if (vc_kbd_led(kbd, K_CAPSLOCK)) {
|
||||
key_map = kbd->key_maps[shift_final ^ (1 << KG_SHIFT)];
|
||||
if (key_map) {
|
||||
keysym = key_map[keycode];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(*k_handler[type])(kbd, keysym & 0xff, !down);
|
||||
|
||||
if (type != KT_SLOCK) {
|
||||
kbd->slockstate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (kbd->text_len > 0) {
|
||||
kbd->text[kbd->text_len] = '\0';
|
||||
SDL_SendKeyboardText(kbd->text);
|
||||
kbd->text_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !SDL_INPUT_LINUXKD */
|
||||
|
||||
SDL_EVDEV_keyboard_state *
|
||||
SDL_EVDEV_kbd_init(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* SDL_INPUT_LINUXKD */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
29
Engine/lib/sdl/src/core/linux/SDL_evdev_kbd.h
Normal file
29
Engine/lib/sdl/src/core/linux/SDL_evdev_kbd.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
struct SDL_EVDEV_keyboard_state;
|
||||
typedef struct SDL_EVDEV_keyboard_state SDL_EVDEV_keyboard_state;
|
||||
|
||||
extern SDL_EVDEV_keyboard_state *SDL_EVDEV_kbd_init(void);
|
||||
extern void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down);
|
||||
extern void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state);
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
284
Engine/lib/sdl/src/core/linux/SDL_evdev_kbd_default_accents.h
Normal file
284
Engine/lib/sdl/src/core/linux/SDL_evdev_kbd_default_accents.h
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
static struct kbdiacrs default_accents = {
|
||||
68,
|
||||
{
|
||||
{ 0x60, 0x41, 0xc0 },
|
||||
{ 0x60, 0x61, 0xe0 },
|
||||
{ 0x27, 0x41, 0xc1 },
|
||||
{ 0x27, 0x61, 0xe1 },
|
||||
{ 0x5e, 0x41, 0xc2 },
|
||||
{ 0x5e, 0x61, 0xe2 },
|
||||
{ 0x7e, 0x41, 0xc3 },
|
||||
{ 0x7e, 0x61, 0xe3 },
|
||||
{ 0x22, 0x41, 0xc4 },
|
||||
{ 0x22, 0x61, 0xe4 },
|
||||
{ 0x4f, 0x41, 0xc5 },
|
||||
{ 0x6f, 0x61, 0xe5 },
|
||||
{ 0x30, 0x41, 0xc5 },
|
||||
{ 0x30, 0x61, 0xe5 },
|
||||
{ 0x41, 0x41, 0xc5 },
|
||||
{ 0x61, 0x61, 0xe5 },
|
||||
{ 0x41, 0x45, 0xc6 },
|
||||
{ 0x61, 0x65, 0xe6 },
|
||||
{ 0x2c, 0x43, 0xc7 },
|
||||
{ 0x2c, 0x63, 0xe7 },
|
||||
{ 0x60, 0x45, 0xc8 },
|
||||
{ 0x60, 0x65, 0xe8 },
|
||||
{ 0x27, 0x45, 0xc9 },
|
||||
{ 0x27, 0x65, 0xe9 },
|
||||
{ 0x5e, 0x45, 0xca },
|
||||
{ 0x5e, 0x65, 0xea },
|
||||
{ 0x22, 0x45, 0xcb },
|
||||
{ 0x22, 0x65, 0xeb },
|
||||
{ 0x60, 0x49, 0xcc },
|
||||
{ 0x60, 0x69, 0xec },
|
||||
{ 0x27, 0x49, 0xcd },
|
||||
{ 0x27, 0x69, 0xed },
|
||||
{ 0x5e, 0x49, 0xce },
|
||||
{ 0x5e, 0x69, 0xee },
|
||||
{ 0x22, 0x49, 0xcf },
|
||||
{ 0x22, 0x69, 0xef },
|
||||
{ 0x2d, 0x44, 0xd0 },
|
||||
{ 0x2d, 0x64, 0xf0 },
|
||||
{ 0x7e, 0x4e, 0xd1 },
|
||||
{ 0x7e, 0x6e, 0xf1 },
|
||||
{ 0x60, 0x4f, 0xd2 },
|
||||
{ 0x60, 0x6f, 0xf2 },
|
||||
{ 0x27, 0x4f, 0xd3 },
|
||||
{ 0x27, 0x6f, 0xf3 },
|
||||
{ 0x5e, 0x4f, 0xd4 },
|
||||
{ 0x5e, 0x6f, 0xf4 },
|
||||
{ 0x7e, 0x4f, 0xd5 },
|
||||
{ 0x7e, 0x6f, 0xf5 },
|
||||
{ 0x22, 0x4f, 0xd6 },
|
||||
{ 0x22, 0x6f, 0xf6 },
|
||||
{ 0x2f, 0x4f, 0xd8 },
|
||||
{ 0x2f, 0x6f, 0xf8 },
|
||||
{ 0x60, 0x55, 0xd9 },
|
||||
{ 0x60, 0x75, 0xf9 },
|
||||
{ 0x27, 0x55, 0xda },
|
||||
{ 0x27, 0x75, 0xfa },
|
||||
{ 0x5e, 0x55, 0xdb },
|
||||
{ 0x5e, 0x75, 0xfb },
|
||||
{ 0x22, 0x55, 0xdc },
|
||||
{ 0x22, 0x75, 0xfc },
|
||||
{ 0x27, 0x59, 0xdd },
|
||||
{ 0x27, 0x79, 0xfd },
|
||||
{ 0x54, 0x48, 0xde },
|
||||
{ 0x74, 0x68, 0xfe },
|
||||
{ 0x73, 0x73, 0xdf },
|
||||
{ 0x22, 0x79, 0xff },
|
||||
{ 0x73, 0x7a, 0xdf },
|
||||
{ 0x69, 0x6a, 0xff },
|
||||
{ 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 },
|
||||
{ 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 },
|
||||
{ 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 },
|
||||
{ 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 },
|
||||
{ 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 },
|
||||
}
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
4763
Engine/lib/sdl/src/core/linux/SDL_evdev_kbd_default_keymap.h
Normal file
4763
Engine/lib/sdl/src/core/linux/SDL_evdev_kbd_default_keymap.h
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -118,71 +118,6 @@ GetAppName()
|
|||
return SDL_strdup("SDL_App");
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from fcitx source
|
||||
*/
|
||||
#define CONT(i) ISUTF8_CB(in[i])
|
||||
#define VAL(i, s) ((in[i]&0x3f) << s)
|
||||
|
||||
static char *
|
||||
_fcitx_utf8_get_char(const char *i, uint32_t *chr)
|
||||
{
|
||||
const unsigned char* in = (const unsigned char *)i;
|
||||
if (!(in[0] & 0x80)) {
|
||||
*(chr) = *(in);
|
||||
return (char *)in + 1;
|
||||
}
|
||||
|
||||
/* 2-byte, 0x80-0x7ff */
|
||||
if ((in[0] & 0xe0) == 0xc0 && CONT(1)) {
|
||||
*chr = ((in[0] & 0x1f) << 6) | VAL(1, 0);
|
||||
return (char *)in + 2;
|
||||
}
|
||||
|
||||
/* 3-byte, 0x800-0xffff */
|
||||
if ((in[0] & 0xf0) == 0xe0 && CONT(1) && CONT(2)) {
|
||||
*chr = ((in[0] & 0xf) << 12) | VAL(1, 6) | VAL(2, 0);
|
||||
return (char *)in + 3;
|
||||
}
|
||||
|
||||
/* 4-byte, 0x10000-0x1FFFFF */
|
||||
if ((in[0] & 0xf8) == 0xf0 && CONT(1) && CONT(2) && CONT(3)) {
|
||||
*chr = ((in[0] & 0x7) << 18) | VAL(1, 12) | VAL(2, 6) | VAL(3, 0);
|
||||
return (char *)in + 4;
|
||||
}
|
||||
|
||||
/* 5-byte, 0x200000-0x3FFFFFF */
|
||||
if ((in[0] & 0xfc) == 0xf8 && CONT(1) && CONT(2) && CONT(3) && CONT(4)) {
|
||||
*chr = ((in[0] & 0x3) << 24) | VAL(1, 18) | VAL(2, 12) | VAL(3, 6) | VAL(4, 0);
|
||||
return (char *)in + 5;
|
||||
}
|
||||
|
||||
/* 6-byte, 0x400000-0x7FFFFFF */
|
||||
if ((in[0] & 0xfe) == 0xfc && CONT(1) && CONT(2) && CONT(3) && CONT(4) && CONT(5)) {
|
||||
*chr = ((in[0] & 0x1) << 30) | VAL(1, 24) | VAL(2, 18) | VAL(3, 12) | VAL(4, 6) | VAL(5, 0);
|
||||
return (char *)in + 6;
|
||||
}
|
||||
|
||||
*chr = *in;
|
||||
|
||||
return (char *)in + 1;
|
||||
}
|
||||
|
||||
static size_t
|
||||
_fcitx_utf8_strlen(const char *s)
|
||||
{
|
||||
unsigned int l = 0;
|
||||
|
||||
while (*s) {
|
||||
uint32_t chr;
|
||||
|
||||
s = _fcitx_utf8_get_char(s, &chr);
|
||||
l++;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static DBusHandlerResult
|
||||
DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
|
|
@ -214,8 +149,8 @@ DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data)
|
|||
size_t cursor = 0;
|
||||
|
||||
while (i < text_bytes) {
|
||||
size_t sz = SDL_utf8strlcpy(buf, text + i, sizeof(buf));
|
||||
size_t chars = _fcitx_utf8_strlen(buf);
|
||||
const size_t sz = SDL_utf8strlcpy(buf, text + i, sizeof(buf));
|
||||
const size_t chars = SDL_utf8strlen(buf);
|
||||
|
||||
SDL_SendEditingText(buf, cursor, chars);
|
||||
|
||||
|
|
@ -231,116 +166,50 @@ DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data)
|
|||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
}
|
||||
|
||||
static DBusMessage*
|
||||
FcitxClientICNewMethod(FcitxClient *client,
|
||||
const char *method)
|
||||
static void
|
||||
FcitxClientICCallMethod(FcitxClient *client, const char *method)
|
||||
{
|
||||
SDL_DBusContext *dbus = client->dbus;
|
||||
return dbus->message_new_method_call(
|
||||
client->servicename,
|
||||
client->icname,
|
||||
FCITX_IC_DBUS_INTERFACE,
|
||||
method);
|
||||
SDL_DBus_CallVoidMethod(client->servicename, client->icname, FCITX_IC_DBUS_INTERFACE, method, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
static void
|
||||
FcitxClientICCallMethod(FcitxClient *client,
|
||||
const char *method)
|
||||
{
|
||||
SDL_DBusContext *dbus = client->dbus;
|
||||
DBusMessage *msg = FcitxClientICNewMethod(client, method);
|
||||
|
||||
if (msg == NULL)
|
||||
return ;
|
||||
|
||||
if (dbus->connection_send(dbus->session_conn, msg, NULL)) {
|
||||
dbus->connection_flush(dbus->session_conn);
|
||||
}
|
||||
|
||||
dbus->message_unref(msg);
|
||||
}
|
||||
|
||||
static void
|
||||
static void SDLCALL
|
||||
Fcitx_SetCapabilities(void *data,
|
||||
const char *name,
|
||||
const char *old_val,
|
||||
const char *internal_editing)
|
||||
{
|
||||
FcitxClient *client = (FcitxClient *)data;
|
||||
SDL_DBusContext *dbus = client->dbus;
|
||||
Uint32 caps = CAPACITY_NONE;
|
||||
|
||||
DBusMessage *msg = FcitxClientICNewMethod(client, "SetCapacity");
|
||||
if (msg == NULL)
|
||||
return ;
|
||||
|
||||
if (!(internal_editing && *internal_editing == '1')) {
|
||||
caps |= CAPACITY_PREEDIT;
|
||||
}
|
||||
|
||||
dbus->message_append_args(msg,
|
||||
DBUS_TYPE_UINT32, &caps,
|
||||
DBUS_TYPE_INVALID);
|
||||
if (dbus->connection_send(dbus->session_conn, msg, NULL)) {
|
||||
dbus->connection_flush(dbus->session_conn);
|
||||
}
|
||||
|
||||
dbus->message_unref(msg);
|
||||
SDL_DBus_CallVoidMethod(client->servicename, client->icname, FCITX_IC_DBUS_INTERFACE, "SetCapacity", DBUS_TYPE_UINT32, &caps, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
static void
|
||||
static SDL_bool
|
||||
FcitxClientCreateIC(FcitxClient *client)
|
||||
{
|
||||
char *appname = NULL;
|
||||
pid_t pid = 0;
|
||||
int id = 0;
|
||||
SDL_bool enable;
|
||||
Uint32 arg1, arg2, arg3, arg4;
|
||||
char *appname = GetAppName();
|
||||
pid_t pid = getpid();
|
||||
int id = -1;
|
||||
Uint32 enable, arg1, arg2, arg3, arg4;
|
||||
|
||||
SDL_DBusContext *dbus = client->dbus;
|
||||
DBusMessage *reply = NULL;
|
||||
DBusMessage *msg = dbus->message_new_method_call(
|
||||
client->servicename,
|
||||
FCITX_IM_DBUS_PATH,
|
||||
FCITX_IM_DBUS_INTERFACE,
|
||||
"CreateICv3"
|
||||
);
|
||||
if (!SDL_DBus_CallMethod(client->servicename, FCITX_IM_DBUS_PATH, FCITX_IM_DBUS_INTERFACE, "CreateICv3",
|
||||
DBUS_TYPE_STRING, &appname, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID,
|
||||
DBUS_TYPE_INT32, &id, DBUS_TYPE_BOOLEAN, &enable, DBUS_TYPE_UINT32, &arg1, DBUS_TYPE_UINT32, &arg2, DBUS_TYPE_UINT32, &arg3, DBUS_TYPE_UINT32, &arg4, DBUS_TYPE_INVALID)) {
|
||||
id = -1; /* just in case. */
|
||||
}
|
||||
|
||||
if (msg == NULL)
|
||||
return ;
|
||||
SDL_free(appname);
|
||||
|
||||
appname = GetAppName();
|
||||
pid = getpid();
|
||||
dbus->message_append_args(msg,
|
||||
DBUS_TYPE_STRING, &appname,
|
||||
DBUS_TYPE_INT32, &pid,
|
||||
DBUS_TYPE_INVALID);
|
||||
if (id >= 0) {
|
||||
SDL_DBusContext *dbus = client->dbus;
|
||||
|
||||
do {
|
||||
reply = dbus->connection_send_with_reply_and_block(
|
||||
dbus->session_conn,
|
||||
msg,
|
||||
DBUS_TIMEOUT,
|
||||
NULL);
|
||||
|
||||
if (!reply)
|
||||
break;
|
||||
if (!dbus->message_get_args(reply, NULL,
|
||||
DBUS_TYPE_INT32, &id,
|
||||
DBUS_TYPE_BOOLEAN, &enable,
|
||||
DBUS_TYPE_UINT32, &arg1,
|
||||
DBUS_TYPE_UINT32, &arg2,
|
||||
DBUS_TYPE_UINT32, &arg3,
|
||||
DBUS_TYPE_UINT32, &arg4,
|
||||
DBUS_TYPE_INVALID))
|
||||
break;
|
||||
|
||||
if (id < 0)
|
||||
break;
|
||||
client->id = id;
|
||||
|
||||
SDL_snprintf(client->icname, IC_NAME_MAX,
|
||||
FCITX_IC_DBUS_PATH, client->id);
|
||||
SDL_snprintf(client->icname, IC_NAME_MAX, FCITX_IC_DBUS_PATH, client->id);
|
||||
|
||||
dbus->bus_add_match(dbus->session_conn,
|
||||
"type='signal', interface='org.fcitx.Fcitx.InputContext'",
|
||||
|
|
@ -350,14 +219,11 @@ FcitxClientCreateIC(FcitxClient *client)
|
|||
NULL);
|
||||
dbus->connection_flush(dbus->session_conn);
|
||||
|
||||
SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &Fcitx_SetCapabilities, client);
|
||||
SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, Fcitx_SetCapabilities, client);
|
||||
return SDL_TRUE;
|
||||
}
|
||||
while (0);
|
||||
|
||||
if (reply)
|
||||
dbus->message_unref(reply);
|
||||
dbus->message_unref(msg);
|
||||
SDL_free(appname);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static Uint32
|
||||
|
|
@ -391,9 +257,7 @@ SDL_Fcitx_Init()
|
|||
"%s-%d",
|
||||
FCITX_DBUS_SERVICE, GetDisplayNumber());
|
||||
|
||||
FcitxClientCreateIC(&fcitx_client);
|
||||
|
||||
return SDL_TRUE;
|
||||
return FcitxClientCreateIC(&fcitx_client);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -422,47 +286,21 @@ SDL_Fcitx_Reset(void)
|
|||
SDL_bool
|
||||
SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
|
||||
{
|
||||
DBusMessage *msg = NULL;
|
||||
DBusMessage *reply = NULL;
|
||||
SDL_DBusContext *dbus = fcitx_client.dbus;
|
||||
|
||||
Uint32 state = 0;
|
||||
SDL_bool handled = SDL_FALSE;
|
||||
Uint32 state = Fcitx_ModState();
|
||||
Uint32 handled = SDL_FALSE;
|
||||
int type = FCITX_PRESS_KEY;
|
||||
Uint32 event_time = 0;
|
||||
|
||||
msg = FcitxClientICNewMethod(&fcitx_client, "ProcessKeyEvent");
|
||||
if (msg == NULL)
|
||||
return SDL_FALSE;
|
||||
|
||||
state = Fcitx_ModState();
|
||||
dbus->message_append_args(msg,
|
||||
DBUS_TYPE_UINT32, &keysym,
|
||||
DBUS_TYPE_UINT32, &keycode,
|
||||
DBUS_TYPE_UINT32, &state,
|
||||
DBUS_TYPE_INT32, &type,
|
||||
DBUS_TYPE_UINT32, &event_time,
|
||||
DBUS_TYPE_INVALID);
|
||||
|
||||
reply = dbus->connection_send_with_reply_and_block(dbus->session_conn,
|
||||
msg,
|
||||
-1,
|
||||
NULL);
|
||||
|
||||
if (reply) {
|
||||
dbus->message_get_args(reply,
|
||||
NULL,
|
||||
DBUS_TYPE_INT32, &handled,
|
||||
DBUS_TYPE_INVALID);
|
||||
|
||||
dbus->message_unref(reply);
|
||||
if (SDL_DBus_CallMethod(fcitx_client.servicename, fcitx_client.icname, FCITX_IC_DBUS_INTERFACE, "ProcessKeyEvent",
|
||||
DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &state, DBUS_TYPE_INT32, &type, DBUS_TYPE_UINT32, &event_time, DBUS_TYPE_INVALID,
|
||||
DBUS_TYPE_INT32, &handled, DBUS_TYPE_INVALID)) {
|
||||
if (handled) {
|
||||
SDL_Fcitx_UpdateTextRect(NULL);
|
||||
return SDL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
SDL_Fcitx_UpdateTextRect(NULL);
|
||||
}
|
||||
|
||||
return handled;
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -473,10 +311,6 @@ SDL_Fcitx_UpdateTextRect(SDL_Rect *rect)
|
|||
int x = 0, y = 0;
|
||||
SDL_Rect *cursor = &fcitx_client.cursor_rect;
|
||||
|
||||
SDL_DBusContext *dbus = fcitx_client.dbus;
|
||||
DBusMessage *msg = NULL;
|
||||
DBusConnection *conn;
|
||||
|
||||
if (rect) {
|
||||
SDL_memcpy(cursor, rect, sizeof(SDL_Rect));
|
||||
}
|
||||
|
|
@ -506,7 +340,7 @@ SDL_Fcitx_UpdateTextRect(SDL_Rect *rect)
|
|||
#endif
|
||||
|
||||
if (cursor->x == -1 && cursor->y == -1 && cursor->w == 0 && cursor->h == 0) {
|
||||
// move to bottom left
|
||||
/* move to bottom left */
|
||||
int w = 0, h = 0;
|
||||
SDL_GetWindowSize(focused_win, &w, &h);
|
||||
cursor->x = 0;
|
||||
|
|
@ -516,26 +350,12 @@ SDL_Fcitx_UpdateTextRect(SDL_Rect *rect)
|
|||
x += cursor->x;
|
||||
y += cursor->y;
|
||||
|
||||
msg = FcitxClientICNewMethod(&fcitx_client, "SetCursorRect");
|
||||
if (msg == NULL)
|
||||
return ;
|
||||
|
||||
dbus->message_append_args(msg,
|
||||
DBUS_TYPE_INT32, &x,
|
||||
DBUS_TYPE_INT32, &y,
|
||||
DBUS_TYPE_INT32, &cursor->w,
|
||||
DBUS_TYPE_INT32, &cursor->h,
|
||||
DBUS_TYPE_INVALID);
|
||||
|
||||
conn = dbus->session_conn;
|
||||
if (dbus->connection_send(conn, msg, NULL))
|
||||
dbus->connection_flush(conn);
|
||||
|
||||
dbus->message_unref(msg);
|
||||
SDL_DBus_CallVoidMethod(fcitx_client.servicename, fcitx_client.icname, FCITX_IC_DBUS_INTERFACE, "SetCursorRect",
|
||||
DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y, DBUS_TYPE_INT32, &cursor->w, DBUS_TYPE_INT32, &cursor->h, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
void
|
||||
SDL_Fcitx_PumpEvents()
|
||||
SDL_Fcitx_PumpEvents(void)
|
||||
{
|
||||
SDL_DBusContext *dbus = fcitx_client.dbus;
|
||||
DBusConnection *conn = dbus->session_conn;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -19,8 +19,8 @@
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef _SDL_fcitx_h
|
||||
#define _SDL_fcitx_h
|
||||
#ifndef SDL_fcitx_h_
|
||||
#define SDL_fcitx_h_
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
|
|
@ -33,8 +33,8 @@ extern void SDL_Fcitx_SetFocus(SDL_bool focused);
|
|||
extern void SDL_Fcitx_Reset(void);
|
||||
extern SDL_bool SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
|
||||
extern void SDL_Fcitx_UpdateTextRect(SDL_Rect *rect);
|
||||
extern void SDL_Fcitx_PumpEvents();
|
||||
extern void SDL_Fcitx_PumpEvents(void);
|
||||
|
||||
#endif /* _SDL_fcitx_h */
|
||||
#endif /* SDL_fcitx_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -45,7 +45,7 @@ static char *input_ctx_path = NULL;
|
|||
static SDL_Rect ibus_cursor_rect = { 0, 0, 0, 0 };
|
||||
static DBusConnection *ibus_conn = NULL;
|
||||
static char *ibus_addr_file = NULL;
|
||||
int inotify_fd = -1, inotify_wd = -1;
|
||||
static int inotify_fd = -1, inotify_wd = -1;
|
||||
|
||||
static Uint32
|
||||
IBus_ModState(void)
|
||||
|
|
@ -107,21 +107,6 @@ IBus_GetVariantText(DBusConnection *conn, DBusMessageIter *iter, SDL_DBusContext
|
|||
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_MessageHandler(DBusConnection *conn, DBusMessage *msg, void *user_data)
|
||||
{
|
||||
|
|
@ -135,7 +120,7 @@ IBus_MessageHandler(DBusConnection *conn, DBusMessage *msg, void *user_data)
|
|||
|
||||
text = IBus_GetVariantText(conn, &iter, dbus);
|
||||
if (text && *text) {
|
||||
char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
|
||||
char buf[SDL_TEXTINPUTEVENT_TEXT_SIZE];
|
||||
size_t text_bytes = SDL_strlen(text), i = 0;
|
||||
|
||||
while (i < text_bytes) {
|
||||
|
|
@ -162,8 +147,8 @@ IBus_MessageHandler(DBusConnection *conn, DBusMessage *msg, void *user_data)
|
|||
size_t cursor = 0;
|
||||
|
||||
do {
|
||||
size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
|
||||
size_t chars = IBus_utf8_strlen(buf);
|
||||
const size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
|
||||
const size_t chars = SDL_utf8strlen(buf);
|
||||
|
||||
SDL_SendEditingText(buf, cursor, chars);
|
||||
|
||||
|
|
@ -302,35 +287,20 @@ IBus_GetDBusAddressFilename(void)
|
|||
|
||||
static SDL_bool IBus_CheckConnection(SDL_DBusContext *dbus);
|
||||
|
||||
static void
|
||||
static void SDLCALL
|
||||
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)) {
|
||||
Uint32 caps = IBUS_CAP_FOCUS;
|
||||
if (!(internal_editing && *internal_editing == '1')) {
|
||||
caps |= IBUS_CAP_PREEDIT_TEXT;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, "SetCapabilities",
|
||||
DBUS_TYPE_UINT32, &caps, DBUS_TYPE_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -338,9 +308,9 @@ IBus_SetCapabilities(void *data, const char *name, const char *old_val,
|
|||
static SDL_bool
|
||||
IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr)
|
||||
{
|
||||
const char *client_name = "SDL2_Application";
|
||||
const char *path = NULL;
|
||||
SDL_bool result = SDL_FALSE;
|
||||
DBusMessage *msg;
|
||||
DBusObjectPathVTable ibus_vtable;
|
||||
|
||||
SDL_zero(ibus_vtable);
|
||||
|
|
@ -361,39 +331,17 @@ IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr)
|
|||
|
||||
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);
|
||||
if (SDL_DBus_CallMethodOnConnection(ibus_conn, IBUS_SERVICE, IBUS_PATH, IBUS_INTERFACE, "CreateInputContext",
|
||||
DBUS_TYPE_STRING, &client_name, DBUS_TYPE_INVALID,
|
||||
DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) {
|
||||
SDL_free(input_ctx_path);
|
||||
input_ctx_path = SDL_strdup(path);
|
||||
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_try_register_object_path(ibus_conn, input_ctx_path, &ibus_vtable, dbus, NULL);
|
||||
dbus->connection_flush(ibus_conn);
|
||||
result = SDL_TRUE;
|
||||
}
|
||||
|
||||
SDL_IBus_SetFocus(SDL_GetKeyboardFocus() != NULL);
|
||||
|
|
@ -521,7 +469,7 @@ SDL_IBus_Quit(void)
|
|||
inotify_wd = -1;
|
||||
}
|
||||
|
||||
SDL_DelHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL);
|
||||
SDL_DelHintCallback(SDL_HINT_IME_INTERNAL_EDITING, IBus_SetCapabilities, NULL);
|
||||
|
||||
SDL_memset(&ibus_cursor_rect, 0, sizeof(ibus_cursor_rect));
|
||||
}
|
||||
|
|
@ -532,16 +480,7 @@ 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);
|
||||
}
|
||||
SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, method, DBUS_TYPE_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -561,43 +500,21 @@ SDL_IBus_Reset(void)
|
|||
SDL_bool
|
||||
SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
|
||||
{
|
||||
SDL_bool result = SDL_FALSE;
|
||||
Uint32 result = 0;
|
||||
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);
|
||||
Uint32 mods = IBus_ModState();
|
||||
if (!SDL_DBus_CallMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, "ProcessKeyEvent",
|
||||
DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &mods, DBUS_TYPE_INVALID,
|
||||
DBUS_TYPE_BOOLEAN, &result, DBUS_TYPE_INVALID)) {
|
||||
result = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
return result ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -643,25 +560,8 @@ SDL_IBus_UpdateTextRect(SDL_Rect *rect)
|
|||
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);
|
||||
}
|
||||
SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, "SetCursorLocation",
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -680,3 +580,5 @@ SDL_IBus_PumpEvents(void)
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_ibus_h
|
||||
#define _SDL_ibus_h
|
||||
#ifndef SDL_ibus_h_
|
||||
#define SDL_ibus_h_
|
||||
|
||||
#ifdef HAVE_IBUS_IBUS_H
|
||||
#define SDL_USE_IBUS 1
|
||||
|
|
@ -49,10 +49,10 @@ 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();
|
||||
extern void SDL_IBus_PumpEvents(void);
|
||||
|
||||
#endif /* HAVE_IBUS_IBUS_H */
|
||||
|
||||
#endif /* _SDL_ibus_h */
|
||||
#endif /* SDL_ibus_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -87,8 +87,20 @@ SDL_IME_Init(void)
|
|||
{
|
||||
InitIME();
|
||||
|
||||
if (SDL_IME_Init_Real)
|
||||
return SDL_IME_Init_Real();
|
||||
if (SDL_IME_Init_Real) {
|
||||
if (SDL_IME_Init_Real()) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
/* uhoh, the IME implementation's init failed! Disable IME support. */
|
||||
SDL_IME_Init_Real = NULL;
|
||||
SDL_IME_Quit_Real = NULL;
|
||||
SDL_IME_SetFocus_Real = NULL;
|
||||
SDL_IME_Reset_Real = NULL;
|
||||
SDL_IME_ProcessKeyEvent_Real = NULL;
|
||||
SDL_IME_UpdateTextRect_Real = NULL;
|
||||
SDL_IME_PumpEvents_Real = NULL;
|
||||
}
|
||||
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
|
@ -136,3 +148,5 @@ SDL_IME_PumpEvents()
|
|||
if (SDL_IME_PumpEvents_Real)
|
||||
SDL_IME_PumpEvents_Real();
|
||||
}
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -19,20 +19,22 @@
|
|||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef _SDL_ime_h
|
||||
#define _SDL_ime_h
|
||||
#ifndef SDL_ime_h_
|
||||
#define SDL_ime_h_
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#include "SDL_stdinc.h"
|
||||
#include "SDL_rect.h"
|
||||
|
||||
extern SDL_bool SDL_IME_Init();
|
||||
extern void SDL_IME_Quit();
|
||||
extern SDL_bool SDL_IME_Init(void);
|
||||
extern void SDL_IME_Quit(void);
|
||||
extern void SDL_IME_SetFocus(SDL_bool focused);
|
||||
extern void SDL_IME_Reset();
|
||||
extern void SDL_IME_Reset(void);
|
||||
extern SDL_bool SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
|
||||
extern void SDL_IME_UpdateTextRect(SDL_Rect *rect);
|
||||
extern void SDL_IME_PumpEvents();
|
||||
extern void SDL_IME_PumpEvents(void);
|
||||
|
||||
#endif /* _SDL_ime_h */
|
||||
#endif /* SDL_ime_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -31,9 +31,12 @@
|
|||
|
||||
#include <linux/input.h>
|
||||
|
||||
#include "SDL.h"
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_loadso.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "../unix/SDL_poll.h"
|
||||
|
||||
static const char* SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" };
|
||||
static const char *SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" };
|
||||
|
||||
#define _THIS SDL_UDEV_PrivateData *_this
|
||||
static _THIS = NULL;
|
||||
|
|
@ -98,14 +101,7 @@ 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))) {
|
||||
if (SDL_IOReady(fd, SDL_FALSE, 0)) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
}
|
||||
|
|
@ -209,7 +205,7 @@ SDL_UDEV_Scan(void)
|
|||
enumerate = _this->udev_enumerate_new(_this->udev);
|
||||
if (enumerate == NULL) {
|
||||
SDL_UDEV_Quit();
|
||||
SDL_SetError("udev_monitor_new_from_netlink() failed");
|
||||
SDL_SetError("udev_enumerate_new() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -252,8 +248,25 @@ SDL_UDEV_LoadLibrary(void)
|
|||
if (_this == NULL) {
|
||||
return SDL_SetError("UDEV not initialized");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* See if there is a udev library already loaded */
|
||||
if (SDL_UDEV_load_syms() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SDL_UDEV_DYNAMIC
|
||||
/* Check for the build environment's libudev first */
|
||||
if (_this->udev_handle == NULL) {
|
||||
_this->udev_handle = SDL_LoadObject(SDL_UDEV_DYNAMIC);
|
||||
if (_this->udev_handle != NULL) {
|
||||
retval = SDL_UDEV_load_syms();
|
||||
if (retval < 0) {
|
||||
SDL_UDEV_UnloadLibrary();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (_this->udev_handle == NULL) {
|
||||
for( i = 0 ; i < SDL_arraysize(SDL_UDEV_LIBS); i++) {
|
||||
_this->udev_handle = SDL_LoadObject(SDL_UDEV_LIBS[i]);
|
||||
|
|
@ -280,7 +293,6 @@ SDL_UDEV_LoadLibrary(void)
|
|||
#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)
|
||||
|
||||
|
|
@ -537,3 +549,5 @@ SDL_UDEV_DelCallback(SDL_UDEV_Callback cb)
|
|||
|
||||
|
||||
#endif /* SDL_USE_LIBUDEV */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_udev_h
|
||||
#define _SDL_udev_h
|
||||
#ifndef SDL_udev_h_
|
||||
#define SDL_udev_h_
|
||||
|
||||
#if HAVE_LIBUDEV_H
|
||||
|
||||
|
|
@ -116,4 +116,6 @@ extern void SDL_UDEV_DelCallback(SDL_UDEV_Callback cb);
|
|||
|
||||
#endif /* HAVE_LIBUDEV_H */
|
||||
|
||||
#endif /* _SDL_udev_h */
|
||||
#endif /* SDL_udev_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
87
Engine/lib/sdl/src/core/unix/SDL_poll.c
Normal file
87
Engine/lib/sdl/src/core/unix/SDL_poll.c
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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_poll.h"
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
#include <poll.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
int
|
||||
SDL_IOReady(int fd, SDL_bool forWrite, int timeoutMS)
|
||||
{
|
||||
int result;
|
||||
|
||||
/* Note: We don't bother to account for elapsed time if we get EINTR */
|
||||
do
|
||||
{
|
||||
#ifdef HAVE_POLL
|
||||
struct pollfd info;
|
||||
|
||||
info.fd = fd;
|
||||
if (forWrite) {
|
||||
info.events = POLLOUT;
|
||||
} else {
|
||||
info.events = POLLIN | POLLPRI;
|
||||
}
|
||||
result = poll(&info, 1, timeoutMS);
|
||||
#else
|
||||
fd_set rfdset, *rfdp = NULL;
|
||||
fd_set wfdset, *wfdp = NULL;
|
||||
struct timeval tv, *tvp = NULL;
|
||||
|
||||
/* If this assert triggers we'll corrupt memory here */
|
||||
SDL_assert(fd >= 0 && fd < FD_SETSIZE);
|
||||
|
||||
if (forWrite) {
|
||||
FD_ZERO(&wfdset);
|
||||
FD_SET(fd, &wfdset);
|
||||
wfdp = &wfdset;
|
||||
} else {
|
||||
FD_ZERO(&rfdset);
|
||||
FD_SET(fd, &rfdset);
|
||||
rfdp = &rfdset;
|
||||
}
|
||||
|
||||
if (timeoutMS >= 0) {
|
||||
tv.tv_sec = timeoutMS / 1000;
|
||||
tv.tv_usec = (timeoutMS % 1000) * 1000;
|
||||
tvp = &tv;
|
||||
}
|
||||
|
||||
result = select(fd + 1, rfdp, wfdp, NULL, tvp);
|
||||
#endif /* HAVE_POLL */
|
||||
|
||||
} while ( result < 0 && errno == EINTR );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
34
Engine/lib/sdl/src/core/unix/SDL_poll.h
Normal file
34
Engine/lib/sdl/src/core/unix/SDL_poll.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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_poll_h_
|
||||
#define SDL_poll_h_
|
||||
|
||||
#include "SDL_stdinc.h"
|
||||
|
||||
|
||||
extern int SDL_IOReady(int fd, SDL_bool forWrite, int timeoutMS);
|
||||
|
||||
#endif /* SDL_poll_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef _SDL_directx_h
|
||||
#define _SDL_directx_h
|
||||
#ifndef SDL_directx_h_
|
||||
#define SDL_directx_h_
|
||||
|
||||
/* Include all of the DirectX 8.0 headers and adds any necessary tweaks */
|
||||
|
||||
|
|
@ -106,6 +106,6 @@
|
|||
typedef struct { int unused; } DIDEVICEINSTANCE;
|
||||
#endif
|
||||
|
||||
#endif /* _SDL_directx_h */
|
||||
#endif /* SDL_directx_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
#endif
|
||||
|
||||
|
||||
/* Sets an error message based on GetLastError() */
|
||||
/* Sets an error message based on an HRESULT */
|
||||
int
|
||||
WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr)
|
||||
{
|
||||
|
|
@ -115,7 +115,7 @@ IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServiceP
|
|||
}
|
||||
#endif
|
||||
|
||||
BOOL WIN_IsWindowsVistaOrGreater()
|
||||
BOOL WIN_IsWindowsVistaOrGreater(void)
|
||||
{
|
||||
#ifdef __WINRT__
|
||||
return TRUE;
|
||||
|
|
@ -124,6 +124,15 @@ BOOL WIN_IsWindowsVistaOrGreater()
|
|||
#endif
|
||||
}
|
||||
|
||||
BOOL WIN_IsWindows7OrGreater(void)
|
||||
{
|
||||
#ifdef __WINRT__
|
||||
return TRUE;
|
||||
#else
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
WAVExxxCAPS gives you 31 bytes for the device name, and just truncates if it's
|
||||
longer. However, since WinXP, you can use the WAVExxxCAPS2 structure, which
|
||||
|
|
@ -142,6 +151,8 @@ Registry, and a unhelpful "Microphone(Yeti Stereo Microph" in winmm. Sigh.
|
|||
|
||||
(Also, DirectSound shouldn't be limited to 32 chars, but its device enum
|
||||
has the same problem.)
|
||||
|
||||
WASAPI doesn't need this. This is just for DirectSound/WinMM.
|
||||
*/
|
||||
char *
|
||||
WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid)
|
||||
|
|
@ -158,7 +169,7 @@ WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid)
|
|||
DWORD len = 0;
|
||||
char *retval = NULL;
|
||||
|
||||
if (SDL_memcmp(guid, &nullguid, sizeof (*guid)) == 0) {
|
||||
if (WIN_IsEqualGUID(guid, &nullguid)) {
|
||||
return WIN_StringToUTF8(name); /* No GUID, go with what we've got. */
|
||||
}
|
||||
|
||||
|
|
@ -202,6 +213,18 @@ WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid)
|
|||
#endif /* if __WINRT__ / else */
|
||||
}
|
||||
|
||||
BOOL
|
||||
WIN_IsEqualGUID(const GUID * a, const GUID * b)
|
||||
{
|
||||
return (SDL_memcmp(a, b, sizeof (*a)) == 0);
|
||||
}
|
||||
|
||||
BOOL
|
||||
WIN_IsEqualIID(REFIID a, REFIID b)
|
||||
{
|
||||
return (SDL_memcmp(a, b, sizeof (*a)) == 0);
|
||||
}
|
||||
|
||||
#endif /* __WIN32__ || __WINRT__ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue