mirror of
https://github.com/love2d/megasource.git
synced 2026-08-18 11:44:19 +02:00
Update SDL to 2.0.7
This commit is contained in:
+4
-7
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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
|
||||
|
||||
+71
-14
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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: */
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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: */
|
||||
|
||||
+75
-64
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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, ...)
|
||||
{
|
||||
@@ -110,16 +112,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.
|
||||
*/
|
||||
@@ -220,63 +289,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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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
|
||||
@@ -59,6 +59,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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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)
|
||||
#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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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,7 +302,7 @@ SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list
|
||||
SDL_stack_free(message);
|
||||
}
|
||||
|
||||
#if defined(__WIN32__)
|
||||
#if defined(__WIN32__) && !defined(HAVE_STDIO_H) && !defined(__WINRT__)
|
||||
/* Flag tracking the attachment of the console: 0=unattached, 1=attached, -1=error */
|
||||
static int consoleAttached = 0;
|
||||
|
||||
@@ -312,7 +310,7 @@ static int consoleAttached = 0;
|
||||
static HANDLE stderrHandle = NULL;
|
||||
#endif
|
||||
|
||||
static void
|
||||
static void SDLCALL
|
||||
SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
|
||||
const char *message)
|
||||
{
|
||||
@@ -335,7 +333,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"));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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);
|
||||
|
||||
|
||||
+300
-340
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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,6 +68,9 @@ static const AudioBootStrap *const bootstrap[] = {
|
||||
#if SDL_AUDIO_DRIVER_NAS
|
||||
&NAS_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_WASAPI
|
||||
&WASAPI_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_XAUDIO2
|
||||
&XAUDIO2_bootstrap,
|
||||
#endif
|
||||
@@ -116,12 +89,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 +100,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 +228,11 @@ SDL_AudioThreadInit_Default(_THIS)
|
||||
{ /* no-op. */
|
||||
}
|
||||
|
||||
static void
|
||||
SDL_AudioThreadDeinit_Default(_THIS)
|
||||
{ /* no-op. */
|
||||
}
|
||||
|
||||
static void
|
||||
SDL_AudioWaitDevice_Default(_THIS)
|
||||
{ /* no-op. */
|
||||
@@ -288,6 +352,7 @@ finish_audio_entry_points_init(void)
|
||||
FILL_STUB(DetectDevices);
|
||||
FILL_STUB(OpenDevice);
|
||||
FILL_STUB(ThreadInit);
|
||||
FILL_STUB(ThreadDeinit);
|
||||
FILL_STUB(WaitDevice);
|
||||
FILL_STUB(PlayDevice);
|
||||
FILL_STUB(GetPendingBytes);
|
||||
@@ -448,136 +513,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 +547,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 +560,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 +582,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 +603,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 +620,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 +628,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 +640,9 @@ 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;
|
||||
Uint8 *data;
|
||||
|
||||
SDL_assert(!device->iscapture);
|
||||
|
||||
@@ -732,51 +655,63 @@ SDL_RunAudio(void *devicep)
|
||||
|
||||
/* Loop, filling the audio buffers */
|
||||
while (!SDL_AtomicGet(&device->shutdown)) {
|
||||
const int 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 +722,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 +735,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 +754,41 @@ SDL_CaptureAudio(void *devicep)
|
||||
int still_need;
|
||||
Uint8 *ptr;
|
||||
|
||||
if (!SDL_AtomicGet(&device->enabled) || SDL_AtomicGet(&device->paused)) {
|
||||
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 +797,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 +929,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 +1063,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 +1144,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 +1283,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 +1373,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 +1409,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 +1539,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 +1621,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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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: */
|
||||
|
||||
+1430
-878
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
+610
-15806
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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,12 @@ 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 (*WaitDevice) (_THIS);
|
||||
void (*PlayDevice) (_THIS);
|
||||
int (*GetPendingBytes) (_THIS);
|
||||
@@ -105,11 +98,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 +125,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 +132,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 +147,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 +161,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 +179,33 @@ 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 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 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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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"
|
||||
@@ -310,12 +309,14 @@ 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
|
||||
@@ -329,20 +330,7 @@ ALSA_PlayDevice(_THIS)
|
||||
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) {
|
||||
@@ -362,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;
|
||||
}
|
||||
@@ -381,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 */
|
||||
@@ -743,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;
|
||||
@@ -761,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".
|
||||
@@ -786,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;
|
||||
@@ -813,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;
|
||||
@@ -828,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
|
||||
@@ -922,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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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>
|
||||
|
||||
@@ -43,6 +43,6 @@ struct SDL_PrivateAudioData
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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: */
|
||||
|
||||
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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: */
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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: */
|
||||
|
||||
+30
-36
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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: */
|
||||
+5
-8
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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: */
|
||||
|
||||
@@ -0,0 +1,964 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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"
|
||||
|
||||
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;
|
||||
|
||||
/* these increment as default devices change. Opened default devices pick up changes in their threads. */
|
||||
static SDL_atomic_t default_playback_generation;
|
||||
static SDL_atomic_t default_capture_generation;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* handle to Avrt.dll--Vista and later!--for flagging the callback thread as "Pro Audio" (low latency). */
|
||||
#ifndef __WINRT__
|
||||
static HMODULE libavrt = NULL;
|
||||
#endif
|
||||
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 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 const PROPERTYKEY SDL_PKEY_Device_FriendlyName = { { 0xa45c254e, 0xdf1c, 0x4efd, { 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, } }, 14 };
|
||||
|
||||
/* 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)
|
||||
|
||||
static void AddWASAPIDevice(const SDL_bool iscapture, IMMDevice *device, LPCWSTR devid);
|
||||
static void RemoveWASAPIDevice(const SDL_bool iscapture, LPCWSTR devid);
|
||||
|
||||
/* 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(&default_playback_generation, 1);
|
||||
break;
|
||||
|
||||
case eCapture:
|
||||
SDL_AtomicAdd(&default_capture_generation, 1);
|
||||
break;
|
||||
|
||||
case eAll:
|
||||
SDL_AtomicAdd(&default_playback_generation, 1);
|
||||
SDL_AtomicAdd(&default_capture_generation, 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) {
|
||||
AddWASAPIDevice(iscapture, device, pwstrDeviceId);
|
||||
} else {
|
||||
RemoveWASAPIDevice(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 } };
|
||||
|
||||
static SDL_bool
|
||||
WStrEqual(const WCHAR *a, const WCHAR *b)
|
||||
{
|
||||
while (*a) {
|
||||
if (*a != *b) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
return *b == 0;
|
||||
}
|
||||
|
||||
static WCHAR *
|
||||
WStrDupe(const WCHAR *wstr)
|
||||
{
|
||||
const int len = (lstrlenW(wstr) + 1) * sizeof (WCHAR);
|
||||
WCHAR *retval = (WCHAR *) SDL_malloc(len);
|
||||
if (retval) {
|
||||
SDL_memcpy(retval, wstr, len);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void
|
||||
RemoveWASAPIDevice(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;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
AddWASAPIDevice(const SDL_bool iscapture, IMMDevice *device, LPCWSTR devid)
|
||||
{
|
||||
IPropertyStore *props = NULL;
|
||||
char *utf8dev = NULL;
|
||||
DevIdList *devidlist;
|
||||
PROPVARIANT var;
|
||||
|
||||
/* 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...?) */
|
||||
|
||||
/* 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. */
|
||||
|
||||
/* 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;
|
||||
|
||||
if (SUCCEEDED(IMMDevice_OpenPropertyStore(device, STGM_READ, &props))) {
|
||||
PropVariantInit(&var);
|
||||
if (SUCCEEDED(IPropertyStore_GetValue(props, &SDL_PKEY_Device_FriendlyName, &var))) {
|
||||
utf8dev = WIN_StringToUTF8(var.pwszVal);
|
||||
if (utf8dev) {
|
||||
SDL_AddAudioDevice(iscapture, utf8dev, (void *) devid);
|
||||
SDL_free(utf8dev);
|
||||
}
|
||||
}
|
||||
PropVariantClear(&var);
|
||||
IPropertyStore_Release(props);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
EnumerateEndpoints(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))) {
|
||||
AddWASAPIDevice(iscapture, device, devid);
|
||||
CoTaskMemFree(devid);
|
||||
}
|
||||
IMMDevice_Release(device);
|
||||
}
|
||||
}
|
||||
|
||||
IMMDeviceCollection_Release(collection);
|
||||
}
|
||||
|
||||
static void
|
||||
WASAPI_DetectDevices(void)
|
||||
{
|
||||
EnumerateEndpoints(SDL_FALSE); /* playback */
|
||||
EnumerateEndpoints(SDL_TRUE); /* capture */
|
||||
|
||||
/* if this fails, we just won't get hotplug events. Carry on anyhow. */
|
||||
IMMDeviceEnumerator_RegisterEndpointNotificationCallback(enumerator, (IMMNotificationClient *) ¬ification_client);
|
||||
}
|
||||
|
||||
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 || 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 PrepWasapiDevice(_THIS, const int iscapture, IMMDevice *device);
|
||||
static void ReleaseWasapiDevice(_THIS);
|
||||
|
||||
static SDL_bool
|
||||
RecoverWasapiDevice(_THIS)
|
||||
{
|
||||
const SDL_AudioSpec oldspec = this->spec;
|
||||
IMMDevice *device = NULL;
|
||||
HRESULT ret = S_OK;
|
||||
|
||||
if (this->hidden->default_device_generation) {
|
||||
const EDataFlow dataflow = this->iscapture ? eCapture : eRender;
|
||||
ReleaseWasapiDevice(this); /* dump the lost device's handles. */
|
||||
this->hidden->default_device_generation = SDL_AtomicGet(this->iscapture ? &default_capture_generation : &default_playback_generation);
|
||||
ret = IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, dataflow, SDL_WASAPI_role, &device);
|
||||
if (FAILED(ret)) {
|
||||
return SDL_FALSE; /* can't find a new default device! */
|
||||
}
|
||||
} else {
|
||||
device = this->hidden->device;
|
||||
this->hidden->device = NULL; /* don't release this in ReleaseWasapiDevice(). */
|
||||
ReleaseWasapiDevice(this); /* dump the lost device's handles. */
|
||||
}
|
||||
|
||||
SDL_assert(device != NULL);
|
||||
|
||||
/* 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 (PrepWasapiDevice(this, this->iscapture, device) == -1) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* 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 SDL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
this->work_buffer = ptr;
|
||||
this->work_buffer_len = this->spec.size;
|
||||
}
|
||||
|
||||
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 (!lost && (generation > 0)) { /* is a default device? */
|
||||
const int newgen = SDL_AtomicGet(this->iscapture ? &default_capture_generation : &default_playback_generation);
|
||||
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)) {
|
||||
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)
|
||||
{
|
||||
/* 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)
|
||||
{
|
||||
const UINT32 maxpadding = this->spec.samples;
|
||||
while (RecoverWasapiIfLost(this)) {
|
||||
UINT32 padding = 0;
|
||||
|
||||
if (!WasapiFailed(this, IAudioClient_GetCurrentPadding(this->hidden->client, &padding))) {
|
||||
if (padding <= maxpadding) {
|
||||
break;
|
||||
}
|
||||
/* Sleep long enough for half the buffer to be free. */
|
||||
SDL_Delay(((padding - maxpadding) * 1000) / this->spec.freq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
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->device) {
|
||||
IMMDevice_Release(this->hidden->device);
|
||||
this->hidden->device = NULL;
|
||||
}
|
||||
|
||||
if (this->hidden->capturestream) {
|
||||
SDL_FreeAudioStream(this->hidden->capturestream);
|
||||
this->hidden->capturestream = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
WASAPI_CloseDevice(_THIS)
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
PrepWasapiDevice(_THIS, const int iscapture, IMMDevice *device)
|
||||
{
|
||||
/* !!! 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 AUDCLNT_SHAREMODE sharemode = AUDCLNT_SHAREMODE_SHARED;
|
||||
UINT32 bufsize = 0; /* this is in sample frames, not samples, not bytes. */
|
||||
REFERENCE_TIME duration = 0;
|
||||
IAudioClient *client = NULL;
|
||||
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;
|
||||
|
||||
this->hidden->device = device;
|
||||
|
||||
ret = IMMDevice_Activate(device, &SDL_IID_IAudioClient, CLSCTX_ALL, NULL, (void **) &client);
|
||||
if (FAILED(ret)) {
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't activate audio endpoint", ret);
|
||||
}
|
||||
|
||||
SDL_assert(client != NULL);
|
||||
this->hidden->client = client;
|
||||
|
||||
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;
|
||||
|
||||
/* WASAPI will not do any conversion on our behalf. Force channels and sample rate. */
|
||||
this->spec.channels = (Uint8) waveformat->nChannels;
|
||||
this->spec.freq = waveformat->nSamplesPerSec;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
ret = IAudioClient_Initialize(client, sharemode, 0, duration, sharemode == AUDCLNT_SHAREMODE_SHARED ? 0 : duration, waveformat, NULL);
|
||||
if (FAILED(ret)) {
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't initialize audio client", 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 (!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 (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);
|
||||
}
|
||||
}
|
||||
|
||||
return 0; /* good to go. */
|
||||
}
|
||||
|
||||
static int
|
||||
WASAPI_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
{
|
||||
const SDL_bool is_default_device = (handle == NULL);
|
||||
IMMDevice *device = NULL;
|
||||
HRESULT ret = S_OK;
|
||||
|
||||
/* 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);
|
||||
|
||||
if (is_default_device) {
|
||||
const EDataFlow dataflow = iscapture ? eCapture : eRender;
|
||||
this->hidden->default_device_generation = SDL_AtomicGet(iscapture ? &default_capture_generation : &default_playback_generation);
|
||||
ret = IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, dataflow, SDL_WASAPI_role, &device);
|
||||
} else {
|
||||
ret = IMMDeviceEnumerator_GetDevice(enumerator, (LPCWSTR) handle, &device);
|
||||
}
|
||||
|
||||
if (FAILED(ret)) {
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't find requested audio endpoint", ret);
|
||||
}
|
||||
|
||||
SDL_assert(device != NULL);
|
||||
return PrepWasapiDevice(this, iscapture, device);
|
||||
}
|
||||
|
||||
static void
|
||||
WASAPI_ThreadInit(_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);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
WASAPI_ThreadDeinit(_THIS)
|
||||
{
|
||||
/* Set this thread to very high "Pro Audio" priority. */
|
||||
if (this->hidden->task && pAvRevertMmThreadCharacteristics) {
|
||||
pAvRevertMmThreadCharacteristics(this->hidden->task);
|
||||
this->hidden->task = NULL;
|
||||
}
|
||||
|
||||
if (this->hidden->coinitialized) {
|
||||
WIN_CoUninitialize();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
WASAPI_Deinitialize(void)
|
||||
{
|
||||
DevIdList *devidlist;
|
||||
DevIdList *next;
|
||||
|
||||
if (enumerator) {
|
||||
IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(enumerator, (IMMNotificationClient *) ¬ification_client);
|
||||
IMMDeviceEnumerator_Release(enumerator);
|
||||
enumerator = NULL;
|
||||
}
|
||||
|
||||
#ifndef __WINRT__
|
||||
if (libavrt) {
|
||||
FreeLibrary(libavrt);
|
||||
libavrt = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
pAvSetMmThreadCharacteristicsW = NULL;
|
||||
pAvRevertMmThreadCharacteristics = NULL;
|
||||
|
||||
for (devidlist = deviceid_list; devidlist; devidlist = next) {
|
||||
next = devidlist->next;
|
||||
SDL_free(devidlist->str);
|
||||
SDL_free(devidlist);
|
||||
}
|
||||
deviceid_list = NULL;
|
||||
|
||||
WIN_CoUninitialize();
|
||||
}
|
||||
|
||||
static int
|
||||
WASAPI_Init(SDL_AudioDriverImpl * impl)
|
||||
{
|
||||
HRESULT ret;
|
||||
|
||||
/* just skip the discussion with COM here. */
|
||||
if (!WIN_IsWindowsVistaOrGreater()) {
|
||||
SDL_SetError("WASAPI support requires Windows Vista or later");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_AtomicSet(&default_playback_generation, 1);
|
||||
SDL_AtomicSet(&default_capture_generation, 1);
|
||||
|
||||
if (FAILED(WIN_CoInitialize())) {
|
||||
SDL_SetError("WASAPI: CoInitialize() failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = CoCreateInstance(&SDL_CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &SDL_IID_IMMDeviceEnumerator, (LPVOID) &enumerator);
|
||||
if (FAILED(ret)) {
|
||||
WIN_CoUninitialize();
|
||||
WIN_SetErrorFromHRESULT("WASAPI CoCreateInstance(MMDeviceEnumerator)", ret);
|
||||
return 0; /* oh well. */
|
||||
}
|
||||
|
||||
#ifdef __WINRT__
|
||||
pAvSetMmThreadCharacteristicsW = AvSetMmThreadCharacteristicsW;
|
||||
pAvRevertMmThreadCharacteristics = AvRevertMmThreadCharacteristics;
|
||||
#else
|
||||
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");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set the function pointers */
|
||||
impl->DetectDevices = WASAPI_DetectDevices;
|
||||
impl->ThreadInit = WASAPI_ThreadInit;
|
||||
impl->ThreadDeinit = WASAPI_ThreadDeinit;
|
||||
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: */
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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_
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *this
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
{
|
||||
IMMDevice *device;
|
||||
WAVEFORMATEX *waveformat;
|
||||
IAudioClient *client;
|
||||
IAudioRenderClient *render;
|
||||
IAudioCaptureClient *capture;
|
||||
SDL_AudioStream *capturestream;
|
||||
HANDLE task;
|
||||
SDL_bool coinitialized;
|
||||
int framesize;
|
||||
int default_device_generation;
|
||||
SDL_bool device_lost;
|
||||
};
|
||||
|
||||
#endif /* SDL_wasapi_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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -78,8 +78,8 @@
|
||||
#else
|
||||
# define SDL_XAUDIO2_HAS_SDK 1
|
||||
#endif
|
||||
#endif
|
||||
#endif /* 0 */
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
#ifdef SDL_XAUDIO2_HAS_SDK
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(_SDL_XAUDIO2_H)
|
||||
#if !defined(SDL_XAUDIO2_H_)
|
||||
#define INITGUID 1
|
||||
#include <xaudio2.h>
|
||||
#endif
|
||||
@@ -453,6 +453,7 @@ XAUDIO2_Init(SDL_AudioDriverImpl * impl)
|
||||
#else
|
||||
/* XAudio2Create() is a macro that uses COM; we don't load the .dll */
|
||||
IXAudio2 *ixa2 = NULL;
|
||||
HRESULT hr = S_FALSE;
|
||||
#if defined(__WIN32__)
|
||||
// TODO, WinRT: Investigate using CoInitializeEx here
|
||||
if (FAILED(WIN_CoInitialize())) {
|
||||
@@ -461,11 +462,12 @@ XAUDIO2_Init(SDL_AudioDriverImpl * impl)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
|
||||
hr = XAudio2Create( &ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR );
|
||||
if ( hr != S_OK) {
|
||||
#if defined(__WIN32__)
|
||||
WIN_CoUninitialize();
|
||||
#endif
|
||||
SDL_SetError("XAudio2: XAudio2Create() failed at initialization");
|
||||
SDL_SetError("XAudio2: XAudio2Create() failed at initialization: 0x%.8x", hr );
|
||||
return 0; /* not available. */
|
||||
}
|
||||
IXAudio2_Release(ixa2);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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_XAUDIO2_H
|
||||
#define _SDL_XAUDIO2_H
|
||||
#ifndef SDL_XAUDIO2_H_
|
||||
#define SDL_XAUDIO2_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmreg.h>
|
||||
@@ -381,6 +381,6 @@ const struct IXAudio2VoiceCallbackVtbl
|
||||
|
||||
#pragma pack(pop) /* Undo pragma push */
|
||||
|
||||
#endif /* _SDL_XAUDIO2_H */
|
||||
#endif /* SDL_XAUDIO2_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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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,9 +34,12 @@ extern "C" {
|
||||
|
||||
/* Interface from the SDL library into the Android Java activity */
|
||||
extern void Android_JNI_SetActivityTitle(const char *title);
|
||||
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);
|
||||
|
||||
/* Audio support */
|
||||
@@ -67,21 +70,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* */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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,18 @@ 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));
|
||||
}
|
||||
if (dbus.shutdown) {
|
||||
dbus.shutdown();
|
||||
}
|
||||
SDL_zero(dbus);
|
||||
UnloadDBUSLibrary();
|
||||
}
|
||||
|
||||
@@ -150,90 +160,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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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: */
|
||||
|
||||
@@ -0,0 +1,677 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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: */
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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: */
|
||||
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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: */
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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_CallVoidMethod(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,35 +331,12 @@ 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);
|
||||
@@ -521,7 +468,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 +479,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 +499,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 +559,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 +579,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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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: */
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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"
|
||||
|
||||
#undef HAVE_POLL
|
||||
#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: */
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -115,7 +115,7 @@ IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServiceP
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOL WIN_IsWindowsVistaOrGreater()
|
||||
BOOL WIN_IsWindowsVistaOrGreater(void)
|
||||
{
|
||||
#ifdef __WINRT__
|
||||
return TRUE;
|
||||
@@ -142,6 +142,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 +160,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 +204,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: */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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,7 @@
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <basetyps.h> /* for REFIID with broken mingw.org headers */
|
||||
|
||||
/* Routines to convert from UTF8 to native Windows text */
|
||||
#if UNICODE
|
||||
@@ -57,11 +58,15 @@ extern HRESULT WIN_CoInitialize(void);
|
||||
extern void WIN_CoUninitialize(void);
|
||||
|
||||
/* Returns SDL_TRUE if we're running on Windows Vista and newer */
|
||||
extern BOOL WIN_IsWindowsVistaOrGreater();
|
||||
extern BOOL WIN_IsWindowsVistaOrGreater(void);
|
||||
|
||||
/* You need to SDL_free() the result of this call. */
|
||||
extern char *WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid);
|
||||
|
||||
/* Checks to see if two GUID are the same. */
|
||||
extern BOOL WIN_IsEqualGUID(const GUID * a, const GUID * b);
|
||||
extern BOOL WIN_IsEqualIID(REFIID a, REFIID b);
|
||||
|
||||
#endif /* _INCLUDED_WINDOWS_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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2017 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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_xinput_h
|
||||
#define _SDL_xinput_h
|
||||
#ifndef SDL_xinput_h_
|
||||
#define SDL_xinput_h_
|
||||
|
||||
#ifdef HAVE_XINPUT_H
|
||||
|
||||
@@ -100,6 +100,8 @@
|
||||
#endif
|
||||
|
||||
/* typedef's for XInput structs we use */
|
||||
|
||||
#ifndef HAVE_XINPUT_GAMEPAD_EX
|
||||
typedef struct
|
||||
{
|
||||
WORD wButtons;
|
||||
@@ -111,12 +113,15 @@ typedef struct
|
||||
SHORT sThumbRY;
|
||||
DWORD dwPaddingReserved;
|
||||
} XINPUT_GAMEPAD_EX;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_XINPUT_STATE_EX
|
||||
typedef struct
|
||||
{
|
||||
DWORD dwPacketNumber;
|
||||
XINPUT_GAMEPAD_EX Gamepad;
|
||||
} XINPUT_STATE_EX;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -167,6 +172,6 @@ extern DWORD SDL_XInputVersion; /* ((major << 16) & 0xFF00) | (minor & 0xFF) */
|
||||
|
||||
#endif /* HAVE_XINPUT_H */
|
||||
|
||||
#endif /* _SDL_xinput_h */
|
||||
#endif /* SDL_xinput_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user