mirror of
https://github.com/love2d/megasource.git
synced 2026-08-18 11:44:19 +02:00
Update SDL to version 2.0.14.
This commit is contained in:
+54
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -22,6 +22,20 @@
|
||||
|
||||
#if defined(__WIN32__)
|
||||
#include "core/windows/SDL_windows.h"
|
||||
#elif defined(__OS2__)
|
||||
#include <stdlib.h> /* For _exit() */
|
||||
#elif !defined(__WINRT__)
|
||||
#include <unistd.h> /* For _exit(), etc. */
|
||||
#endif
|
||||
#if defined(__OS2__)
|
||||
#include "core/os2/SDL_os2.h"
|
||||
#endif
|
||||
#if SDL_THREAD_OS2
|
||||
#include "thread/os2/SDL_systls_c.h"
|
||||
#endif
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
/* Initialization code for SDL */
|
||||
@@ -45,6 +59,34 @@ extern int SDL_HelperWindowDestroy(void);
|
||||
#endif
|
||||
|
||||
|
||||
/* This is not declared in any header, although it is shared between some
|
||||
parts of SDL, because we don't want anything calling it without an
|
||||
extremely good reason. */
|
||||
extern SDL_NORETURN void SDL_ExitProcess(int exitcode);
|
||||
SDL_NORETURN void SDL_ExitProcess(int exitcode)
|
||||
{
|
||||
#ifdef __WIN32__
|
||||
/* "if you do not know the state of all threads in your process, it is
|
||||
better to call TerminateProcess than ExitProcess"
|
||||
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx */
|
||||
TerminateProcess(GetCurrentProcess(), exitcode);
|
||||
/* MingW doesn't have TerminateProcess marked as noreturn, so add an
|
||||
ExitProcess here that will never be reached but make MingW happy. */
|
||||
ExitProcess(exitcode);
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
emscripten_cancel_main_loop(); /* this should "kill" the app. */
|
||||
emscripten_force_exit(exitcode); /* this should "kill" the app. */
|
||||
exit(exitcode);
|
||||
#elif defined(__HAIKU__) /* Haiku has _Exit, but it's not marked noreturn. */
|
||||
_exit(exitcode);
|
||||
#elif defined(HAVE__EXIT) /* Upper case _Exit() */
|
||||
_Exit(exitcode);
|
||||
#else
|
||||
_exit(exitcode);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* The initialized subsystems */
|
||||
#ifdef SDL_MAIN_NEEDED
|
||||
static SDL_bool SDL_MainIsReady = SDL_FALSE;
|
||||
@@ -123,6 +165,10 @@ SDL_InitSubSystem(Uint32 flags)
|
||||
flags |= SDL_INIT_EVENTS;
|
||||
}
|
||||
|
||||
#if SDL_THREAD_OS2
|
||||
SDL_OS2TLSAlloc(); /* thread/os2/SDL_systls.c */
|
||||
#endif
|
||||
|
||||
#if SDL_VIDEO_DRIVER_WINDOWS
|
||||
if ((flags & (SDL_INIT_HAPTIC|SDL_INIT_JOYSTICK))) {
|
||||
if (SDL_HelperWindowCreate() < 0) {
|
||||
@@ -258,6 +304,13 @@ SDL_Init(Uint32 flags)
|
||||
void
|
||||
SDL_QuitSubSystem(Uint32 flags)
|
||||
{
|
||||
#if SDL_THREAD_OS2
|
||||
SDL_OS2TLSFree(); /* thread/os2/SDL_systls.c */
|
||||
#endif
|
||||
#if defined(__OS2__)
|
||||
SDL_OS2Quit();
|
||||
#endif
|
||||
|
||||
/* Shut down requested initialized subsystems */
|
||||
#if !SDL_SENSOR_DISABLED
|
||||
if ((flags & SDL_INIT_SENSOR)) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -36,12 +36,9 @@
|
||||
#ifndef WS_OVERLAPPEDWINDOW
|
||||
#define WS_OVERLAPPEDWINDOW 0
|
||||
#endif
|
||||
#else /* fprintf, _exit(), etc. */
|
||||
#else /* fprintf, etc. */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#if ! defined(__WINRT__)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
@@ -120,34 +117,18 @@ static void SDL_GenerateAssertionReport(void)
|
||||
}
|
||||
|
||||
|
||||
/* This is not declared in any header, although it is shared between some
|
||||
parts of SDL, because we don't want anything calling it without an
|
||||
extremely good reason. */
|
||||
#if defined(__WATCOMC__)
|
||||
extern void SDL_ExitProcess(int exitcode);
|
||||
#pragma aux SDL_ExitProcess aborts;
|
||||
#endif
|
||||
static SDL_NORETURN void SDL_ExitProcess(int exitcode)
|
||||
{
|
||||
#ifdef __WIN32__
|
||||
/* "if you do not know the state of all threads in your process, it is
|
||||
better to call TerminateProcess than ExitProcess"
|
||||
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx */
|
||||
TerminateProcess(GetCurrentProcess(), exitcode);
|
||||
/* MingW doesn't have TerminateProcess marked as noreturn, so add an
|
||||
ExitProcess here that will never be reached but make MingW happy. */
|
||||
ExitProcess(exitcode);
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
emscripten_cancel_main_loop(); /* this should "kill" the app. */
|
||||
emscripten_force_exit(exitcode); /* this should "kill" the app. */
|
||||
exit(exitcode);
|
||||
#elif defined(__HAIKU__) /* Haiku has _Exit, but it's not marked noreturn. */
|
||||
_exit(exitcode);
|
||||
#elif defined(HAVE__EXIT) /* Upper case _Exit() */
|
||||
_Exit(exitcode);
|
||||
#else
|
||||
_exit(exitcode);
|
||||
#endif
|
||||
}
|
||||
extern SDL_NORETURN void SDL_ExitProcess(int exitcode);
|
||||
|
||||
|
||||
#if defined(__WATCOMC__)
|
||||
static void SDL_AbortAssertion (void);
|
||||
#pragma aux SDL_AbortAssertion aborts;
|
||||
#endif
|
||||
static SDL_NORETURN void SDL_AbortAssertion(void)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -18,11 +18,10 @@
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "./SDL_internal.h"
|
||||
|
||||
#include "SDL.h"
|
||||
#include "./SDL_dataqueue.h"
|
||||
#include "SDL_assert.h"
|
||||
|
||||
typedef struct SDL_DataQueuePacket
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
+22
-222
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -22,116 +22,31 @@
|
||||
|
||||
/* Simple error handling in SDL */
|
||||
|
||||
#include "SDL_log.h"
|
||||
#include "SDL_error.h"
|
||||
#include "SDL_error_c.h"
|
||||
|
||||
|
||||
/* Routine to get the thread-specific error variable */
|
||||
#if SDL_THREADS_DISABLED
|
||||
/* The default (non-thread-safe) global error variable */
|
||||
static SDL_error SDL_global_error;
|
||||
#define SDL_GetErrBuf() (&SDL_global_error)
|
||||
#else
|
||||
extern SDL_error *SDL_GetErrBuf(void);
|
||||
#endif /* SDL_THREADS_DISABLED */
|
||||
|
||||
#define SDL_ERRBUFIZE 1024
|
||||
|
||||
/* Private functions */
|
||||
|
||||
static const char *
|
||||
SDL_LookupString(const char *key)
|
||||
{
|
||||
/* FIXME: Add code to lookup key in language string hash-table */
|
||||
return key;
|
||||
}
|
||||
|
||||
/* Public functions */
|
||||
|
||||
static char *SDL_GetErrorMsg(char *errstr, int maxlen);
|
||||
|
||||
int
|
||||
SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
SDL_error *error;
|
||||
|
||||
/* Ignore call if invalid format pointer was passed */
|
||||
if (fmt == NULL) return -1;
|
||||
if (fmt != NULL) {
|
||||
va_list ap;
|
||||
SDL_error *error = SDL_GetErrBuf();
|
||||
|
||||
/* Copy in the key, mark error as valid */
|
||||
error = SDL_GetErrBuf();
|
||||
error->error = 1;
|
||||
SDL_strlcpy((char *) error->key, fmt, sizeof(error->key));
|
||||
error->error = 1; /* mark error as valid */
|
||||
|
||||
va_start(ap, fmt);
|
||||
error->argc = 0;
|
||||
while (*fmt) {
|
||||
if (*fmt++ == '%') {
|
||||
while (*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) {
|
||||
++fmt;
|
||||
}
|
||||
switch (*fmt++) {
|
||||
case 0: /* Malformed format string.. */
|
||||
--fmt;
|
||||
break;
|
||||
case 'l':
|
||||
switch (*fmt++) {
|
||||
case 0: /* Malformed format string.. */
|
||||
--fmt;
|
||||
break;
|
||||
case 'i': case 'd': case 'u': case 'x': case 'X':
|
||||
error->args[error->argc++].value_l = va_arg(ap, long);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
case 'i':
|
||||
case 'd':
|
||||
case 'u':
|
||||
case 'o':
|
||||
case 'x':
|
||||
case 'X':
|
||||
error->args[error->argc++].value_i = va_arg(ap, int);
|
||||
break;
|
||||
case 'f':
|
||||
error->args[error->argc++].value_f = va_arg(ap, double);
|
||||
break;
|
||||
case 'p':
|
||||
error->args[error->argc++].value_ptr = va_arg(ap, void *);
|
||||
break;
|
||||
case 's':
|
||||
{
|
||||
int i = error->argc;
|
||||
const char *str = va_arg(ap, const char *);
|
||||
if (str == NULL)
|
||||
str = "(null)";
|
||||
SDL_strlcpy((char *) error->args[i].buf, str,
|
||||
ERR_MAX_STRLEN);
|
||||
error->argc++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (error->argc >= ERR_MAX_ARGS) {
|
||||
break;
|
||||
}
|
||||
va_start(ap, fmt);
|
||||
SDL_vsnprintf(error->str, ERR_MAX_STRLEN, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (SDL_LogGetPriority(SDL_LOG_CATEGORY_ERROR) <= SDL_LOG_PRIORITY_DEBUG) {
|
||||
/* If we are in debug mode, print out the error message */
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_ERROR, "%s", error->str);
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
if (SDL_LogGetPriority(SDL_LOG_CATEGORY_ERROR) <= SDL_LOG_PRIORITY_DEBUG) {
|
||||
/* If we are in debug mode, print out an error message
|
||||
* Avoid stomping on the static buffer in GetError, just
|
||||
* in case this is called while processing a ShowMessageBox to
|
||||
* show an error already in that static buffer.
|
||||
*/
|
||||
char errmsg[SDL_ERRBUFIZE];
|
||||
SDL_GetErrorMsg(errmsg, sizeof(errmsg));
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_ERROR, "%s", errmsg);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -139,18 +54,14 @@ SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
|
||||
const char *
|
||||
SDL_GetError(void)
|
||||
{
|
||||
static char errmsg[SDL_ERRBUFIZE];
|
||||
|
||||
return SDL_GetErrorMsg(errmsg, SDL_ERRBUFIZE);
|
||||
const SDL_error *error = SDL_GetErrBuf();
|
||||
return error->error ? error->str : "";
|
||||
}
|
||||
|
||||
void
|
||||
SDL_ClearError(void)
|
||||
{
|
||||
SDL_error *error;
|
||||
|
||||
error = SDL_GetErrBuf();
|
||||
error->error = 0;
|
||||
SDL_GetErrBuf()->error = 0;
|
||||
}
|
||||
|
||||
/* Very common errors go here */
|
||||
@@ -191,129 +102,18 @@ main(int argc, char *argv[])
|
||||
#endif
|
||||
|
||||
|
||||
/* keep this at the end of the file so it works with GCC builds that don't
|
||||
support "#pragma GCC diagnostic push" ... we'll just leave the warning
|
||||
disabled after this. */
|
||||
/* this pragma arrived in GCC 4.2 and causes a warning on older GCCs! Sigh. */
|
||||
#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 2))))
|
||||
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||
#endif
|
||||
|
||||
/* This function has a bit more overhead than most error functions
|
||||
so that it supports internationalization and thread-safe errors.
|
||||
*/
|
||||
static char *
|
||||
char *
|
||||
SDL_GetErrorMsg(char *errstr, int maxlen)
|
||||
{
|
||||
SDL_error *error;
|
||||
const SDL_error *error = SDL_GetErrBuf();
|
||||
|
||||
/* Clear the error string */
|
||||
*errstr = '\0';
|
||||
--maxlen;
|
||||
|
||||
/* Get the thread-safe error, and print it out */
|
||||
error = SDL_GetErrBuf();
|
||||
if (error->error) {
|
||||
const char *fmt;
|
||||
char *msg = errstr;
|
||||
int len;
|
||||
int argi;
|
||||
|
||||
fmt = SDL_LookupString(error->key);
|
||||
argi = 0;
|
||||
while (*fmt && (maxlen > 0)) {
|
||||
if (*fmt == '%') {
|
||||
char tmp[32], *spot = tmp;
|
||||
*spot++ = *fmt++;
|
||||
while ((*fmt == '.' || (*fmt >= '0' && *fmt <= '9'))
|
||||
&& spot < (tmp + SDL_arraysize(tmp) - 2)) {
|
||||
*spot++ = *fmt++;
|
||||
}
|
||||
if (*fmt == 'l') {
|
||||
*spot++ = *fmt++;
|
||||
*spot++ = *fmt++;
|
||||
*spot++ = '\0';
|
||||
switch (spot[-2]) {
|
||||
case 'i': case 'd': case 'u': case 'x': case 'X':
|
||||
len = SDL_snprintf(msg, maxlen, tmp,
|
||||
error->args[argi++].value_l);
|
||||
if (len > 0) {
|
||||
msg += len;
|
||||
maxlen -= len;
|
||||
}
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
*spot++ = *fmt++;
|
||||
*spot++ = '\0';
|
||||
switch (spot[-2]) {
|
||||
case '%':
|
||||
*msg++ = '%';
|
||||
maxlen -= 1;
|
||||
break;
|
||||
case 'c':
|
||||
case 'i':
|
||||
case 'd':
|
||||
case 'u':
|
||||
case 'o':
|
||||
case 'x':
|
||||
case 'X':
|
||||
len =
|
||||
SDL_snprintf(msg, maxlen, tmp,
|
||||
error->args[argi++].value_i);
|
||||
if (len > 0) {
|
||||
msg += len;
|
||||
maxlen -= len;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
len =
|
||||
SDL_snprintf(msg, maxlen, tmp,
|
||||
error->args[argi++].value_f);
|
||||
if (len > 0) {
|
||||
msg += len;
|
||||
maxlen -= len;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
len =
|
||||
SDL_snprintf(msg, maxlen, tmp,
|
||||
error->args[argi++].value_ptr);
|
||||
if (len > 0) {
|
||||
msg += len;
|
||||
maxlen -= len;
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
len =
|
||||
SDL_snprintf(msg, maxlen, tmp,
|
||||
SDL_LookupString(error->args[argi++].
|
||||
buf));
|
||||
if (len > 0) {
|
||||
msg += len;
|
||||
maxlen -= len;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
} else {
|
||||
*msg++ = *fmt++;
|
||||
maxlen -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* slide back if we've overshot the end of our buffer. */
|
||||
if (maxlen < 0) {
|
||||
msg -= (-maxlen) + 1;
|
||||
}
|
||||
|
||||
*msg = 0; /* NULL terminate the string */
|
||||
SDL_strlcpy(errstr, error->str, maxlen);
|
||||
} else {
|
||||
*errstr = '\0';
|
||||
}
|
||||
return (errstr);
|
||||
|
||||
return errstr;
|
||||
}
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -28,33 +28,11 @@
|
||||
#define SDL_error_c_h_
|
||||
|
||||
#define ERR_MAX_STRLEN 128
|
||||
#define ERR_MAX_ARGS 5
|
||||
|
||||
typedef struct SDL_error
|
||||
{
|
||||
/* This is a numeric value corresponding to the current error */
|
||||
int error;
|
||||
|
||||
/* This is a key used to index into a language hashtable containing
|
||||
internationalized versions of the SDL error messages. If the key
|
||||
is not in the hashtable, or no hashtable is available, the key is
|
||||
used directly as an error message format string.
|
||||
*/
|
||||
char key[ERR_MAX_STRLEN];
|
||||
|
||||
/* These are the arguments for the error functions */
|
||||
int argc;
|
||||
union
|
||||
{
|
||||
void *value_ptr;
|
||||
#if 0 /* What is a character anyway? (UNICODE issues) */
|
||||
unsigned char value_c;
|
||||
#endif
|
||||
int value_i;
|
||||
long value_l;
|
||||
double value_f;
|
||||
char buf[ERR_MAX_STRLEN];
|
||||
} args[ERR_MAX_ARGS];
|
||||
int error; /* This is a numeric value corresponding to the current error */
|
||||
char str[ERR_MAX_STRLEN];
|
||||
} SDL_error;
|
||||
|
||||
/* Defined in SDL_thread.c */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "SDL_hints.h"
|
||||
#include "SDL_error.h"
|
||||
#include "SDL_hints_c.h"
|
||||
|
||||
|
||||
/* Assuming there aren't many hints set and they aren't being queried in
|
||||
@@ -119,18 +120,24 @@ SDL_GetHint(const char *name)
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_GetHintBoolean(const char *name, SDL_bool default_value)
|
||||
SDL_GetStringBoolean(const char *value, SDL_bool default_value)
|
||||
{
|
||||
const char *hint = SDL_GetHint(name);
|
||||
if (!hint || !*hint) {
|
||||
if (!value || !*value) {
|
||||
return default_value;
|
||||
}
|
||||
if (*hint == '0' || SDL_strcasecmp(hint, "false") == 0) {
|
||||
if (*value == '0' || SDL_strcasecmp(value, "false") == 0) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_GetHintBoolean(const char *name, SDL_bool default_value)
|
||||
{
|
||||
const char *hint = SDL_GetHint(name);
|
||||
return SDL_GetStringBoolean(hint, default_value);
|
||||
}
|
||||
|
||||
void
|
||||
SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "./SDL_internal.h"
|
||||
|
||||
/* This file defines useful function for working with SDL hints */
|
||||
|
||||
#ifndef SDL_hints_c_h_
|
||||
#define SDL_hints_c_h_
|
||||
|
||||
extern SDL_bool SDL_GetStringBoolean(const char *value, SDL_bool default_value);
|
||||
|
||||
#endif /* SDL_hints_c_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -51,6 +51,74 @@
|
||||
|
||||
#include "SDL_config.h"
|
||||
|
||||
/* A few #defines to reduce SDL2 footprint.
|
||||
Only effective when library is statically linked.
|
||||
You have to manually edit this file. */
|
||||
#ifndef SDL_LEAN_AND_MEAN
|
||||
#define SDL_LEAN_AND_MEAN 0
|
||||
#endif
|
||||
|
||||
/* Optimized functions from 'SDL_blit_0.c'
|
||||
- blit with source BitsPerPixel < 8, palette */
|
||||
#ifndef SDL_HAVE_BLIT_0
|
||||
#define SDL_HAVE_BLIT_0 !SDL_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
/* Optimized functions from 'SDL_blit_1.c'
|
||||
- blit with source BytesPerPixel == 1, palette */
|
||||
#ifndef SDL_HAVE_BLIT_1
|
||||
#define SDL_HAVE_BLIT_1 !SDL_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
/* Optimized functions from 'SDL_blit_A.c'
|
||||
- blit with 'SDL_BLENDMODE_BLEND' blending mode */
|
||||
#ifndef SDL_HAVE_BLIT_A
|
||||
#define SDL_HAVE_BLIT_A !SDL_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
/* Optimized functions from 'SDL_blit_N.c'
|
||||
- blit with COLORKEY mode, or nothing */
|
||||
#ifndef SDL_HAVE_BLIT_N
|
||||
#define SDL_HAVE_BLIT_N !SDL_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
/* Optimized functions from 'SDL_blit_N.c'
|
||||
- RGB565 conversion with Lookup tables */
|
||||
#ifndef SDL_HAVE_BLIT_N_RGB565
|
||||
#define SDL_HAVE_BLIT_N_RGB565 !SDL_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
/* Optimized functions from 'SDL_blit_AUTO.c'
|
||||
- blit with modulate color, modulate alpha, any blending mode
|
||||
- scaling or not */
|
||||
#ifndef SDL_HAVE_BLIT_AUTO
|
||||
#define SDL_HAVE_BLIT_AUTO !SDL_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
/* Run-Length-Encoding
|
||||
- SDL_SetColorKey() called with SDL_RLEACCEL flag */
|
||||
#ifndef SDL_HAVE_RLE
|
||||
#define SDL_HAVE_RLE !SDL_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
/* Software SDL_Renderer
|
||||
- creation of software renderer
|
||||
- *not* general blitting functions
|
||||
- {blend,draw}{fillrect,line,point} internal functions */
|
||||
#ifndef SDL_VIDEO_RENDER_SW
|
||||
#define SDL_VIDEO_RENDER_SW !SDL_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
/* YUV formats
|
||||
- handling of YUV surfaces
|
||||
- blitting and conversion functions */
|
||||
#ifndef SDL_HAVE_YUV
|
||||
#define SDL_HAVE_YUV !SDL_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_log.h"
|
||||
|
||||
#endif /* SDL_internal_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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,10 @@
|
||||
#include <atomic.h>
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_GCC_ATOMICS) && defined(__RISCOS__)
|
||||
#include <unixlib/local.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
@@ -79,10 +83,21 @@ SDL_AtomicTryLock(SDL_SpinLock *lock)
|
||||
return (__sync_lock_test_and_set(lock, 1) == 0);
|
||||
|
||||
#elif defined(__GNUC__) && defined(__arm__) && \
|
||||
(defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \
|
||||
(defined(__ARM_ARCH_3__) || defined(__ARM_ARCH_3M__) || \
|
||||
defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \
|
||||
defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5TE__) || \
|
||||
defined(__ARM_ARCH_5TEJ__))
|
||||
int result;
|
||||
|
||||
#if defined(__RISCOS__)
|
||||
if (__cpucap_have_rex()) {
|
||||
__asm__ __volatile__ (
|
||||
"ldrex %0, [%2]\nteq %0, #0\nstrexeq %0, %1, [%2]"
|
||||
: "=&r" (result) : "r" (1), "r" (lock) : "cc", "memory");
|
||||
return (result == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"swp %0, %1, [%2]\n"
|
||||
: "=&r,&r" (result) : "r,0" (1), "r,r" (lock) : "memory");
|
||||
@@ -123,6 +138,8 @@ SDL_AtomicTryLock(SDL_SpinLock *lock)
|
||||
/* "REP NOP" is PAUSE, coded for tools that don't know it by that name. */
|
||||
#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
|
||||
#define PAUSE_INSTRUCTION() __asm__ __volatile__("pause\n") /* Some assemblers can't do REP NOP, so go with PAUSE. */
|
||||
#elif (defined(__arm__) && __ARM_ARCH__ >= 7) || defined(__aarch64__)
|
||||
#define PAUSE_INSTRUCTION() __asm__ __volatile__("yield" ::: "memory")
|
||||
#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
|
||||
#define PAUSE_INSTRUCTION() _mm_pause() /* this is actually "rep nop" and not a SIMD instruction. No inline asm in MSVC x86-64! */
|
||||
#elif defined(__WATCOMC__) && defined(__386__)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -104,6 +104,9 @@ static const AudioBootStrap *const bootstrap[] = {
|
||||
#if SDL_AUDIO_DRIVER_JACK
|
||||
&JACK_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_OS2
|
||||
&OS2AUDIO_bootstrap,
|
||||
#endif
|
||||
#if SDL_AUDIO_DRIVER_DISK
|
||||
&DISKAUDIO_bootstrap,
|
||||
#endif
|
||||
@@ -574,7 +577,7 @@ SDL_BufferQueueDrainCallback(void *userdata, Uint8 *stream, int len)
|
||||
|
||||
if (len > 0) { /* fill any remaining space in the stream with silence. */
|
||||
SDL_assert(SDL_CountDataQueue(device->buffer_queue) == 0);
|
||||
SDL_memset(stream, device->spec.silence, len);
|
||||
SDL_memset(stream, device->callbackspec.silence, len);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,7 +733,7 @@ SDL_RunAudio(void *devicep)
|
||||
/* !!! FIXME: this should be LockDevice. */
|
||||
SDL_LockMutex(device->mixer_lock);
|
||||
if (SDL_AtomicGet(&device->paused)) {
|
||||
SDL_memset(data, device->spec.silence, data_len);
|
||||
SDL_memset(data, device->callbackspec.silence, data_len);
|
||||
} else {
|
||||
callback(udata, data, data_len);
|
||||
}
|
||||
@@ -948,7 +951,7 @@ SDL_AudioInit(const char *driver_name)
|
||||
}
|
||||
|
||||
SDL_zero(current_audio);
|
||||
SDL_zero(open_devices);
|
||||
SDL_zeroa(open_devices);
|
||||
|
||||
/* Select the proper audio driver */
|
||||
if (driver_name == NULL) {
|
||||
@@ -1076,7 +1079,7 @@ SDL_GetAudioDeviceName(int index, int iscapture)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
|
||||
if (iscapture && !current_audio.impl.HasCaptureSupport) {
|
||||
SDL_SetError("No capture support");
|
||||
return NULL;
|
||||
}
|
||||
@@ -1230,7 +1233,7 @@ open_audio_device(const char *devname, int iscapture,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
|
||||
if (iscapture && !current_audio.impl.HasCaptureSupport) {
|
||||
SDL_SetError("No capture support");
|
||||
return 0;
|
||||
}
|
||||
@@ -1608,7 +1611,7 @@ SDL_AudioQuit(void)
|
||||
SDL_DestroyMutex(current_audio.detectionLock);
|
||||
|
||||
SDL_zero(current_audio);
|
||||
SDL_zero(open_devices);
|
||||
SDL_zeroa(open_devices);
|
||||
|
||||
#ifdef HAVE_LIBSAMPLERATE_H
|
||||
UnloadLibSampleRate();
|
||||
@@ -1664,17 +1667,28 @@ SDL_NextAudioFormat(void)
|
||||
return format_list[format_idx][format_idx_sub++];
|
||||
}
|
||||
|
||||
Uint8
|
||||
SDL_SilenceValueForFormat(const SDL_AudioFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
/* !!! FIXME: 0x80 isn't perfect for U16, but we can't fit 0x8000 in a
|
||||
!!! FIXME: byte for memset() use. This is actually 0.1953 percent
|
||||
!!! FIXME: off from silence. Maybe just don't use U16. */
|
||||
case AUDIO_U16LSB:
|
||||
case AUDIO_U16MSB:
|
||||
case AUDIO_U8:
|
||||
return 0x80;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_CalculateAudioSpec(SDL_AudioSpec * spec)
|
||||
{
|
||||
switch (spec->format) {
|
||||
case AUDIO_U8:
|
||||
spec->silence = 0x80;
|
||||
break;
|
||||
default:
|
||||
spec->silence = 0x00;
|
||||
break;
|
||||
}
|
||||
spec->silence = SDL_SilenceValueForFormat(spec->format);
|
||||
spec->size = SDL_AUDIO_BITSIZE(spec->format) / 8;
|
||||
spec->size *= spec->channels;
|
||||
spec->size *= spec->samples;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -52,6 +52,7 @@ extern SDL_AudioFormat SDL_FirstAudioFormat(SDL_AudioFormat format);
|
||||
extern SDL_AudioFormat SDL_NextAudioFormat(void);
|
||||
|
||||
/* Function to calculate the size and silence for a SDL_AudioSpec */
|
||||
extern Uint8 SDL_SilenceValueForFormat(const SDL_AudioFormat format);
|
||||
extern void SDL_CalculateAudioSpec(SDL_AudioSpec * spec);
|
||||
|
||||
/* Choose the audio filter functions below */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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,7 +30,6 @@
|
||||
#include "SDL_audio_c.h"
|
||||
|
||||
#include "SDL_loadso.h"
|
||||
#include "SDL_assert.h"
|
||||
#include "../SDL_dataqueue.h"
|
||||
#include "SDL_cpuinfo.h"
|
||||
|
||||
@@ -677,7 +676,7 @@ SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt)
|
||||
}
|
||||
|
||||
if (!filter) {
|
||||
return SDL_SetError("No conversion from float to destination format available");
|
||||
return SDL_SetError("No conversion from float to format 0x%.4x available", dst_fmt);
|
||||
}
|
||||
|
||||
if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
|
||||
@@ -915,7 +914,7 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
|
||||
cvt->dst_format = dst_fmt;
|
||||
cvt->needed = 0;
|
||||
cvt->filter_index = 0;
|
||||
SDL_zero(cvt->filters);
|
||||
SDL_zeroa(cvt->filters);
|
||||
cvt->len_mult = 1;
|
||||
cvt->len_ratio = 1.0;
|
||||
cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -18,12 +18,11 @@
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "../SDL_internal.h"
|
||||
|
||||
#include "SDL_audio.h"
|
||||
#include "SDL_audio_c.h"
|
||||
#include "SDL_cpuinfo.h"
|
||||
#include "SDL_assert.h"
|
||||
|
||||
#ifdef __ARM_NEON
|
||||
#define HAVE_NEON_INTRINSICS 1
|
||||
@@ -482,7 +481,7 @@ SDL_Convert_U16_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
||||
if ((((size_t) src) & 15) == 0) {
|
||||
/* Aligned! Do SSE blocks as long as we have 16 bytes available. */
|
||||
const __m128 divby32768 = _mm_set1_ps(DIVBY32768);
|
||||
const __m128 minus1 = _mm_set1_ps(1.0f);
|
||||
const __m128 minus1 = _mm_set1_ps(-1.0f);
|
||||
while (i >= 8) { /* 8 * 16-bit */
|
||||
const __m128i ints = _mm_load_si128((__m128i const *) src); /* get 8 sint16 into an XMM register. */
|
||||
/* treat as int32, shift left to clear every other sint16, then back right with zero-extend. Now sint32. */
|
||||
@@ -614,7 +613,7 @@ static void SDLCALL
|
||||
SDL_Convert_F32_to_U8_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
||||
{
|
||||
const float *src = (const float *) cvt->buf;
|
||||
Uint8 *dst = (Uint8 *) cvt->buf;
|
||||
Uint8 *dst = cvt->buf;
|
||||
int i;
|
||||
|
||||
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U8 (using SSE2)");
|
||||
@@ -879,10 +878,10 @@ SDL_Convert_S8_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
||||
const int16x8_t int16hi = vmovl_s8(vget_high_s8(bytes)); /* convert top 8 bytes to 8 int16 */
|
||||
const int16x8_t int16lo = vmovl_s8(vget_low_s8(bytes)); /* convert bottom 8 bytes to 8 int16 */
|
||||
/* split int16 to two int32, then convert to float, then multiply to normalize, store. */
|
||||
vst1q_f32(dst, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(int16hi))), divby128));
|
||||
vst1q_f32(dst+4, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(int16hi))), divby128));
|
||||
vst1q_f32(dst+8, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(int16lo))), divby128));
|
||||
vst1q_f32(dst+12, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(int16lo))), divby128));
|
||||
vst1q_f32(dst, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(int16lo))), divby128));
|
||||
vst1q_f32(dst+4, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(int16lo))), divby128));
|
||||
vst1q_f32(dst+8, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(int16hi))), divby128));
|
||||
vst1q_f32(dst+12, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(int16hi))), divby128));
|
||||
i -= 16; mmsrc -= 16; dst -= 16;
|
||||
}
|
||||
|
||||
@@ -931,10 +930,10 @@ SDL_Convert_U8_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
|
||||
const uint16x8_t uint16hi = vmovl_u8(vget_high_u8(bytes)); /* convert top 8 bytes to 8 uint16 */
|
||||
const uint16x8_t uint16lo = vmovl_u8(vget_low_u8(bytes)); /* convert bottom 8 bytes to 8 uint16 */
|
||||
/* split uint16 to two uint32, then convert to float, then multiply to normalize, subtract to adjust for sign, store. */
|
||||
vst1q_f32(dst, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16hi))), divby128));
|
||||
vst1q_f32(dst+4, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16hi))), divby128));
|
||||
vst1q_f32(dst+8, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16lo))), divby128));
|
||||
vst1q_f32(dst+12, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16lo))), divby128));
|
||||
vst1q_f32(dst, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16lo))), divby128));
|
||||
vst1q_f32(dst+4, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16lo))), divby128));
|
||||
vst1q_f32(dst+8, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16hi))), divby128));
|
||||
vst1q_f32(dst+12, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16hi))), divby128));
|
||||
i -= 16; mmsrc -= 16; dst -= 16;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -207,6 +207,7 @@ extern AudioBootStrap openslES_bootstrap;
|
||||
extern AudioBootStrap ANDROIDAUDIO_bootstrap;
|
||||
extern AudioBootStrap PSPAUDIO_bootstrap;
|
||||
extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
|
||||
extern AudioBootStrap OS2AUDIO_bootstrap;
|
||||
|
||||
#endif /* SDL_sysaudio_h_ */
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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,22 +22,21 @@
|
||||
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#else
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX ((size_t)-1)
|
||||
#endif
|
||||
#ifndef INT_MAX
|
||||
/* Make a lucky guess. */
|
||||
#define INT_MAX SDL_MAX_SINT32
|
||||
#endif
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX ((size_t)-1)
|
||||
#endif
|
||||
|
||||
/* Microsoft WAVE file loading routines */
|
||||
|
||||
#include "SDL_log.h"
|
||||
#include "SDL_hints.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "SDL_wave.h"
|
||||
#include "SDL_audio_c.h"
|
||||
|
||||
/* Reads the value stored at the location of the f1 pointer, multiplies it
|
||||
* with the second argument and then stores the result to f1.
|
||||
@@ -112,7 +111,7 @@ WaveDebugLogFormat(WaveFile *file)
|
||||
Uint32 wavebps = format->byterate;
|
||||
char channelstr[64];
|
||||
|
||||
SDL_zero(channelstr);
|
||||
SDL_zeroa(channelstr);
|
||||
|
||||
switch (format->encoding) {
|
||||
case PCM_CODE:
|
||||
@@ -647,7 +646,7 @@ MS_ADPCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
|
||||
MS_ADPCM_ChannelState cstate[2];
|
||||
|
||||
SDL_zero(state);
|
||||
SDL_zero(cstate);
|
||||
SDL_zeroa(cstate);
|
||||
|
||||
if (chunk->size != chunk->length) {
|
||||
/* Could not read everything. Recalculate number of sample frames. */
|
||||
@@ -691,7 +690,7 @@ MS_ADPCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
state.cstate = &cstate;
|
||||
state.cstate = cstate;
|
||||
|
||||
/* Decode block by block. A truncated block will stop the decoding. */
|
||||
bytesleft = state.input.size - state.input.pos;
|
||||
@@ -717,7 +716,7 @@ MS_ADPCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
|
||||
result = MS_ADPCM_DecodeBlockData(&state);
|
||||
if (result == -1) {
|
||||
/* Unexpected end. Stop decoding and return partial data if necessary. */
|
||||
if (file->trunchint == TruncVeryStrict || file->trunchint == TruncVeryStrict) {
|
||||
if (file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict) {
|
||||
SDL_free(state.output.data);
|
||||
return SDL_SetError("Truncated data chunk");
|
||||
} else if (file->trunchint != TruncDropFrame) {
|
||||
@@ -928,7 +927,7 @@ IMA_ADPCM_DecodeBlockHeader(ADPCM_DecoderState *state)
|
||||
{
|
||||
Sint16 step;
|
||||
Uint32 c;
|
||||
Uint8 *cstate = state->cstate;
|
||||
Uint8 *cstate = (Uint8 *) state->cstate;
|
||||
|
||||
for (c = 0; c < state->channels; c++) {
|
||||
size_t o = state->block.pos + c * 4;
|
||||
@@ -1114,7 +1113,7 @@ IMA_ADPCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
|
||||
|
||||
if (result == -1) {
|
||||
/* Unexpected end. Stop decoding and return partial data if necessary. */
|
||||
if (file->trunchint == TruncVeryStrict || file->trunchint == TruncVeryStrict) {
|
||||
if (file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict) {
|
||||
SDL_free(state.output.data);
|
||||
SDL_free(cstate);
|
||||
return SDL_SetError("Truncated data chunk");
|
||||
@@ -1334,7 +1333,8 @@ PCM_Init(WaveFile *file, size_t datalength)
|
||||
/* It wouldn't be that hard to support more exotic block sizes, but
|
||||
* the most common formats should do for now.
|
||||
*/
|
||||
if (format->blockalign * 8 != format->channels * format->bitspersample) {
|
||||
/* Make sure we're a multiple of the blockalign, at least. */
|
||||
if ((format->channels * format->bitspersample) % (format->blockalign * 8)) {
|
||||
return SDL_SetError("Unsupported block alignment");
|
||||
}
|
||||
|
||||
@@ -1560,7 +1560,7 @@ WaveReadPartialChunkData(SDL_RWops *src, WaveChunk *chunk, size_t length)
|
||||
}
|
||||
|
||||
if (length > 0) {
|
||||
chunk->data = SDL_malloc(length);
|
||||
chunk->data = (Uint8 *) SDL_malloc(length);
|
||||
if (chunk->data == NULL) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
@@ -2081,6 +2081,8 @@ WaveLoad(SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 **audio_buf,
|
||||
break;
|
||||
}
|
||||
|
||||
spec->silence = SDL_SilenceValueForFormat(spec->format);
|
||||
|
||||
/* Report the end position back to the cleanup code. */
|
||||
if (RIFFlengthknown) {
|
||||
chunk->position = RIFFend;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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,7 +32,6 @@
|
||||
#include <signal.h> /* For kill() */
|
||||
#include <string.h>
|
||||
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
@@ -340,7 +339,6 @@ swizzle_alsa_channels(_THIS, void *buffer, Uint32 bufferlen)
|
||||
static void
|
||||
no_swizzle(_THIS, void *buffer, Uint32 bufferlen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif /* SND_CHMAP_API_VERSION */
|
||||
|
||||
@@ -349,7 +347,7 @@ static void
|
||||
ALSA_PlayDevice(_THIS)
|
||||
{
|
||||
const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf;
|
||||
const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
|
||||
const int frame_size = ((SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
|
||||
this->spec.channels;
|
||||
snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples);
|
||||
|
||||
@@ -398,7 +396,7 @@ static int
|
||||
ALSA_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||
{
|
||||
Uint8 *sample_buf = (Uint8 *) buffer;
|
||||
const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
|
||||
const int frame_size = ((SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
|
||||
this->spec.channels;
|
||||
const int total_frames = buflen / frame_size;
|
||||
snd_pcm_uframes_t frames_left = total_frames;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
/* Output audio to Android */
|
||||
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "SDL_androidaudio.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
#if MACOSX_COREAUDIO
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#else
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <UIKit/UIApplication.h>
|
||||
@@ -47,6 +46,7 @@ struct SDL_PrivateAudioData
|
||||
{
|
||||
SDL_Thread *thread;
|
||||
AudioQueueRef audioQueue;
|
||||
int numAudioBuffers;
|
||||
AudioQueueBufferRef *audioBuffer;
|
||||
void *buffer;
|
||||
UInt32 bufferOffset;
|
||||
@@ -57,6 +57,7 @@ struct SDL_PrivateAudioData
|
||||
SDL_atomic_t shutdown;
|
||||
#if MACOSX_COREAUDIO
|
||||
AudioDeviceID deviceID;
|
||||
SDL_atomic_t device_change_flag;
|
||||
#else
|
||||
SDL_bool interrupted;
|
||||
CFTypeRef interruption_listener;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -29,16 +29,25 @@
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_sysaudio.h"
|
||||
#include "SDL_coreaudio.h"
|
||||
#include "SDL_assert.h"
|
||||
#include "../../thread/SDL_systhread.h"
|
||||
|
||||
#define DEBUG_COREAUDIO 0
|
||||
|
||||
#define CHECK_RESULT(msg) \
|
||||
if (result != noErr) { \
|
||||
SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
|
||||
return 0; \
|
||||
}
|
||||
#if DEBUG_COREAUDIO
|
||||
#define CHECK_RESULT(msg) \
|
||||
if (result != noErr) { \
|
||||
printf("COREAUDIO: Got error %d from '%s'!\n", (int) result, msg); \
|
||||
SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
|
||||
return 0; \
|
||||
}
|
||||
#else
|
||||
#define CHECK_RESULT(msg) \
|
||||
if (result != noErr) { \
|
||||
SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \
|
||||
return 0; \
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if MACOSX_COREAUDIO
|
||||
static const AudioObjectPropertyAddress devlist_address = {
|
||||
@@ -270,11 +279,47 @@ device_list_changed(AudioObjectID systemObj, UInt32 num_addr, const AudioObjectP
|
||||
#endif
|
||||
|
||||
|
||||
static int open_playback_devices = 0;
|
||||
static int open_capture_devices = 0;
|
||||
static int open_playback_devices;
|
||||
static int open_capture_devices;
|
||||
static int num_open_devices;
|
||||
static SDL_AudioDevice **open_devices;
|
||||
|
||||
#if !MACOSX_COREAUDIO
|
||||
|
||||
static BOOL session_active = NO;
|
||||
|
||||
static void pause_audio_devices()
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!open_devices) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_open_devices; ++i) {
|
||||
SDL_AudioDevice *device = open_devices[i];
|
||||
if (device->hidden->audioQueue && !device->hidden->interrupted) {
|
||||
AudioQueuePause(device->hidden->audioQueue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void resume_audio_devices()
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!open_devices) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_open_devices; ++i) {
|
||||
SDL_AudioDevice *device = open_devices[i];
|
||||
if (device->hidden->audioQueue && !device->hidden->interrupted) {
|
||||
AudioQueueStart(device->hidden->audioQueue, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void interruption_begin(_THIS)
|
||||
{
|
||||
if (this != NULL && this->hidden->audioQueue != NULL) {
|
||||
@@ -321,47 +366,107 @@ static void interruption_end(_THIS)
|
||||
|
||||
@end
|
||||
|
||||
static BOOL update_audio_session(_THIS, SDL_bool open)
|
||||
static BOOL update_audio_session(_THIS, SDL_bool open, SDL_bool allow_playandrecord)
|
||||
{
|
||||
@autoreleasepool {
|
||||
AVAudioSession *session = [AVAudioSession sharedInstance];
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
/* 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) {
|
||||
NSString *category = AVAudioSessionCategoryPlayback;
|
||||
NSString *mode = AVAudioSessionModeDefault;
|
||||
NSUInteger options = AVAudioSessionCategoryOptionMixWithOthers;
|
||||
NSError *err = nil;
|
||||
const char *hint;
|
||||
|
||||
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;
|
||||
options &= ~AVAudioSessionCategoryOptionMixWithOthers;
|
||||
} else if (SDL_strcasecmp(hint, "AVAudioSessionCategoryPlayback") == 0 ||
|
||||
SDL_strcasecmp(hint, "playback") == 0) {
|
||||
category = AVAudioSessionCategoryPlayback;
|
||||
options &= ~AVAudioSessionCategoryOptionMixWithOthers;
|
||||
} else if (SDL_strcasecmp(hint, "AVAudioSessionCategoryPlayAndRecord") == 0 ||
|
||||
SDL_strcasecmp(hint, "playandrecord") == 0) {
|
||||
if (allow_playandrecord) {
|
||||
category = AVAudioSessionCategoryPlayAndRecord;
|
||||
}
|
||||
}
|
||||
} else if (open_playback_devices && open_capture_devices) {
|
||||
category = AVAudioSessionCategoryPlayAndRecord;
|
||||
} else if (open_capture_devices) {
|
||||
category = AVAudioSessionCategoryRecord;
|
||||
}
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
if (category == AVAudioSessionCategoryPlayAndRecord) {
|
||||
options |= AVAudioSessionCategoryOptionDefaultToSpeaker;
|
||||
}
|
||||
#endif
|
||||
if (category == AVAudioSessionCategoryRecord ||
|
||||
category == AVAudioSessionCategoryPlayAndRecord) {
|
||||
/* AVAudioSessionCategoryOptionAllowBluetooth isn't available in the SDK for
|
||||
Apple TV but is still needed in order to output to Bluetooth devices.
|
||||
*/
|
||||
options |= 0x4; /* AVAudioSessionCategoryOptionAllowBluetooth; */
|
||||
}
|
||||
if (category == AVAudioSessionCategoryPlayAndRecord) {
|
||||
options |= AVAudioSessionCategoryOptionAllowBluetoothA2DP |
|
||||
AVAudioSessionCategoryOptionAllowAirPlay;
|
||||
}
|
||||
if (category == AVAudioSessionCategoryPlayback ||
|
||||
category == AVAudioSessionCategoryPlayAndRecord) {
|
||||
options |= AVAudioSessionCategoryOptionDuckOthers;
|
||||
}
|
||||
|
||||
if ([session respondsToSelector:@selector(setCategory:mode:options:error:)]) {
|
||||
if (![session.category isEqualToString:category] || session.categoryOptions != options) {
|
||||
/* Stop the current session so we don't interrupt other application audio */
|
||||
pause_audio_devices();
|
||||
[session setActive:NO error:nil];
|
||||
session_active = NO;
|
||||
|
||||
if (![session setCategory:category mode:mode options:options error:&err]) {
|
||||
NSString *desc = err.description;
|
||||
SDL_SetError("Could not set Audio Session category: %s", desc.UTF8String);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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.category isEqualToString:category]) {
|
||||
/* Stop the current session so we don't interrupt other application audio */
|
||||
pause_audio_devices();
|
||||
[session setActive:NO error:nil];
|
||||
session_active = NO;
|
||||
|
||||
if (![session setCategory:category error:&err]) {
|
||||
NSString *desc = err.description;
|
||||
SDL_SetError("Could not set Audio Session category: %s", desc.UTF8String);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (![session setCategory:category error:&err]) {
|
||||
NSString *desc = err.description;
|
||||
SDL_SetError("Could not set Audio Session category: %s", desc.UTF8String);
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (open && (open_playback_devices + open_capture_devices) == 1) {
|
||||
if ((open_playback_devices || open_capture_devices) && !session_active) {
|
||||
if (![session setActive:YES error:&err]) {
|
||||
if ([err code] == AVAudioSessionErrorCodeResourceNotAvailable &&
|
||||
category == AVAudioSessionCategoryPlayAndRecord) {
|
||||
return update_audio_session(this, open, SDL_FALSE);
|
||||
}
|
||||
|
||||
NSString *desc = err.description;
|
||||
SDL_SetError("Could not activate Audio Session: %s", desc.UTF8String);
|
||||
return NO;
|
||||
}
|
||||
} else if (!open_playback_devices && !open_capture_devices) {
|
||||
session_active = YES;
|
||||
resume_audio_devices();
|
||||
} else if (!open_playback_devices && !open_capture_devices && session_active) {
|
||||
pause_audio_devices();
|
||||
[session setActive:NO error:nil];
|
||||
session_active = NO;
|
||||
}
|
||||
|
||||
if (open) {
|
||||
@@ -376,7 +481,7 @@ static BOOL update_audio_session(_THIS, SDL_bool open)
|
||||
/* An interruption end notification is not guaranteed to be sent if
|
||||
we were previously interrupted... resuming if needed when the app
|
||||
becomes active seems to be the way to go. */
|
||||
// Note: object: below needs to be nil, as otherwise it filters by the object, and session doesn't send foreground / active notifications. johna
|
||||
// Note: object: below needs to be nil, as otherwise it filters by the object, and session doesn't send foreground / active notifications. johna
|
||||
[center addObserver:listener
|
||||
selector:@selector(applicationBecameActive:)
|
||||
name:UIApplicationDidBecomeActiveNotification
|
||||
@@ -389,13 +494,11 @@ static BOOL update_audio_session(_THIS, SDL_bool open)
|
||||
|
||||
this->hidden->interruption_listener = CFBridgingRetain(listener);
|
||||
} else {
|
||||
if (this->hidden->interruption_listener != NULL) {
|
||||
SDLInterruptionListener *listener = nil;
|
||||
listener = (SDLInterruptionListener *) CFBridgingRelease(this->hidden->interruption_listener);
|
||||
[center removeObserver:listener];
|
||||
@synchronized (listener) {
|
||||
listener.device = NULL;
|
||||
}
|
||||
SDLInterruptionListener *listener = nil;
|
||||
listener = (SDLInterruptionListener *) CFBridgingRelease(this->hidden->interruption_listener);
|
||||
[center removeObserver:listener];
|
||||
@synchronized (listener) {
|
||||
listener.device = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -417,6 +520,34 @@ outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffe
|
||||
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
|
||||
/* Supply silence if audio is not enabled or paused */
|
||||
SDL_memset(inBuffer->mAudioData, this->spec.silence, inBuffer->mAudioDataBytesCapacity);
|
||||
} else if (this->stream) {
|
||||
UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
|
||||
Uint8 *ptr = (Uint8 *) inBuffer->mAudioData;
|
||||
|
||||
while (remaining > 0) {
|
||||
if (SDL_AudioStreamAvailable(this->stream) == 0) {
|
||||
/* Generate the data */
|
||||
SDL_LockMutex(this->mixer_lock);
|
||||
(*this->callbackspec.callback)(this->callbackspec.userdata,
|
||||
this->hidden->buffer, this->hidden->bufferSize);
|
||||
SDL_UnlockMutex(this->mixer_lock);
|
||||
this->hidden->bufferOffset = 0;
|
||||
SDL_AudioStreamPut(this->stream, this->hidden->buffer, this->hidden->bufferSize);
|
||||
}
|
||||
if (SDL_AudioStreamAvailable(this->stream) > 0) {
|
||||
int got;
|
||||
UInt32 len = SDL_AudioStreamAvailable(this->stream);
|
||||
if (len > remaining)
|
||||
len = remaining;
|
||||
got = SDL_AudioStreamGet(this->stream, ptr, len);
|
||||
SDL_assert((got < 0) || (got == len));
|
||||
if (got != len) {
|
||||
SDL_memset(ptr, this->spec.silence, len);
|
||||
}
|
||||
ptr = ptr + len;
|
||||
remaining -= len;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
|
||||
Uint8 *ptr = (Uint8 *) inBuffer->mAudioData;
|
||||
@@ -452,7 +583,7 @@ outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffe
|
||||
static void
|
||||
inputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer,
|
||||
const AudioTimeStamp *inStartTime, UInt32 inNumberPacketDescriptions,
|
||||
const AudioStreamPacketDescription *inPacketDescs )
|
||||
const AudioStreamPacketDescription *inPacketDescs)
|
||||
{
|
||||
SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
|
||||
|
||||
@@ -524,24 +655,58 @@ device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectProperty
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* macOS calls this when the default device changed (if we have a default device open). */
|
||||
static OSStatus
|
||||
default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inUserData)
|
||||
{
|
||||
SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
|
||||
#if DEBUG_COREAUDIO
|
||||
printf("COREAUDIO: default device changed for SDL audio device %p!\n", this);
|
||||
#endif
|
||||
SDL_AtomicSet(&this->hidden->device_change_flag, 1); /* let the audioqueue thread pick up on this when safe to do so. */
|
||||
return noErr;
|
||||
}
|
||||
#endif
|
||||
|
||||
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?) */
|
||||
#if MACOSX_COREAUDIO
|
||||
/* Fire a callback if the device stops being "alive" (disconnected, etc). */
|
||||
AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
|
||||
if (this->handle != NULL) { /* we don't register this listener for default devices. */
|
||||
AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (iscapture) {
|
||||
open_capture_devices--;
|
||||
} else {
|
||||
open_playback_devices--;
|
||||
}
|
||||
|
||||
#if !MACOSX_COREAUDIO
|
||||
update_audio_session(this, SDL_FALSE);
|
||||
update_audio_session(this, SDL_FALSE, SDL_TRUE);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < num_open_devices; ++i) {
|
||||
if (open_devices[i] == this) {
|
||||
--num_open_devices;
|
||||
if (i < num_open_devices) {
|
||||
SDL_memmove(&open_devices[i], &open_devices[i+1], sizeof(open_devices[i])*(num_open_devices - i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (num_open_devices == 0) {
|
||||
SDL_free(open_devices);
|
||||
open_devices = NULL;
|
||||
}
|
||||
|
||||
/* if callback fires again, feed silence; don't call into the app. */
|
||||
SDL_AtomicSet(&this->paused, 1);
|
||||
|
||||
@@ -563,12 +728,6 @@ COREAUDIO_CloseDevice(_THIS)
|
||||
SDL_free(this->hidden->thread_error);
|
||||
SDL_free(this->hidden->buffer);
|
||||
SDL_free(this->hidden);
|
||||
|
||||
if (iscapture) {
|
||||
open_capture_devices--;
|
||||
} else {
|
||||
open_playback_devices--;
|
||||
}
|
||||
}
|
||||
|
||||
#if MACOSX_COREAUDIO
|
||||
@@ -624,6 +783,26 @@ prepare_device(_THIS, void *handle, int iscapture)
|
||||
this->hidden->deviceID = devid;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
assign_device_to_audioqueue(_THIS)
|
||||
{
|
||||
const AudioObjectPropertyAddress prop = {
|
||||
kAudioDevicePropertyDeviceUID,
|
||||
this->iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
|
||||
OSStatus result;
|
||||
CFStringRef devuid;
|
||||
UInt32 devuidsize = sizeof (devuid);
|
||||
result = AudioObjectGetPropertyData(this->hidden->deviceID, &prop, 0, NULL, &devuidsize, &devuid);
|
||||
CHECK_RESULT("AudioObjectGetPropertyData (kAudioDevicePropertyDeviceUID)");
|
||||
result = AudioQueueSetProperty(this->hidden->audioQueue, kAudioQueueProperty_CurrentDevice, &devuid, devuidsize);
|
||||
CHECK_RESULT("AudioQueueSetProperty (kAudioQueueProperty_CurrentDevice)");
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
@@ -644,30 +823,60 @@ prepare_audioqueue(_THIS)
|
||||
CHECK_RESULT("AudioQueueNewOutput");
|
||||
}
|
||||
|
||||
#if MACOSX_COREAUDIO
|
||||
{
|
||||
const AudioObjectPropertyAddress prop = {
|
||||
kAudioDevicePropertyDeviceUID,
|
||||
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
CFStringRef devuid;
|
||||
UInt32 devuidsize = sizeof (devuid);
|
||||
result = AudioObjectGetPropertyData(this->hidden->deviceID, &prop, 0, NULL, &devuidsize, &devuid);
|
||||
CHECK_RESULT("AudioObjectGetPropertyData (kAudioDevicePropertyDeviceUID)");
|
||||
result = AudioQueueSetProperty(this->hidden->audioQueue, kAudioQueueProperty_CurrentDevice, &devuid, devuidsize);
|
||||
CHECK_RESULT("AudioQueueSetProperty (kAudioQueueProperty_CurrentDevice)");
|
||||
#if MACOSX_COREAUDIO
|
||||
if (!assign_device_to_audioqueue(this)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* !!! 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?) */
|
||||
/* Fire a callback if the device stops being "alive" (disconnected, etc). */
|
||||
AudioObjectAddPropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
|
||||
}
|
||||
#endif
|
||||
/* only listen for unplugging on specific devices, not the default device, as that should
|
||||
switch to a different device (or hang out silently if there _is_ no other device). */
|
||||
if (this->handle != NULL) {
|
||||
/* !!! 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?) */
|
||||
/* Fire a callback if the device stops being "alive" (disconnected, etc). */
|
||||
/* If this fails, oh well, we won't notice a device had an extraordinary event take place. */
|
||||
AudioObjectAddPropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Set the channel layout for the audio queue */
|
||||
AudioChannelLayout layout;
|
||||
SDL_zero(layout);
|
||||
switch (this->spec.channels) {
|
||||
case 1:
|
||||
layout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
|
||||
break;
|
||||
case 2:
|
||||
layout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
|
||||
break;
|
||||
case 3:
|
||||
layout.mChannelLayoutTag = kAudioChannelLayoutTag_DVD_4;
|
||||
break;
|
||||
case 4:
|
||||
layout.mChannelLayoutTag = kAudioChannelLayoutTag_Quadraphonic;
|
||||
break;
|
||||
case 5:
|
||||
layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_5_0_A;
|
||||
break;
|
||||
case 6:
|
||||
layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_5_1_A;
|
||||
break;
|
||||
case 7:
|
||||
/* FIXME: Need to move channel[4] (BC) to channel[6] */
|
||||
layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_6_1_A;
|
||||
break;
|
||||
case 8:
|
||||
layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_7_1_A;
|
||||
break;
|
||||
}
|
||||
if (layout.mChannelLayoutTag != 0) {
|
||||
result = AudioQueueSetProperty(this->hidden->audioQueue, kAudioQueueProperty_ChannelLayout, &layout, sizeof(layout));
|
||||
CHECK_RESULT("AudioQueueSetProperty(kAudioQueueProperty_ChannelLayout)");
|
||||
}
|
||||
|
||||
/* Allocate a sample buffer */
|
||||
this->hidden->bufferSize = this->spec.size;
|
||||
this->hidden->bufferOffset = iscapture ? 0 : this->hidden->bufferSize;
|
||||
@@ -692,6 +901,7 @@ prepare_audioqueue(_THIS)
|
||||
numAudioBuffers = ((int)SDL_ceil(MINIMUM_AUDIO_BUFFER_TIME_MS / msecs) * 2);
|
||||
}
|
||||
|
||||
this->hidden->numAudioBuffers = numAudioBuffers;
|
||||
this->hidden->audioBuffer = SDL_calloc(1, sizeof (AudioQueueBufferRef) * numAudioBuffers);
|
||||
if (this->hidden->audioBuffer == NULL) {
|
||||
SDL_OutOfMemory();
|
||||
@@ -707,6 +917,7 @@ prepare_audioqueue(_THIS)
|
||||
CHECK_RESULT("AudioQueueAllocateBuffer");
|
||||
SDL_memset(this->hidden->audioBuffer[i]->mAudioData, this->spec.silence, this->hidden->audioBuffer[i]->mAudioDataBytesCapacity);
|
||||
this->hidden->audioBuffer[i]->mAudioDataByteSize = this->hidden->audioBuffer[i]->mAudioDataBytesCapacity;
|
||||
/* !!! FIXME: should we use AudioQueueEnqueueBufferWithParameters and specify all frames be "trimmed" so these are immediately ready to refill with SDL callback data? */
|
||||
result = AudioQueueEnqueueBuffer(this->hidden->audioQueue, this->hidden->audioBuffer[i], 0, NULL);
|
||||
CHECK_RESULT("AudioQueueEnqueueBuffer");
|
||||
}
|
||||
@@ -722,6 +933,20 @@ static int
|
||||
audioqueue_thread(void *arg)
|
||||
{
|
||||
SDL_AudioDevice *this = (SDL_AudioDevice *) arg;
|
||||
|
||||
#if MACOSX_COREAUDIO
|
||||
const AudioObjectPropertyAddress default_device_address = {
|
||||
this->iscapture ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
kAudioObjectPropertyElementMaster
|
||||
};
|
||||
|
||||
if (this->handle == NULL) { /* opened the default device? Register to know if the user picks a new default. */
|
||||
/* we don't care if this fails; we just won't change to new default devices, but we still otherwise function in this case. */
|
||||
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &default_device_address, default_device_changed, this);
|
||||
}
|
||||
#endif
|
||||
|
||||
const int rc = prepare_audioqueue(this);
|
||||
if (!rc) {
|
||||
this->hidden->thread_error = SDL_strdup(SDL_GetError());
|
||||
@@ -733,8 +958,36 @@ audioqueue_thread(void *arg)
|
||||
|
||||
/* init was successful, alert parent thread and start running... */
|
||||
SDL_SemPost(this->hidden->ready_semaphore);
|
||||
|
||||
while (!SDL_AtomicGet(&this->hidden->shutdown)) {
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
|
||||
|
||||
#if MACOSX_COREAUDIO
|
||||
if ((this->handle == NULL) && SDL_AtomicGet(&this->hidden->device_change_flag)) {
|
||||
SDL_AtomicSet(&this->hidden->device_change_flag, 0);
|
||||
|
||||
#if DEBUG_COREAUDIO
|
||||
printf("COREAUDIO: audioqueue_thread is trying to switch to new default device!\n");
|
||||
#endif
|
||||
|
||||
/* if any of this fails, there's not much to do but wait to see if the user gives up
|
||||
and quits (flagging the audioqueue for shutdown), or toggles to some other system
|
||||
output device (in which case we'll try again). */
|
||||
const AudioDeviceID prev_devid = this->hidden->deviceID;
|
||||
if (prepare_device(this, this->handle, this->iscapture) && (prev_devid != this->hidden->deviceID)) {
|
||||
AudioQueueStop(this->hidden->audioQueue, 1);
|
||||
if (assign_device_to_audioqueue(this)) {
|
||||
int i;
|
||||
for (i = 0; i < this->hidden->numAudioBuffers; i++) {
|
||||
SDL_memset(this->hidden->audioBuffer[i]->mAudioData, this->spec.silence, this->hidden->audioBuffer[i]->mAudioDataBytesCapacity);
|
||||
/* !!! FIXME: should we use AudioQueueEnqueueBufferWithParameters and specify all frames be "trimmed" so these are immediately ready to refill with SDL callback data? */
|
||||
AudioQueueEnqueueBuffer(this->hidden->audioQueue, this->hidden->audioBuffer[i], 0, NULL);
|
||||
}
|
||||
AudioQueueStart(this->hidden->audioQueue, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!this->iscapture) { /* Drain off any pending playback. */
|
||||
@@ -742,6 +995,13 @@ audioqueue_thread(void *arg)
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, secs, 0);
|
||||
}
|
||||
|
||||
#if MACOSX_COREAUDIO
|
||||
if (this->handle == NULL) {
|
||||
/* we don't care if this fails; we just won't change to new default devices, but we still otherwise function in this case. */
|
||||
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &default_device_address, default_device_changed, this);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -751,6 +1011,7 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
AudioStreamBasicDescription *strdesc;
|
||||
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
|
||||
int valid_datatype = 0;
|
||||
SDL_AudioDevice **new_open_devices;
|
||||
|
||||
/* Initialize all variables that we clean on shutdown */
|
||||
this->hidden = (struct SDL_PrivateAudioData *)
|
||||
@@ -768,8 +1029,14 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
open_playback_devices++;
|
||||
}
|
||||
|
||||
new_open_devices = (SDL_AudioDevice **)SDL_realloc(open_devices, sizeof(open_devices[0]) * (num_open_devices + 1));
|
||||
if (new_open_devices) {
|
||||
open_devices = new_open_devices;
|
||||
open_devices[num_open_devices++] = this;
|
||||
}
|
||||
|
||||
#if !MACOSX_COREAUDIO
|
||||
if (!update_audio_session(this, SDL_TRUE)) {
|
||||
if (!update_audio_session(this, SDL_TRUE, SDL_TRUE)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -778,6 +1045,17 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
AVAudioSession* session = [AVAudioSession sharedInstance];
|
||||
[session setPreferredSampleRate:this->spec.freq error:nil];
|
||||
this->spec.freq = (int)session.sampleRate;
|
||||
#if TARGET_OS_TV
|
||||
if (iscapture) {
|
||||
[session setPreferredInputNumberOfChannels:this->spec.channels error:nil];
|
||||
this->spec.channels = session.preferredInputNumberOfChannels;
|
||||
} else {
|
||||
[session setPreferredOutputNumberOfChannels:this->spec.channels error:nil];
|
||||
this->spec.channels = session.preferredOutputNumberOfChannels;
|
||||
}
|
||||
#else
|
||||
/* Calling setPreferredOutputNumberOfChannels seems to break audio output on iOS */
|
||||
#endif /* TARGET_OS_TV */
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -791,13 +1069,11 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
|
||||
while ((!valid_datatype) && (test_format)) {
|
||||
this->spec.format = test_format;
|
||||
/* Just a list of valid SDL formats, so people don't pass junk here. */
|
||||
/* CoreAudio handles most of SDL's formats natively, but not U16, apparently. */
|
||||
switch (test_format) {
|
||||
case AUDIO_U8:
|
||||
case AUDIO_S8:
|
||||
case AUDIO_U16LSB:
|
||||
case AUDIO_S16LSB:
|
||||
case AUDIO_U16MSB:
|
||||
case AUDIO_S16MSB:
|
||||
case AUDIO_S32LSB:
|
||||
case AUDIO_S32MSB:
|
||||
@@ -813,6 +1089,10 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
else if (SDL_AUDIO_ISSIGNED(this->spec.format))
|
||||
strdesc->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
|
||||
break;
|
||||
|
||||
default:
|
||||
test_format = SDL_NextAudioFormat();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -820,7 +1100,7 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
return SDL_SetError("Unsupported audio format");
|
||||
}
|
||||
|
||||
strdesc->mBytesPerFrame = strdesc->mBitsPerChannel * strdesc->mChannelsPerFrame / 8;
|
||||
strdesc->mBytesPerFrame = strdesc->mChannelsPerFrame * strdesc->mBitsPerChannel / 8;
|
||||
strdesc->mBytesPerPacket = strdesc->mBytesPerFrame * strdesc->mFramesPerPacket;
|
||||
|
||||
#if MACOSX_COREAUDIO
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
/* Allow access to a raw mixing buffer */
|
||||
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_loadso.h"
|
||||
#include "SDL_audio.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "SDL_audio.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "SDL_diskaudio.h"
|
||||
#include "SDL_log.h"
|
||||
|
||||
/* !!! FIXME: these should be SDL hints, not environment variables. */
|
||||
/* environment variables and defaults. */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -23,10 +23,8 @@
|
||||
#if SDL_AUDIO_DRIVER_EMSCRIPTEN
|
||||
|
||||
#include "SDL_audio.h"
|
||||
#include "SDL_log.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "SDL_emscriptenaudio.h"
|
||||
#include "SDL_assert.h"
|
||||
|
||||
#include <emscripten/emscripten.h>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -36,7 +36,6 @@ extern "C"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_sysaudio.h"
|
||||
#include "SDL_haikuaudio.h"
|
||||
#include "SDL_assert.h"
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -18,12 +18,10 @@
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#if SDL_AUDIO_DRIVER_JACK
|
||||
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
@@ -278,6 +276,7 @@ JACK_CloseDevice(_THIS)
|
||||
}
|
||||
|
||||
SDL_free(this->hidden->iobuffer);
|
||||
SDL_free(this->hidden);
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
/*
|
||||
* Driver for native NetBSD audio(4).
|
||||
* vedge@vedge.com.ar.
|
||||
* nia@NetBSD.org
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
@@ -261,6 +261,14 @@ NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
prinfo->encoding = AUDIO_ENCODING_ULINEAR_BE;
|
||||
prinfo->precision = 16;
|
||||
break;
|
||||
case AUDIO_S32LSB:
|
||||
prinfo->encoding = AUDIO_ENCODING_SLINEAR_LE;
|
||||
prinfo->precision = 32;
|
||||
break;
|
||||
case AUDIO_S32MSB:
|
||||
prinfo->encoding = AUDIO_ENCODING_SLINEAR_BE;
|
||||
prinfo->precision = 32;
|
||||
break;
|
||||
}
|
||||
if (prinfo->encoding != AUDIO_ENCODING_NONE) {
|
||||
break;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "SDL_audio.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../../core/android/SDL_android.h"
|
||||
#include "SDL_openslES.h"
|
||||
|
||||
/* for native audio */
|
||||
@@ -36,9 +37,8 @@
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#define LOG_TAG "SDL_openslES"
|
||||
|
||||
#if 0
|
||||
#define LOG_TAG "SDL_openslES"
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
|
||||
//#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__)
|
||||
@@ -49,42 +49,50 @@
|
||||
#define LOGV(...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
#define SL_SPEAKER_FRONT_LEFT ((SLuint32) 0x00000001)
|
||||
#define SL_SPEAKER_FRONT_RIGHT ((SLuint32) 0x00000002)
|
||||
#define SL_SPEAKER_FRONT_CENTER ((SLuint32) 0x00000004)
|
||||
#define SL_SPEAKER_LOW_FREQUENCY ((SLuint32) 0x00000008)
|
||||
#define SL_SPEAKER_BACK_LEFT ((SLuint32) 0x00000010)
|
||||
#define SL_SPEAKER_BACK_RIGHT ((SLuint32) 0x00000020)
|
||||
#define SL_SPEAKER_FRONT_LEFT_OF_CENTER ((SLuint32) 0x00000040)
|
||||
#define SL_SPEAKER_FRONT_RIGHT_OF_CENTER ((SLuint32) 0x00000080)
|
||||
#define SL_SPEAKER_BACK_CENTER ((SLuint32) 0x00000100)
|
||||
#define SL_SPEAKER_SIDE_LEFT ((SLuint32) 0x00000200)
|
||||
#define SL_SPEAKER_SIDE_RIGHT ((SLuint32) 0x00000400)
|
||||
#define SL_SPEAKER_TOP_CENTER ((SLuint32) 0x00000800)
|
||||
#define SL_SPEAKER_TOP_FRONT_LEFT ((SLuint32) 0x00001000)
|
||||
#define SL_SPEAKER_TOP_FRONT_CENTER ((SLuint32) 0x00002000)
|
||||
#define SL_SPEAKER_TOP_FRONT_RIGHT ((SLuint32) 0x00004000)
|
||||
#define SL_SPEAKER_TOP_BACK_LEFT ((SLuint32) 0x00008000)
|
||||
#define SL_SPEAKER_TOP_BACK_CENTER ((SLuint32) 0x00010000)
|
||||
#define SL_SPEAKER_TOP_BACK_RIGHT ((SLuint32) 0x00020000)
|
||||
*/
|
||||
#define SL_ANDROID_SPEAKER_STEREO (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT)
|
||||
#define SL_ANDROID_SPEAKER_QUAD (SL_ANDROID_SPEAKER_STEREO | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT)
|
||||
#define SL_ANDROID_SPEAKER_5DOT1 (SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY)
|
||||
#define SL_ANDROID_SPEAKER_7DOT1 (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT)
|
||||
|
||||
/* engine interfaces */
|
||||
static SLObjectItf engineObject = NULL;
|
||||
static SLEngineItf engineEngine = NULL;
|
||||
static SLObjectItf engineObject;
|
||||
static SLEngineItf engineEngine;
|
||||
|
||||
/* output mix interfaces */
|
||||
static SLObjectItf outputMixObject = NULL;
|
||||
// static SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL;
|
||||
|
||||
/* aux effect on the output mix, used by the buffer queue player */
|
||||
/* static const SLEnvironmentalReverbSettings reverbSettings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR; */
|
||||
static SLObjectItf outputMixObject;
|
||||
|
||||
/* buffer queue player interfaces */
|
||||
static SLObjectItf bqPlayerObject = NULL;
|
||||
static SLPlayItf bqPlayerPlay = NULL;
|
||||
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue = NULL;
|
||||
static SLObjectItf bqPlayerObject;
|
||||
static SLPlayItf bqPlayerPlay;
|
||||
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
|
||||
#if 0
|
||||
static SLEffectSendItf bqPlayerEffectSend = NULL;
|
||||
static SLMuteSoloItf bqPlayerMuteSolo = NULL;
|
||||
static SLVolumeItf bqPlayerVolume = NULL;
|
||||
static SLVolumeItf bqPlayerVolume;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* recorder interfaces TODO */
|
||||
static SLObjectItf recorderObject = NULL;
|
||||
static SLRecordItf recorderRecord;
|
||||
/* recorder interfaces */
|
||||
static SLObjectItf recorderObject;
|
||||
static SLRecordItf recorderRecord;
|
||||
static SLAndroidSimpleBufferQueueItf recorderBufferQueue;
|
||||
#endif
|
||||
|
||||
/* pointer and size of the next player buffer to enqueue, and number of remaining buffers */
|
||||
#if 0
|
||||
static short *nextBuffer;
|
||||
static unsigned nextSize;
|
||||
static int nextCount;
|
||||
#endif
|
||||
|
||||
// static SDL_AudioDevice* audioDevice = NULL;
|
||||
|
||||
#if 0
|
||||
static const char *sldevaudiorecorderstr = "SLES Audio Recorder";
|
||||
@@ -94,19 +102,34 @@ static const char *sldevaudioplayerstr = "SLES Audio Player";
|
||||
#define SLES_DEV_AUDIO_PLAYER sldevaudioplayerstr
|
||||
static void openslES_DetectDevices( int iscapture )
|
||||
{
|
||||
LOGI( "openSLES_DetectDevices()" );
|
||||
LOGI( "openSLES_DetectDevices()" );
|
||||
if ( iscapture )
|
||||
addfn( SLES_DEV_AUDIO_RECORDER );
|
||||
else
|
||||
else
|
||||
addfn( SLES_DEV_AUDIO_PLAYER );
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void openslES_DestroyEngine();
|
||||
static void openslES_DestroyEngine(void)
|
||||
{
|
||||
LOGI("openslES_DestroyEngine()");
|
||||
|
||||
/* destroy output mix object, and invalidate all associated interfaces */
|
||||
if (outputMixObject != NULL) {
|
||||
(*outputMixObject)->Destroy(outputMixObject);
|
||||
outputMixObject = NULL;
|
||||
}
|
||||
|
||||
/* destroy engine object, and invalidate all associated interfaces */
|
||||
if (engineObject != NULL) {
|
||||
(*engineObject)->Destroy(engineObject);
|
||||
engineObject = NULL;
|
||||
engineEngine = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
openslES_CreateEngine()
|
||||
openslES_CreateEngine(void)
|
||||
{
|
||||
SLresult result;
|
||||
|
||||
@@ -115,40 +138,33 @@ openslES_CreateEngine()
|
||||
/* create engine */
|
||||
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("slCreateEngine failed");
|
||||
LOGE("slCreateEngine failed: %d", result);
|
||||
goto error;
|
||||
}
|
||||
|
||||
LOGI("slCreateEngine OK");
|
||||
|
||||
/* realize the engine */
|
||||
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("RealizeEngine failed");
|
||||
LOGE("RealizeEngine failed: %d", result);
|
||||
goto error;
|
||||
}
|
||||
|
||||
LOGI("RealizeEngine OK");
|
||||
|
||||
/* get the engine interface, which is needed in order to create other objects */
|
||||
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("EngineGetInterface failed");
|
||||
LOGE("EngineGetInterface failed: %d", result);
|
||||
goto error;
|
||||
}
|
||||
|
||||
LOGI("EngineGetInterface OK");
|
||||
|
||||
/* create output mix, with environmental reverb specified as a non-required interface */
|
||||
/* const SLInterfaceID ids[1] = { SL_IID_ENVIRONMENTALREVERB }; */
|
||||
/* const SLboolean req[1] = { SL_BOOLEAN_FALSE }; */
|
||||
|
||||
/* create output mix */
|
||||
const SLInterfaceID ids[1] = { SL_IID_VOLUME };
|
||||
const SLboolean req[1] = { SL_BOOLEAN_FALSE };
|
||||
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);
|
||||
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("CreateOutputMix failed");
|
||||
LOGE("CreateOutputMix failed: %d", result);
|
||||
goto error;
|
||||
}
|
||||
LOGI("CreateOutputMix OK");
|
||||
@@ -156,7 +172,7 @@ openslES_CreateEngine()
|
||||
/* realize the output mix */
|
||||
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("RealizeOutputMix failed");
|
||||
LOGE("RealizeOutputMix failed: %d", result);
|
||||
goto error;
|
||||
}
|
||||
return 1;
|
||||
@@ -166,31 +182,182 @@ error:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void openslES_DestroyPCMPlayer(_THIS);
|
||||
static void openslES_DestroyPCMRecorder(_THIS);
|
||||
|
||||
static void openslES_DestroyEngine()
|
||||
/* this callback handler is called every time a buffer finishes recording */
|
||||
static void
|
||||
bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
|
||||
{
|
||||
LOGI("openslES_DestroyEngine()");
|
||||
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) context;
|
||||
|
||||
// openslES_DestroyPCMPlayer(this);
|
||||
// openslES_DestroyPCMRecorder(this);
|
||||
LOGV("SLES: Recording Callback");
|
||||
SDL_SemPost(audiodata->playsem);
|
||||
}
|
||||
|
||||
/* destroy output mix object, and invalidate all associated interfaces */
|
||||
if (outputMixObject != NULL) {
|
||||
(*outputMixObject)->Destroy(outputMixObject);
|
||||
outputMixObject = NULL;
|
||||
/* outputMixEnvironmentalReverb = NULL; */
|
||||
static void
|
||||
openslES_DestroyPCMRecorder(_THIS)
|
||||
{
|
||||
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
||||
SLresult result;
|
||||
|
||||
/* stop recording */
|
||||
if (recorderRecord != NULL) {
|
||||
result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("SetRecordState stopped: %d", result);
|
||||
}
|
||||
}
|
||||
|
||||
/* destroy engine object, and invalidate all associated interfaces */
|
||||
if (engineObject != NULL) {
|
||||
(*engineObject)->Destroy(engineObject);
|
||||
engineObject = NULL;
|
||||
engineEngine = NULL;
|
||||
/* destroy audio recorder object, and invalidate all associated interfaces */
|
||||
if (recorderObject != NULL) {
|
||||
(*recorderObject)->Destroy(recorderObject);
|
||||
recorderObject = NULL;
|
||||
recorderRecord = NULL;
|
||||
recorderBufferQueue = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
if (audiodata->playsem) {
|
||||
SDL_DestroySemaphore(audiodata->playsem);
|
||||
audiodata->playsem = NULL;
|
||||
}
|
||||
|
||||
if (audiodata->mixbuff) {
|
||||
SDL_free(audiodata->mixbuff);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
openslES_CreatePCMRecorder(_THIS)
|
||||
{
|
||||
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
||||
SLDataFormat_PCM format_pcm;
|
||||
SLresult result;
|
||||
int i;
|
||||
|
||||
if (!Android_JNI_RequestPermission("android.permission.RECORD_AUDIO")) {
|
||||
LOGE("This app doesn't have RECORD_AUDIO permission");
|
||||
return SDL_SetError("This app doesn't have RECORD_AUDIO permission");
|
||||
}
|
||||
|
||||
/* Just go with signed 16-bit audio as it's the most compatible */
|
||||
this->spec.format = AUDIO_S16SYS;
|
||||
this->spec.channels = 1;
|
||||
/*this->spec.freq = SL_SAMPLINGRATE_16 / 1000;*/
|
||||
|
||||
/* Update the fragment size as size in bytes */
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
LOGI("Try to open %u hz %u bit chan %u %s samples %u",
|
||||
this->spec.freq, SDL_AUDIO_BITSIZE(this->spec.format),
|
||||
this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples);
|
||||
|
||||
/* configure audio source */
|
||||
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
|
||||
SLDataSource audioSrc = {&loc_dev, NULL};
|
||||
|
||||
/* configure audio sink */
|
||||
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, NUM_BUFFERS };
|
||||
|
||||
format_pcm.formatType = SL_DATAFORMAT_PCM;
|
||||
format_pcm.numChannels = this->spec.channels;
|
||||
format_pcm.samplesPerSec = this->spec.freq * 1000; /* / kilo Hz to milli Hz */
|
||||
format_pcm.bitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
|
||||
format_pcm.containerSize = SDL_AUDIO_BITSIZE(this->spec.format);
|
||||
format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
||||
format_pcm.channelMask = SL_SPEAKER_FRONT_CENTER;
|
||||
|
||||
SLDataSink audioSnk = { &loc_bufq, &format_pcm };
|
||||
|
||||
/* create audio recorder */
|
||||
/* (requires the RECORD_AUDIO permission) */
|
||||
const SLInterfaceID ids[1] = {
|
||||
SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
|
||||
};
|
||||
const SLboolean req[1] = {
|
||||
SL_BOOLEAN_TRUE,
|
||||
};
|
||||
|
||||
result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audioSrc, &audioSnk, 1, ids, req);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("CreateAudioRecorder failed: %d", result);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* realize the recorder */
|
||||
result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("RealizeAudioPlayer failed: %d", result);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* get the record interface */
|
||||
result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("SL_IID_RECORD interface get failed: %d", result);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* get the buffer queue interface */
|
||||
result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recorderBufferQueue);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("SL_IID_BUFFERQUEUE interface get failed: %d", result);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* register callback on the buffer queue */
|
||||
/* context is '(SDL_PrivateAudioData *)this->hidden' */
|
||||
result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback, this->hidden);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("RegisterCallback failed: %d", result);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Create the audio buffer semaphore */
|
||||
audiodata->playsem = SDL_CreateSemaphore(0);
|
||||
if (!audiodata->playsem) {
|
||||
LOGE("cannot create Semaphore!");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Create the sound buffers */
|
||||
audiodata->mixbuff = (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
|
||||
if (audiodata->mixbuff == NULL) {
|
||||
LOGE("mixbuffer allocate - out of memory");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_BUFFERS; i++) {
|
||||
audiodata->pmixbuff[i] = audiodata->mixbuff + i * this->spec.size;
|
||||
}
|
||||
|
||||
/* in case already recording, stop recording and clear buffer queue */
|
||||
result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("Record set state failed: %d", result);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* enqueue empty buffers to be filled by the recorder */
|
||||
for (i = 0; i < NUM_BUFFERS; i++) {
|
||||
result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[i], this->spec.size);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("Record enqueue buffers failed: %d", result);
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
/* start recording */
|
||||
result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("Record set state failed: %d", result);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
|
||||
openslES_DestroyPCMRecorder(this);
|
||||
|
||||
return SDL_SetError("Open device failed!");
|
||||
}
|
||||
|
||||
/* this callback handler is called every time a buffer finishes playing */
|
||||
@@ -198,32 +365,49 @@ static void
|
||||
bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
|
||||
{
|
||||
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) context;
|
||||
LOGV("SLES: Playback Callmeback");
|
||||
|
||||
LOGV("SLES: Playback Callback");
|
||||
SDL_SemPost(audiodata->playsem);
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
openslES_CreatePCMRecorder(_THIS)
|
||||
{
|
||||
/* struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden; */
|
||||
|
||||
LOGE("openslES_CreatePCMRecorder not implimented yet!");
|
||||
return SDL_SetError("openslES_CreatePCMRecorder not implimented yet!");
|
||||
}
|
||||
|
||||
static void
|
||||
openslES_DestroyPCMRecorder(_THIS)
|
||||
openslES_DestroyPCMPlayer(_THIS)
|
||||
{
|
||||
/* struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden; */
|
||||
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
||||
SLresult result;
|
||||
|
||||
return;
|
||||
/* set the player's state to 'stopped' */
|
||||
if (bqPlayerPlay != NULL) {
|
||||
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("SetPlayState stopped failed: %d", result);
|
||||
}
|
||||
}
|
||||
|
||||
/* destroy buffer queue audio player object, and invalidate all associated interfaces */
|
||||
if (bqPlayerObject != NULL) {
|
||||
|
||||
(*bqPlayerObject)->Destroy(bqPlayerObject);
|
||||
|
||||
bqPlayerObject = NULL;
|
||||
bqPlayerPlay = NULL;
|
||||
bqPlayerBufferQueue = NULL;
|
||||
}
|
||||
|
||||
if (audiodata->playsem) {
|
||||
SDL_DestroySemaphore(audiodata->playsem);
|
||||
audiodata->playsem = NULL;
|
||||
}
|
||||
|
||||
if (audiodata->mixbuff) {
|
||||
SDL_free(audiodata->mixbuff);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
openslES_CreatePCMPlayer(_THIS)
|
||||
{
|
||||
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
|
||||
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
||||
SLDataFormat_PCM format_pcm;
|
||||
SLresult result;
|
||||
int i;
|
||||
@@ -274,31 +458,6 @@ openslES_CreatePCMPlayer(_THIS)
|
||||
format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
||||
}
|
||||
|
||||
/*
|
||||
#define SL_SPEAKER_FRONT_LEFT ((SLuint32) 0x00000001)
|
||||
#define SL_SPEAKER_FRONT_RIGHT ((SLuint32) 0x00000002)
|
||||
#define SL_SPEAKER_FRONT_CENTER ((SLuint32) 0x00000004)
|
||||
#define SL_SPEAKER_LOW_FREQUENCY ((SLuint32) 0x00000008)
|
||||
#define SL_SPEAKER_BACK_LEFT ((SLuint32) 0x00000010)
|
||||
#define SL_SPEAKER_BACK_RIGHT ((SLuint32) 0x00000020)
|
||||
#define SL_SPEAKER_FRONT_LEFT_OF_CENTER ((SLuint32) 0x00000040)
|
||||
#define SL_SPEAKER_FRONT_RIGHT_OF_CENTER ((SLuint32) 0x00000080)
|
||||
#define SL_SPEAKER_BACK_CENTER ((SLuint32) 0x00000100)
|
||||
#define SL_SPEAKER_SIDE_LEFT ((SLuint32) 0x00000200)
|
||||
#define SL_SPEAKER_SIDE_RIGHT ((SLuint32) 0x00000400)
|
||||
#define SL_SPEAKER_TOP_CENTER ((SLuint32) 0x00000800)
|
||||
#define SL_SPEAKER_TOP_FRONT_LEFT ((SLuint32) 0x00001000)
|
||||
#define SL_SPEAKER_TOP_FRONT_CENTER ((SLuint32) 0x00002000)
|
||||
#define SL_SPEAKER_TOP_FRONT_RIGHT ((SLuint32) 0x00004000)
|
||||
#define SL_SPEAKER_TOP_BACK_LEFT ((SLuint32) 0x00008000)
|
||||
#define SL_SPEAKER_TOP_BACK_CENTER ((SLuint32) 0x00010000)
|
||||
#define SL_SPEAKER_TOP_BACK_RIGHT ((SLuint32) 0x00020000)
|
||||
*/
|
||||
#define SL_ANDROID_SPEAKER_STEREO (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT)
|
||||
#define SL_ANDROID_SPEAKER_QUAD (SL_ANDROID_SPEAKER_STEREO | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT)
|
||||
#define SL_ANDROID_SPEAKER_5DOT1 (SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY)
|
||||
#define SL_ANDROID_SPEAKER_7DOT1 (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT)
|
||||
|
||||
switch (this->spec.channels)
|
||||
{
|
||||
case 1:
|
||||
@@ -351,28 +510,28 @@ openslES_CreatePCMPlayer(_THIS)
|
||||
|
||||
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("CreateAudioPlayer failed");
|
||||
LOGE("CreateAudioPlayer failed: %d", result);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* realize the player */
|
||||
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("RealizeAudioPlayer failed");
|
||||
LOGE("RealizeAudioPlayer failed: %d", result);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* get the play interface */
|
||||
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("SL_IID_PLAY interface get failed");
|
||||
LOGE("SL_IID_PLAY interface get failed: %d", result);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* get the buffer queue interface */
|
||||
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bqPlayerBufferQueue);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("SL_IID_BUFFERQUEUE interface get failed");
|
||||
LOGE("SL_IID_BUFFERQUEUE interface get failed: %d", result);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
@@ -380,33 +539,15 @@ openslES_CreatePCMPlayer(_THIS)
|
||||
/* context is '(SDL_PrivateAudioData *)this->hidden' */
|
||||
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, this->hidden);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("RegisterCallback failed");
|
||||
LOGE("RegisterCallback failed: %d", result);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* get the effect send interface */
|
||||
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND, &bqPlayerEffectSend);
|
||||
if (SL_RESULT_SUCCESS != result)
|
||||
{
|
||||
|
||||
LOGE("SL_IID_EFFECTSEND interface get failed");
|
||||
goto failed;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0 /* mute/solo is not supported for sources that are known to be mono, as this is */
|
||||
/* get the mute/solo interface */
|
||||
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_MUTESOLO, &bqPlayerMuteSolo);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
(void) result;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* get the volume interface */
|
||||
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("SL_IID_VOLUME interface get failed");
|
||||
LOGE("SL_IID_VOLUME interface get failed: %d", result);
|
||||
/* goto failed; */
|
||||
}
|
||||
#endif
|
||||
@@ -432,7 +573,7 @@ openslES_CreatePCMPlayer(_THIS)
|
||||
/* set the player's state to playing */
|
||||
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("Play set state failed");
|
||||
LOGE("Play set state failed: %d", result);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
@@ -445,47 +586,6 @@ failed:
|
||||
return SDL_SetError("Open device failed!");
|
||||
}
|
||||
|
||||
static void
|
||||
openslES_DestroyPCMPlayer(_THIS)
|
||||
{
|
||||
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
|
||||
SLresult result;
|
||||
|
||||
/* set the player's state to 'stopped' */
|
||||
if (bqPlayerPlay != NULL) {
|
||||
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
SDL_SetError("Stopped set state failed");
|
||||
}
|
||||
}
|
||||
|
||||
/* destroy buffer queue audio player object, and invalidate all associated interfaces */
|
||||
if (bqPlayerObject != NULL) {
|
||||
|
||||
(*bqPlayerObject)->Destroy(bqPlayerObject);
|
||||
|
||||
bqPlayerObject = NULL;
|
||||
bqPlayerPlay = NULL;
|
||||
bqPlayerBufferQueue = NULL;
|
||||
#if 0
|
||||
bqPlayerEffectSend = NULL;
|
||||
bqPlayerMuteSolo = NULL;
|
||||
bqPlayerVolume = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (audiodata->playsem) {
|
||||
SDL_DestroySemaphore(audiodata->playsem);
|
||||
audiodata->playsem = NULL;
|
||||
}
|
||||
|
||||
if (audiodata->mixbuff) {
|
||||
SDL_free(audiodata->mixbuff);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
openslES_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
{
|
||||
@@ -495,44 +595,46 @@ openslES_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
}
|
||||
|
||||
if (iscapture) {
|
||||
LOGI("openslES_OpenDevice( ) %s for capture", devname);
|
||||
LOGI("openslES_OpenDevice() %s for capture", devname);
|
||||
return openslES_CreatePCMRecorder(this);
|
||||
} else {
|
||||
LOGI("openslES_OpenDevice( ) %s for playing", devname);
|
||||
LOGI("openslES_OpenDevice() %s for playing", devname);
|
||||
return openslES_CreatePCMPlayer(this);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
openslES_CloseDevice(_THIS)
|
||||
openslES_WaitDevice(_THIS)
|
||||
{
|
||||
/* struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden; */
|
||||
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
||||
|
||||
if (this->iscapture) {
|
||||
LOGI("openslES_CloseDevice( ) for capture");
|
||||
openslES_DestroyPCMRecorder(this);
|
||||
} else {
|
||||
LOGI("openslES_CloseDevice( ) for playing");
|
||||
openslES_DestroyPCMPlayer(this);
|
||||
}
|
||||
LOGV("openslES_WaitDevice()");
|
||||
|
||||
SDL_free(this->hidden);
|
||||
|
||||
return;
|
||||
/* Wait for an audio chunk to finish */
|
||||
SDL_SemWait(audiodata->playsem);
|
||||
}
|
||||
|
||||
static void
|
||||
openslES_WaitDevice(_THIS)
|
||||
openslES_PlayDevice(_THIS)
|
||||
{
|
||||
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
|
||||
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
||||
SLresult result;
|
||||
|
||||
LOGV("openslES_WaitDevice( )");
|
||||
LOGV("======openslES_PlayDevice()======");
|
||||
|
||||
/* Wait for an audio chunk to finish */
|
||||
/* WaitForSingleObject(this->hidden->audio_sem, INFINITE); */
|
||||
SDL_SemWait(audiodata->playsem);
|
||||
/* Queue it up */
|
||||
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
|
||||
|
||||
return;
|
||||
audiodata->next_buffer++;
|
||||
if (audiodata->next_buffer >= NUM_BUFFERS) {
|
||||
audiodata->next_buffer = 0;
|
||||
}
|
||||
|
||||
/* If Enqueue fails, callback won't be called.
|
||||
* Post the semphore, not to run out of buffer */
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
SDL_SemPost(audiodata->playsem);
|
||||
}
|
||||
}
|
||||
|
||||
/*/ n playn sem */
|
||||
@@ -550,35 +652,54 @@ openslES_WaitDevice(_THIS)
|
||||
static Uint8 *
|
||||
openslES_GetDeviceBuf(_THIS)
|
||||
{
|
||||
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
|
||||
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
||||
|
||||
LOGV("openslES_GetDeviceBuf( )");
|
||||
LOGV("openslES_GetDeviceBuf()");
|
||||
return audiodata->pmixbuff[audiodata->next_buffer];
|
||||
}
|
||||
|
||||
static void
|
||||
openslES_PlayDevice(_THIS)
|
||||
static int
|
||||
openslES_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||
{
|
||||
struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *) this->hidden;
|
||||
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
||||
SLresult result;
|
||||
|
||||
LOGV("======openslES_PlayDevice( )======");
|
||||
/* Wait for new recorded data */
|
||||
SDL_SemWait(audiodata->playsem);
|
||||
|
||||
/* Queue it up */
|
||||
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
|
||||
/* Copy it to the output buffer */
|
||||
SDL_assert(buflen == this->spec.size);
|
||||
SDL_memcpy(buffer, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
|
||||
|
||||
/* Re-enqueue the buffer */
|
||||
result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGE("Record enqueue buffers failed: %d", result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
audiodata->next_buffer++;
|
||||
if (audiodata->next_buffer >= NUM_BUFFERS) {
|
||||
audiodata->next_buffer = 0;
|
||||
}
|
||||
|
||||
/* If Enqueue fails, callback won't be called.
|
||||
* Post the semphore, not to run out of buffer */
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
SDL_SemPost(audiodata->playsem);
|
||||
return this->spec.size;
|
||||
}
|
||||
|
||||
static void
|
||||
openslES_CloseDevice(_THIS)
|
||||
{
|
||||
/* struct SDL_PrivateAudioData *audiodata = this->hidden; */
|
||||
|
||||
if (this->iscapture) {
|
||||
LOGI("openslES_CloseDevice() for capture");
|
||||
openslES_DestroyPCMRecorder(this);
|
||||
} else {
|
||||
LOGI("openslES_CloseDevice() for playing");
|
||||
openslES_DestroyPCMPlayer(this);
|
||||
}
|
||||
|
||||
return;
|
||||
SDL_free(this->hidden);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -595,18 +716,19 @@ openslES_Init(SDL_AudioDriverImpl * impl)
|
||||
/* Set the function pointers */
|
||||
/* impl->DetectDevices = openslES_DetectDevices; */
|
||||
impl->OpenDevice = openslES_OpenDevice;
|
||||
impl->CloseDevice = openslES_CloseDevice;
|
||||
impl->WaitDevice = openslES_WaitDevice;
|
||||
impl->PlayDevice = openslES_PlayDevice;
|
||||
impl->GetDeviceBuf = openslES_GetDeviceBuf;
|
||||
impl->CaptureFromDevice = openslES_CaptureFromDevice;
|
||||
impl->CloseDevice = openslES_CloseDevice;
|
||||
impl->Deinitialize = openslES_DestroyEngine;
|
||||
impl->WaitDevice = openslES_WaitDevice;
|
||||
|
||||
/* and the capabilities */
|
||||
impl->HasCaptureSupport = 0; /* TODO */
|
||||
impl->OnlyHasDefaultOutputDevice = 1;
|
||||
/* impl->OnlyHasDefaultInputDevice = 1; */
|
||||
impl->HasCaptureSupport = 1;
|
||||
impl->OnlyHasDefaultOutputDevice = 1;
|
||||
impl->OnlyHasDefaultCaptureDevice = 1;
|
||||
|
||||
LOGI("openslES_Init() - succes");
|
||||
LOGI("openslES_Init() - success");
|
||||
|
||||
/* this audio target is available. */
|
||||
return 1;
|
||||
@@ -616,24 +738,24 @@ AudioBootStrap openslES_bootstrap = {
|
||||
"openslES", "opensl ES audio driver", openslES_Init, 0
|
||||
};
|
||||
|
||||
void openslES_ResumeDevices()
|
||||
void openslES_ResumeDevices(void)
|
||||
{
|
||||
if (bqPlayerPlay != NULL) {
|
||||
/* set the player's state to 'playing' */
|
||||
SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
SDL_SetError("openslES_ResumeDevices failed");
|
||||
LOGE("openslES_ResumeDevices failed: %d", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void openslES_PauseDevices()
|
||||
void openslES_PauseDevices(void)
|
||||
{
|
||||
if (bqPlayerPlay != NULL) {
|
||||
/* set the player's state to 'paused' */
|
||||
SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
SDL_SetError("openslES_PauseDevices failed");
|
||||
LOGE("openslES_PauseDevices failed: %d", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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,14 +32,10 @@
|
||||
|
||||
struct SDL_PrivateAudioData
|
||||
{
|
||||
/* The file descriptor for the audio device */
|
||||
Uint8 *mixbuff;
|
||||
int next_buffer;
|
||||
Uint8 *pmixbuff[NUM_BUFFERS];
|
||||
SDL_sem *playsem;
|
||||
#if 0
|
||||
SDL_sem *recsem;
|
||||
#endif
|
||||
};
|
||||
|
||||
void openslES_ResumeDevices(void);
|
||||
|
||||
@@ -0,0 +1,454 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#if SDL_AUDIO_DRIVER_OS2
|
||||
|
||||
/* Allow access to a raw mixing buffer */
|
||||
|
||||
#include "../../core/os2/SDL_os2.h"
|
||||
|
||||
#include "SDL_audio.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "SDL_os2audio.h"
|
||||
|
||||
/*
|
||||
void lockIncr(volatile int *piVal);
|
||||
#pragma aux lockIncr = \
|
||||
"lock add [eax], 1 "\
|
||||
parm [eax];
|
||||
|
||||
void lockDecr(volatile int *piVal);
|
||||
#pragma aux lockDecr = \
|
||||
"lock sub [eax], 1 "\
|
||||
parm [eax];
|
||||
*/
|
||||
|
||||
static ULONG _getEnvULong(PSZ pszName, ULONG ulMax, ULONG ulDefault)
|
||||
{
|
||||
ULONG ulValue;
|
||||
PCHAR pcEnd;
|
||||
PSZ pszEnvVal = SDL_getenv(pszName);
|
||||
|
||||
if (pszEnvVal == NULL)
|
||||
return ulDefault;
|
||||
|
||||
ulValue = SDL_strtoul((const char *)pszEnvVal, &pcEnd, 10);
|
||||
return (pcEnd == pszEnvVal) || (ulValue > ulMax)? ulDefault : ulMax;
|
||||
}
|
||||
|
||||
static int _MCIError(PSZ pszFunc, ULONG ulResult)
|
||||
{
|
||||
CHAR acBuf[128];
|
||||
mciGetErrorString(ulResult, acBuf, sizeof(acBuf));
|
||||
return SDL_SetError("[%s] %s", pszFunc, acBuf);
|
||||
}
|
||||
|
||||
static void _mixIOError(PSZ pszFunction, ULONG ulRC)
|
||||
{
|
||||
debug_os2("%s() - failed, rc = 0x%X (%s)",
|
||||
pszFunction, ulRC,
|
||||
(ulRC == MCIERR_INVALID_MODE) ? "Mixer mode does not match request" :
|
||||
(ulRC == MCIERR_INVALID_BUFFER) ? "Caller sent an invalid buffer" : "unknown");
|
||||
}
|
||||
|
||||
LONG APIENTRY cbAudioWriteEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer,
|
||||
ULONG ulFlags)
|
||||
{
|
||||
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)pBuffer->ulUserParm;
|
||||
ULONG ulRC;
|
||||
|
||||
if (ulFlags != MIX_WRITE_COMPLETE) {
|
||||
debug_os2("flags = 0x%X", ulFlags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*lockDecr((int *)&pAData->ulQueuedBuf);*/
|
||||
ulRC = DosPostEventSem(pAData->hevBuf);
|
||||
if (ulRC != NO_ERROR && ulRC != ERROR_ALREADY_POSTED) {
|
||||
debug_os2("DosPostEventSem(), rc = %u", ulRC);
|
||||
}
|
||||
|
||||
return 1; /* It seems, return value is not matter. */
|
||||
}
|
||||
|
||||
LONG APIENTRY cbAudioReadEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer,
|
||||
ULONG ulFlags)
|
||||
{
|
||||
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)pBuffer->ulUserParm;
|
||||
ULONG ulRC;
|
||||
|
||||
if (ulFlags != MIX_READ_COMPLETE) {
|
||||
debug_os2("flags = 0x%X", ulFlags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pAData->stMCIMixSetup.pmixRead(pAData->stMCIMixSetup.ulMixHandle, pBuffer, 1);
|
||||
|
||||
ulRC = DosPostEventSem(pAData->hevBuf);
|
||||
if (ulRC != NO_ERROR && ulRC != ERROR_ALREADY_POSTED) {
|
||||
debug_os2("DosPostEventSem(), rc = %u", ulRC);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void OS2_DetectDevices(void)
|
||||
{
|
||||
MCI_SYSINFO_PARMS stMCISysInfo;
|
||||
CHAR acBuf[256];
|
||||
ULONG ulDevicesNum;
|
||||
MCI_SYSINFO_LOGDEVICE stLogDevice;
|
||||
MCI_SYSINFO_PARMS stSysInfoParams;
|
||||
ULONG ulRC;
|
||||
ULONG ulHandle = 0;
|
||||
|
||||
acBuf[0] = '\0';
|
||||
stMCISysInfo.pszReturn = acBuf;
|
||||
stMCISysInfo.ulRetSize = sizeof(acBuf);
|
||||
stMCISysInfo.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX;
|
||||
ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_QUANTITY,
|
||||
&stMCISysInfo, 0);
|
||||
if (ulRC != NO_ERROR) {
|
||||
debug_os2("MCI_SYSINFO, MCI_SYSINFO_QUANTITY - failed, rc = 0x%X", ulRC);
|
||||
return;
|
||||
}
|
||||
|
||||
ulDevicesNum = atol(stMCISysInfo.pszReturn);
|
||||
|
||||
for (stSysInfoParams.ulNumber = 0; stSysInfoParams.ulNumber < ulDevicesNum;
|
||||
stSysInfoParams.ulNumber++) {
|
||||
/* Get device install name. */
|
||||
stSysInfoParams.pszReturn = acBuf;
|
||||
stSysInfoParams.ulRetSize = sizeof(acBuf);
|
||||
stSysInfoParams.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX;
|
||||
ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_INSTALLNAME,
|
||||
&stSysInfoParams, 0);
|
||||
if (ulRC != NO_ERROR) {
|
||||
debug_os2("MCI_SYSINFO, MCI_SYSINFO_INSTALLNAME - failed, rc = 0x%X", ulRC);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get textual product description. */
|
||||
stSysInfoParams.ulItem = MCI_SYSINFO_QUERY_DRIVER;
|
||||
stSysInfoParams.pSysInfoParm = &stLogDevice;
|
||||
strcpy(stLogDevice.szInstallName, stSysInfoParams.pszReturn);
|
||||
ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_ITEM,
|
||||
&stSysInfoParams, 0);
|
||||
if (ulRC != NO_ERROR) {
|
||||
debug_os2("MCI_SYSINFO, MCI_SYSINFO_ITEM - failed, rc = 0x%X", ulRC);
|
||||
continue;
|
||||
}
|
||||
|
||||
ulHandle++;
|
||||
SDL_AddAudioDevice(0, stLogDevice.szProductInfo, (void *)(ulHandle));
|
||||
ulHandle++;
|
||||
SDL_AddAudioDevice(1, stLogDevice.szProductInfo, (void *)(ulHandle));
|
||||
}
|
||||
}
|
||||
|
||||
static void OS2_WaitDevice(_THIS)
|
||||
{
|
||||
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
|
||||
ULONG ulRC;
|
||||
|
||||
/* Wait for an audio chunk to finish */
|
||||
ulRC = DosWaitEventSem(pAData->hevBuf, 5000);
|
||||
if (ulRC != NO_ERROR) {
|
||||
debug_os2("DosWaitEventSem(), rc = %u", ulRC);
|
||||
}
|
||||
}
|
||||
|
||||
static Uint8 *OS2_GetDeviceBuf(_THIS)
|
||||
{
|
||||
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
|
||||
return (Uint8 *) pAData->aMixBuffers[pAData->ulNextBuf].pBuffer;
|
||||
}
|
||||
|
||||
static void OS2_PlayDevice(_THIS)
|
||||
{
|
||||
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
|
||||
ULONG ulRC;
|
||||
PMCI_MIX_BUFFER pMixBuffer = &pAData->aMixBuffers[pAData->ulNextBuf];
|
||||
|
||||
/* Queue it up */
|
||||
/*lockIncr((int *)&pAData->ulQueuedBuf);*/
|
||||
ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle,
|
||||
pMixBuffer, 1);
|
||||
if (ulRC != MCIERR_SUCCESS) {
|
||||
_mixIOError("pmixWrite", ulRC);
|
||||
} else {
|
||||
pAData->ulNextBuf = (pAData->ulNextBuf + 1) % pAData->cMixBuffers;
|
||||
}
|
||||
}
|
||||
|
||||
static void OS2_CloseDevice(_THIS)
|
||||
{
|
||||
SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
|
||||
MCI_GENERIC_PARMS sMCIGenericParms;
|
||||
ULONG ulRC;
|
||||
|
||||
if (pAData == NULL)
|
||||
return;
|
||||
|
||||
/* Close up audio */
|
||||
if (pAData->usDeviceId != (USHORT)~0) {
|
||||
/* Device is open. */
|
||||
if (pAData->stMCIMixSetup.ulBitsPerSample != 0) {
|
||||
/* Mixer was initialized. */
|
||||
ulRC = mciSendCommand(pAData->usDeviceId, MCI_MIXSETUP,
|
||||
MCI_WAIT | MCI_MIXSETUP_DEINIT,
|
||||
&pAData->stMCIMixSetup, 0);
|
||||
if (ulRC != MCIERR_SUCCESS) {
|
||||
debug_os2("MCI_MIXSETUP, MCI_MIXSETUP_DEINIT - failed");
|
||||
}
|
||||
}
|
||||
|
||||
if (pAData->cMixBuffers != 0) {
|
||||
/* Buffers was allocated. */
|
||||
MCI_BUFFER_PARMS stMCIBuffer;
|
||||
|
||||
stMCIBuffer.ulBufferSize = pAData->aMixBuffers[0].ulBufferLength;
|
||||
stMCIBuffer.ulNumBuffers = pAData->cMixBuffers;
|
||||
stMCIBuffer.pBufList = pAData->aMixBuffers;
|
||||
|
||||
ulRC = mciSendCommand(pAData->usDeviceId, MCI_BUFFER,
|
||||
MCI_WAIT | MCI_DEALLOCATE_MEMORY, &stMCIBuffer, 0);
|
||||
if (ulRC != MCIERR_SUCCESS) {
|
||||
debug_os2("MCI_BUFFER, MCI_DEALLOCATE_MEMORY - failed");
|
||||
}
|
||||
}
|
||||
|
||||
ulRC = mciSendCommand(pAData->usDeviceId, MCI_CLOSE, MCI_WAIT,
|
||||
&sMCIGenericParms, 0);
|
||||
if (ulRC != MCIERR_SUCCESS) {
|
||||
debug_os2("MCI_CLOSE - failed");
|
||||
}
|
||||
}
|
||||
|
||||
if (pAData->hevBuf != NULLHANDLE)
|
||||
DosCloseEventSem(pAData->hevBuf);
|
||||
|
||||
SDL_free(pAData);
|
||||
}
|
||||
|
||||
static int OS2_OpenDevice(_THIS, void *handle, const char *devname,
|
||||
int iscapture)
|
||||
{
|
||||
SDL_PrivateAudioData *pAData;
|
||||
SDL_AudioFormat SDLAudioFmt;
|
||||
MCI_AMP_OPEN_PARMS stMCIAmpOpen;
|
||||
MCI_BUFFER_PARMS stMCIBuffer;
|
||||
ULONG ulRC;
|
||||
ULONG ulIdx;
|
||||
BOOL new_freq;
|
||||
|
||||
new_freq = FALSE;
|
||||
SDL_zero(stMCIAmpOpen);
|
||||
SDL_zero(stMCIBuffer);
|
||||
|
||||
for (SDLAudioFmt = SDL_FirstAudioFormat(_this->spec.format);
|
||||
SDLAudioFmt != 0; SDLAudioFmt = SDL_NextAudioFormat()) {
|
||||
if (SDLAudioFmt == AUDIO_U8 || SDLAudioFmt == AUDIO_S16)
|
||||
break;
|
||||
}
|
||||
if (SDLAudioFmt == 0) {
|
||||
debug_os2("Unsupported audio format, AUDIO_S16 used");
|
||||
SDLAudioFmt = AUDIO_S16;
|
||||
}
|
||||
|
||||
pAData = (SDL_PrivateAudioData *) SDL_calloc(1, sizeof(struct SDL_PrivateAudioData));
|
||||
if (pAData == NULL)
|
||||
return SDL_OutOfMemory();
|
||||
_this->hidden = pAData;
|
||||
|
||||
ulRC = DosCreateEventSem(NULL, &pAData->hevBuf, DCE_AUTORESET, TRUE);
|
||||
if (ulRC != NO_ERROR) {
|
||||
debug_os2("DosCreateEventSem() failed, rc = %u", ulRC);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Open audio device */
|
||||
stMCIAmpOpen.usDeviceID = (handle != NULL) ? ((ULONG)handle - 1) : 0;
|
||||
stMCIAmpOpen.pszDeviceType = (PSZ)MCI_DEVTYPE_AUDIO_AMPMIX;
|
||||
ulRC = mciSendCommand(0, MCI_OPEN,
|
||||
(_getEnvULong("SDL_AUDIO_SHARE", 1, 0) != 0)?
|
||||
MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE :
|
||||
MCI_WAIT | MCI_OPEN_TYPE_ID,
|
||||
&stMCIAmpOpen, 0);
|
||||
if (ulRC != MCIERR_SUCCESS) {
|
||||
stMCIAmpOpen.usDeviceID = (USHORT)~0;
|
||||
return _MCIError("MCI_OPEN", ulRC);
|
||||
}
|
||||
pAData->usDeviceId = stMCIAmpOpen.usDeviceID;
|
||||
|
||||
if (iscapture != 0) {
|
||||
MCI_CONNECTOR_PARMS stMCIConnector;
|
||||
MCI_AMP_SET_PARMS stMCIAmpSet;
|
||||
BOOL fLineIn = _getEnvULong("SDL_AUDIO_LINEIN", 1, 0);
|
||||
|
||||
/* Set particular connector. */
|
||||
SDL_zero(stMCIConnector);
|
||||
stMCIConnector.ulConnectorType = (fLineIn)? MCI_LINE_IN_CONNECTOR :
|
||||
MCI_MICROPHONE_CONNECTOR;
|
||||
mciSendCommand(stMCIAmpOpen.usDeviceID, MCI_CONNECTOR,
|
||||
MCI_WAIT | MCI_ENABLE_CONNECTOR |
|
||||
MCI_CONNECTOR_TYPE, &stMCIConnector, 0);
|
||||
|
||||
/* Disable monitor. */
|
||||
SDL_zero(stMCIAmpSet);
|
||||
stMCIAmpSet.ulItem = MCI_AMP_SET_MONITOR;
|
||||
mciSendCommand(stMCIAmpOpen.usDeviceID, MCI_SET,
|
||||
MCI_WAIT | MCI_SET_OFF | MCI_SET_ITEM,
|
||||
&stMCIAmpSet, 0);
|
||||
|
||||
/* Set record volume. */
|
||||
stMCIAmpSet.ulLevel = _getEnvULong("SDL_AUDIO_RECVOL", 100, 90);
|
||||
stMCIAmpSet.ulItem = MCI_AMP_SET_AUDIO;
|
||||
stMCIAmpSet.ulAudio = MCI_SET_AUDIO_ALL; /* Both cnannels. */
|
||||
stMCIAmpSet.ulValue = (fLineIn) ? MCI_LINE_IN_CONNECTOR :
|
||||
MCI_MICROPHONE_CONNECTOR ;
|
||||
|
||||
mciSendCommand(stMCIAmpOpen.usDeviceID, MCI_SET,
|
||||
MCI_WAIT | MCI_SET_AUDIO | MCI_AMP_SET_GAIN,
|
||||
&stMCIAmpSet, 0);
|
||||
}
|
||||
|
||||
_this->spec.format = SDLAudioFmt;
|
||||
_this->spec.channels = _this->spec.channels > 1 ? 2 : 1;
|
||||
if (_this->spec.freq < 8000) {
|
||||
_this->spec.freq = 8000;
|
||||
new_freq = TRUE;
|
||||
} else if (_this->spec.freq > 48000) {
|
||||
_this->spec.freq = 48000;
|
||||
new_freq = TRUE;
|
||||
}
|
||||
|
||||
/* Setup mixer. */
|
||||
pAData->stMCIMixSetup.ulFormatTag = MCI_WAVE_FORMAT_PCM;
|
||||
pAData->stMCIMixSetup.ulBitsPerSample = SDL_AUDIO_BITSIZE(SDLAudioFmt);
|
||||
pAData->stMCIMixSetup.ulSamplesPerSec = _this->spec.freq;
|
||||
pAData->stMCIMixSetup.ulChannels = _this->spec.channels;
|
||||
pAData->stMCIMixSetup.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
|
||||
if (iscapture == 0) {
|
||||
pAData->stMCIMixSetup.ulFormatMode= MCI_PLAY;
|
||||
pAData->stMCIMixSetup.pmixEvent = cbAudioWriteEvent;
|
||||
} else {
|
||||
pAData->stMCIMixSetup.ulFormatMode= MCI_RECORD;
|
||||
pAData->stMCIMixSetup.pmixEvent = cbAudioReadEvent;
|
||||
}
|
||||
|
||||
ulRC = mciSendCommand(pAData->usDeviceId, MCI_MIXSETUP,
|
||||
MCI_WAIT | MCI_MIXSETUP_INIT, &pAData->stMCIMixSetup, 0);
|
||||
if (ulRC != MCIERR_SUCCESS && _this->spec.freq > 44100) {
|
||||
new_freq = TRUE;
|
||||
pAData->stMCIMixSetup.ulSamplesPerSec = 44100;
|
||||
_this->spec.freq = 44100;
|
||||
ulRC = mciSendCommand(pAData->usDeviceId, MCI_MIXSETUP,
|
||||
MCI_WAIT | MCI_MIXSETUP_INIT, &pAData->stMCIMixSetup, 0);
|
||||
}
|
||||
|
||||
debug_os2("Setup mixer [BPS: %u, Freq.: %u, Channels: %u]: %s",
|
||||
pAData->stMCIMixSetup.ulBitsPerSample,
|
||||
pAData->stMCIMixSetup.ulSamplesPerSec,
|
||||
pAData->stMCIMixSetup.ulChannels,
|
||||
(ulRC == MCIERR_SUCCESS)? "SUCCESS" : "FAIL");
|
||||
|
||||
if (ulRC != MCIERR_SUCCESS) {
|
||||
pAData->stMCIMixSetup.ulBitsPerSample = 0;
|
||||
return _MCIError("MCI_MIXSETUP", ulRC);
|
||||
}
|
||||
|
||||
if (_this->spec.samples == 0 || new_freq == TRUE) {
|
||||
/* also see SDL_audio.c:prepare_audiospec() */
|
||||
/* Pick a default of ~46 ms at desired frequency */
|
||||
Uint32 samples = (_this->spec.freq / 1000) * 46;
|
||||
Uint32 power2 = 1;
|
||||
while (power2 < samples) {
|
||||
power2 <<= 1;
|
||||
}
|
||||
_this->spec.samples = power2;
|
||||
}
|
||||
/* Update the fragment size as size in bytes */
|
||||
SDL_CalculateAudioSpec(&_this->spec);
|
||||
|
||||
/* Allocate memory buffers */
|
||||
stMCIBuffer.ulBufferSize = _this->spec.size;/* (_this->spec.freq / 1000) * 100 */
|
||||
stMCIBuffer.ulNumBuffers = NUM_BUFFERS;
|
||||
stMCIBuffer.pBufList = pAData->aMixBuffers;
|
||||
|
||||
ulRC = mciSendCommand(pAData->usDeviceId, MCI_BUFFER,
|
||||
MCI_WAIT | MCI_ALLOCATE_MEMORY, &stMCIBuffer, 0);
|
||||
if (ulRC != MCIERR_SUCCESS) {
|
||||
return _MCIError("MCI_BUFFER", ulRC);
|
||||
}
|
||||
pAData->cMixBuffers = stMCIBuffer.ulNumBuffers;
|
||||
_this->spec.size = stMCIBuffer.ulBufferSize;
|
||||
|
||||
/* Fill all device buffers with data */
|
||||
for (ulIdx = 0; ulIdx < stMCIBuffer.ulNumBuffers; ulIdx++) {
|
||||
pAData->aMixBuffers[ulIdx].ulFlags = 0;
|
||||
pAData->aMixBuffers[ulIdx].ulBufferLength = stMCIBuffer.ulBufferSize;
|
||||
pAData->aMixBuffers[ulIdx].ulUserParm = (ULONG)pAData;
|
||||
|
||||
memset(((PMCI_MIX_BUFFER)stMCIBuffer.pBufList)[ulIdx].pBuffer,
|
||||
_this->spec.silence, stMCIBuffer.ulBufferSize);
|
||||
}
|
||||
|
||||
/* Write buffers to kick off the amp mixer */
|
||||
/*pAData->ulQueuedBuf = 1;//stMCIBuffer.ulNumBuffers */
|
||||
ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle,
|
||||
pAData->aMixBuffers,
|
||||
1 /*stMCIBuffer.ulNumBuffers*/);
|
||||
if (ulRC != MCIERR_SUCCESS) {
|
||||
_mixIOError("pmixWrite", ulRC);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int OS2_Init(SDL_AudioDriverImpl * impl)
|
||||
{
|
||||
/* Set the function pointers */
|
||||
impl->DetectDevices = OS2_DetectDevices;
|
||||
impl->OpenDevice = OS2_OpenDevice;
|
||||
impl->PlayDevice = OS2_PlayDevice;
|
||||
impl->WaitDevice = OS2_WaitDevice;
|
||||
impl->GetDeviceBuf = OS2_GetDeviceBuf;
|
||||
impl->CloseDevice = OS2_CloseDevice;
|
||||
|
||||
/* TODO: IMPLEMENT CAPTURE SUPPORT:
|
||||
impl->CaptureFromDevice = ;
|
||||
impl->FlushCapture = ;
|
||||
impl->HasCaptureSupport = SDL_TRUE;
|
||||
*/
|
||||
return 1; /* this audio target is available. */
|
||||
}
|
||||
|
||||
|
||||
AudioBootStrap OS2AUDIO_bootstrap = { "MMOS2", "OS/2 DART", OS2_Init, 0 };
|
||||
|
||||
#endif /* SDL_AUDIO_DRIVER_OS2 */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef SDL_os2mm_h_
|
||||
#define SDL_os2mm_h_
|
||||
|
||||
#include "../SDL_sysaudio.h"
|
||||
|
||||
#define INCL_OS2MM
|
||||
#define INCL_PM
|
||||
#define INCL_DOS
|
||||
#define INCL_DOSERRORS
|
||||
#include <os2.h>
|
||||
#include <os2me.h>
|
||||
|
||||
/* Hidden "this" pointer for the audio functions */
|
||||
#define _THIS SDL_AudioDevice *_this
|
||||
|
||||
#define NUM_BUFFERS 3
|
||||
|
||||
typedef struct SDL_PrivateAudioData
|
||||
{
|
||||
USHORT usDeviceId;
|
||||
BYTE _pad[2];
|
||||
MCI_MIXSETUP_PARMS stMCIMixSetup;
|
||||
HEV hevBuf;
|
||||
ULONG ulNextBuf;
|
||||
ULONG cMixBuffers;
|
||||
MCI_MIX_BUFFER aMixBuffers[NUM_BUFFERS];
|
||||
/* ULONG ulQueuedBuf;*/
|
||||
} SDL_PrivateAudioData;
|
||||
|
||||
#endif /* SDL_os2mm_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -26,7 +26,7 @@
|
||||
Stéphan Kochen: stephan .a.t. kochen.nl
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_hints.h"
|
||||
|
||||
#if SDL_AUDIO_DRIVER_PULSEAUDIO
|
||||
|
||||
@@ -237,16 +237,20 @@ squashVersion(const int major, const int minor, const int patch)
|
||||
static const char *
|
||||
getAppName(void)
|
||||
{
|
||||
const char *verstr = PULSEAUDIO_pa_get_library_version();
|
||||
if (verstr != NULL) {
|
||||
int maj, min, patch;
|
||||
if (SDL_sscanf(verstr, "%d.%d.%d", &maj, &min, &patch) == 3) {
|
||||
if (squashVersion(maj, min, patch) >= squashVersion(0, 9, 15)) {
|
||||
return NULL; /* 0.9.15+ handles NULL correctly. */
|
||||
const char *retval = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME);
|
||||
if (!retval || !*retval) {
|
||||
const char *verstr = PULSEAUDIO_pa_get_library_version();
|
||||
retval = "SDL Application"; /* the "oh well" default. */
|
||||
if (verstr != NULL) {
|
||||
int maj, min, patch;
|
||||
if (SDL_sscanf(verstr, "%d.%d.%d", &maj, &min, &patch) == 3) {
|
||||
if (squashVersion(maj, min, patch) >= squashVersion(0, 9, 15)) {
|
||||
retval = NULL; /* 0.9.15+ handles NULL correctly. */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "SDL Application"; /* oh well. */
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -290,32 +294,39 @@ ConnectToPulseServer_Internal(pa_mainloop **_mainloop, pa_context **_context)
|
||||
return SDL_SetError("pa_mainloop_new() failed");
|
||||
}
|
||||
|
||||
*_mainloop = mainloop;
|
||||
|
||||
mainloop_api = PULSEAUDIO_pa_mainloop_get_api(mainloop);
|
||||
SDL_assert(mainloop_api); /* this never fails, right? */
|
||||
|
||||
context = PULSEAUDIO_pa_context_new(mainloop_api, getAppName());
|
||||
if (!context) {
|
||||
PULSEAUDIO_pa_mainloop_free(mainloop);
|
||||
return SDL_SetError("pa_context_new() failed");
|
||||
}
|
||||
*_context = context;
|
||||
|
||||
/* Connect to the PulseAudio server */
|
||||
if (PULSEAUDIO_pa_context_connect(context, NULL, 0, NULL) < 0) {
|
||||
PULSEAUDIO_pa_context_unref(context);
|
||||
PULSEAUDIO_pa_mainloop_free(mainloop);
|
||||
return SDL_SetError("Could not setup connection to PulseAudio");
|
||||
}
|
||||
|
||||
do {
|
||||
if (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1, NULL) < 0) {
|
||||
PULSEAUDIO_pa_context_unref(context);
|
||||
PULSEAUDIO_pa_mainloop_free(mainloop);
|
||||
return SDL_SetError("pa_mainloop_iterate() failed");
|
||||
}
|
||||
state = PULSEAUDIO_pa_context_get_state(context);
|
||||
if (!PA_CONTEXT_IS_GOOD(state)) {
|
||||
PULSEAUDIO_pa_context_unref(context);
|
||||
PULSEAUDIO_pa_mainloop_free(mainloop);
|
||||
return SDL_SetError("Could not connect to PulseAudio");
|
||||
}
|
||||
} while (state != PA_CONTEXT_READY);
|
||||
|
||||
*_context = context;
|
||||
*_mainloop = mainloop;
|
||||
|
||||
return 0; /* connected and ready! */
|
||||
}
|
||||
|
||||
@@ -429,7 +440,7 @@ PULSEAUDIO_FlushCapture(_THIS)
|
||||
h->capturelen = 0;
|
||||
}
|
||||
|
||||
while (SDL_TRUE) {
|
||||
while (SDL_AtomicGet(&this->enabled)) {
|
||||
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
|
||||
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
|
||||
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
|
||||
@@ -513,6 +524,7 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
pa_buffer_attr paattr;
|
||||
pa_channel_map pacmap;
|
||||
pa_stream_flags_t flags = 0;
|
||||
const char *name = NULL;
|
||||
int state = 0;
|
||||
int rc = 0;
|
||||
|
||||
@@ -615,9 +627,11 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
PULSEAUDIO_pa_channel_map_init_auto(&pacmap, this->spec.channels,
|
||||
PA_CHANNEL_MAP_WAVEEX);
|
||||
|
||||
name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME);
|
||||
|
||||
h->stream = PULSEAUDIO_pa_stream_new(
|
||||
h->context,
|
||||
"Simple DirectMedia Layer", /* stream description */
|
||||
(name && *name) ? name : "Audio Stream", /* stream description */
|
||||
&paspec, /* sample format spec */
|
||||
&pacmap /* channel map */
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -619,8 +619,8 @@ QSA_Deinitialize(void)
|
||||
{
|
||||
/* Clear devices array on shutdown */
|
||||
/* !!! FIXME: we zero these on init...any reason to do it here? */
|
||||
SDL_zero(qsa_playback_device);
|
||||
SDL_zero(qsa_capture_device);
|
||||
SDL_zeroa(qsa_playback_device);
|
||||
SDL_zeroa(qsa_capture_device);
|
||||
qsa_playback_devices = 0;
|
||||
qsa_capture_devices = 0;
|
||||
}
|
||||
@@ -629,8 +629,8 @@ static int
|
||||
QSA_Init(SDL_AudioDriverImpl * impl)
|
||||
{
|
||||
/* Clear devices array */
|
||||
SDL_zero(qsa_playback_device);
|
||||
SDL_zero(qsa_capture_device);
|
||||
SDL_zeroa(qsa_playback_device);
|
||||
SDL_zeroa(qsa_capture_device);
|
||||
qsa_playback_devices = 0;
|
||||
qsa_capture_devices = 0;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -18,7 +18,6 @@
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#if SDL_AUDIO_DRIVER_WASAPI
|
||||
@@ -28,8 +27,6 @@
|
||||
#include "SDL_timer.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_sysaudio.h"
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_log.h"
|
||||
|
||||
#define COBJMACROS
|
||||
#include <mmdeviceapi.h>
|
||||
@@ -508,7 +505,7 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
|
||||
const SDL_AudioSpec oldspec = this->spec;
|
||||
const AUDCLNT_SHAREMODE sharemode = AUDCLNT_SHAREMODE_SHARED;
|
||||
UINT32 bufsize = 0; /* this is in sample frames, not samples, not bytes. */
|
||||
REFERENCE_TIME duration = 0;
|
||||
REFERENCE_TIME default_period = 0;
|
||||
IAudioClient *client = this->hidden->client;
|
||||
IAudioRenderClient *render = NULL;
|
||||
IAudioCaptureClient *capture = NULL;
|
||||
@@ -572,7 +569,7 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
|
||||
return SDL_SetError("WASAPI: Unsupported audio format");
|
||||
}
|
||||
|
||||
ret = IAudioClient_GetDevicePeriod(client, NULL, &duration);
|
||||
ret = IAudioClient_GetDevicePeriod(client, &default_period, NULL);
|
||||
if (FAILED(ret)) {
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't determine minimum device period", ret);
|
||||
}
|
||||
@@ -591,7 +588,7 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
|
||||
}
|
||||
|
||||
streamflags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
|
||||
ret = IAudioClient_Initialize(client, sharemode, streamflags, duration, sharemode == AUDCLNT_SHAREMODE_SHARED ? 0 : duration, waveformat, NULL);
|
||||
ret = IAudioClient_Initialize(client, sharemode, streamflags, 0, 0, waveformat, NULL);
|
||||
if (FAILED(ret)) {
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't initialize audio client", ret);
|
||||
}
|
||||
@@ -606,9 +603,12 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't determine buffer size", ret);
|
||||
}
|
||||
|
||||
this->spec.samples = (Uint16) bufsize;
|
||||
if (!this->iscapture) {
|
||||
this->spec.samples /= 2; /* fill half of the DMA buffer on each run. */
|
||||
/* Match the callback size to the period size to cut down on the number of
|
||||
interrupts waited for in each call to WaitDevice */
|
||||
{
|
||||
const float period_millis = default_period / 10000.0f;
|
||||
const float period_frames = period_millis * this->spec.freq / 1000.0f;
|
||||
this->spec.samples = (Uint16)SDL_ceilf(period_frames);
|
||||
}
|
||||
|
||||
/* Update the fragment size as size in bytes */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -18,7 +18,6 @@
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
/* This is code that Windows uses to talk to WASAPI-related system APIs.
|
||||
@@ -34,8 +33,6 @@
|
||||
#include "SDL_timer.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_sysaudio.h"
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_log.h"
|
||||
|
||||
#define COBJMACROS
|
||||
#include <mmdeviceapi.h>
|
||||
@@ -248,7 +245,7 @@ WASAPI_PlatformInit(void)
|
||||
return SDL_SetError("WASAPI: CoInitialize() failed");
|
||||
}
|
||||
|
||||
ret = CoCreateInstance(&SDL_CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &SDL_IID_IMMDeviceEnumerator, (LPVOID) &enumerator);
|
||||
ret = CoCreateInstance(&SDL_CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &SDL_IID_IMMDeviceEnumerator, (LPVOID *) &enumerator);
|
||||
if (FAILED(ret)) {
|
||||
WIN_CoUninitialize();
|
||||
return WIN_SetErrorFromHRESULT("WASAPI CoCreateInstance(MMDeviceEnumerator)", ret);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -18,7 +18,6 @@
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
// This is C++/CX code that the WinRT port uses to talk to WASAPI-related
|
||||
@@ -40,8 +39,6 @@ extern "C" {
|
||||
#include "SDL_timer.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
#include "../SDL_sysaudio.h"
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_log.h"
|
||||
}
|
||||
|
||||
#define COBJMACROS
|
||||
@@ -63,8 +60,10 @@ public:
|
||||
void OnDeviceAdded(DeviceWatcher^ sender, DeviceInformation^ args);
|
||||
void OnDeviceRemoved(DeviceWatcher^ sender, DeviceInformationUpdate^ args);
|
||||
void OnDeviceUpdated(DeviceWatcher^ sender, DeviceInformationUpdate^ args);
|
||||
void OnEnumerationCompleted(DeviceWatcher^ sender, Platform::Object^ args);
|
||||
void OnDefaultRenderDeviceChanged(Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args);
|
||||
void OnDefaultCaptureDeviceChanged(Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args);
|
||||
SDL_semaphore* completed;
|
||||
|
||||
private:
|
||||
const SDL_bool iscapture;
|
||||
@@ -72,20 +71,23 @@ private:
|
||||
Windows::Foundation::EventRegistrationToken added_handler;
|
||||
Windows::Foundation::EventRegistrationToken removed_handler;
|
||||
Windows::Foundation::EventRegistrationToken updated_handler;
|
||||
Windows::Foundation::EventRegistrationToken completed_handler;
|
||||
Windows::Foundation::EventRegistrationToken default_changed_handler;
|
||||
};
|
||||
|
||||
SDL_WasapiDeviceEventHandler::SDL_WasapiDeviceEventHandler(const SDL_bool _iscapture)
|
||||
: iscapture(_iscapture)
|
||||
, completed(SDL_CreateSemaphore(0))
|
||||
, watcher(DeviceInformation::CreateWatcher(_iscapture ? DeviceClass::AudioCapture : DeviceClass::AudioRender))
|
||||
{
|
||||
if (!watcher)
|
||||
if (!watcher || !completed)
|
||||
return; // uhoh.
|
||||
|
||||
// !!! FIXME: this doesn't need a lambda here, I think, if I make SDL_WasapiDeviceEventHandler a proper C++/CX class. --ryan.
|
||||
added_handler = watcher->Added += ref new TypedEventHandler<DeviceWatcher^, DeviceInformation^>([this](DeviceWatcher^ sender, DeviceInformation^ args) { OnDeviceAdded(sender, args); } );
|
||||
removed_handler = watcher->Removed += ref new TypedEventHandler<DeviceWatcher^, DeviceInformationUpdate^>([this](DeviceWatcher^ sender, DeviceInformationUpdate^ args) { OnDeviceRemoved(sender, args); } );
|
||||
updated_handler = watcher->Updated += ref new TypedEventHandler<DeviceWatcher^, DeviceInformationUpdate^>([this](DeviceWatcher^ sender, DeviceInformationUpdate^ args) { OnDeviceUpdated(sender, args); } );
|
||||
completed_handler = watcher->EnumerationCompleted += ref new TypedEventHandler<DeviceWatcher^, Platform::Object^>([this](DeviceWatcher^ sender, Platform::Object^ args) { OnEnumerationCompleted(sender, args); } );
|
||||
if (iscapture) {
|
||||
default_changed_handler = MediaDevice::DefaultAudioCaptureDeviceChanged += ref new TypedEventHandler<Platform::Object^, DefaultAudioCaptureDeviceChangedEventArgs^>([this](Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args) { OnDefaultCaptureDeviceChanged(sender, args); } );
|
||||
} else {
|
||||
@@ -100,9 +102,14 @@ SDL_WasapiDeviceEventHandler::~SDL_WasapiDeviceEventHandler()
|
||||
watcher->Added -= added_handler;
|
||||
watcher->Removed -= removed_handler;
|
||||
watcher->Updated -= updated_handler;
|
||||
watcher->EnumerationCompleted -= completed_handler;
|
||||
watcher->Stop();
|
||||
watcher = nullptr;
|
||||
}
|
||||
if (completed) {
|
||||
SDL_DestroySemaphore(completed);
|
||||
completed = nullptr;
|
||||
}
|
||||
|
||||
if (iscapture) {
|
||||
MediaDevice::DefaultAudioCaptureDeviceChanged -= default_changed_handler;
|
||||
@@ -135,6 +142,13 @@ SDL_WasapiDeviceEventHandler::OnDeviceUpdated(DeviceWatcher^ sender, DeviceInfor
|
||||
SDL_assert(sender == this->watcher);
|
||||
}
|
||||
|
||||
void
|
||||
SDL_WasapiDeviceEventHandler::OnEnumerationCompleted(DeviceWatcher^ sender, Platform::Object^ args)
|
||||
{
|
||||
SDL_assert(sender == this->watcher);
|
||||
SDL_SemPost(this->completed);
|
||||
}
|
||||
|
||||
void
|
||||
SDL_WasapiDeviceEventHandler::OnDefaultRenderDeviceChanged(Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args)
|
||||
{
|
||||
@@ -173,6 +187,8 @@ void WASAPI_EnumerateEndpoints(void)
|
||||
// listening for updates.
|
||||
playback_device_event_handler = new SDL_WasapiDeviceEventHandler(SDL_FALSE);
|
||||
capture_device_event_handler = new SDL_WasapiDeviceEventHandler(SDL_TRUE);
|
||||
SDL_SemWait(playback_device_event_handler->completed);
|
||||
SDL_SemWait(capture_device_event_handler->completed);
|
||||
}
|
||||
|
||||
struct SDL_WasapiActivationHandler : public RuntimeClass< RuntimeClassFlags< ClassicCom >, FtmBase, IActivateAudioInterfaceCompletionHandler >
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "../../core/windows/SDL_windows.h"
|
||||
#include <mmsystem.h>
|
||||
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_audio.h"
|
||||
#include "../SDL_audio_c.h"
|
||||
@@ -387,7 +386,7 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
SDL_zero(this->hidden->wavebuf);
|
||||
SDL_zeroa(this->hidden->wavebuf);
|
||||
for (i = 0; i < NUM_BUFFERS; ++i) {
|
||||
this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
|
||||
this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -104,6 +104,9 @@ void Android_JNI_InitTouch(void);
|
||||
JNIEnv *Android_JNI_GetEnv(void);
|
||||
int Android_JNI_SetupThread(void);
|
||||
|
||||
/* Locale */
|
||||
int Android_JNI_GetLocale(char *buf, size_t buflen);
|
||||
|
||||
/* Generic messages */
|
||||
int Android_JNI_SendMessage(int command, int param);
|
||||
|
||||
@@ -123,6 +126,10 @@ SDL_bool Android_JNI_SetSystemCursor(int cursorID);
|
||||
SDL_bool Android_JNI_SupportsRelativeMouse(void);
|
||||
SDL_bool Android_JNI_SetRelativeMouseEnabled(SDL_bool enabled);
|
||||
|
||||
/* Request permission */
|
||||
SDL_bool Android_JNI_RequestPermission(const char *permission);
|
||||
|
||||
int Android_JNI_OpenURL(const char *url);
|
||||
|
||||
int SDL_GetAndroidSDKVersion(void);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
#include <sys/kbio.h>
|
||||
|
||||
/*
|
||||
* Automatically generated from /usr/share/vt/keymaps/us.acc.kbd.
|
||||
* DO NOT EDIT!
|
||||
*/
|
||||
static keymap_t keymap_default_us_acc = { 0x6d, {
|
||||
/* alt
|
||||
* scan cntrl alt alt cntrl
|
||||
* code base shift cntrl shift alt shift cntrl shift spcl flgs
|
||||
* ---------------------------------------------------------------------------
|
||||
*/
|
||||
/*00*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 },
|
||||
/*01*/{{ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, DBG, }, 0x03,0x00 },
|
||||
/*02*/{{ '1', '!', NOP, NOP, '1', '!', NOP, NOP, }, 0x33,0x00 },
|
||||
/*03*/{{ '2', '@', 0x00, 0x00, '2', '@', 0x00, 0x00, }, 0x00,0x00 },
|
||||
/*04*/{{ '3', '#', NOP, NOP, '3', '#', NOP, NOP, }, 0x33,0x00 },
|
||||
/*05*/{{ '4', '$', NOP, NOP, '4', '$', NOP, NOP, }, 0x33,0x00 },
|
||||
/*06*/{{ '5', '%', NOP, NOP, '5', '%', NOP, NOP, }, 0x33,0x00 },
|
||||
/*07*/{{ '6', '^', 0x1E, 0x1E, '6', DCIR, 0x1E, 0x1E, }, 0x04,0x00 },
|
||||
/*08*/{{ '7', '&', NOP, NOP, '7', '&', NOP, NOP, }, 0x33,0x00 },
|
||||
/*09*/{{ '8', '*', NOP, NOP, '8', DRIN, NOP, NOP, }, 0x37,0x00 },
|
||||
/*0a*/{{ '9', '(', NOP, NOP, '9', '(', NOP, NOP, }, 0x33,0x00 },
|
||||
/*0b*/{{ '0', ')', NOP, NOP, '0', ')', NOP, NOP, }, 0x33,0x00 },
|
||||
/*0c*/{{ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, }, 0x00,0x00 },
|
||||
/*0d*/{{ '=', '+', NOP, NOP, '=', '+', NOP, NOP, }, 0x33,0x00 },
|
||||
/*0e*/{{ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, }, 0x00,0x00 },
|
||||
/*0f*/{{ 0x09, BTAB, NEXT, NEXT, 0x09, BTAB, NOP, NOP, }, 0x77,0x00 },
|
||||
/*10*/{{ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, }, 0x00,0x01 },
|
||||
/*11*/{{ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, }, 0x00,0x01 },
|
||||
/*12*/{{ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, }, 0x00,0x01 },
|
||||
/*13*/{{ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, }, 0x00,0x01 },
|
||||
/*14*/{{ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, }, 0x00,0x01 },
|
||||
/*15*/{{ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, }, 0x00,0x01 },
|
||||
/*16*/{{ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, }, 0x00,0x01 },
|
||||
/*17*/{{ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, }, 0x00,0x01 },
|
||||
/*18*/{{ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, }, 0x00,0x01 },
|
||||
/*19*/{{ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, }, 0x00,0x01 },
|
||||
/*1a*/{{ '[', '{', 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, }, 0x00,0x00 },
|
||||
/*1b*/{{ ']', '}', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, }, 0x00,0x00 },
|
||||
/*1c*/{{ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, }, 0x00,0x00 },
|
||||
/*1d*/{{ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, }, 0xFF,0x00 },
|
||||
/*1e*/{{ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, }, 0x00,0x01 },
|
||||
/*1f*/{{ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, }, 0x00,0x01 },
|
||||
/*20*/{{ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, }, 0x00,0x01 },
|
||||
/*21*/{{ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, }, 0x00,0x01 },
|
||||
/*22*/{{ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, }, 0x00,0x01 },
|
||||
/*23*/{{ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, }, 0x00,0x01 },
|
||||
/*24*/{{ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, }, 0x00,0x01 },
|
||||
/*25*/{{ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, }, 0x00,0x01 },
|
||||
/*26*/{{ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, }, 0x00,0x01 },
|
||||
/*27*/{{ ';', ':', NOP, NOP, ';', ':', NOP, NOP, }, 0x33,0x00 },
|
||||
/*28*/{{ '\'', '"', NOP, NOP, DACU, DUML, NOP, NOP, }, 0x3F,0x00 },
|
||||
/*29*/{{ '`', '~', NOP, NOP, DGRA, DTIL, NOP, NOP, }, 0x3F,0x00 },
|
||||
/*2a*/{{ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, }, 0xFF,0x00 },
|
||||
/*2b*/{{ '\\', '|', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, }, 0x00,0x00 },
|
||||
/*2c*/{{ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, }, 0x00,0x01 },
|
||||
/*2d*/{{ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, }, 0x00,0x01 },
|
||||
/*2e*/{{ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, }, 0x00,0x01 },
|
||||
/*2f*/{{ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, }, 0x00,0x01 },
|
||||
/*30*/{{ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, }, 0x00,0x01 },
|
||||
/*31*/{{ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, }, 0x00,0x01 },
|
||||
/*32*/{{ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, }, 0x00,0x01 },
|
||||
/*33*/{{ ',', '<', NOP, NOP, DCED, '<', NOP, NOP, }, 0x3B,0x00 },
|
||||
/*34*/{{ '.', '>', NOP, NOP, '.', '>', NOP, NOP, }, 0x33,0x00 },
|
||||
/*35*/{{ '/', '?', NOP, NOP, '/', '?', NOP, NOP, }, 0x33,0x00 },
|
||||
/*36*/{{ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, }, 0xFF,0x00 },
|
||||
/*37*/{{ '*', '*', '*', '*', '*', '*', '*', '*', }, 0x00,0x00 },
|
||||
/*38*/{{ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, }, 0xFF,0x00 },
|
||||
/*39*/{{ ' ', ' ', 0x00, 0x00, ' ', ' ', SUSP, SUSP, }, 0x03,0x00 },
|
||||
/*3a*/{{ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, }, 0xFF,0x00 },
|
||||
/*3b*/{{ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11),}, 0xFF,0x00 },
|
||||
/*3c*/{{ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12),}, 0xFF,0x00 },
|
||||
/*3d*/{{ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13),}, 0xFF,0x00 },
|
||||
/*3e*/{{ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14),}, 0xFF,0x00 },
|
||||
/*3f*/{{ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15),}, 0xFF,0x00 },
|
||||
/*40*/{{ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16),}, 0xFF,0x00 },
|
||||
/*41*/{{ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7),}, 0xFF,0x00 },
|
||||
/*42*/{{ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8),}, 0xFF,0x00 },
|
||||
/*43*/{{ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9),}, 0xFF,0x00 },
|
||||
/*44*/{{ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10),}, 0xFF,0x00 },
|
||||
/*45*/{{ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, }, 0xFF,0x00 },
|
||||
/*46*/{{ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, }, 0xFF,0x00 },
|
||||
/*47*/{{ F(49), '7', '7', '7', '7', '7', '7', '7', }, 0x80,0x02 },
|
||||
/*48*/{{ F(50), '8', '8', '8', '8', '8', '8', '8', }, 0x80,0x02 },
|
||||
/*49*/{{ F(51), '9', '9', '9', '9', '9', '9', '9', }, 0x80,0x02 },
|
||||
/*4a*/{{ F(52), '-', '-', '-', '-', '-', '-', '-', }, 0x80,0x02 },
|
||||
/*4b*/{{ F(53), '4', '4', '4', '4', '4', '4', '4', }, 0x80,0x02 },
|
||||
/*4c*/{{ F(54), '5', '5', '5', '5', '5', '5', '5', }, 0x80,0x02 },
|
||||
/*4d*/{{ F(55), '6', '6', '6', '6', '6', '6', '6', }, 0x80,0x02 },
|
||||
/*4e*/{{ F(56), '+', '+', '+', '+', '+', '+', '+', }, 0x80,0x02 },
|
||||
/*4f*/{{ F(57), '1', '1', '1', '1', '1', '1', '1', }, 0x80,0x02 },
|
||||
/*50*/{{ F(58), '2', '2', '2', '2', '2', '2', '2', }, 0x80,0x02 },
|
||||
/*51*/{{ F(59), '3', '3', '3', '3', '3', '3', '3', }, 0x80,0x02 },
|
||||
/*52*/{{ F(60), '0', '0', '0', '0', '0', '0', '0', }, 0x80,0x02 },
|
||||
/*53*/{{ 0x7F, '.', '.', '.', '.', '.', RBT, RBT, }, 0x03,0x02 },
|
||||
/*54*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 },
|
||||
/*55*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 },
|
||||
/*56*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 },
|
||||
/*57*/{{ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11),}, 0xFF,0x00 },
|
||||
/*58*/{{ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12),}, 0xFF,0x00 },
|
||||
/*59*/{{ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, }, 0x00,0x00 },
|
||||
/*5a*/{{ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, }, 0xFF,0x00 },
|
||||
/*5b*/{{ '/', '/', '/', '/', '/', '/', '/', '/', }, 0x00,0x02 },
|
||||
/*5c*/{{ NEXT, NEXT, NOP, NOP, DBG, DBG, DBG, DBG, }, 0xFF,0x00 },
|
||||
/*5d*/{{ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, }, 0xFF,0x00 },
|
||||
/*5e*/{{ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49),}, 0xFF,0x00 },
|
||||
/*5f*/{{ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50),}, 0xFF,0x00 },
|
||||
/*60*/{{ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51),}, 0xFF,0x00 },
|
||||
/*61*/{{ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53),}, 0xFF,0x00 },
|
||||
/*62*/{{ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55),}, 0xFF,0x00 },
|
||||
/*63*/{{ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57),}, 0xFF,0x00 },
|
||||
/*64*/{{ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58),}, 0xFF,0x00 },
|
||||
/*65*/{{ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59),}, 0xFF,0x00 },
|
||||
/*66*/{{ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60),}, 0xFF,0x00 },
|
||||
/*67*/{{ F(61), F(61), F(61), F(61), F(61), F(61), RBT, F(61),}, 0xFF,0x00 },
|
||||
/*68*/{{ SPSC, SPSC, SUSP, SUSP, NOP, NOP, SUSP, SUSP, }, 0xFF,0x00 },
|
||||
/*69*/{{ F(62), F(62), F(62), F(62), F(62), F(62), F(62), F(62),}, 0xFF,0x00 },
|
||||
/*6a*/{{ F(63), F(63), F(63), F(63), F(63), F(63), F(63), F(63),}, 0xFF,0x00 },
|
||||
/*6b*/{{ F(64), F(64), F(64), F(64), F(64), F(64), F(64), F(64),}, 0xFF,0x00 },
|
||||
/*6c*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 },
|
||||
} };
|
||||
|
||||
static accentmap_t accentmap_default_us_acc = { 11, {
|
||||
/* dgra=0 */
|
||||
{ '`', { { 'a',0xe0 }, { 'A',0xc0 }, { 'e',0xe8 }, { 'E',0xc8 },
|
||||
{ 'i',0xec }, { 'I',0xcc }, { 'o',0xf2 }, { 'O',0xd2 },
|
||||
{ 'u',0xf9 }, { 'U',0xd9 }, }, },
|
||||
/* dacu=1 */
|
||||
{ 0xb4, { { 'a',0xe1 }, { 'A',0xc1 }, { 'e',0xe9 }, { 'E',0xc9 },
|
||||
{ 'i',0xed }, { 'I',0xcd }, { 'o',0xf3 }, { 'O',0xd3 },
|
||||
{ 'u',0xfa }, { 'U',0xda }, { 'y',0xfd }, { 'Y',0xdd }, }, },
|
||||
/* dcir=2 */
|
||||
{ '^', { { 'a',0xe2 }, { 'A',0xc2 }, { 'e',0xea }, { 'E',0xca },
|
||||
{ 'i',0xee }, { 'I',0xce }, { 'o',0xf4 }, { 'O',0xd4 },
|
||||
{ 'u',0xfb }, { 'U',0xdb }, }, },
|
||||
/* dtil=3 */
|
||||
{ '~', { { 'a',0xe3 }, { 'A',0xc3 }, { 'n',0xf1 }, { 'N',0xd1 },
|
||||
{ 'o',0xf5 }, { 'O',0xd5 }, }, },
|
||||
/* dmac=4 */
|
||||
{ 0x00 },
|
||||
/* dbre=5 */
|
||||
{ 0x00 },
|
||||
/* ddot=6 */
|
||||
{ 0x00 },
|
||||
/* duml=7 */
|
||||
{ 0xa8, { { 'a',0xe4 }, { 'A',0xc4 }, { 'e',0xeb }, { 'E',0xcb },
|
||||
{ 'i',0xef }, { 'I',0xcf }, { 'o',0xf6 }, { 'O',0xd6 },
|
||||
{ 'u',0xfc }, { 'U',0xdc }, { 'y',0xff }, }, },
|
||||
/* dsla=8 */
|
||||
{ 0x00 },
|
||||
/* drin=9 */
|
||||
{ 0xb0, { { 'a',0xe5 }, { 'A',0xc5 }, }, },
|
||||
/* dced=10 */
|
||||
{ 0xb8, { { 'c',0xe7 }, { 'C',0xc7 }, }, },
|
||||
/* dapo=11 */
|
||||
{ 0x00 },
|
||||
/* ddac=12 */
|
||||
{ 0x00 },
|
||||
/* dogo=13 */
|
||||
{ 0x00 },
|
||||
/* dcar=14 */
|
||||
{ 0x00 },
|
||||
} };
|
||||
|
||||
@@ -0,0 +1,572 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#include "../linux/SDL_evdev_kbd.h"
|
||||
#include "SDL_hints.h"
|
||||
|
||||
#ifdef SDL_INPUT_FBSDKBIO
|
||||
|
||||
/* This logic is adapted from drivers/tty/vt/keyboard.c in the Linux kernel source, slightly modified to work with FreeBSD */
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/kbio.h>
|
||||
#include <sys/consio.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "../../events/SDL_events_c.h"
|
||||
#include "SDL_evdev_kbd_default_keyaccmap.h"
|
||||
|
||||
typedef void (fn_handler_fn)(SDL_EVDEV_keyboard_state *kbd);
|
||||
|
||||
/*
|
||||
* Keyboard State
|
||||
*/
|
||||
|
||||
struct SDL_EVDEV_keyboard_state
|
||||
{
|
||||
int console_fd;
|
||||
int keyboard_fd;
|
||||
unsigned long old_kbd_mode;
|
||||
unsigned short **key_maps;
|
||||
keymap_t* key_map;
|
||||
keyboard_info_t* kbInfo;
|
||||
unsigned char shift_down[4]; /* shift state counters.. */
|
||||
SDL_bool dead_key_next;
|
||||
int npadch; /* -1 or number assembled on pad */
|
||||
accentmap_t *accents;
|
||||
unsigned int diacr;
|
||||
SDL_bool rep; /* flag telling character repeat */
|
||||
unsigned char lockstate;
|
||||
unsigned char ledflagstate;
|
||||
char shift_state;
|
||||
char text[128];
|
||||
unsigned int text_len;
|
||||
};
|
||||
|
||||
static int SDL_EVDEV_kbd_load_keymaps(SDL_EVDEV_keyboard_state *kbd)
|
||||
{
|
||||
return (ioctl(kbd->keyboard_fd, GIO_KEYMAP, kbd->key_map) >= 0);
|
||||
}
|
||||
|
||||
static SDL_EVDEV_keyboard_state * kbd_cleanup_state = NULL;
|
||||
static int kbd_cleanup_sigactions_installed = 0;
|
||||
static int kbd_cleanup_atexit_installed = 0;
|
||||
|
||||
static struct sigaction old_sigaction[NSIG];
|
||||
|
||||
static int fatal_signals[] =
|
||||
{
|
||||
/* Handlers for SIGTERM and SIGINT are installed in SDL_QuitInit. */
|
||||
SIGHUP, SIGQUIT, SIGILL, SIGABRT,
|
||||
SIGFPE, SIGSEGV, SIGPIPE, SIGBUS,
|
||||
SIGSYS
|
||||
};
|
||||
|
||||
static void kbd_cleanup(void)
|
||||
{
|
||||
SDL_EVDEV_keyboard_state* kbd = kbd_cleanup_state;
|
||||
if (kbd == NULL) {
|
||||
return;
|
||||
}
|
||||
kbd_cleanup_state = NULL;
|
||||
|
||||
ioctl(kbd->keyboard_fd, KDSKBMODE, kbd->old_kbd_mode);
|
||||
if (kbd->keyboard_fd != kbd->console_fd) close(kbd->keyboard_fd);
|
||||
ioctl(kbd->console_fd, CONS_SETKBD, (unsigned long)(kbd->kbInfo->kb_index));
|
||||
}
|
||||
|
||||
void
|
||||
SDL_EVDEV_kbd_reraise_signal(int sig)
|
||||
{
|
||||
raise(sig);
|
||||
}
|
||||
|
||||
siginfo_t* SDL_EVDEV_kdb_cleanup_siginfo = NULL;
|
||||
void* SDL_EVDEV_kdb_cleanup_ucontext = NULL;
|
||||
|
||||
static void kbd_cleanup_signal_action(int signum, siginfo_t* info, void* ucontext)
|
||||
{
|
||||
struct sigaction* old_action_p = &(old_sigaction[signum]);
|
||||
sigset_t sigset;
|
||||
|
||||
/* Restore original signal handler before going any further. */
|
||||
sigaction(signum, old_action_p, NULL);
|
||||
|
||||
/* Unmask current signal. */
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, signum);
|
||||
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
|
||||
|
||||
/* Save original signal info and context for archeologists. */
|
||||
SDL_EVDEV_kdb_cleanup_siginfo = info;
|
||||
SDL_EVDEV_kdb_cleanup_ucontext = ucontext;
|
||||
|
||||
/* Restore keyboard. */
|
||||
kbd_cleanup();
|
||||
|
||||
/* Reraise signal. */
|
||||
SDL_EVDEV_kbd_reraise_signal(signum);
|
||||
}
|
||||
|
||||
static void kbd_unregister_emerg_cleanup()
|
||||
{
|
||||
int tabidx, signum;
|
||||
|
||||
kbd_cleanup_state = NULL;
|
||||
|
||||
if (!kbd_cleanup_sigactions_installed) {
|
||||
return;
|
||||
}
|
||||
kbd_cleanup_sigactions_installed = 0;
|
||||
|
||||
for (tabidx = 0; tabidx < sizeof(fatal_signals) / sizeof(fatal_signals[0]); ++tabidx) {
|
||||
struct sigaction* old_action_p;
|
||||
struct sigaction cur_action;
|
||||
signum = fatal_signals[tabidx];
|
||||
old_action_p = &(old_sigaction[signum]);
|
||||
|
||||
/* Examine current signal action */
|
||||
if (sigaction(signum, NULL, &cur_action))
|
||||
continue;
|
||||
|
||||
/* Check if action installed and not modifed */
|
||||
if (!(cur_action.sa_flags & SA_SIGINFO)
|
||||
|| cur_action.sa_sigaction != &kbd_cleanup_signal_action)
|
||||
continue;
|
||||
|
||||
/* Restore original action */
|
||||
sigaction(signum, old_action_p, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void kbd_cleanup_atexit(void)
|
||||
{
|
||||
/* Restore keyboard. */
|
||||
kbd_cleanup();
|
||||
|
||||
/* Try to restore signal handlers in case shared library is being unloaded */
|
||||
kbd_unregister_emerg_cleanup();
|
||||
}
|
||||
|
||||
static void kbd_register_emerg_cleanup(SDL_EVDEV_keyboard_state * kbd)
|
||||
{
|
||||
int tabidx, signum;
|
||||
|
||||
if (kbd_cleanup_state != NULL) {
|
||||
return;
|
||||
}
|
||||
kbd_cleanup_state = kbd;
|
||||
|
||||
if (!kbd_cleanup_atexit_installed) {
|
||||
/* Since glibc 2.2.3, atexit() (and on_exit(3)) can be used within a shared library to establish
|
||||
* functions that are called when the shared library is unloaded.
|
||||
* -- man atexit(3)
|
||||
*/
|
||||
atexit(kbd_cleanup_atexit);
|
||||
kbd_cleanup_atexit_installed = 1;
|
||||
}
|
||||
|
||||
if (kbd_cleanup_sigactions_installed) {
|
||||
return;
|
||||
}
|
||||
kbd_cleanup_sigactions_installed = 1;
|
||||
|
||||
for (tabidx = 0; tabidx < sizeof(fatal_signals) / sizeof(fatal_signals[0]); ++tabidx) {
|
||||
struct sigaction* old_action_p;
|
||||
struct sigaction new_action;
|
||||
signum = fatal_signals[tabidx];
|
||||
old_action_p = &(old_sigaction[signum]);
|
||||
if (sigaction(signum, NULL, old_action_p))
|
||||
continue;
|
||||
|
||||
/* Skip SIGHUP and SIGPIPE if handler is already installed
|
||||
* - assume the handler will do the cleanup
|
||||
*/
|
||||
if ((signum == SIGHUP || signum == SIGPIPE)
|
||||
&& (old_action_p->sa_handler != SIG_DFL
|
||||
|| (void (*)(int))old_action_p->sa_sigaction != SIG_DFL))
|
||||
continue;
|
||||
|
||||
new_action = *old_action_p;
|
||||
new_action.sa_flags |= SA_SIGINFO;
|
||||
new_action.sa_sigaction = &kbd_cleanup_signal_action;
|
||||
sigaction(signum, &new_action, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_EVDEV_keyboard_state *
|
||||
SDL_EVDEV_kbd_init(void)
|
||||
{
|
||||
SDL_EVDEV_keyboard_state *kbd;
|
||||
char flag_state;
|
||||
char* devicePath;
|
||||
|
||||
kbd = (SDL_EVDEV_keyboard_state *)SDL_calloc(1, sizeof(SDL_EVDEV_keyboard_state));
|
||||
if (!kbd) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kbd->npadch = -1;
|
||||
|
||||
/* This might fail if we're not connected to a tty (e.g. on the Steam Link) */
|
||||
kbd->keyboard_fd = kbd->console_fd = open("/dev/tty", O_RDONLY);
|
||||
|
||||
kbd->shift_state = 0;
|
||||
|
||||
kbd->accents = SDL_calloc(sizeof(accentmap_t), 1);
|
||||
kbd->key_map = SDL_calloc(sizeof(keymap_t), 1);
|
||||
kbd->kbInfo = SDL_calloc(sizeof(keyboard_info_t), 1);
|
||||
|
||||
ioctl(kbd->console_fd, KDGKBINFO, kbd->kbInfo);
|
||||
|
||||
if (ioctl(kbd->console_fd, KDGKBSTATE, &flag_state) == 0) {
|
||||
kbd->ledflagstate = flag_state;
|
||||
}
|
||||
|
||||
if (ioctl(kbd->console_fd, GIO_DEADKEYMAP, kbd->accents) < 0)
|
||||
{
|
||||
SDL_free(kbd->accents);
|
||||
kbd->accents = &accentmap_default_us_acc;
|
||||
}
|
||||
|
||||
if (ioctl(kbd->console_fd, KDGKBMODE, &kbd->old_kbd_mode) == 0) {
|
||||
/* Set the keyboard in XLATE mode and load the keymaps */
|
||||
ioctl(kbd->console_fd, KDSKBMODE, (unsigned long)(K_XLATE));
|
||||
if(!SDL_EVDEV_kbd_load_keymaps(kbd))
|
||||
{
|
||||
SDL_free(kbd->key_map);
|
||||
kbd->key_map = &keymap_default_us_acc;
|
||||
}
|
||||
/* Allow inhibiting keyboard mute with env. variable for debugging etc. */
|
||||
if (getenv("SDL_INPUT_FREEBSD_KEEP_KBD") == NULL) {
|
||||
/* Take keyboard from console and open the actual keyboard device.
|
||||
* Ensures that the keystrokes do not leak through to the console.
|
||||
*/
|
||||
ioctl(kbd->console_fd, CONS_RELKBD, 1ul);
|
||||
asprintf(&devicePath, "/dev/kbd%d", kbd->kbInfo->kb_index);
|
||||
kbd->keyboard_fd = open(devicePath, O_WRONLY);
|
||||
if (kbd->keyboard_fd == -1)
|
||||
{
|
||||
// Give keyboard back.
|
||||
ioctl(kbd->console_fd, CONS_SETKBD, (unsigned long)(kbd->kbInfo->kb_index));
|
||||
kbd->keyboard_fd = kbd->console_fd;
|
||||
}
|
||||
|
||||
/* Make sure to restore keyboard if application fails to call
|
||||
* SDL_Quit before exit or fatal signal is raised.
|
||||
*/
|
||||
if (!SDL_GetHintBoolean(SDL_HINT_NO_SIGNAL_HANDLERS, SDL_FALSE)) {
|
||||
kbd_register_emerg_cleanup(kbd);
|
||||
}
|
||||
free(devicePath);
|
||||
}
|
||||
else kbd->keyboard_fd = kbd->console_fd;
|
||||
}
|
||||
|
||||
return kbd;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *kbd)
|
||||
{
|
||||
if (!kbd) {
|
||||
return;
|
||||
}
|
||||
|
||||
kbd_unregister_emerg_cleanup();
|
||||
|
||||
if (kbd->keyboard_fd >= 0) {
|
||||
/* Restore the original keyboard mode */
|
||||
ioctl(kbd->keyboard_fd, KDSKBMODE, kbd->old_kbd_mode);
|
||||
|
||||
close(kbd->keyboard_fd);
|
||||
if (kbd->console_fd != kbd->keyboard_fd && kbd->console_fd >= 0)
|
||||
{
|
||||
// Give back keyboard.
|
||||
ioctl(kbd->console_fd, CONS_SETKBD, (unsigned long)(kbd->kbInfo->kb_index));
|
||||
}
|
||||
kbd->console_fd = kbd->keyboard_fd = -1;
|
||||
}
|
||||
|
||||
SDL_free(kbd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper Functions.
|
||||
*/
|
||||
static void put_queue(SDL_EVDEV_keyboard_state *kbd, uint c)
|
||||
{
|
||||
/* c is already part of a UTF-8 sequence and safe to add as a character */
|
||||
if (kbd->text_len < (sizeof(kbd->text)-1)) {
|
||||
kbd->text[kbd->text_len++] = (char)c;
|
||||
}
|
||||
}
|
||||
|
||||
static void put_utf8(SDL_EVDEV_keyboard_state *kbd, uint c)
|
||||
{
|
||||
if (c < 0x80)
|
||||
/* 0******* */
|
||||
put_queue(kbd, c);
|
||||
else if (c < 0x800) {
|
||||
/* 110***** 10****** */
|
||||
put_queue(kbd, 0xc0 | (c >> 6));
|
||||
put_queue(kbd, 0x80 | (c & 0x3f));
|
||||
} else if (c < 0x10000) {
|
||||
if (c >= 0xD800 && c < 0xE000)
|
||||
return;
|
||||
if (c == 0xFFFF)
|
||||
return;
|
||||
/* 1110**** 10****** 10****** */
|
||||
put_queue(kbd, 0xe0 | (c >> 12));
|
||||
put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
|
||||
put_queue(kbd, 0x80 | (c & 0x3f));
|
||||
} else if (c < 0x110000) {
|
||||
/* 11110*** 10****** 10****** 10****** */
|
||||
put_queue(kbd, 0xf0 | (c >> 18));
|
||||
put_queue(kbd, 0x80 | ((c >> 12) & 0x3f));
|
||||
put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
|
||||
put_queue(kbd, 0x80 | (c & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a combining character DIACR here, followed by the character CH.
|
||||
* If the combination occurs in the table, return the corresponding value.
|
||||
* Otherwise, if CH is a space or equals DIACR, return DIACR.
|
||||
* Otherwise, conclude that DIACR was not combining after all,
|
||||
* queue it and return CH.
|
||||
*/
|
||||
static unsigned int handle_diacr(SDL_EVDEV_keyboard_state *kbd, unsigned int ch)
|
||||
{
|
||||
unsigned int d = kbd->diacr;
|
||||
unsigned int i, j;
|
||||
|
||||
kbd->diacr = 0;
|
||||
|
||||
for (i = 0; i < kbd->accents->n_accs; i++) {
|
||||
if (kbd->accents->acc[i].accchar == d)
|
||||
{
|
||||
for (j = 0; j < NUM_ACCENTCHARS; ++j) {
|
||||
if (kbd->accents->acc[i].map[j][0] == 0) /* end of table */
|
||||
break;
|
||||
if (kbd->accents->acc[i].map[j][0] == ch)
|
||||
return kbd->accents->acc[i].map[j][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ch == ' ' || ch == d) {
|
||||
put_utf8(kbd, d);
|
||||
return 0;
|
||||
}
|
||||
put_utf8(kbd, d);
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
static int vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
|
||||
{
|
||||
return (kbd->ledflagstate & flag) != 0;
|
||||
}
|
||||
|
||||
static void chg_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
|
||||
{
|
||||
kbd->ledflagstate ^= flag;
|
||||
ioctl(kbd->keyboard_fd, KDSKBSTATE, (unsigned long)(kbd->ledflagstate));
|
||||
}
|
||||
|
||||
/*
|
||||
* Special function handlers
|
||||
*/
|
||||
|
||||
static void k_self(SDL_EVDEV_keyboard_state *kbd, unsigned int value, char up_flag)
|
||||
{
|
||||
if (up_flag)
|
||||
return; /* no action, if this is a key release */
|
||||
|
||||
if (kbd->diacr)
|
||||
value = handle_diacr(kbd, value);
|
||||
|
||||
if (kbd->dead_key_next) {
|
||||
kbd->dead_key_next = SDL_FALSE;
|
||||
kbd->diacr = value;
|
||||
return;
|
||||
}
|
||||
put_utf8(kbd, value);
|
||||
}
|
||||
|
||||
static void k_deadunicode(SDL_EVDEV_keyboard_state *kbd, unsigned int value, char up_flag)
|
||||
{
|
||||
if (up_flag)
|
||||
return;
|
||||
|
||||
kbd->diacr = (kbd->diacr ? handle_diacr(kbd, value) : value);
|
||||
}
|
||||
|
||||
static void k_shift(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
|
||||
{
|
||||
int old_state = kbd->shift_state;
|
||||
|
||||
if (kbd->rep)
|
||||
return;
|
||||
|
||||
if (up_flag) {
|
||||
/*
|
||||
* handle the case that two shift or control
|
||||
* keys are depressed simultaneously
|
||||
*/
|
||||
if (kbd->shift_down[value])
|
||||
kbd->shift_down[value]--;
|
||||
} else
|
||||
kbd->shift_down[value]++;
|
||||
|
||||
if (kbd->shift_down[value])
|
||||
kbd->shift_state |= (1 << value);
|
||||
else
|
||||
kbd->shift_state &= ~(1 << value);
|
||||
|
||||
/* kludge */
|
||||
if (up_flag && kbd->shift_state != old_state && kbd->npadch != -1) {
|
||||
put_utf8(kbd, kbd->npadch);
|
||||
kbd->npadch = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode, int down)
|
||||
{
|
||||
keymap_t key_map;
|
||||
struct keyent_t keysym;
|
||||
unsigned int final_key_state;
|
||||
unsigned int map_from_key_sym;
|
||||
|
||||
key_map = *kbd->key_map;
|
||||
|
||||
if (!kbd) {
|
||||
return;
|
||||
}
|
||||
|
||||
kbd->rep = (down == 2);
|
||||
|
||||
if (keycode < NUM_KEYS) {
|
||||
if (keycode >= 89 && keycode <= 95) {
|
||||
/* These constitute unprintable language-related keys, so ignore them. */
|
||||
return;
|
||||
}
|
||||
if (keycode > 95)
|
||||
keycode -= 7;
|
||||
if (vc_kbd_led(kbd, ALKED) || (kbd->shift_state & 0x8))
|
||||
{
|
||||
keycode += ALTGR_OFFSET;
|
||||
}
|
||||
keysym = key_map.key[keycode];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
final_key_state = kbd->shift_state & 0x7;
|
||||
if ((keysym.flgs & FLAG_LOCK_C) && vc_kbd_led(kbd, LED_CAP))
|
||||
final_key_state ^= 0x1;
|
||||
if ((keysym.flgs & FLAG_LOCK_N) && vc_kbd_led(kbd, LED_NUM))
|
||||
final_key_state ^= 0x1;
|
||||
|
||||
map_from_key_sym = keysym.map[final_key_state];
|
||||
if ((keysym.spcl & (0x80 >> final_key_state)) || (map_from_key_sym & SPCLKEY)) {
|
||||
/* Special function.*/
|
||||
if (map_from_key_sym == 0)
|
||||
return; /* Nothing to do. */
|
||||
if (map_from_key_sym & SPCLKEY)
|
||||
map_from_key_sym &= ~SPCLKEY;
|
||||
if (map_from_key_sym >= F_ACC && map_from_key_sym <= L_ACC) {
|
||||
/* Accent function.*/
|
||||
unsigned int accent_index = map_from_key_sym - F_ACC;
|
||||
if (kbd->accents->acc[accent_index].accchar != 0) {
|
||||
k_deadunicode(kbd, kbd->accents->acc[accent_index].accchar, !down);
|
||||
}
|
||||
} else {
|
||||
switch(map_from_key_sym) {
|
||||
case ASH: /* alt/meta shift */
|
||||
k_shift(kbd, 3, down == 0);
|
||||
break;
|
||||
case LSHA: /* left shift + alt lock */
|
||||
case RSHA: /* right shift + alt lock */
|
||||
if (down == 0) chg_vc_kbd_led(kbd, ALKED);
|
||||
case LSH: /* left shift */
|
||||
case RSH: /* right shift */
|
||||
k_shift(kbd, 0, down == 0);
|
||||
break;
|
||||
case LCTRA: /* left ctrl + alt lock */
|
||||
case RCTRA: /* right ctrl + alt lock */
|
||||
if (down == 0) chg_vc_kbd_led(kbd, ALKED);
|
||||
case LCTR: /* left ctrl */
|
||||
case RCTR: /* right ctrl */
|
||||
k_shift(kbd, 1, down == 0);
|
||||
break;
|
||||
case LALTA: /* left alt + alt lock */
|
||||
case RALTA: /* right alt + alt lock */
|
||||
if (down == 0) chg_vc_kbd_led(kbd, ALKED);
|
||||
case LALT: /* left alt */
|
||||
case RALT: /* right alt */
|
||||
k_shift(kbd, 2, down == 0);
|
||||
break;
|
||||
case ALK: /* alt lock */
|
||||
if (down == 1) chg_vc_kbd_led(kbd, ALKED);
|
||||
break;
|
||||
case CLK: /* caps lock*/
|
||||
if (down == 1) chg_vc_kbd_led(kbd, CLKED);
|
||||
break;
|
||||
case NLK: /* num lock */
|
||||
if (down == 1) chg_vc_kbd_led(kbd, NLKED);
|
||||
break;
|
||||
case SLK: /* scroll lock */
|
||||
if (down == 1) chg_vc_kbd_led(kbd, SLKED);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (map_from_key_sym == '\n' || map_from_key_sym == '\r') {
|
||||
if (kbd->diacr) {
|
||||
kbd->diacr = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (map_from_key_sym >= ' ' && map_from_key_sym != 127) {
|
||||
k_self(kbd, map_from_key_sym, !down);
|
||||
}
|
||||
}
|
||||
|
||||
if (kbd->text_len > 0) {
|
||||
kbd->text[kbd->text_len] = '\0';
|
||||
SDL_SendKeyboardText(kbd->text);
|
||||
kbd->text_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SDL_INPUT_FBSDKBIO */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -57,6 +57,10 @@ LoadDBUSSyms(void)
|
||||
SDL_DBUS_SYM(message_new_method_call);
|
||||
SDL_DBUS_SYM(message_append_args);
|
||||
SDL_DBUS_SYM(message_append_args_valist);
|
||||
SDL_DBUS_SYM(message_iter_init_append);
|
||||
SDL_DBUS_SYM(message_iter_open_container);
|
||||
SDL_DBUS_SYM(message_iter_append_basic);
|
||||
SDL_DBUS_SYM(message_iter_close_container);
|
||||
SDL_DBUS_SYM(message_get_args);
|
||||
SDL_DBUS_SYM(message_get_args_valist);
|
||||
SDL_DBUS_SYM(message_iter_init);
|
||||
@@ -65,6 +69,7 @@ LoadDBUSSyms(void)
|
||||
SDL_DBUS_SYM(message_iter_get_arg_type);
|
||||
SDL_DBUS_SYM(message_iter_recurse);
|
||||
SDL_DBUS_SYM(message_unref);
|
||||
SDL_DBUS_SYM(threads_init_default);
|
||||
SDL_DBUS_SYM(error_init);
|
||||
SDL_DBUS_SYM(error_is_set);
|
||||
SDL_DBUS_SYM(error_free);
|
||||
@@ -111,20 +116,43 @@ LoadDBUSLibrary(void)
|
||||
void
|
||||
SDL_DBus_Init(void)
|
||||
{
|
||||
if (!dbus.session_conn && LoadDBUSLibrary() != -1) {
|
||||
static SDL_bool is_dbus_available = SDL_TRUE;
|
||||
if (!is_dbus_available) {
|
||||
return; /* don't keep trying if this fails. */
|
||||
}
|
||||
|
||||
if (!dbus.session_conn) {
|
||||
DBusError err;
|
||||
dbus.error_init(&err);
|
||||
dbus.session_conn = dbus.bus_get_private(DBUS_BUS_SESSION, &err);
|
||||
if (!dbus.error_is_set(&err)) {
|
||||
dbus.system_conn = dbus.bus_get_private(DBUS_BUS_SYSTEM, &err);
|
||||
|
||||
if (LoadDBUSLibrary() == -1) {
|
||||
is_dbus_available = SDL_FALSE; /* can't load at all? Don't keep trying. */
|
||||
return; /* oh well */
|
||||
}
|
||||
|
||||
if (!dbus.threads_init_default()) {
|
||||
is_dbus_available = SDL_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
dbus.error_init(&err);
|
||||
/* session bus is required */
|
||||
|
||||
dbus.session_conn = dbus.bus_get_private(DBUS_BUS_SESSION, &err);
|
||||
if (dbus.error_is_set(&err)) {
|
||||
dbus.error_free(&err);
|
||||
SDL_DBus_Quit();
|
||||
is_dbus_available = SDL_FALSE;
|
||||
return; /* oh well */
|
||||
}
|
||||
dbus.connection_set_exit_on_disconnect(dbus.system_conn, 0);
|
||||
dbus.connection_set_exit_on_disconnect(dbus.session_conn, 0);
|
||||
|
||||
/* system bus is optional */
|
||||
dbus.system_conn = dbus.bus_get_private(DBUS_BUS_SYSTEM, &err);
|
||||
if (!dbus.error_is_set(&err)) {
|
||||
dbus.connection_set_exit_on_disconnect(dbus.system_conn, 0);
|
||||
}
|
||||
|
||||
dbus.error_free(&err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,15 +182,11 @@ SDL_DBus_Quit(void)
|
||||
SDL_DBusContext *
|
||||
SDL_DBus_GetContext(void)
|
||||
{
|
||||
if(!dbus_handle || !dbus.session_conn){
|
||||
if (!dbus_handle || !dbus.session_conn) {
|
||||
SDL_DBus_Init();
|
||||
}
|
||||
|
||||
if(dbus_handle && dbus.session_conn){
|
||||
return &dbus;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
return (dbus_handle && dbus.session_conn) ? &dbus : NULL;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -54,6 +54,10 @@ typedef struct SDL_DBusContext {
|
||||
DBusMessage *(*message_new_method_call)(const char *, const char *, const char *, const char *);
|
||||
dbus_bool_t (*message_append_args)(DBusMessage *, int, ...);
|
||||
dbus_bool_t (*message_append_args_valist)(DBusMessage *, int, va_list);
|
||||
void (*message_iter_init_append)(DBusMessage *, DBusMessageIter *);
|
||||
dbus_bool_t (*message_iter_open_container)(DBusMessageIter *, int, const char *, DBusMessageIter *);
|
||||
dbus_bool_t (*message_iter_append_basic)(DBusMessageIter *, int, const void *);
|
||||
dbus_bool_t (*message_iter_close_container)(DBusMessageIter *, DBusMessageIter *);
|
||||
dbus_bool_t (*message_get_args)(DBusMessage *, DBusError *, int, ...);
|
||||
dbus_bool_t (*message_get_args_valist)(DBusMessage *, DBusError *, int, va_list);
|
||||
dbus_bool_t (*message_iter_init)(DBusMessage *, DBusMessageIter *);
|
||||
@@ -62,6 +66,7 @@ typedef struct SDL_DBusContext {
|
||||
int (*message_iter_get_arg_type)(DBusMessageIter *);
|
||||
void (*message_iter_recurse)(DBusMessageIter *, DBusMessageIter *);
|
||||
void (*message_unref)(DBusMessage *);
|
||||
dbus_bool_t (*threads_init_default)(void);
|
||||
void (*error_init)(DBusError *);
|
||||
dbus_bool_t (*error_is_set)(const DBusError *);
|
||||
void (*error_free)(DBusError *);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -39,11 +39,11 @@
|
||||
#include <linux/input.h>
|
||||
|
||||
#include "SDL.h"
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_endian.h"
|
||||
#include "SDL_scancode.h"
|
||||
#include "../../events/SDL_events_c.h"
|
||||
#include "../../events/scancodes_linux.h" /* adds linux_scancode_table */
|
||||
#include "../../core/linux/SDL_evdev_capabilities.h"
|
||||
#include "../../core/linux/SDL_udev.h"
|
||||
|
||||
/* These are not defined in older Linux kernel headers */
|
||||
@@ -401,18 +401,21 @@ SDL_EVDEV_Poll(void)
|
||||
norm_pressure = 1.0f;
|
||||
}
|
||||
|
||||
/* FIXME: the touch's window shouldn't be null, but
|
||||
* the coordinate space of touch positions needs to
|
||||
* be window-relative in that case. */
|
||||
switch(item->touchscreen_data->slots[j].delta) {
|
||||
case EVDEV_TOUCH_SLOTDELTA_DOWN:
|
||||
SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_TRUE, norm_x, norm_y, norm_pressure);
|
||||
SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, SDL_TRUE, norm_x, norm_y, norm_pressure);
|
||||
item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
|
||||
break;
|
||||
case EVDEV_TOUCH_SLOTDELTA_UP:
|
||||
SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_FALSE, norm_x, norm_y, norm_pressure);
|
||||
SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, SDL_FALSE, norm_x, norm_y, norm_pressure);
|
||||
item->touchscreen_data->slots[j].tracking_id = -1;
|
||||
item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
|
||||
break;
|
||||
case EVDEV_TOUCH_SLOTDELTA_MOVE:
|
||||
SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, norm_x, norm_y, norm_pressure);
|
||||
SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, norm_x, norm_y, norm_pressure);
|
||||
item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
|
||||
break;
|
||||
default:
|
||||
@@ -443,18 +446,19 @@ SDL_EVDEV_translate_keycode(int keycode)
|
||||
{
|
||||
SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
|
||||
|
||||
if (keycode < SDL_arraysize(linux_scancode_table))
|
||||
if (keycode < SDL_arraysize(linux_scancode_table)) {
|
||||
scancode = linux_scancode_table[keycode];
|
||||
|
||||
if (scancode == SDL_SCANCODE_UNKNOWN) {
|
||||
/* BTN_TOUCH is handled elsewhere, but we might still end up here if
|
||||
you get an unexpected BTN_TOUCH from something SDL believes is not
|
||||
a touch device. In this case, we'd rather not get a misleading
|
||||
SDL_Log message about an unknown key. */
|
||||
if (keycode != BTN_TOUCH) {
|
||||
SDL_Log("The key you just pressed is not recognized by SDL. To help "
|
||||
"get this fixed, please report this to the SDL forums/mailing list "
|
||||
"<https://discourse.libsdl.org/> EVDEV KeyCode %d", keycode);
|
||||
if (scancode == SDL_SCANCODE_UNKNOWN) {
|
||||
/* BTN_TOUCH is handled elsewhere, but we might still end up here if
|
||||
you get an unexpected BTN_TOUCH from something SDL believes is not
|
||||
a touch device. In this case, we'd rather not get a misleading
|
||||
SDL_Log message about an unknown key. */
|
||||
if (keycode != BTN_TOUCH) {
|
||||
SDL_Log("The key you just pressed is not recognized by SDL. To help "
|
||||
"get this fixed, please report this to the SDL forums/mailing list "
|
||||
"<https://discourse.libsdl.org/> EVDEV KeyCode %d", keycode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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,98 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 2020 Collabora Ltd.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "SDL_evdev_capabilities.h"
|
||||
|
||||
#if HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX)
|
||||
|
||||
extern int
|
||||
SDL_EVDEV_GuessDeviceClass(unsigned long bitmask_ev[NBITS(EV_MAX)],
|
||||
unsigned long bitmask_abs[NBITS(ABS_MAX)],
|
||||
unsigned long bitmask_key[NBITS(KEY_MAX)],
|
||||
unsigned long bitmask_rel[NBITS(REL_MAX)])
|
||||
{
|
||||
int devclass = 0;
|
||||
unsigned long keyboard_mask;
|
||||
|
||||
/* X, Y, Z axes but no buttons probably means an accelerometer */
|
||||
if (test_bit(EV_ABS, bitmask_ev) &&
|
||||
test_bit(ABS_X, bitmask_abs) &&
|
||||
test_bit(ABS_Y, bitmask_abs) &&
|
||||
test_bit(ABS_Z, bitmask_abs) &&
|
||||
!test_bit(EV_KEY, bitmask_ev)) {
|
||||
return SDL_UDEV_DEVICE_ACCELEROMETER;
|
||||
}
|
||||
|
||||
/* RX, RY, RZ axes but no buttons also probably means an accelerometer */
|
||||
if (test_bit(EV_ABS, bitmask_ev) &&
|
||||
test_bit(ABS_RX, bitmask_abs) &&
|
||||
test_bit(ABS_RY, bitmask_abs) &&
|
||||
test_bit(ABS_RZ, bitmask_abs) &&
|
||||
!test_bit(EV_KEY, bitmask_ev)) {
|
||||
return SDL_UDEV_DEVICE_ACCELEROMETER;
|
||||
}
|
||||
|
||||
if (test_bit(EV_ABS, bitmask_ev) &&
|
||||
test_bit(ABS_X, bitmask_abs) && test_bit(ABS_Y, bitmask_abs)) {
|
||||
if (test_bit(BTN_STYLUS, bitmask_key) || test_bit(BTN_TOOL_PEN, bitmask_key)) {
|
||||
; /* ID_INPUT_TABLET */
|
||||
} else if (test_bit(BTN_TOOL_FINGER, bitmask_key) && !test_bit(BTN_TOOL_PEN, bitmask_key)) {
|
||||
; /* ID_INPUT_TOUCHPAD */
|
||||
} else if (test_bit(BTN_MOUSE, bitmask_key)) {
|
||||
devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */
|
||||
} else if (test_bit(BTN_TOUCH, bitmask_key)) {
|
||||
/* TODO: better determining between touchscreen and multitouch touchpad,
|
||||
see https://github.com/systemd/systemd/blob/master/src/udev/udev-builtin-input_id.c */
|
||||
devclass |= SDL_UDEV_DEVICE_TOUCHSCREEN; /* ID_INPUT_TOUCHSCREEN */
|
||||
}
|
||||
|
||||
if (test_bit(BTN_TRIGGER, bitmask_key) ||
|
||||
test_bit(BTN_A, bitmask_key) ||
|
||||
test_bit(BTN_1, bitmask_key) ||
|
||||
test_bit(ABS_RX, bitmask_abs) ||
|
||||
test_bit(ABS_RY, bitmask_abs) ||
|
||||
test_bit(ABS_RZ, bitmask_abs) ||
|
||||
test_bit(ABS_THROTTLE, bitmask_abs) ||
|
||||
test_bit(ABS_RUDDER, bitmask_abs) ||
|
||||
test_bit(ABS_WHEEL, bitmask_abs) ||
|
||||
test_bit(ABS_GAS, bitmask_abs) ||
|
||||
test_bit(ABS_BRAKE, bitmask_abs)) {
|
||||
devclass |= SDL_UDEV_DEVICE_JOYSTICK; /* ID_INPUT_JOYSTICK */
|
||||
}
|
||||
}
|
||||
|
||||
if (test_bit(EV_REL, bitmask_ev) &&
|
||||
test_bit(REL_X, bitmask_rel) && test_bit(REL_Y, bitmask_rel) &&
|
||||
test_bit(BTN_MOUSE, bitmask_key)) {
|
||||
devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */
|
||||
}
|
||||
|
||||
/* the first 32 bits are ESC, numbers, and Q to D; if we have any of
|
||||
* those, consider it a keyboard device; do not test KEY_RESERVED, though */
|
||||
keyboard_mask = 0xFFFFFFFE;
|
||||
if ((bitmask_key[0] & keyboard_mask) != 0)
|
||||
devclass |= SDL_UDEV_DEVICE_KEYBOARD; /* ID_INPUT_KEYBOARD */
|
||||
|
||||
return devclass;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 2020 Collabora Ltd.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef SDL_evdev_capabilities_h_
|
||||
#define SDL_evdev_capabilities_h_
|
||||
|
||||
#if HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX)
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
/* A device can be any combination of these classes */
|
||||
typedef enum
|
||||
{
|
||||
SDL_UDEV_DEVICE_UNKNOWN = 0x0000,
|
||||
SDL_UDEV_DEVICE_MOUSE = 0x0001,
|
||||
SDL_UDEV_DEVICE_KEYBOARD = 0x0002,
|
||||
SDL_UDEV_DEVICE_JOYSTICK = 0x0004,
|
||||
SDL_UDEV_DEVICE_SOUND = 0x0008,
|
||||
SDL_UDEV_DEVICE_TOUCHSCREEN = 0x0010,
|
||||
SDL_UDEV_DEVICE_ACCELEROMETER = 0x0020
|
||||
} SDL_UDEV_deviceclass;
|
||||
|
||||
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
|
||||
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
|
||||
#define EVDEV_OFF(x) ((x)%BITS_PER_LONG)
|
||||
#define EVDEV_LONG(x) ((x)/BITS_PER_LONG)
|
||||
#define test_bit(bit, array) ((array[EVDEV_LONG(bit)] >> EVDEV_OFF(bit)) & 1)
|
||||
|
||||
extern int SDL_EVDEV_GuessDeviceClass(unsigned long bitmask_ev[NBITS(EV_MAX)],
|
||||
unsigned long bitmask_abs[NBITS(ABS_MAX)],
|
||||
unsigned long bitmask_key[NBITS(KEY_MAX)],
|
||||
unsigned long bitmask_rel[NBITS(REL_MAX)]);
|
||||
|
||||
#endif /* HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX) */
|
||||
|
||||
#endif /* SDL_evdev_capabilities_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -819,7 +819,7 @@ SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode, int d
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !SDL_INPUT_LINUXKD */
|
||||
#elif !defined(SDL_INPUT_FBSDKBIO) /* !SDL_INPUT_LINUXKD */
|
||||
|
||||
SDL_EVDEV_keyboard_state *
|
||||
SDL_EVDEV_kbd_init(void)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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,6 @@
|
||||
*/
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifdef HAVE_FCITX_FRONTEND_H
|
||||
|
||||
#include <fcitx/frontend.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "SDL_fcitx.h"
|
||||
@@ -36,23 +33,20 @@
|
||||
#endif
|
||||
#include "SDL_hints.h"
|
||||
|
||||
#define FCITX_DBUS_SERVICE "org.fcitx.Fcitx"
|
||||
#define FCITX_DBUS_SERVICE "org.freedesktop.portal.Fcitx"
|
||||
|
||||
#define FCITX_IM_DBUS_PATH "/inputmethod"
|
||||
#define FCITX_IC_DBUS_PATH "/inputcontext_%d"
|
||||
#define FCITX_IM_DBUS_PATH "/org/freedesktop/portal/inputmethod"
|
||||
|
||||
#define FCITX_IM_DBUS_INTERFACE "org.fcitx.Fcitx.InputMethod"
|
||||
#define FCITX_IC_DBUS_INTERFACE "org.fcitx.Fcitx.InputContext"
|
||||
#define FCITX_IM_DBUS_INTERFACE "org.fcitx.Fcitx.InputMethod1"
|
||||
#define FCITX_IC_DBUS_INTERFACE "org.fcitx.Fcitx.InputContext1"
|
||||
|
||||
#define IC_NAME_MAX 64
|
||||
#define DBUS_TIMEOUT 500
|
||||
|
||||
typedef struct _FcitxClient
|
||||
{
|
||||
SDL_DBusContext *dbus;
|
||||
|
||||
char servicename[IC_NAME_MAX];
|
||||
char icname[IC_NAME_MAX];
|
||||
char *ic_path;
|
||||
|
||||
int id;
|
||||
|
||||
@@ -61,34 +55,6 @@ typedef struct _FcitxClient
|
||||
|
||||
static FcitxClient fcitx_client;
|
||||
|
||||
static int
|
||||
GetDisplayNumber()
|
||||
{
|
||||
const char *display = SDL_getenv("DISPLAY");
|
||||
const char *p = NULL;
|
||||
int number = 0;
|
||||
|
||||
if (display == NULL)
|
||||
return 0;
|
||||
|
||||
display = SDL_strchr(display, ':');
|
||||
if (display == NULL)
|
||||
return 0;
|
||||
|
||||
display++;
|
||||
p = SDL_strchr(display, '.');
|
||||
if (p == NULL && display != NULL) {
|
||||
number = SDL_strtod(display, NULL);
|
||||
} else {
|
||||
char *buffer = SDL_strdup(display);
|
||||
buffer[p - display] = '\0';
|
||||
number = SDL_strtod(buffer, NULL);
|
||||
SDL_free(buffer);
|
||||
}
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
static char*
|
||||
GetAppName()
|
||||
{
|
||||
@@ -118,6 +84,54 @@ GetAppName()
|
||||
return SDL_strdup("SDL_App");
|
||||
}
|
||||
|
||||
size_t Fcitx_GetPreeditString(SDL_DBusContext *dbus, DBusMessage *msg, char **ret) {
|
||||
char *text = NULL, *subtext;
|
||||
size_t text_bytes = 0;
|
||||
DBusMessageIter iter, array, sub;
|
||||
|
||||
dbus->message_iter_init(msg, &iter);
|
||||
/* Message type is a(si)i, we only need string part */
|
||||
if (dbus->message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) {
|
||||
/* First pass: calculate string length */
|
||||
dbus->message_iter_recurse(&iter, &array);
|
||||
while (dbus->message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
|
||||
dbus->message_iter_recurse(&array, &sub);
|
||||
if (dbus->message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
|
||||
dbus->message_iter_get_basic(&sub, &subtext);
|
||||
if (subtext && *subtext) {
|
||||
text_bytes += SDL_strlen(subtext);
|
||||
}
|
||||
}
|
||||
dbus->message_iter_next(&array);
|
||||
}
|
||||
if (text_bytes) {
|
||||
text = SDL_malloc(text_bytes + 1);
|
||||
}
|
||||
|
||||
if (text) {
|
||||
char* pivot = text;
|
||||
/* Second pass: join all the sub string */
|
||||
dbus->message_iter_recurse(&iter, &array);
|
||||
while (dbus->message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
|
||||
dbus->message_iter_recurse(&array, &sub);
|
||||
if (dbus->message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
|
||||
dbus->message_iter_get_basic(&sub, &subtext);
|
||||
if (subtext && *subtext) {
|
||||
size_t length = SDL_strlen(subtext);
|
||||
SDL_strlcpy(pivot, subtext, length + 1);
|
||||
pivot += length;
|
||||
}
|
||||
}
|
||||
dbus->message_iter_next(&array);
|
||||
}
|
||||
} else {
|
||||
text_bytes = 0;
|
||||
}
|
||||
}
|
||||
*ret= text;
|
||||
return text_bytes;
|
||||
}
|
||||
|
||||
static DBusHandlerResult
|
||||
DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
@@ -130,22 +144,27 @@ DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
dbus->message_iter_init(msg, &iter);
|
||||
dbus->message_iter_get_basic(&iter, &text);
|
||||
|
||||
if (text)
|
||||
SDL_SendKeyboardText(text);
|
||||
if (text && *text) {
|
||||
char buf[SDL_TEXTINPUTEVENT_TEXT_SIZE];
|
||||
size_t text_bytes = SDL_strlen(text), i = 0;
|
||||
|
||||
while (i < text_bytes) {
|
||||
size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
|
||||
SDL_SendKeyboardText(buf);
|
||||
|
||||
i += sz;
|
||||
}
|
||||
}
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
if (dbus->message_is_signal(msg, FCITX_IC_DBUS_INTERFACE, "UpdatePreedit")) {
|
||||
DBusMessageIter iter;
|
||||
const char *text;
|
||||
|
||||
dbus->message_iter_init(msg, &iter);
|
||||
dbus->message_iter_get_basic(&iter, &text);
|
||||
|
||||
if (text && *text) {
|
||||
if (dbus->message_is_signal(msg, FCITX_IC_DBUS_INTERFACE, "UpdateFormattedPreedit")) {
|
||||
char *text = NULL;
|
||||
size_t text_bytes = Fcitx_GetPreeditString(dbus, msg, &text);
|
||||
if (text_bytes) {
|
||||
char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
|
||||
size_t text_bytes = SDL_strlen(text), i = 0;
|
||||
size_t i = 0;
|
||||
size_t cursor = 0;
|
||||
|
||||
while (i < text_bytes) {
|
||||
@@ -157,6 +176,9 @@ DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
i += sz;
|
||||
cursor += chars;
|
||||
}
|
||||
SDL_free(text);
|
||||
} else {
|
||||
SDL_SendEditingText("", 0, 0);
|
||||
}
|
||||
|
||||
SDL_Fcitx_UpdateTextRect(NULL);
|
||||
@@ -169,7 +191,10 @@ DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
static void
|
||||
FcitxClientICCallMethod(FcitxClient *client, const char *method)
|
||||
{
|
||||
SDL_DBus_CallVoidMethod(client->servicename, client->icname, FCITX_IC_DBUS_INTERFACE, method, DBUS_TYPE_INVALID);
|
||||
if (!client->ic_path) {
|
||||
return;
|
||||
}
|
||||
SDL_DBus_CallVoidMethod(FCITX_DBUS_SERVICE, client->ic_path, FCITX_IC_DBUS_INTERFACE, method, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
static void SDLCALL
|
||||
@@ -179,40 +204,68 @@ Fcitx_SetCapabilities(void *data,
|
||||
const char *internal_editing)
|
||||
{
|
||||
FcitxClient *client = (FcitxClient *)data;
|
||||
Uint32 caps = CAPACITY_NONE;
|
||||
|
||||
if (!(internal_editing && *internal_editing == '1')) {
|
||||
caps |= CAPACITY_PREEDIT;
|
||||
Uint32 caps = 0;
|
||||
if (!client->ic_path) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_DBus_CallVoidMethod(client->servicename, client->icname, FCITX_IC_DBUS_INTERFACE, "SetCapacity", DBUS_TYPE_UINT32, &caps, DBUS_TYPE_INVALID);
|
||||
if (!(internal_editing && *internal_editing == '1')) {
|
||||
caps |= (1 << 1); /* Preedit Flag */
|
||||
caps |= (1 << 4); /* Formatted Preedit Flag */
|
||||
}
|
||||
|
||||
SDL_DBus_CallVoidMethod(FCITX_DBUS_SERVICE, client->ic_path, FCITX_IC_DBUS_INTERFACE, "SetCapability", DBUS_TYPE_UINT64, &caps, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
FcitxCreateInputContext(SDL_DBusContext* dbus, const char *appname, char **ic_path) {
|
||||
const char *program = "program";
|
||||
SDL_bool retval = SDL_FALSE;
|
||||
if (dbus->session_conn) {
|
||||
DBusMessage *msg = dbus->message_new_method_call(FCITX_DBUS_SERVICE, FCITX_IM_DBUS_PATH, FCITX_IM_DBUS_INTERFACE, "CreateInputContext");
|
||||
if (msg) {
|
||||
DBusMessage *reply = NULL;
|
||||
DBusMessageIter args, array, sub;
|
||||
dbus->message_iter_init_append(msg, &args);
|
||||
dbus->message_iter_open_container(&args, DBUS_TYPE_ARRAY, "(ss)", &array);
|
||||
dbus->message_iter_open_container(&array, DBUS_TYPE_STRUCT, 0, &sub);
|
||||
dbus->message_iter_append_basic(&sub, DBUS_TYPE_STRING, &program);
|
||||
dbus->message_iter_append_basic(&sub, DBUS_TYPE_STRING, &appname);
|
||||
dbus->message_iter_close_container(&array, &sub);
|
||||
dbus->message_iter_close_container(&args, &array);
|
||||
reply = dbus->connection_send_with_reply_and_block(dbus->session_conn, msg, 300, NULL);
|
||||
if (reply) {
|
||||
if (dbus->message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, ic_path, DBUS_TYPE_INVALID)) {
|
||||
retval = SDL_TRUE;
|
||||
}
|
||||
dbus->message_unref(reply);
|
||||
}
|
||||
dbus->message_unref(msg);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
FcitxClientCreateIC(FcitxClient *client)
|
||||
{
|
||||
char *appname = GetAppName();
|
||||
pid_t pid = getpid();
|
||||
int id = -1;
|
||||
Uint32 enable, arg1, arg2, arg3, arg4;
|
||||
char *ic_path = NULL;
|
||||
SDL_DBusContext *dbus = client->dbus;
|
||||
|
||||
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. */
|
||||
/* SDL_DBus_CallMethod cannot handle a(ss) type, call dbus function directly */
|
||||
if (!FcitxCreateInputContext(dbus, appname, &ic_path)) {
|
||||
ic_path = NULL; /* just in case. */
|
||||
}
|
||||
|
||||
SDL_free(appname);
|
||||
|
||||
if (id >= 0) {
|
||||
SDL_DBusContext *dbus = client->dbus;
|
||||
|
||||
client->id = id;
|
||||
|
||||
SDL_snprintf(client->icname, IC_NAME_MAX, FCITX_IC_DBUS_PATH, client->id);
|
||||
if (ic_path) {
|
||||
SDL_free(client->ic_path);
|
||||
client->ic_path = SDL_strdup(ic_path);
|
||||
|
||||
dbus->bus_add_match(dbus->session_conn,
|
||||
"type='signal', interface='org.fcitx.Fcitx.InputContext'",
|
||||
"type='signal', interface='org.fcitx.Fcitx.InputContext1'",
|
||||
NULL);
|
||||
dbus->connection_add_filter(dbus->session_conn,
|
||||
&DBus_MessageFilter, dbus,
|
||||
@@ -232,13 +285,14 @@ Fcitx_ModState(void)
|
||||
Uint32 fcitx_mods = 0;
|
||||
SDL_Keymod sdl_mods = SDL_GetModState();
|
||||
|
||||
if (sdl_mods & KMOD_SHIFT) fcitx_mods |= FcitxKeyState_Shift;
|
||||
if (sdl_mods & KMOD_CAPS) fcitx_mods |= FcitxKeyState_CapsLock;
|
||||
if (sdl_mods & KMOD_CTRL) fcitx_mods |= FcitxKeyState_Ctrl;
|
||||
if (sdl_mods & KMOD_ALT) fcitx_mods |= FcitxKeyState_Alt;
|
||||
if (sdl_mods & KMOD_NUM) fcitx_mods |= FcitxKeyState_NumLock;
|
||||
if (sdl_mods & KMOD_LGUI) fcitx_mods |= FcitxKeyState_Super;
|
||||
if (sdl_mods & KMOD_RGUI) fcitx_mods |= FcitxKeyState_Meta;
|
||||
if (sdl_mods & KMOD_SHIFT) fcitx_mods |= (1 << 0);
|
||||
if (sdl_mods & KMOD_CAPS) fcitx_mods |= (1 << 1);
|
||||
if (sdl_mods & KMOD_CTRL) fcitx_mods |= (1 << 2);
|
||||
if (sdl_mods & KMOD_ALT) fcitx_mods |= (1 << 3);
|
||||
if (sdl_mods & KMOD_NUM) fcitx_mods |= (1 << 4);
|
||||
if (sdl_mods & KMOD_MODE) fcitx_mods |= (1 << 7);
|
||||
if (sdl_mods & KMOD_LGUI) fcitx_mods |= (1 << 6);
|
||||
if (sdl_mods & KMOD_RGUI) fcitx_mods |= (1 << 28);
|
||||
|
||||
return fcitx_mods;
|
||||
}
|
||||
@@ -253,10 +307,6 @@ SDL_Fcitx_Init()
|
||||
fcitx_client.cursor_rect.w = 0;
|
||||
fcitx_client.cursor_rect.h = 0;
|
||||
|
||||
SDL_snprintf(fcitx_client.servicename, IC_NAME_MAX,
|
||||
"%s-%d",
|
||||
FCITX_DBUS_SERVICE, GetDisplayNumber());
|
||||
|
||||
return FcitxClientCreateIC(&fcitx_client);
|
||||
}
|
||||
|
||||
@@ -264,6 +314,10 @@ void
|
||||
SDL_Fcitx_Quit()
|
||||
{
|
||||
FcitxClientICCallMethod(&fcitx_client, "DestroyIC");
|
||||
if (fcitx_client.ic_path) {
|
||||
SDL_free(fcitx_client.ic_path);
|
||||
fcitx_client.ic_path = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -288,12 +342,16 @@ SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
|
||||
{
|
||||
Uint32 state = Fcitx_ModState();
|
||||
Uint32 handled = SDL_FALSE;
|
||||
int type = FCITX_PRESS_KEY;
|
||||
Uint32 is_release = SDL_FALSE;
|
||||
Uint32 event_time = 0;
|
||||
|
||||
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 (!fcitx_client.ic_path) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (SDL_DBus_CallMethod(FCITX_DBUS_SERVICE, fcitx_client.ic_path, FCITX_IC_DBUS_INTERFACE, "ProcessKeyEvent",
|
||||
DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &state, DBUS_TYPE_BOOLEAN, &is_release, DBUS_TYPE_UINT32, &event_time, DBUS_TYPE_INVALID,
|
||||
DBUS_TYPE_BOOLEAN, &handled, DBUS_TYPE_INVALID)) {
|
||||
if (handled) {
|
||||
SDL_Fcitx_UpdateTextRect(NULL);
|
||||
return SDL_TRUE;
|
||||
@@ -350,7 +408,7 @@ SDL_Fcitx_UpdateTextRect(SDL_Rect *rect)
|
||||
x += cursor->x;
|
||||
y += cursor->y;
|
||||
|
||||
SDL_DBus_CallVoidMethod(fcitx_client.servicename, fcitx_client.icname, FCITX_IC_DBUS_INTERFACE, "SetCursorRect",
|
||||
SDL_DBus_CallVoidMethod(FCITX_DBUS_SERVICE, fcitx_client.ic_path, 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);
|
||||
}
|
||||
|
||||
@@ -368,6 +426,4 @@ SDL_Fcitx_PumpEvents(void)
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_FCITX_FRONTEND_H */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
@@ -43,7 +43,7 @@ static void
|
||||
InitIME()
|
||||
{
|
||||
static SDL_bool inited = SDL_FALSE;
|
||||
#ifdef HAVE_FCITX_FRONTEND_H
|
||||
#ifdef HAVE_FCITX
|
||||
const char *im_module = SDL_getenv("SDL_IM_MODULE");
|
||||
const char *xmodifiers = SDL_getenv("XMODIFIERS");
|
||||
#endif
|
||||
@@ -54,7 +54,7 @@ InitIME()
|
||||
inited = SDL_TRUE;
|
||||
|
||||
/* See if fcitx IME support is being requested */
|
||||
#ifdef HAVE_FCITX_FRONTEND_H
|
||||
#ifdef HAVE_FCITX
|
||||
if (!SDL_IME_Init_Real &&
|
||||
((im_module && SDL_strcmp(im_module, "fcitx") == 0) ||
|
||||
(!im_module && xmodifiers && SDL_strstr(xmodifiers, "@im=fcitx") != NULL))) {
|
||||
@@ -66,7 +66,7 @@ InitIME()
|
||||
SDL_IME_UpdateTextRect_Real = SDL_Fcitx_UpdateTextRect;
|
||||
SDL_IME_PumpEvents_Real = SDL_Fcitx_PumpEvents;
|
||||
}
|
||||
#endif /* HAVE_FCITX_FRONTEND_H */
|
||||
#endif /* HAVE_FCITX */
|
||||
|
||||
/* default to IBus */
|
||||
#ifdef HAVE_IBUS_IBUS_H
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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,9 @@
|
||||
|
||||
#ifdef __LINUX__
|
||||
|
||||
#include "SDL_error.h"
|
||||
#include "SDL_stdinc.h"
|
||||
#include "SDL_thread.h"
|
||||
|
||||
#if !SDL_THREADS_DISABLED
|
||||
#include <sys/time.h>
|
||||
@@ -30,8 +32,20 @@
|
||||
#include <pthread.h>
|
||||
#include "SDL_system.h"
|
||||
|
||||
#if SDL_USE_LIBDBUS
|
||||
/* RLIMIT_RTTIME requires kernel >= 2.6.25 and is in glibc >= 2.14 */
|
||||
#ifndef RLIMIT_RTTIME
|
||||
#define RLIMIT_RTTIME 15
|
||||
#endif
|
||||
/* SCHED_RESET_ON_FORK is in kernel >= 2.6.32. */
|
||||
#ifndef SCHED_RESET_ON_FORK
|
||||
#define SCHED_RESET_ON_FORK 0x40000000
|
||||
#endif
|
||||
|
||||
#include "SDL_dbus.h"
|
||||
|
||||
#if SDL_USE_LIBDBUS
|
||||
#include <sched.h>
|
||||
|
||||
/* d-bus queries to org.freedesktop.RealtimeKit1. */
|
||||
#define RTKIT_DBUS_NODE "org.freedesktop.RealtimeKit1"
|
||||
#define RTKIT_DBUS_PATH "/org/freedesktop/RealtimeKit1"
|
||||
@@ -39,6 +53,8 @@
|
||||
|
||||
static pthread_once_t rtkit_initialize_once = PTHREAD_ONCE_INIT;
|
||||
static Sint32 rtkit_min_nice_level = -20;
|
||||
static Sint32 rtkit_max_realtime_priority = 99;
|
||||
static Sint64 rtkit_max_rttime_usec = 200000;
|
||||
|
||||
static void
|
||||
rtkit_initialize()
|
||||
@@ -50,10 +66,84 @@ rtkit_initialize()
|
||||
DBUS_TYPE_INT32, &rtkit_min_nice_level)) {
|
||||
rtkit_min_nice_level = -20;
|
||||
}
|
||||
|
||||
/* Try getting maximum realtime priority: this can be less than the POSIX default (99). */
|
||||
if (!dbus || !SDL_DBus_QueryPropertyOnConnection(dbus->system_conn, RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "MaxRealtimePriority",
|
||||
DBUS_TYPE_INT32, &rtkit_max_realtime_priority)) {
|
||||
rtkit_max_realtime_priority = 99;
|
||||
}
|
||||
|
||||
/* Try getting maximum rttime allowed by rtkit: exceeding this value will result in SIGKILL */
|
||||
if (!dbus || !SDL_DBus_QueryPropertyOnConnection(dbus->system_conn, RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "RTTimeUSecMax",
|
||||
DBUS_TYPE_INT64, &rtkit_max_rttime_usec)) {
|
||||
rtkit_max_rttime_usec = 200000;
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
rtkit_setpriority(pid_t thread, int nice_level)
|
||||
rtkit_initialize_realtime_thread()
|
||||
{
|
||||
// Following is an excerpt from rtkit README that outlines the requirements
|
||||
// a thread must meet before making rtkit requests:
|
||||
//
|
||||
// * Only clients with RLIMIT_RTTIME set will get RT scheduling
|
||||
//
|
||||
// * RT scheduling will only be handed out to processes with
|
||||
// SCHED_RESET_ON_FORK set to guarantee that the scheduling
|
||||
// settings cannot 'leak' to child processes, thus making sure
|
||||
// that 'RT fork bombs' cannot be used to bypass RLIMIT_RTTIME
|
||||
// and take the system down.
|
||||
//
|
||||
// * Limits are enforced on all user controllable resources, only
|
||||
// a maximum number of users, processes, threads can request RT
|
||||
// scheduling at the same time.
|
||||
//
|
||||
// * Only a limited number of threads may be made RT in a
|
||||
// specific time frame.
|
||||
//
|
||||
// * Client authorization is verified with PolicyKit
|
||||
|
||||
int err;
|
||||
struct rlimit rlimit;
|
||||
int nLimit = RLIMIT_RTTIME;
|
||||
pid_t nPid = 0; //self
|
||||
int nSchedPolicy = sched_getscheduler(nPid) | SCHED_RESET_ON_FORK;
|
||||
struct sched_param schedParam = {};
|
||||
|
||||
// Requirement #1: Set RLIMIT_RTTIME
|
||||
err = getrlimit(nLimit, &rlimit);
|
||||
if (err)
|
||||
{
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
// Current rtkit allows a max of 200ms right now
|
||||
rlimit.rlim_max = rtkit_max_rttime_usec;
|
||||
rlimit.rlim_cur = rlimit.rlim_max / 2;
|
||||
err = setrlimit(nLimit, &rlimit);
|
||||
if (err)
|
||||
{
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
// Requirement #2: Add SCHED_RESET_ON_FORK to the scheduler policy
|
||||
err = sched_getparam(nPid, &schedParam);
|
||||
if (err)
|
||||
{
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
err = sched_setscheduler(nPid, nSchedPolicy, &schedParam);
|
||||
if (err)
|
||||
{
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
rtkit_setpriority_nice(pid_t thread, int nice_level)
|
||||
{
|
||||
Uint64 ui64 = (Uint64)thread;
|
||||
Sint32 si32 = (Sint32)nice_level;
|
||||
@@ -72,10 +162,42 @@ rtkit_setpriority(pid_t thread, int nice_level)
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
rtkit_setpriority_realtime(pid_t thread, int rt_priority)
|
||||
{
|
||||
Uint64 ui64 = (Uint64)thread;
|
||||
Uint32 ui32 = (Uint32)rt_priority;
|
||||
SDL_DBusContext *dbus = SDL_DBus_GetContext();
|
||||
|
||||
pthread_once(&rtkit_initialize_once, rtkit_initialize);
|
||||
|
||||
if (ui32 > rtkit_max_realtime_priority)
|
||||
ui32 = rtkit_max_realtime_priority;
|
||||
|
||||
// We always perform the thread state changes necessary for rtkit.
|
||||
// This wastes some system calls if the state is already set but
|
||||
// typically code sets a thread priority and leaves it so it's
|
||||
// not expected that this wasted effort will be an issue.
|
||||
// We also do not quit if this fails, we let the rtkit request
|
||||
// go through to determine whether it really needs to fail or not.
|
||||
rtkit_initialize_realtime_thread();
|
||||
|
||||
if (!dbus || !SDL_DBus_CallMethodOnConnection(dbus->system_conn,
|
||||
RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "MakeThreadRealtime",
|
||||
DBUS_TYPE_UINT64, &ui64, DBUS_TYPE_UINT32, &ui32, DBUS_TYPE_INVALID,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
#else
|
||||
|
||||
#define rtkit_max_realtime_priority 99
|
||||
|
||||
#endif /* dbus */
|
||||
#endif /* threads */
|
||||
|
||||
|
||||
/* this is a public symbol, so it has to exist even if threads are disabled. */
|
||||
int
|
||||
SDL_LinuxSetThreadPriority(Sint64 threadID, int priority)
|
||||
@@ -88,18 +210,19 @@ SDL_LinuxSetThreadPriority(Sint64 threadID, int priority)
|
||||
}
|
||||
|
||||
#if SDL_USE_LIBDBUS
|
||||
/* Note that this fails if you're trying to set high priority
|
||||
and you don't have root permission. BUT DON'T RUN AS ROOT!
|
||||
|
||||
You can grant the ability to increase thread priority by
|
||||
running the following command on your application binary:
|
||||
sudo setcap 'cap_sys_nice=eip' <application>
|
||||
|
||||
Let's try setting priority with RealtimeKit...
|
||||
/* Note that this fails you most likely:
|
||||
* Have your process's scheduler incorrectly configured.
|
||||
See the requirements at:
|
||||
http://git.0pointer.net/rtkit.git/tree/README#n16
|
||||
* Encountered dbus/polkit security restrictions. Note
|
||||
that the RealtimeKit1 dbus endpoint is inaccessible
|
||||
over ssh connections for most common distro configs.
|
||||
You might want to check your local config for details:
|
||||
/usr/share/polkit-1/actions/org.freedesktop.RealtimeKit1.policy
|
||||
|
||||
README and sample code at: http://git.0pointer.net/rtkit.git
|
||||
*/
|
||||
if (rtkit_setpriority((pid_t)threadID, priority)) {
|
||||
if (rtkit_setpriority_nice((pid_t)threadID, priority)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -108,6 +231,69 @@ SDL_LinuxSetThreadPriority(Sint64 threadID, int priority)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* this is a public symbol, so it has to exist even if threads are disabled. */
|
||||
int
|
||||
SDL_LinuxSetThreadPriorityAndPolicy(Sint64 threadID, int sdlPriority, int schedPolicy)
|
||||
{
|
||||
#if SDL_THREADS_DISABLED
|
||||
return SDL_Unsupported();
|
||||
#else
|
||||
int osPriority;
|
||||
|
||||
if (schedPolicy == SCHED_RR || schedPolicy == SCHED_FIFO) {
|
||||
if (sdlPriority == SDL_THREAD_PRIORITY_LOW) {
|
||||
osPriority = 1;
|
||||
} else if (sdlPriority == SDL_THREAD_PRIORITY_HIGH) {
|
||||
osPriority = rtkit_max_realtime_priority * 3 / 4;
|
||||
} else if (sdlPriority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
|
||||
osPriority = rtkit_max_realtime_priority;
|
||||
} else {
|
||||
osPriority = rtkit_max_realtime_priority / 2;
|
||||
}
|
||||
} else {
|
||||
if (sdlPriority == SDL_THREAD_PRIORITY_LOW) {
|
||||
osPriority = 19;
|
||||
} else if (sdlPriority == SDL_THREAD_PRIORITY_HIGH) {
|
||||
osPriority = -10;
|
||||
} else if (sdlPriority == SDL_THREAD_PRIORITY_TIME_CRITICAL) {
|
||||
osPriority = -20;
|
||||
} else {
|
||||
osPriority = 0;
|
||||
}
|
||||
|
||||
if (setpriority(PRIO_PROCESS, (id_t)threadID, osPriority) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if SDL_USE_LIBDBUS
|
||||
/* Note that this fails you most likely:
|
||||
* Have your process's scheduler incorrectly configured.
|
||||
See the requirements at:
|
||||
http://git.0pointer.net/rtkit.git/tree/README#n16
|
||||
* Encountered dbus/polkit security restrictions. Note
|
||||
that the RealtimeKit1 dbus endpoint is inaccessible
|
||||
over ssh connections for most common distro configs.
|
||||
You might want to check your local config for details:
|
||||
/usr/share/polkit-1/actions/org.freedesktop.RealtimeKit1.policy
|
||||
|
||||
README and sample code at: http://git.0pointer.net/rtkit.git
|
||||
*/
|
||||
if (schedPolicy == SCHED_RR || schedPolicy == SCHED_FIFO) {
|
||||
if (rtkit_setpriority_realtime((pid_t)threadID, osPriority)) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (rtkit_setpriority_nice((pid_t)threadID, osPriority)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return SDL_SetError("setpriority() failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* __LINUX__ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
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,8 +32,10 @@
|
||||
#include <linux/input.h>
|
||||
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_evdev_capabilities.h"
|
||||
#include "SDL_loadso.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_hints.h"
|
||||
#include "../unix/SDL_poll.h"
|
||||
|
||||
static const char *SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" };
|
||||
@@ -290,12 +292,6 @@ SDL_UDEV_LoadLibrary(void)
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
|
||||
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
|
||||
#define OFF(x) ((x)%BITS_PER_LONG)
|
||||
#define LONG(x) ((x)/BITS_PER_LONG)
|
||||
#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
|
||||
|
||||
static void get_caps(struct udev_device *dev, struct udev_device *pdev, const char *attr, unsigned long *bitmask, size_t bitmask_len)
|
||||
{
|
||||
const char *value;
|
||||
@@ -329,13 +325,11 @@ static void get_caps(struct udev_device *dev, struct udev_device *pdev, const ch
|
||||
static int
|
||||
guess_device_class(struct udev_device *dev)
|
||||
{
|
||||
int devclass = 0;
|
||||
struct udev_device *pdev;
|
||||
unsigned long bitmask_ev[NBITS(EV_MAX)];
|
||||
unsigned long bitmask_abs[NBITS(ABS_MAX)];
|
||||
unsigned long bitmask_key[NBITS(KEY_MAX)];
|
||||
unsigned long bitmask_rel[NBITS(REL_MAX)];
|
||||
unsigned long keyboard_mask;
|
||||
|
||||
/* walk up the parental chain until we find the real input device; the
|
||||
* argument is very likely a subdevice of this, like eventN */
|
||||
@@ -352,48 +346,10 @@ guess_device_class(struct udev_device *dev)
|
||||
get_caps(dev, pdev, "capabilities/rel", bitmask_rel, SDL_arraysize(bitmask_rel));
|
||||
get_caps(dev, pdev, "capabilities/key", bitmask_key, SDL_arraysize(bitmask_key));
|
||||
|
||||
if (test_bit(EV_ABS, bitmask_ev) &&
|
||||
test_bit(ABS_X, bitmask_abs) && test_bit(ABS_Y, bitmask_abs)) {
|
||||
if (test_bit(BTN_STYLUS, bitmask_key) || test_bit(BTN_TOOL_PEN, bitmask_key)) {
|
||||
; /* ID_INPUT_TABLET */
|
||||
} else if (test_bit(BTN_TOOL_FINGER, bitmask_key) && !test_bit(BTN_TOOL_PEN, bitmask_key)) {
|
||||
; /* ID_INPUT_TOUCHPAD */
|
||||
} else if (test_bit(BTN_MOUSE, bitmask_key)) {
|
||||
devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */
|
||||
} else if (test_bit(BTN_TOUCH, bitmask_key)) {
|
||||
/* TODO: better determining between touchscreen and multitouch touchpad,
|
||||
see https://github.com/systemd/systemd/blob/master/src/udev/udev-builtin-input_id.c */
|
||||
devclass |= SDL_UDEV_DEVICE_TOUCHSCREEN; /* ID_INPUT_TOUCHSCREEN */
|
||||
}
|
||||
|
||||
if (test_bit(BTN_TRIGGER, bitmask_key) ||
|
||||
test_bit(BTN_A, bitmask_key) ||
|
||||
test_bit(BTN_1, bitmask_key) ||
|
||||
test_bit(ABS_RX, bitmask_abs) ||
|
||||
test_bit(ABS_RY, bitmask_abs) ||
|
||||
test_bit(ABS_RZ, bitmask_abs) ||
|
||||
test_bit(ABS_THROTTLE, bitmask_abs) ||
|
||||
test_bit(ABS_RUDDER, bitmask_abs) ||
|
||||
test_bit(ABS_WHEEL, bitmask_abs) ||
|
||||
test_bit(ABS_GAS, bitmask_abs) ||
|
||||
test_bit(ABS_BRAKE, bitmask_abs)) {
|
||||
devclass |= SDL_UDEV_DEVICE_JOYSTICK; /* ID_INPUT_JOYSTICK */
|
||||
}
|
||||
}
|
||||
|
||||
if (test_bit(EV_REL, bitmask_ev) &&
|
||||
test_bit(REL_X, bitmask_rel) && test_bit(REL_Y, bitmask_rel) &&
|
||||
test_bit(BTN_MOUSE, bitmask_key)) {
|
||||
devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */
|
||||
}
|
||||
|
||||
/* the first 32 bits are ESC, numbers, and Q to D; if we have any of
|
||||
* those, consider it a keyboard device; do not test KEY_RESERVED, though */
|
||||
keyboard_mask = 0xFFFFFFFE;
|
||||
if ((bitmask_key[0] & keyboard_mask) != 0)
|
||||
devclass |= SDL_UDEV_DEVICE_KEYBOARD; /* ID_INPUT_KEYBOARD */
|
||||
|
||||
return devclass;
|
||||
return SDL_EVDEV_GuessDeviceClass(&bitmask_ev[0],
|
||||
&bitmask_abs[0],
|
||||
&bitmask_key[0],
|
||||
&bitmask_rel[0]);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -420,6 +376,12 @@ device_event(SDL_UDEV_deviceevent type, struct udev_device *dev)
|
||||
if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
|
||||
devclass |= SDL_UDEV_DEVICE_JOYSTICK;
|
||||
}
|
||||
|
||||
val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_ACCELEROMETER");
|
||||
if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE) &&
|
||||
val != NULL && SDL_strcmp(val, "1") == 0 ) {
|
||||
devclass |= SDL_UDEV_DEVICE_JOYSTICK;
|
||||
}
|
||||
|
||||
val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_MOUSE");
|
||||
if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user