Updates SDL to 2.0.5

This commit is contained in:
Areloch 2016-11-08 20:49:49 -06:00
parent 00a4a21e3f
commit 1e671bfc7a
274 changed files with 11502 additions and 4656 deletions

View file

@ -115,6 +115,16 @@ SDL_InitSubSystem(Uint32 flags)
/* Clear the error message */
SDL_ClearError();
if ((flags & SDL_INIT_GAMECONTROLLER)) {
/* game controller implies joystick */
flags |= SDL_INIT_JOYSTICK;
}
if ((flags & (SDL_INIT_VIDEO|SDL_INIT_JOYSTICK))) {
/* video or joystick implies events */
flags |= SDL_INIT_EVENTS;
}
#if SDL_VIDEO_DRIVER_WINDOWS
if ((flags & (SDL_INIT_HAPTIC|SDL_INIT_JOYSTICK))) {
if (SDL_HelperWindowCreate() < 0) {
@ -127,16 +137,6 @@ SDL_InitSubSystem(Uint32 flags)
SDL_TicksInit();
#endif
if ((flags & SDL_INIT_GAMECONTROLLER)) {
/* game controller implies joystick */
flags |= SDL_INIT_JOYSTICK;
}
if ((flags & (SDL_INIT_VIDEO|SDL_INIT_JOYSTICK))) {
/* video or joystick implies events */
flags |= SDL_INIT_EVENTS;
}
/* Initialize the event subsystem */
if ((flags & SDL_INIT_EVENTS)) {
#if !SDL_EVENTS_DISABLED
@ -443,6 +443,8 @@ SDL_GetPlatform()
return "Windows";
#elif __WINRT__
return "WinRT";
#elif __TVOS__
return "tvOS";
#elif __IPHONEOS__
return "iOS";
#elif __PSP__

View file

@ -116,6 +116,10 @@ SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
return -1;
}
#ifdef __GNUC__
#pragma GCC diagnostic push
#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.
*/
@ -216,6 +220,9 @@ SDL_GetErrorMsg(char *errstr, int maxlen)
}
return (errstr);
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
/* Available for backwards compatibility */
const char *

View file

@ -118,6 +118,19 @@ SDL_GetHint(const char *name)
return env;
}
SDL_bool
SDL_GetHintBoolean(const char *name, SDL_bool default_value)
{
const char *hint = SDL_GetHint(name);
if (!hint) {
return default_value;
}
if (*hint == '0' || SDL_strcasecmp(hint, "false") == 0) {
return SDL_FALSE;
}
return SDL_TRUE;
}
void
SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata)
{

View file

@ -324,7 +324,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
size_t length;
LPTSTR tstr;
#ifndef __WINRT__
#if !defined(HAVE_STDIO_H) && !defined(__WINRT__)
BOOL attachResult;
DWORD attachError;
unsigned long charsWritten;
@ -356,7 +356,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
}
}
#endif /* ifndef __WINRT__ */
#endif /* !defined(HAVE_STDIO_H) && !defined(__WINRT__) */
length = SDL_strlen(SDL_priority_prefixes[priority]) + 2 + SDL_strlen(message) + 1 + 1 + 1;
output = SDL_stack_alloc(char, length);
@ -366,7 +366,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
/* Output to debugger */
OutputDebugString(tstr);
#ifndef __WINRT__
#if !defined(HAVE_STDIO_H) && !defined(__WINRT__)
/* Screen output to stderr, if console was attached. */
if (consoleAttached == 1) {
if (!WriteConsole(stderrHandle, tstr, lstrlen(tstr), &charsWritten, NULL)) {
@ -376,7 +376,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
}
}
}
#endif /* ifndef __WINRT__ */
#endif /* !defined(HAVE_STDIO_H) && !defined(__WINRT__) */
SDL_free(tstr);
SDL_stack_free(output);

View file

@ -25,33 +25,29 @@
#include "SDL.h"
#include "SDL_audio.h"
#include "SDL_audio_c.h"
#include "SDL_audiomem.h"
#include "SDL_sysaudio.h"
#include "../thread/SDL_systhread.h"
#define _THIS SDL_AudioDevice *_this
static SDL_AudioDriver current_audio;
static SDL_AudioDevice *open_devices[16];
/* !!! FIXME: These are wordy and unlocalized... */
#define DEFAULT_OUTPUT_DEVNAME "System audio output device"
#define DEFAULT_INPUT_DEVNAME "System audio capture device"
/*
* Not all of these will be compiled and linked in, but it's convenient
* to have a complete list here and saves yet-another block of #ifdefs...
* Please see bootstrap[], below, for the actual #ifdef mess.
*/
extern AudioBootStrap PULSEAUDIO_bootstrap;
extern AudioBootStrap ALSA_bootstrap;
extern AudioBootStrap SNDIO_bootstrap;
extern AudioBootStrap BSD_AUDIO_bootstrap;
extern AudioBootStrap DSP_bootstrap;
extern AudioBootStrap ALSA_bootstrap;
extern AudioBootStrap PULSEAUDIO_bootstrap;
extern AudioBootStrap QSAAUDIO_bootstrap;
extern AudioBootStrap SUNAUDIO_bootstrap;
extern AudioBootStrap ARTS_bootstrap;
extern AudioBootStrap ESD_bootstrap;
extern AudioBootStrap NACLAUD_bootstrap;
extern AudioBootStrap NACLAUDIO_bootstrap;
extern AudioBootStrap NAS_bootstrap;
extern AudioBootStrap XAUDIO2_bootstrap;
extern AudioBootStrap DSOUND_bootstrap;
@ -59,18 +55,13 @@ extern AudioBootStrap WINMM_bootstrap;
extern AudioBootStrap PAUDIO_bootstrap;
extern AudioBootStrap HAIKUAUDIO_bootstrap;
extern AudioBootStrap COREAUDIO_bootstrap;
extern AudioBootStrap SNDMGR_bootstrap;
extern AudioBootStrap DISKAUD_bootstrap;
extern AudioBootStrap DUMMYAUD_bootstrap;
extern AudioBootStrap DCAUD_bootstrap;
extern AudioBootStrap DART_bootstrap;
extern AudioBootStrap NDSAUD_bootstrap;
extern AudioBootStrap DISKAUDIO_bootstrap;
extern AudioBootStrap DUMMYAUDIO_bootstrap;
extern AudioBootStrap FUSIONSOUND_bootstrap;
extern AudioBootStrap ANDROIDAUD_bootstrap;
extern AudioBootStrap PSPAUD_bootstrap;
extern AudioBootStrap ANDROIDAUDIO_bootstrap;
extern AudioBootStrap PSPAUDIO_bootstrap;
extern AudioBootStrap SNDIO_bootstrap;
extern AudioBootStrap EmscriptenAudio_bootstrap;
extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
/* Available audio drivers */
static const AudioBootStrap *const bootstrap[] = {
@ -102,7 +93,7 @@ static const AudioBootStrap *const bootstrap[] = {
&ESD_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_NACL
&NACLAUD_bootstrap,
&NACLAUDIO_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_NAS
&NAS_bootstrap,
@ -126,22 +117,22 @@ static const AudioBootStrap *const bootstrap[] = {
&COREAUDIO_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_DISK
&DISKAUD_bootstrap,
&DISKAUDIO_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_DUMMY
&DUMMYAUD_bootstrap,
&DUMMYAUDIO_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_FUSIONSOUND
&FUSIONSOUND_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_ANDROID
&ANDROIDAUD_bootstrap,
&ANDROIDAUDIO_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_PSP
&PSPAUD_bootstrap,
&PSPAUDIO_bootstrap,
#endif
#if SDL_AUDIO_DRIVER_EMSCRIPTEN
&EmscriptenAudio_bootstrap,
&EMSCRIPTENAUDIO_bootstrap,
#endif
NULL
};
@ -165,7 +156,7 @@ SDL_AudioDetectDevices_Default(void)
{
/* you have to write your own implementation if these assertions fail. */
SDL_assert(current_audio.impl.OnlyHasDefaultOutputDevice);
SDL_assert(current_audio.impl.OnlyHasDefaultInputDevice || !current_audio.impl.HasCaptureSupport);
SDL_assert(current_audio.impl.OnlyHasDefaultCaptureDevice || !current_audio.impl.HasCaptureSupport);
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) ((size_t) 0x1));
if (current_audio.impl.HasCaptureSupport) {
@ -200,8 +191,19 @@ SDL_AudioGetDeviceBuf_Default(_THIS)
return NULL;
}
static int
SDL_AudioCaptureFromDevice_Default(_THIS, void *buffer, int buflen)
{
return -1; /* just fail immediately. */
}
static void
SDL_AudioWaitDone_Default(_THIS)
SDL_AudioFlushCapture_Default(_THIS)
{ /* no-op. */
}
static void
SDL_AudioPrepareToClose_Default(_THIS)
{ /* no-op. */
}
@ -257,15 +259,28 @@ SDL_AudioUnlockDevice_Default(SDL_AudioDevice * device)
}
}
static void
SDL_AudioLockOrUnlockDeviceWithNoMixerLock(SDL_AudioDevice * device)
{
}
static void
finalize_audio_entry_points(void)
finish_audio_entry_points_init(void)
{
/*
* Fill in stub functions for unused driver entry points. This lets us
* blindly call them without having to check for validity first.
*/
if (current_audio.impl.SkipMixerLock) {
if (current_audio.impl.LockDevice == NULL) {
current_audio.impl.LockDevice = SDL_AudioLockOrUnlockDeviceWithNoMixerLock;
}
if (current_audio.impl.UnlockDevice == NULL) {
current_audio.impl.UnlockDevice = SDL_AudioLockOrUnlockDeviceWithNoMixerLock;
}
}
#define FILL_STUB(x) \
if (current_audio.impl.x == NULL) { \
current_audio.impl.x = SDL_Audio##x##_Default; \
@ -277,7 +292,9 @@ finalize_audio_entry_points(void)
FILL_STUB(PlayDevice);
FILL_STUB(GetPendingBytes);
FILL_STUB(GetDeviceBuf);
FILL_STUB(WaitDone);
FILL_STUB(CaptureFromDevice);
FILL_STUB(FlushCapture);
FILL_STUB(PrepareToClose);
FILL_STUB(CloseDevice);
FILL_STUB(LockDevice);
FILL_STUB(UnlockDevice);
@ -316,7 +333,7 @@ add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices,
static SDL_INLINE int
add_capture_device(const char *name, void *handle)
{
/* !!! FIXME: add this later. SDL_assert(current_audio.impl.HasCaptureSupport);*/
SDL_assert(current_audio.impl.HasCaptureSupport);
return add_audio_device(name, handle, &current_audio.inputDevices, &current_audio.inputDeviceCount);
}
@ -365,14 +382,14 @@ void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
{
SDL_assert(get_audio_device(device->id) == device);
if (!device->enabled) {
if (!SDL_AtomicGet(&device->enabled)) {
return;
}
/* Ends the audio callback and mark the device as STOPPED, but the
app still needs to close the device to free resources. */
current_audio.impl.LockDevice(device);
device->enabled = 0;
SDL_AtomicSet(&device->enabled, 0);
current_audio.impl.UnlockDevice(device);
/* Post the event, if desired */
@ -404,13 +421,26 @@ mark_device_removed(void *handle, SDL_AudioDeviceItem *devices, SDL_bool *remove
void
SDL_RemoveAudioDevice(const int iscapture, void *handle)
{
int device_index;
SDL_AudioDevice *device = NULL;
SDL_LockMutex(current_audio.detectionLock);
if (iscapture) {
mark_device_removed(handle, current_audio.inputDevices, &current_audio.captureDevicesRemoved);
} else {
mark_device_removed(handle, current_audio.outputDevices, &current_audio.outputDevicesRemoved);
}
for (device_index = 0; device_index < SDL_arraysize(open_devices); device_index++)
{
device = open_devices[device_index];
if (device != NULL && device->handle == handle)
{
SDL_OpenedAudioDeviceDisconnected(device);
break;
}
}
SDL_UnlockMutex(current_audio.detectionLock);
current_audio.impl.FreeDeviceHandle(handle);
}
@ -420,77 +450,24 @@ SDL_RemoveAudioDevice(const int iscapture, void *handle)
/* this expects that you managed thread safety elsewhere. */
static void
free_audio_queue(SDL_AudioBufferQueue *buffer)
free_audio_queue(SDL_AudioBufferQueue *packet)
{
while (buffer) {
SDL_AudioBufferQueue *next = buffer->next;
SDL_free(buffer);
buffer = next;
while (packet) {
SDL_AudioBufferQueue *next = packet->next;
SDL_free(packet);
packet = next;
}
}
static void SDLCALL
SDL_BufferQueueDrainCallback(void *userdata, Uint8 *stream, int _len)
/* NOTE: This assumes you'll hold the mixer lock before calling! */
static int
queue_audio_to_device(SDL_AudioDevice *device, const Uint8 *data, Uint32 len)
{
/* this function always holds the mixer lock before being called. */
Uint32 len = (Uint32) _len;
SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
SDL_AudioBufferQueue *buffer;
SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */
SDL_assert(_len >= 0); /* this shouldn't ever happen, right?! */
while ((len > 0) && ((buffer = device->buffer_queue_head) != NULL)) {
const Uint32 avail = buffer->datalen - buffer->startpos;
const Uint32 cpy = SDL_min(len, avail);
SDL_assert(device->queued_bytes >= avail);
SDL_memcpy(stream, buffer->data + buffer->startpos, cpy);
buffer->startpos += cpy;
stream += cpy;
device->queued_bytes -= cpy;
len -= cpy;
if (buffer->startpos == buffer->datalen) { /* packet is done, put it in the pool. */
device->buffer_queue_head = buffer->next;
SDL_assert((buffer->next != NULL) || (buffer == device->buffer_queue_tail));
buffer->next = device->buffer_queue_pool;
device->buffer_queue_pool = buffer;
}
}
SDL_assert((device->buffer_queue_head != NULL) == (device->queued_bytes != 0));
if (len > 0) { /* fill any remaining space in the stream with silence. */
SDL_assert(device->buffer_queue_head == NULL);
SDL_memset(stream, device->spec.silence, len);
}
if (device->buffer_queue_head == NULL) {
device->buffer_queue_tail = NULL; /* in case we drained the queue entirely. */
}
}
int
SDL_QueueAudio(SDL_AudioDeviceID devid, const void *_data, Uint32 len)
{
SDL_AudioDevice *device = get_audio_device(devid);
const Uint8 *data = (const Uint8 *) _data;
SDL_AudioBufferQueue *orighead;
SDL_AudioBufferQueue *origtail;
Uint32 origlen;
Uint32 datalen;
if (!device) {
return -1; /* get_audio_device() will have set the error state */
}
if (device->spec.callback != SDL_BufferQueueDrainCallback) {
return SDL_SetError("Audio device has a callback, queueing not allowed");
}
current_audio.impl.LockDevice(device);
orighead = device->buffer_queue_head;
origtail = device->buffer_queue_tail;
origlen = origtail ? origtail->datalen : 0;
@ -520,8 +497,6 @@ SDL_QueueAudio(SDL_AudioDeviceID devid, const void *_data, Uint32 len)
device->buffer_queue_tail = origtail;
device->buffer_queue_pool = NULL;
current_audio.impl.UnlockDevice(device);
free_audio_queue(packet); /* give back what we can. */
return SDL_OutOfMemory();
@ -548,22 +523,142 @@ SDL_QueueAudio(SDL_AudioDeviceID devid, const void *_data, Uint32 len)
device->queued_bytes += datalen;
}
current_audio.impl.UnlockDevice(device);
return 0;
}
/* NOTE: This assumes you'll hold the mixer lock before calling! */
static Uint32
dequeue_audio_from_device(SDL_AudioDevice *device, Uint8 *stream, Uint32 len)
{
SDL_AudioBufferQueue *packet;
Uint8 *ptr = stream;
while ((len > 0) && ((packet = device->buffer_queue_head) != NULL)) {
const Uint32 avail = packet->datalen - packet->startpos;
const Uint32 cpy = SDL_min(len, avail);
SDL_assert(device->queued_bytes >= avail);
SDL_memcpy(ptr, packet->data + packet->startpos, cpy);
packet->startpos += cpy;
ptr += cpy;
device->queued_bytes -= cpy;
len -= cpy;
if (packet->startpos == packet->datalen) { /* packet is done, put it in the pool. */
device->buffer_queue_head = packet->next;
SDL_assert((packet->next != NULL) || (packet == device->buffer_queue_tail));
packet->next = device->buffer_queue_pool;
device->buffer_queue_pool = packet;
}
}
SDL_assert((device->buffer_queue_head != NULL) == (device->queued_bytes != 0));
if (device->buffer_queue_head == NULL) {
device->buffer_queue_tail = NULL; /* in case we drained the queue entirely. */
}
return (Uint32) (ptr - stream);
}
static void SDLCALL
SDL_BufferQueueDrainCallback(void *userdata, Uint8 *stream, int len)
{
/* this function always holds the mixer lock before being called. */
SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
Uint32 written;
SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */
SDL_assert(!device->iscapture); /* this shouldn't ever happen, right?! */
SDL_assert(len >= 0); /* this shouldn't ever happen, right?! */
written = dequeue_audio_from_device(device, stream, (Uint32) len);
stream += written;
len -= (int) written;
if (len > 0) { /* fill any remaining space in the stream with silence. */
SDL_assert(device->buffer_queue_head == NULL);
SDL_memset(stream, device->spec.silence, len);
}
}
static void SDLCALL
SDL_BufferQueueFillCallback(void *userdata, Uint8 *stream, int len)
{
/* this function always holds the mixer lock before being called. */
SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */
SDL_assert(device->iscapture); /* this shouldn't ever happen, right?! */
SDL_assert(len >= 0); /* this shouldn't ever happen, right?! */
/* note that if this needs to allocate more space and run out of memory,
we have no choice but to quietly drop the data and hope it works out
later, but you probably have bigger problems in this case anyhow. */
queue_audio_to_device(device, stream, (Uint32) len);
}
int
SDL_QueueAudio(SDL_AudioDeviceID devid, const void *data, Uint32 len)
{
SDL_AudioDevice *device = get_audio_device(devid);
int rc = 0;
if (!device) {
return -1; /* get_audio_device() will have set the error state */
} else if (device->iscapture) {
return SDL_SetError("This is a capture device, queueing not allowed");
} else if (device->spec.callback != SDL_BufferQueueDrainCallback) {
return SDL_SetError("Audio device has a callback, queueing not allowed");
}
if (len > 0) {
current_audio.impl.LockDevice(device);
rc = queue_audio_to_device(device, data, len);
current_audio.impl.UnlockDevice(device);
}
return rc;
}
Uint32
SDL_DequeueAudio(SDL_AudioDeviceID devid, void *data, Uint32 len)
{
SDL_AudioDevice *device = get_audio_device(devid);
Uint32 rc;
if ( (len == 0) || /* nothing to do? */
(!device) || /* called with bogus device id */
(!device->iscapture) || /* playback devices can't dequeue */
(device->spec.callback != SDL_BufferQueueFillCallback) ) { /* not set for queueing */
return 0; /* just report zero bytes dequeued. */
}
current_audio.impl.LockDevice(device);
rc = dequeue_audio_from_device(device, data, len);
current_audio.impl.UnlockDevice(device);
return rc;
}
Uint32
SDL_GetQueuedAudioSize(SDL_AudioDeviceID devid)
{
Uint32 retval = 0;
SDL_AudioDevice *device = get_audio_device(devid);
if (!device) {
return 0;
}
/* Nothing to do unless we're set up for queueing. */
if (device && (device->spec.callback == SDL_BufferQueueDrainCallback)) {
if (device->spec.callback == SDL_BufferQueueDrainCallback) {
current_audio.impl.LockDevice(device);
retval = device->queued_bytes + current_audio.impl.GetPendingBytes(device);
current_audio.impl.UnlockDevice(device);
} else if (device->spec.callback == SDL_BufferQueueFillCallback) {
current_audio.impl.LockDevice(device);
retval = device->queued_bytes;
current_audio.impl.UnlockDevice(device);
}
return retval;
@ -573,25 +668,49 @@ void
SDL_ClearQueuedAudio(SDL_AudioDeviceID devid)
{
SDL_AudioDevice *device = get_audio_device(devid);
SDL_AudioBufferQueue *buffer = NULL;
SDL_AudioBufferQueue *packet;
if (!device) {
return; /* nothing to do. */
}
/* Blank out the device and release the mutex. Free it afterwards. */
current_audio.impl.LockDevice(device);
buffer = device->buffer_queue_head;
/* merge the available pool and the current queue into one list. */
packet = device->buffer_queue_head;
if (packet) {
device->buffer_queue_tail->next = device->buffer_queue_pool;
} else {
packet = device->buffer_queue_pool;
}
/* Remove the queued packets from the device. */
device->buffer_queue_tail = NULL;
device->buffer_queue_head = NULL;
device->queued_bytes = 0;
device->buffer_queue_pool = packet;
/* Keep up to two packets in the pool to reduce future malloc pressure. */
if (packet) {
if (!packet->next) {
packet = NULL; /* one packet (the only one) for the pool. */
} else {
SDL_AudioBufferQueue *next = packet->next->next;
packet->next->next = NULL; /* two packets for the pool. */
packet = next; /* rest will be freed. */
}
}
current_audio.impl.UnlockDevice(device);
free_audio_queue(buffer);
/* free any extra packets we didn't keep in the pool. */
free_audio_queue(packet);
}
/* The general mixing thread function */
int SDLCALL
static int SDLCALL
SDL_RunAudio(void *devicep)
{
SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
@ -600,7 +719,9 @@ SDL_RunAudio(void *devicep)
const int stream_len = (device->convert.needed) ? device->convert.len : device->spec.size;
Uint8 *stream;
void *udata = device->spec.userdata;
void (SDLCALL *fill) (void *, Uint8 *, int) = device->spec.callback;
void (SDLCALL *callback) (void *, Uint8 *, int) = device->spec.callback;
SDL_assert(!device->iscapture);
/* The audio mixing is always a high priority thread */
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
@ -610,11 +731,11 @@ SDL_RunAudio(void *devicep)
current_audio.impl.ThreadInit(device);
/* Loop, filling the audio buffers */
while (!device->shutdown) {
while (!SDL_AtomicGet(&device->shutdown)) {
/* Fill the current buffer with sound */
if (device->convert.needed) {
stream = device->convert.buf;
} else if (device->enabled) {
} else if (SDL_AtomicGet(&device->enabled)) {
stream = current_audio.impl.GetDeviceBuf(device);
} else {
/* if the device isn't enabled, we still write to the
@ -630,16 +751,18 @@ SDL_RunAudio(void *devicep)
}
/* !!! FIXME: this should be LockDevice. */
SDL_LockMutex(device->mixer_lock);
if (device->paused) {
SDL_memset(stream, silence, stream_len);
} else {
(*fill) (udata, stream, stream_len);
if ( SDL_AtomicGet(&device->enabled) ) {
SDL_LockMutex(device->mixer_lock);
if (SDL_AtomicGet(&device->paused)) {
SDL_memset(stream, silence, stream_len);
} else {
(*callback) (udata, stream, stream_len);
}
SDL_UnlockMutex(device->mixer_lock);
}
SDL_UnlockMutex(device->mixer_lock);
/* Convert the audio if necessary */
if (device->enabled && device->convert.needed) {
if (device->convert.needed && SDL_AtomicGet(&device->enabled)) {
SDL_ConvertAudio(&device->convert);
stream = current_audio.impl.GetDeviceBuf(device);
if (stream == NULL) {
@ -659,8 +782,91 @@ SDL_RunAudio(void *devicep)
}
}
current_audio.impl.PrepareToClose(device);
/* Wait for the audio to drain. */
current_audio.impl.WaitDone(device);
SDL_Delay(((device->spec.samples * 1000) / device->spec.freq) * 2);
return 0;
}
/* The general capture thread function */
static int SDLCALL
SDL_CaptureAudio(void *devicep)
{
SDL_AudioDevice *device = (SDL_AudioDevice *) devicep;
const int silence = (int) device->spec.silence;
const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq);
const int stream_len = (device->convert.needed) ? device->convert.len : device->spec.size;
Uint8 *stream;
void *udata = device->spec.userdata;
void (SDLCALL *callback) (void *, Uint8 *, int) = device->spec.callback;
SDL_assert(device->iscapture);
/* The audio mixing is always a high priority thread */
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
/* Perform any thread setup */
device->threadid = SDL_ThreadID();
current_audio.impl.ThreadInit(device);
/* Loop, filling the audio buffers */
while (!SDL_AtomicGet(&device->shutdown)) {
int still_need;
Uint8 *ptr;
if (!SDL_AtomicGet(&device->enabled) || SDL_AtomicGet(&device->paused)) {
SDL_Delay(delay); /* just so we don't cook the CPU. */
current_audio.impl.FlushCapture(device); /* dump anything pending. */
continue;
}
/* Fill the current buffer with sound */
still_need = stream_len;
if (device->convert.needed) {
ptr = stream = device->convert.buf;
} else {
/* just use the "fake" stream to hold data read from the device. */
ptr = stream = device->fake_stream;
}
/* We still read from the device when "paused" to keep the state sane,
and block when there isn't data so this thread isn't eating CPU.
But we don't process it further or call the app's callback. */
while (still_need > 0) {
const int rc = current_audio.impl.CaptureFromDevice(device, ptr, still_need);
SDL_assert(rc <= still_need); /* device should not overflow buffer. :) */
if (rc > 0) {
still_need -= rc;
ptr += rc;
} else { /* uhoh, device failed for some reason! */
SDL_OpenedAudioDeviceDisconnected(device);
break;
}
}
if (still_need > 0) {
/* Keep any data we already read, silence the rest. */
SDL_memset(ptr, silence, still_need);
}
if (device->convert.needed) {
SDL_ConvertAudio(&device->convert);
}
/* !!! FIXME: this should be LockDevice. */
SDL_LockMutex(device->mixer_lock);
if (SDL_AtomicGet(&device->paused)) {
current_audio.impl.FlushCapture(device); /* one snuck in! */
} else {
(*callback)(udata, stream, stream_len);
}
SDL_UnlockMutex(device->mixer_lock);
}
current_audio.impl.FlushCapture(device);
return 0;
}
@ -757,7 +963,7 @@ SDL_AudioInit(const char *driver_name)
current_audio.detectionLock = SDL_CreateMutex();
finalize_audio_entry_points();
finish_audio_entry_points_init();
/* Make sure we have a list of devices available at startup. */
current_audio.impl.DetectDevices();
@ -872,27 +1078,38 @@ SDL_GetAudioDeviceName(int index, int iscapture)
static void
close_audio_device(SDL_AudioDevice * device)
{
device->enabled = 0;
device->shutdown = 1;
if (!device) {
return;
}
if (device->id > 0) {
SDL_AudioDevice *opendev = open_devices[device->id - 1];
SDL_assert((opendev == device) || (opendev == NULL));
if (opendev == device) {
open_devices[device->id - 1] = NULL;
}
}
SDL_AtomicSet(&device->shutdown, 1);
SDL_AtomicSet(&device->enabled, 0);
if (device->thread != NULL) {
SDL_WaitThread(device->thread, NULL);
}
if (device->mixer_lock != NULL) {
SDL_DestroyMutex(device->mixer_lock);
}
SDL_FreeAudioMem(device->fake_stream);
SDL_free(device->fake_stream);
if (device->convert.needed) {
SDL_FreeAudioMem(device->convert.buf);
SDL_free(device->convert.buf);
}
if (device->opened) {
if (device->hidden != NULL) {
current_audio.impl.CloseDevice(device);
device->opened = 0;
}
free_audio_queue(device->buffer_queue_head);
free_audio_queue(device->buffer_queue_pool);
SDL_FreeAudioMem(device);
SDL_free(device);
}
@ -963,12 +1180,12 @@ open_audio_device(const char *devname, int iscapture,
const SDL_AudioSpec * desired, SDL_AudioSpec * obtained,
int allowed_changes, int min_id)
{
const SDL_bool is_internal_thread = (desired->callback != NULL);
SDL_AudioDeviceID id = 0;
SDL_AudioSpec _obtained;
SDL_AudioDevice *device;
SDL_bool build_cvt;
void *handle = NULL;
Uint32 stream_len;
int i = 0;
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
@ -981,6 +1198,7 @@ open_audio_device(const char *devname, int iscapture,
return 0;
}
/* !!! FIXME: there is a race condition here if two devices open from two threads at once. */
/* Find an available device ID... */
for (id = min_id - 1; id < SDL_arraysize(open_devices); id++) {
if (open_devices[id] == NULL) {
@ -1015,7 +1233,7 @@ open_audio_device(const char *devname, int iscapture,
* opens of the default system device.
*/
if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
if ((iscapture) && (current_audio.impl.OnlyHasDefaultCaptureDevice)) {
if ((devname) && (SDL_strcmp(devname, DEFAULT_INPUT_DEVNAME) != 0)) {
SDL_SetError("No such device");
return 0;
@ -1067,17 +1285,19 @@ open_audio_device(const char *devname, int iscapture,
}
}
device = (SDL_AudioDevice *) SDL_AllocAudioMem(sizeof(SDL_AudioDevice));
device = (SDL_AudioDevice *) SDL_calloc(1, sizeof (SDL_AudioDevice));
if (device == NULL) {
SDL_OutOfMemory();
return 0;
}
SDL_zerop(device);
device->id = id + 1;
device->spec = *obtained;
device->enabled = 1;
device->paused = 1;
device->iscapture = iscapture;
device->iscapture = iscapture ? SDL_TRUE : SDL_FALSE;
device->handle = handle;
SDL_AtomicSet(&device->shutdown, 0); /* just in case. */
SDL_AtomicSet(&device->paused, 1);
SDL_AtomicSet(&device->enabled, 1);
/* Create a mutex for locking the sound buffers */
if (!current_audio.impl.SkipMixerLock) {
@ -1093,7 +1313,10 @@ open_audio_device(const char *devname, int iscapture,
close_audio_device(device);
return 0;
}
device->opened = 1;
/* if your target really doesn't need it, set it to 0x1 or something. */
/* otherwise, close_audio_device() won't call impl.CloseDevice(). */
SDL_assert(device->hidden != NULL);
/* See if we need to do any conversion */
build_cvt = SDL_FALSE;
@ -1143,7 +1366,7 @@ open_audio_device(const char *devname, int iscapture,
device->convert.len_ratio);
device->convert.buf =
(Uint8 *) SDL_AllocAudioMem(device->convert.len *
(Uint8 *) SDL_malloc(device->convert.len *
device->convert.len_mult);
if (device->convert.buf == NULL) {
close_audio_device(device);
@ -1153,19 +1376,6 @@ open_audio_device(const char *devname, int iscapture,
}
}
/* Allocate a fake audio memory buffer */
stream_len = (device->convert.needed) ? device->convert.len_cvt : 0;
if (device->spec.size > stream_len) {
stream_len = device->spec.size;
}
SDL_assert(stream_len > 0);
device->fake_stream = (Uint8 *)SDL_AllocAudioMem(stream_len);
if (device->fake_stream == NULL) {
close_audio_device(device);
SDL_OutOfMemory();
return 0;
}
if (device->spec.callback == NULL) { /* use buffer queueing? */
/* pool a few packets to start. Enough for two callbacks. */
const int packetlen = SDL_AUDIOBUFFERQUEUE_PACKETLEN;
@ -1181,7 +1391,7 @@ open_audio_device(const char *devname, int iscapture,
}
}
device->spec.callback = SDL_BufferQueueDrainCallback;
device->spec.callback = iscapture ? SDL_BufferQueueFillCallback : SDL_BufferQueueDrainCallback;
device->spec.userdata = device;
}
@ -1191,21 +1401,30 @@ open_audio_device(const char *devname, int iscapture,
/* Start the audio thread if necessary */
if (!current_audio.impl.ProvidesOwnCallbackThread) {
/* Start the audio thread */
char name[64];
SDL_snprintf(name, sizeof (name), "SDLAudioDev%d", (int) device->id);
/* !!! FIXME: this is nasty. */
#if defined(__WIN32__) && !defined(HAVE_LIBC)
#undef SDL_CreateThread
#if SDL_DYNAMIC_API
device->thread = SDL_CreateThread_REAL(SDL_RunAudio, name, device, NULL, NULL);
#else
device->thread = SDL_CreateThread(SDL_RunAudio, name, device, NULL, NULL);
#endif
#else
device->thread = SDL_CreateThread(SDL_RunAudio, name, device);
#endif
/* !!! FIXME: we don't force the audio thread stack size here if it calls into user code, but maybe we should? */
/* buffer queueing callback only needs a few bytes, so make the stack tiny. */
const size_t stacksize = is_internal_thread ? 64 * 1024 : 0;
char threadname[64];
/* Allocate a fake audio buffer; only used by our internal threads. */
Uint32 stream_len = (device->convert.needed) ? device->convert.len_cvt : 0;
if (device->spec.size > stream_len) {
stream_len = device->spec.size;
}
SDL_assert(stream_len > 0);
device->fake_stream = (Uint8 *) SDL_malloc(stream_len);
if (device->fake_stream == NULL) {
close_audio_device(device);
SDL_OutOfMemory();
return 0;
}
SDL_snprintf(threadname, sizeof (threadname), "SDLAudioDev%d", (int) device->id);
device->thread = SDL_CreateThreadInternal(iscapture ? SDL_CaptureAudio : SDL_RunAudio, threadname, stacksize, device);
if (device->thread == NULL) {
SDL_CloseAudioDevice(device->id);
close_audio_device(device);
SDL_SetError("Couldn't create audio thread");
return 0;
}
@ -1258,8 +1477,8 @@ SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid)
{
SDL_AudioDevice *device = get_audio_device(devid);
SDL_AudioStatus status = SDL_AUDIO_STOPPED;
if (device && device->enabled) {
if (device->paused) {
if (device && SDL_AtomicGet(&device->enabled)) {
if (SDL_AtomicGet(&device->paused)) {
status = SDL_AUDIO_PAUSED;
} else {
status = SDL_AUDIO_PLAYING;
@ -1281,7 +1500,7 @@ SDL_PauseAudioDevice(SDL_AudioDeviceID devid, int pause_on)
SDL_AudioDevice *device = get_audio_device(devid);
if (device) {
current_audio.impl.LockDevice(device);
device->paused = pause_on;
SDL_AtomicSet(&device->paused, pause_on ? 1 : 0);
current_audio.impl.UnlockDevice(device);
}
}
@ -1328,11 +1547,7 @@ SDL_UnlockAudio(void)
void
SDL_CloseAudioDevice(SDL_AudioDeviceID devid)
{
SDL_AudioDevice *device = get_audio_device(devid);
if (device) {
close_audio_device(device);
open_devices[devid - 1] = NULL;
}
close_audio_device(get_audio_device(devid));
}
void
@ -1351,9 +1566,7 @@ SDL_AudioQuit(void)
}
for (i = 0; i < SDL_arraysize(open_devices); i++) {
if (open_devices[i] != NULL) {
SDL_CloseAudioDevice(i+1);
}
close_audio_device(open_devices[i]);
}
free_device_list(&current_audio.outputDevices, &current_audio.outputDeviceCount);

View file

@ -29,9 +29,6 @@ extern SDL_AudioFormat SDL_NextAudioFormat(void);
/* Function to calculate the size and silence for a SDL_AudioSpec */
extern void SDL_CalculateAudioSpec(SDL_AudioSpec * spec);
/* The actual mixing thread function */
extern int SDLCALL SDL_RunAudio(void *audiop);
/* this is used internally to access some autogenerated code. */
typedef struct
{

View file

@ -202,6 +202,54 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
}
break;
case AUDIO_U16LSB:
{
Uint16 src1, src2;
int dst_sample;
const int max_audioval = 0xFFFF;
len /= 2;
while (len--) {
src1 = ((src[1]) << 8 | src[0]);
ADJUST_VOLUME(src1, volume);
src2 = ((dst[1]) << 8 | dst[0]);
src += 2;
dst_sample = src1 + src2;
if (dst_sample > max_audioval) {
dst_sample = max_audioval;
}
dst[0] = dst_sample & 0xFF;
dst_sample >>= 8;
dst[1] = dst_sample & 0xFF;
dst += 2;
}
}
break;
case AUDIO_U16MSB:
{
Uint16 src1, src2;
int dst_sample;
const int max_audioval = 0xFFFF;
len /= 2;
while (len--) {
src1 = ((src[0]) << 8 | src[1]);
ADJUST_VOLUME(src1, volume);
src2 = ((dst[0]) << 8 | dst[1]);
src += 2;
dst_sample = src1 + src2;
if (dst_sample > max_audioval) {
dst_sample = max_audioval;
}
dst[1] = dst_sample & 0xFF;
dst_sample >>= 8;
dst[0] = dst_sample & 0xFF;
dst += 2;
}
}
break;
case AUDIO_S32LSB:
{
const Uint32 *src32 = (Uint32 *) src;
@ -313,7 +361,7 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format,
break;
default: /* If this happens... FIXME! */
SDL_SetError("SDL_MixAudio(): unknown audio format");
SDL_SetError("SDL_MixAudioFormat(): unknown audio format");
return;
}
}

View file

@ -26,6 +26,10 @@
#include "SDL_mutex.h"
#include "SDL_thread.h"
/* !!! FIXME: These are wordy and unlocalized... */
#define DEFAULT_OUTPUT_DEVNAME "System audio output device"
#define DEFAULT_INPUT_DEVNAME "System audio capture device"
/* The SDL audio driver */
typedef struct SDL_AudioDevice SDL_AudioDevice;
#define _THIS SDL_AudioDevice *_this
@ -75,7 +79,9 @@ typedef struct SDL_AudioDriverImpl
void (*PlayDevice) (_THIS);
int (*GetPendingBytes) (_THIS);
Uint8 *(*GetDeviceBuf) (_THIS);
void (*WaitDone) (_THIS);
int (*CaptureFromDevice) (_THIS, void *buffer, int buflen);
void (*FlushCapture) (_THIS);
void (*PrepareToClose) (_THIS); /**< Called between run and draining wait for playback devices */
void (*CloseDevice) (_THIS);
void (*LockDevice) (_THIS);
void (*UnlockDevice) (_THIS);
@ -87,10 +93,10 @@ typedef struct SDL_AudioDriverImpl
/* Some flags to push duplicate code into the core and reduce #ifdefs. */
/* !!! FIXME: these should be SDL_bool */
int ProvidesOwnCallbackThread;
int SkipMixerLock; /* !!! FIXME: do we need this anymore? */
int SkipMixerLock;
int HasCaptureSupport;
int OnlyHasDefaultOutputDevice;
int OnlyHasDefaultInputDevice;
int OnlyHasDefaultCaptureDevice;
int AllowsArbitraryDeviceNames;
} SDL_AudioDriverImpl;
@ -157,12 +163,10 @@ struct SDL_AudioDevice
SDL_AudioStreamer streamer;
/* Current state flags */
/* !!! FIXME: should be SDL_bool */
int iscapture;
int enabled; /* true if device is functioning and connected. */
int shutdown; /* true if we are signaling the play thread to end. */
int paused;
int opened;
SDL_atomic_t shutdown; /* true if we are signaling the play thread to end. */
SDL_atomic_t enabled; /* true if device is functioning and connected. */
SDL_atomic_t paused;
SDL_bool iscapture;
/* Fake audio buffer for when the audio hardware is busy */
Uint8 *fake_stream;
@ -183,6 +187,8 @@ struct SDL_AudioDevice
/* * * */
/* Data private to this driver */
struct SDL_PrivateAudioData *hidden;
void *handle;
};
#undef _THIS

View file

@ -504,7 +504,7 @@ SDL_LoadWAV_RW(SDL_RWops * src, int freesrc,
was_error = 1;
goto done;
}
SDL_memset(spec, 0, (sizeof *spec));
SDL_zerop(spec);
spec->freq = SDL_SwapLE32(format->frequency);
if (IEEE_float_encoded) {

View file

@ -29,9 +29,9 @@
#include <errno.h>
#include <string.h>
#include "SDL_assert.h"
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_alsa_audio.h"
@ -42,8 +42,10 @@
static int (*ALSA_snd_pcm_open)
(snd_pcm_t **, const char *, snd_pcm_stream_t, int);
static int (*ALSA_snd_pcm_close) (snd_pcm_t * pcm);
static snd_pcm_sframes_t(*ALSA_snd_pcm_writei)
static snd_pcm_sframes_t (*ALSA_snd_pcm_writei)
(snd_pcm_t *, const void *, snd_pcm_uframes_t);
static snd_pcm_sframes_t (*ALSA_snd_pcm_readi)
(snd_pcm_t *, void *, snd_pcm_uframes_t);
static int (*ALSA_snd_pcm_recover) (snd_pcm_t *, int, int);
static int (*ALSA_snd_pcm_prepare) (snd_pcm_t *);
static int (*ALSA_snd_pcm_drain) (snd_pcm_t *);
@ -85,6 +87,10 @@ static int (*ALSA_snd_pcm_nonblock) (snd_pcm_t *, int);
static int (*ALSA_snd_pcm_wait)(snd_pcm_t *, int);
static int (*ALSA_snd_pcm_sw_params_set_avail_min)
(snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
static int (*ALSA_snd_pcm_reset)(snd_pcm_t *);
static int (*ALSA_snd_device_name_hint) (int, const char *, void ***);
static char* (*ALSA_snd_device_name_get_hint) (const void *, const char *);
static int (*ALSA_snd_device_name_free_hint) (void **);
#ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
#define snd_pcm_hw_params_sizeof ALSA_snd_pcm_hw_params_sizeof
@ -118,6 +124,7 @@ load_alsa_syms(void)
SDL_ALSA_SYM(snd_pcm_open);
SDL_ALSA_SYM(snd_pcm_close);
SDL_ALSA_SYM(snd_pcm_writei);
SDL_ALSA_SYM(snd_pcm_readi);
SDL_ALSA_SYM(snd_pcm_recover);
SDL_ALSA_SYM(snd_pcm_prepare);
SDL_ALSA_SYM(snd_pcm_drain);
@ -144,6 +151,11 @@ load_alsa_syms(void)
SDL_ALSA_SYM(snd_pcm_nonblock);
SDL_ALSA_SYM(snd_pcm_wait);
SDL_ALSA_SYM(snd_pcm_sw_params_set_avail_min);
SDL_ALSA_SYM(snd_pcm_reset);
SDL_ALSA_SYM(snd_device_name_hint);
SDL_ALSA_SYM(snd_device_name_get_hint);
SDL_ALSA_SYM(snd_device_name_free_hint);
return 0;
}
@ -196,25 +208,27 @@ LoadALSALibrary(void)
#endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */
static const char *
get_audio_device(int channels)
get_audio_device(void *handle, const int channels)
{
const char *device;
device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */
if (device == NULL) {
switch (channels) {
case 6:
device = "plug:surround51";
break;
case 4:
device = "plug:surround40";
break;
default:
device = "default";
break;
}
if (handle != NULL) {
return (const char *) handle;
}
return device;
/* !!! FIXME: we also check "SDL_AUDIO_DEVICE_NAME" at the higher level. */
device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */
if (device != NULL) {
return device;
}
if (channels == 6) {
return "plug:surround51";
} else if (channels == 4) {
return "plug:surround40";
}
return "default";
}
@ -232,37 +246,37 @@ ALSA_WaitDevice(_THIS)
* "For Linux ALSA, this is FL-FR-RL-RR-C-LFE
* and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR"
*/
#define SWIZ6(T) \
T *ptr = (T *) this->hidden->mixbuf; \
#define SWIZ6(T, buf, numframes) \
T *ptr = (T *) buf; \
Uint32 i; \
for (i = 0; i < this->spec.samples; i++, ptr += 6) { \
for (i = 0; i < numframes; i++, ptr += 6) { \
T tmp; \
tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \
tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \
}
static SDL_INLINE void
swizzle_alsa_channels_6_64bit(_THIS)
swizzle_alsa_channels_6_64bit(void *buffer, Uint32 bufferlen)
{
SWIZ6(Uint64);
SWIZ6(Uint64, buffer, bufferlen);
}
static SDL_INLINE void
swizzle_alsa_channels_6_32bit(_THIS)
swizzle_alsa_channels_6_32bit(void *buffer, Uint32 bufferlen)
{
SWIZ6(Uint32);
SWIZ6(Uint32, buffer, bufferlen);
}
static SDL_INLINE void
swizzle_alsa_channels_6_16bit(_THIS)
swizzle_alsa_channels_6_16bit(void *buffer, Uint32 bufferlen)
{
SWIZ6(Uint16);
SWIZ6(Uint16, buffer, bufferlen);
}
static SDL_INLINE void
swizzle_alsa_channels_6_8bit(_THIS)
swizzle_alsa_channels_6_8bit(void *buffer, Uint32 bufferlen)
{
SWIZ6(Uint8);
SWIZ6(Uint8, buffer, bufferlen);
}
#undef SWIZ6
@ -273,18 +287,16 @@ swizzle_alsa_channels_6_8bit(_THIS)
* channels from Windows/Mac order to the format alsalib will want.
*/
static SDL_INLINE void
swizzle_alsa_channels(_THIS)
swizzle_alsa_channels(_THIS, void *buffer, Uint32 bufferlen)
{
if (this->spec.channels == 6) {
const Uint16 fmtsize = (this->spec.format & 0xFF); /* bits/channel. */
if (fmtsize == 16)
swizzle_alsa_channels_6_16bit(this);
else if (fmtsize == 8)
swizzle_alsa_channels_6_8bit(this);
else if (fmtsize == 32)
swizzle_alsa_channels_6_32bit(this);
else if (fmtsize == 64)
swizzle_alsa_channels_6_64bit(this);
switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
case 8: swizzle_alsa_channels_6_8bit(buffer, bufferlen); break;
case 16: swizzle_alsa_channels_6_16bit(buffer, bufferlen); break;
case 32: swizzle_alsa_channels_6_32bit(buffer, bufferlen); break;
case 64: swizzle_alsa_channels_6_64bit(buffer, bufferlen); break;
default: SDL_assert(!"unhandled bitsize"); break;
}
}
/* !!! FIXME: update this for 7.1 if needed, later. */
@ -294,19 +306,29 @@ swizzle_alsa_channels(_THIS)
static void
ALSA_PlayDevice(_THIS)
{
int status;
const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf;
const int frame_size = (((int) (this->spec.format & 0xFF)) / 8) *
const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
this->spec.channels;
snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples);
swizzle_alsa_channels(this);
swizzle_alsa_channels(this, this->hidden->mixbuf, frames_left);
while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
int status;
/* This wait is a work-around for a hang when USB devices are
unplugged. Normally it should not result in any waiting,
but in the case of a USB unplug, it serves as a way to
join the playback thread after the timeout occurs */
status = ALSA_snd_pcm_wait(this->hidden->pcm_handle, 1000);
if (status == 0) {
/*fprintf(stderr, "ALSA timeout waiting for available buffer space\n");*/
SDL_OpenedAudioDeviceDisconnected(this);
return;
}
while ( frames_left > 0 && this->enabled ) {
/* !!! FIXME: This works, but needs more testing before going live */
/* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */
status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
sample_buf, frames_left);
sample_buf, frames_left);
if (status < 0) {
if (status == -EAGAIN) {
@ -336,20 +358,71 @@ ALSA_GetDeviceBuf(_THIS)
return (this->hidden->mixbuf);
}
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) *
this->spec.channels;
const int total_frames = buflen / frame_size;
snd_pcm_uframes_t frames_left = total_frames;
SDL_assert((buflen % frame_size) == 0);
while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
/* !!! FIXME: This works, but needs more testing before going live */
/* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */
int status = ALSA_snd_pcm_readi(this->hidden->pcm_handle,
sample_buf, frames_left);
if (status < 0) {
/*printf("ALSA: capture error %d\n", status);*/
if (status == -EAGAIN) {
/* Apparently snd_pcm_recover() doesn't handle this case -
does it assume snd_pcm_wait() above? */
SDL_Delay(1);
continue;
}
status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
if (status < 0) {
/* Hmm, not much we can do - abort */
fprintf(stderr, "ALSA read failed (unrecoverable): %s\n",
ALSA_snd_strerror(status));
return -1;
}
continue;
}
/*printf("ALSA: captured %d bytes\n", status * frame_size);*/
sample_buf += status * frame_size;
frames_left -= status;
}
swizzle_alsa_channels(this, buffer, total_frames - frames_left);
return (total_frames - frames_left) * frame_size;
}
static void
ALSA_FlushCapture(_THIS)
{
ALSA_snd_pcm_reset(this->hidden->pcm_handle);
}
static void
ALSA_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->pcm_handle) {
ALSA_snd_pcm_drain(this->hidden->pcm_handle);
ALSA_snd_pcm_close(this->hidden->pcm_handle);
this->hidden->pcm_handle = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
if (this->hidden->pcm_handle) {
/* Wait for the submitted audio to drain
ALSA_snd_pcm_drop() can hang, so don't use that.
*/
Uint32 delay = ((this->spec.samples * 1000) / this->spec.freq) * 2;
SDL_Delay(delay);
ALSA_snd_pcm_close(this->hidden->pcm_handle);
}
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
}
static int
@ -482,16 +555,16 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_zerop(this->hidden);
/* Open the audio device */
/* Name of device should depend on # channels in spec */
status = ALSA_snd_pcm_open(&pcm_handle,
get_audio_device(this->spec.channels),
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
get_audio_device(handle, this->spec.channels),
iscapture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("ALSA: Couldn't open audio device: %s",
ALSA_snd_strerror(status));
}
@ -502,7 +575,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
snd_pcm_hw_params_alloca(&hwparams);
status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("ALSA: Couldn't get hardware config: %s",
ALSA_snd_strerror(status));
}
@ -511,7 +583,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams,
SND_PCM_ACCESS_RW_INTERLEAVED);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("ALSA: Couldn't set interleaved access: %s",
ALSA_snd_strerror(status));
}
@ -565,7 +636,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
}
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("ALSA: Couldn't find any hardware audio formats");
}
this->spec.format = test_format;
@ -577,7 +647,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (status < 0) {
status = ALSA_snd_pcm_hw_params_get_channels(hwparams, &channels);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("ALSA: Couldn't set audio channels");
}
this->spec.channels = channels;
@ -588,7 +657,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
&rate, NULL);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("ALSA: Couldn't set audio frequency: %s",
ALSA_snd_strerror(status));
}
@ -598,8 +666,8 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if ( ALSA_set_period_size(this, hwparams, 0) < 0 &&
ALSA_set_buffer_size(this, hwparams, 0) < 0 ) {
/* Failed to set desired buffer size, do the best you can... */
if ( ALSA_set_period_size(this, hwparams, 1) < 0 ) {
ALSA_CloseDevice(this);
status = ALSA_set_period_size(this, hwparams, 1);
if (status < 0) {
return SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status));
}
}
@ -607,26 +675,22 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
snd_pcm_sw_params_alloca(&swparams);
status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("ALSA: Couldn't get software config: %s",
ALSA_snd_strerror(status));
}
status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, this->spec.samples);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("Couldn't set minimum available samples: %s",
ALSA_snd_strerror(status));
}
status =
ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 1);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("ALSA: Couldn't set start threshold: %s",
ALSA_snd_strerror(status));
}
status = ALSA_snd_pcm_sw_params(pcm_handle, swparams);
if (status < 0) {
ALSA_CloseDevice(this);
return SDL_SetError("Couldn't set software audio parameters: %s",
ALSA_snd_strerror(status));
}
@ -635,13 +699,14 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SDL_CalculateAudioSpec(&this->spec);
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
ALSA_CloseDevice(this);
return SDL_OutOfMemory();
if (!iscapture) {
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
/* Switch to blocking mode for playback */
ALSA_snd_pcm_nonblock(pcm_handle, 0);
@ -650,9 +715,238 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
return 0;
}
typedef struct ALSA_Device
{
char *name;
SDL_bool iscapture;
struct ALSA_Device *next;
} ALSA_Device;
static void
add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSeen)
{
ALSA_Device *dev = SDL_malloc(sizeof (ALSA_Device));
char *desc = ALSA_snd_device_name_get_hint(hint, "DESC");
char *handle = NULL;
char *ptr;
if (!desc) {
SDL_free(dev);
return;
} else if (!dev) {
free(desc);
return;
}
SDL_assert(name != NULL);
/* some strings have newlines, like "HDA NVidia, HDMI 0\nHDMI Audio Output".
just chop the extra lines off, this seems to get a reasonable device
name without extra details. */
if ((ptr = strchr(desc, '\n')) != NULL) {
*ptr = '\0';
}
/*printf("ALSA: adding %s device '%s' (%s)\n", iscapture ? "capture" : "output", name, desc);*/
handle = SDL_strdup(name);
if (!handle) {
free(desc);
SDL_free(dev);
return;
}
SDL_AddAudioDevice(iscapture, desc, handle);
free(desc);
dev->name = handle;
dev->iscapture = iscapture;
dev->next = *pSeen;
*pSeen = dev;
}
static SDL_atomic_t ALSA_hotplug_shutdown;
static SDL_Thread *ALSA_hotplug_thread;
static int SDLCALL
ALSA_HotplugThread(void *arg)
{
SDL_sem *first_run_semaphore = (SDL_sem *) arg;
ALSA_Device *devices = NULL;
ALSA_Device *next;
ALSA_Device *dev;
Uint32 ticks;
while (!SDL_AtomicGet(&ALSA_hotplug_shutdown)) {
void **hints = NULL;
if (ALSA_snd_device_name_hint(-1, "pcm", &hints) != -1) {
ALSA_Device *unseen = devices;
ALSA_Device *seen = NULL;
ALSA_Device *prev;
int i, j;
const char *match = NULL;
int bestmatch = 0xFFFF;
size_t match_len = 0;
int defaultdev = -1;
static const char * const prefixes[] = {
"hw:", "sysdefault:", "default:", NULL
};
/* Apparently there are several different ways that ALSA lists
actual hardware. It could be prefixed with "hw:" or "default:"
or "sysdefault:" and maybe others. Go through the list and see
if we can find a preferred prefix for the system. */
for (i = 0; hints[i]; i++) {
char *name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
if (!name) {
continue;
}
/* full name, not a prefix */
if ((defaultdev == -1) && (SDL_strcmp(name, "default") == 0)) {
defaultdev = i;
}
for (j = 0; prefixes[j]; j++) {
const char *prefix = prefixes[j];
const size_t prefixlen = SDL_strlen(prefix);
if (SDL_strncmp(name, prefix, prefixlen) == 0) {
if (j < bestmatch) {
bestmatch = j;
match = prefix;
match_len = prefixlen;
}
}
}
free(name);
}
/* look through the list of device names to find matches */
for (i = 0; hints[i]; i++) {
char *name;
/* if we didn't find a device name prefix we like at all... */
if ((!match) && (defaultdev != i)) {
continue; /* ...skip anything that isn't the default device. */
}
name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
if (!name) {
continue;
}
/* only want physical hardware interfaces */
if (!match || (SDL_strncmp(name, match, match_len) == 0)) {
char *ioid = ALSA_snd_device_name_get_hint(hints[i], "IOID");
const SDL_bool isoutput = (ioid == NULL) || (SDL_strcmp(ioid, "Output") == 0);
const SDL_bool isinput = (ioid == NULL) || (SDL_strcmp(ioid, "Input") == 0);
SDL_bool have_output = SDL_FALSE;
SDL_bool have_input = SDL_FALSE;
free(ioid);
if (!isoutput && !isinput) {
free(name);
continue;
}
prev = NULL;
for (dev = unseen; dev; dev = next) {
next = dev->next;
if ( (SDL_strcmp(dev->name, name) == 0) && (((isinput) && dev->iscapture) || ((isoutput) && !dev->iscapture)) ) {
if (prev) {
prev->next = next;
} else {
unseen = next;
}
dev->next = seen;
seen = dev;
if (isinput) have_input = SDL_TRUE;
if (isoutput) have_output = SDL_TRUE;
} else {
prev = dev;
}
}
if (isinput && !have_input) {
add_device(SDL_TRUE, name, hints[i], &seen);
}
if (isoutput && !have_output) {
add_device(SDL_FALSE, name, hints[i], &seen);
}
}
free(name);
}
ALSA_snd_device_name_free_hint(hints);
devices = seen; /* now we have a known-good list of attached devices. */
/* report anything still in unseen as removed. */
for (dev = unseen; dev; dev = next) {
/*printf("ALSA: removing %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
next = dev->next;
SDL_RemoveAudioDevice(dev->iscapture, dev->name);
SDL_free(dev->name);
SDL_free(dev);
}
}
/* On first run, tell ALSA_DetectDevices() that we have a complete device list so it can return. */
if (first_run_semaphore) {
SDL_SemPost(first_run_semaphore);
first_run_semaphore = NULL; /* let other thread clean it up. */
}
/* Block awhile before checking again, unless we're told to stop. */
ticks = SDL_GetTicks() + 5000;
while (!SDL_AtomicGet(&ALSA_hotplug_shutdown) && !SDL_TICKS_PASSED(SDL_GetTicks(), ticks)) {
SDL_Delay(100);
}
}
/* Shutting down! Clean up any data we've gathered. */
for (dev = devices; dev; dev = next) {
/*printf("ALSA: at shutdown, removing %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/
next = dev->next;
SDL_free(dev->name);
SDL_free(dev);
}
return 0;
}
static void
ALSA_DetectDevices(void)
{
/* Start the device detection thread here, wait for an initial iteration to complete. */
SDL_sem *semaphore = SDL_CreateSemaphore(0);
if (!semaphore) {
return; /* oh well. */
}
SDL_AtomicSet(&ALSA_hotplug_shutdown, 0);
ALSA_hotplug_thread = SDL_CreateThread(ALSA_HotplugThread, "SDLHotplugALSA", semaphore);
if (ALSA_hotplug_thread) {
SDL_SemWait(semaphore); /* wait for the first iteration to finish. */
}
SDL_DestroySemaphore(semaphore);
}
static void
ALSA_Deinitialize(void)
{
if (ALSA_hotplug_thread != NULL) {
SDL_AtomicSet(&ALSA_hotplug_shutdown, 1);
SDL_WaitThread(ALSA_hotplug_thread, NULL);
ALSA_hotplug_thread = NULL;
}
UnloadALSALibrary();
}
@ -664,13 +958,17 @@ ALSA_Init(SDL_AudioDriverImpl * impl)
}
/* Set the function pointers */
impl->DetectDevices = ALSA_DetectDevices;
impl->OpenDevice = ALSA_OpenDevice;
impl->WaitDevice = ALSA_WaitDevice;
impl->GetDeviceBuf = ALSA_GetDeviceBuf;
impl->PlayDevice = ALSA_PlayDevice;
impl->CloseDevice = ALSA_CloseDevice;
impl->Deinitialize = ALSA_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: Add device enum! */
impl->CaptureFromDevice = ALSA_CaptureFromDevice;
impl->FlushCapture = ALSA_FlushCapture;
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
}

View file

@ -24,6 +24,7 @@
/* Output audio to Android */
#include "SDL_assert.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "SDL_androidaudio.h"
@ -33,23 +34,22 @@
#include <android/log.h>
static SDL_AudioDevice* audioDevice = NULL;
static SDL_AudioDevice* captureDevice = NULL;
static int
AndroidAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
SDL_AudioFormat test_format;
SDL_assert((captureDevice == NULL) || !iscapture);
SDL_assert((audioDevice == NULL) || iscapture);
if (iscapture) {
/* TODO: implement capture */
return SDL_SetError("Capture not supported on Android");
captureDevice = this;
} else {
audioDevice = this;
}
if (audioDevice != NULL) {
return SDL_SetError("Only one audio device at a time please!");
}
audioDevice = this;
this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *this->hidden));
if (this->hidden == NULL) {
return SDL_OutOfMemory();
@ -82,100 +82,137 @@ AndroidAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
this->spec.freq = 48000;
}
/* TODO: pass in/return a (Java) device ID, also whether we're opening for input or output */
this->spec.samples = Android_JNI_OpenAudioDevice(this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
SDL_CalculateAudioSpec(&this->spec);
/* TODO: pass in/return a (Java) device ID */
this->spec.samples = Android_JNI_OpenAudioDevice(iscapture, this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
if (this->spec.samples == 0) {
/* Init failed? */
return SDL_SetError("Java-side initialization failed!");
}
SDL_CalculateAudioSpec(&this->spec);
return 0;
}
static void
AndroidAUD_PlayDevice(_THIS)
ANDROIDAUDIO_PlayDevice(_THIS)
{
Android_JNI_WriteAudioBuffer();
}
static Uint8 *
AndroidAUD_GetDeviceBuf(_THIS)
ANDROIDAUDIO_GetDeviceBuf(_THIS)
{
return Android_JNI_GetAudioBuffer();
}
static int
ANDROIDAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
return Android_JNI_CaptureAudioBuffer(buffer, buflen);
}
static void
AndroidAUD_CloseDevice(_THIS)
ANDROIDAUDIO_FlushCapture(_THIS)
{
Android_JNI_FlushCapturedAudio();
}
static void
ANDROIDAUDIO_CloseDevice(_THIS)
{
/* At this point SDL_CloseAudioDevice via close_audio_device took care of terminating the audio thread
so it's safe to terminate the Java side buffer and AudioTrack
*/
Android_JNI_CloseAudioDevice();
if (audioDevice == this) {
if (audioDevice->hidden != NULL) {
SDL_free(this->hidden);
this->hidden = NULL;
}
Android_JNI_CloseAudioDevice(this->iscapture);
if (this->iscapture) {
SDL_assert(captureDevice == this);
captureDevice = NULL;
} else {
SDL_assert(audioDevice == this);
audioDevice = NULL;
}
SDL_free(this->hidden);
}
static int
AndroidAUD_Init(SDL_AudioDriverImpl * impl)
ANDROIDAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->OpenDevice = AndroidAUD_OpenDevice;
impl->PlayDevice = AndroidAUD_PlayDevice;
impl->GetDeviceBuf = AndroidAUD_GetDeviceBuf;
impl->CloseDevice = AndroidAUD_CloseDevice;
impl->OpenDevice = ANDROIDAUDIO_OpenDevice;
impl->PlayDevice = ANDROIDAUDIO_PlayDevice;
impl->GetDeviceBuf = ANDROIDAUDIO_GetDeviceBuf;
impl->CloseDevice = ANDROIDAUDIO_CloseDevice;
impl->CaptureFromDevice = ANDROIDAUDIO_CaptureFromDevice;
impl->FlushCapture = ANDROIDAUDIO_FlushCapture;
/* and the capabilities */
impl->HasCaptureSupport = 0; /* TODO */
impl->HasCaptureSupport = SDL_TRUE;
impl->OnlyHasDefaultOutputDevice = 1;
impl->OnlyHasDefaultInputDevice = 1;
impl->OnlyHasDefaultCaptureDevice = 1;
return 1; /* this audio target is available. */
}
AudioBootStrap ANDROIDAUD_bootstrap = {
"android", "SDL Android audio driver", AndroidAUD_Init, 0
AudioBootStrap ANDROIDAUDIO_bootstrap = {
"android", "SDL Android audio driver", ANDROIDAUDIO_Init, 0
};
/* Pause (block) all non already paused audio devices by taking their mixer lock */
void AndroidAUD_PauseDevices(void)
void ANDROIDAUDIO_PauseDevices(void)
{
/* TODO: Handle multiple devices? */
struct SDL_PrivateAudioData *private;
if(audioDevice != NULL && audioDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
if (audioDevice->paused) {
if (SDL_AtomicGet(&audioDevice->paused)) {
/* The device is already paused, leave it alone */
private->resume = SDL_FALSE;
}
else {
SDL_LockMutex(audioDevice->mixer_lock);
audioDevice->paused = SDL_TRUE;
SDL_AtomicSet(&audioDevice->paused, 1);
private->resume = SDL_TRUE;
}
}
if(captureDevice != NULL && captureDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *) captureDevice->hidden;
if (SDL_AtomicGet(&captureDevice->paused)) {
/* The device is already paused, leave it alone */
private->resume = SDL_FALSE;
}
else {
SDL_LockMutex(captureDevice->mixer_lock);
SDL_AtomicSet(&captureDevice->paused, 1);
private->resume = SDL_TRUE;
}
}
}
/* Resume (unblock) all non already paused audio devices by releasing their mixer lock */
void AndroidAUD_ResumeDevices(void)
void ANDROIDAUDIO_ResumeDevices(void)
{
/* TODO: Handle multiple devices? */
struct SDL_PrivateAudioData *private;
if(audioDevice != NULL && audioDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
if (private->resume) {
audioDevice->paused = SDL_FALSE;
SDL_AtomicSet(&audioDevice->paused, 0);
private->resume = SDL_FALSE;
SDL_UnlockMutex(audioDevice->mixer_lock);
}
}
if(captureDevice != NULL && captureDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *) captureDevice->hidden;
if (private->resume) {
SDL_AtomicSet(&captureDevice->paused, 0);
private->resume = SDL_FALSE;
SDL_UnlockMutex(captureDevice->mixer_lock);
}
}
}

View file

@ -34,8 +34,6 @@ struct SDL_PrivateAudioData
int resume;
};
static void AndroidAUD_CloseDevice(_THIS);
#endif /* _SDL_androidaudio_h */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -32,7 +32,6 @@
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_artsaudio.h"
@ -186,13 +185,6 @@ ARTS_PlayDevice(_THIS)
#endif
}
static void
ARTS_WaitDone(_THIS)
{
/* !!! FIXME: camp here until buffer drains... SDL_Delay(???); */
}
static Uint8 *
ARTS_GetDeviceBuf(_THIS)
{
@ -203,17 +195,12 @@ ARTS_GetDeviceBuf(_THIS)
static void
ARTS_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->stream) {
SDL_NAME(arts_close_stream) (this->hidden->stream);
this->hidden->stream = 0;
}
SDL_NAME(arts_free) ();
SDL_free(this->hidden);
this->hidden = NULL;
if (this->hidden->stream) {
SDL_NAME(arts_close_stream) (this->hidden->stream);
}
SDL_NAME(arts_free) ();
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
}
static int
@ -241,7 +228,7 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_zerop(this->hidden);
/* Try for a closest match on audio format */
for (test_format = SDL_FirstAudioFormat(this->spec.format);
@ -267,19 +254,16 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
}
if (format == 0) {
ARTS_CloseDevice(this);
return SDL_SetError("Couldn't find any hardware audio formats");
}
this->spec.format = test_format;
if ((rc = SDL_NAME(arts_init) ()) != 0) {
ARTS_CloseDevice(this);
return SDL_SetError("Unable to initialize ARTS: %s",
SDL_NAME(arts_error_text) (rc));
}
if (!ARTS_Suspend()) {
ARTS_CloseDevice(this);
return SDL_SetError("ARTS can not open audio device");
}
@ -297,7 +281,6 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Determine the power of two of the fragment size */
for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec);
if ((0x01 << frag_spec) != this->spec.size) {
ARTS_CloseDevice(this);
return SDL_SetError("Fragment size must be a power of two");
}
frag_spec |= 0x00020000; /* two fragments, for low latency */
@ -316,9 +299,8 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
ARTS_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
@ -367,7 +349,6 @@ ARTS_Init(SDL_AudioDriverImpl * impl)
impl->WaitDevice = ARTS_WaitDevice;
impl->GetDeviceBuf = ARTS_GetDeviceBuf;
impl->CloseDevice = ARTS_CloseDevice;
impl->WaitDone = ARTS_WaitDone;
impl->Deinitialize = ARTS_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1;

View file

@ -38,7 +38,6 @@
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_bsdaudio.h"
@ -63,13 +62,17 @@ BSDAUDIO_Status(_THIS)
#ifdef DEBUG_AUDIO
/* *INDENT-OFF* */
audio_info_t info;
const audio_prinfo *prinfo;
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
fprintf(stderr, "AUDIO_GETINFO failed.\n");
return;
}
prinfo = this->iscapture ? &info.play : &info.record;
fprintf(stderr, "\n"
"[play/record info]\n"
"[%s info]\n"
"buffer size : %d bytes\n"
"sample rate : %i Hz\n"
"channels : %i\n"
@ -83,18 +86,19 @@ BSDAUDIO_Status(_THIS)
"waiting : %s\n"
"active : %s\n"
"",
info.play.buffer_size,
info.play.sample_rate,
info.play.channels,
info.play.precision,
info.play.encoding,
info.play.seek,
info.play.samples,
info.play.eof,
info.play.pause ? "yes" : "no",
info.play.error ? "yes" : "no",
info.play.waiting ? "yes" : "no",
info.play.active ? "yes" : "no");
this->iscapture ? "record" : "play",
prinfo->buffer_size,
prinfo->sample_rate,
prinfo->channels,
prinfo->precision,
prinfo->encoding,
prinfo->seek,
prinfo->samples,
prinfo->eof,
prinfo->pause ? "yes" : "no",
prinfo->error ? "yes" : "no",
prinfo->waiting ? "yes" : "no",
prinfo->active ? "yes" : "no");
fprintf(stderr, "\n"
"[audio info]\n"
@ -182,11 +186,15 @@ BSDAUDIO_PlayDevice(_THIS)
break;
}
if (p < written
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
if (p < this->hidden->mixlen
|| ((written < 0) && ((errno == 0) || (errno == EAGAIN)))) {
SDL_Delay(1); /* Let a little CPU time go by */
}
} while (p < written);
} while (p < this->hidden->mixlen);
/* If timer synchronization is enabled, set the next write frame */
if (this->hidden->frame_ticks) {
@ -197,9 +205,6 @@ BSDAUDIO_PlayDevice(_THIS)
if (written < 0) {
SDL_OpenedAudioDeviceDisconnected(this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
#endif
}
static Uint8 *
@ -208,27 +213,74 @@ BSDAUDIO_GetDeviceBuf(_THIS)
return (this->hidden->mixbuf);
}
static int
BSDAUDIO_CaptureFromDevice(_THIS, void *_buffer, int buflen)
{
Uint8 *buffer = (Uint8 *) _buffer;
int br, p = 0;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
do {
br = read(this->hidden->audio_fd, buffer + p, buflen - p);
if (br > 0)
p += br;
if (br == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) {
/* Non recoverable error has occurred. It should be reported!!! */
perror("audio");
return p ? p : -1;
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Captured %d bytes of audio data\n", br);
#endif
if (p < buflen
|| ((br < 0) && ((errno == 0) || (errno == EAGAIN)))) {
SDL_Delay(1); /* Let a little CPU time go by */
}
} while (p < buflen);
}
static void
BSDAUDIO_FlushCapture(_THIS)
{
audio_info_t info;
size_t remain;
Uint8 buf[512];
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
return; /* oh well. */
}
remain = (size_t) (info.record.samples * (SDL_AUDIO_BITSIZE(this->spec.format) / 8));
while (remain > 0) {
const size_t len = SDL_min(sizeof (buf), remain);
const int br = read(this->hidden->audio_fd, buf, len);
if (br <= 0) {
return; /* oh well. */
}
remain -= br;
}
}
static void
BSDAUDIO_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
}
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
}
static int
BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT;
SDL_AudioFormat format = 0;
audio_info_t info;
audio_prinfo *prinfo = iscapture ? &info.play : &info.record;
/* We don't care what the devname is...we'll try to open anything. */
/* ...but default to first name in the list... */
@ -245,7 +297,7 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_zerop(this->hidden);
/* Open the audio device */
this->hidden->audio_fd = open(devname, flags, 0);
@ -259,9 +311,8 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SDL_CalculateAudioSpec(&this->spec);
/* Set to play mode */
info.mode = AUMODE_PLAY;
info.mode = iscapture ? AUMODE_RECORD : AUMODE_PLAY;
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
BSDAUDIO_CloseDevice(this);
return SDL_SetError("Couldn't put device into play mode");
}
@ -270,28 +321,28 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
format; format = SDL_NextAudioFormat()) {
switch (format) {
case AUDIO_U8:
info.play.encoding = AUDIO_ENCODING_ULINEAR;
info.play.precision = 8;
prinfo->encoding = AUDIO_ENCODING_ULINEAR;
prinfo->precision = 8;
break;
case AUDIO_S8:
info.play.encoding = AUDIO_ENCODING_SLINEAR;
info.play.precision = 8;
prinfo->encoding = AUDIO_ENCODING_SLINEAR;
prinfo->precision = 8;
break;
case AUDIO_S16LSB:
info.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
info.play.precision = 16;
prinfo->encoding = AUDIO_ENCODING_SLINEAR_LE;
prinfo->precision = 16;
break;
case AUDIO_S16MSB:
info.play.encoding = AUDIO_ENCODING_SLINEAR_BE;
info.play.precision = 16;
prinfo->encoding = AUDIO_ENCODING_SLINEAR_BE;
prinfo->precision = 16;
break;
case AUDIO_U16LSB:
info.play.encoding = AUDIO_ENCODING_ULINEAR_LE;
info.play.precision = 16;
prinfo->encoding = AUDIO_ENCODING_ULINEAR_LE;
prinfo->precision = 16;
break;
case AUDIO_U16MSB:
info.play.encoding = AUDIO_ENCODING_ULINEAR_BE;
info.play.precision = 16;
prinfo->encoding = AUDIO_ENCODING_ULINEAR_BE;
prinfo->precision = 16;
break;
default:
continue;
@ -303,33 +354,34 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
if (!format) {
BSDAUDIO_CloseDevice(this);
return SDL_SetError("No supported encoding for 0x%x", this->spec.format);
}
this->spec.format = format;
AUDIO_INITINFO(&info);
info.play.channels = this->spec.channels;
prinfo->channels = this->spec.channels;
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) {
this->spec.channels = 1;
}
AUDIO_INITINFO(&info);
info.play.sample_rate = this->spec.freq;
prinfo->sample_rate = this->spec.freq;
info.blocksize = this->spec.size;
info.hiwat = 5;
info.lowat = 3;
(void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info);
(void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info);
this->spec.freq = info.play.sample_rate;
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
BSDAUDIO_CloseDevice(this);
return SDL_OutOfMemory();
this->spec.freq = prinfo->sample_rate;
if (!iscapture) {
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
BSDAUDIO_Status(this);
@ -347,7 +399,10 @@ BSDAUDIO_Init(SDL_AudioDriverImpl * impl)
impl->WaitDevice = BSDAUDIO_WaitDevice;
impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf;
impl->CloseDevice = BSDAUDIO_CloseDevice;
impl->CaptureFromDevice = BSDAUDIO_CaptureFromDevice;
impl->FlushCapture = BSDAUDIO_FlushCapture;
impl->HasCaptureSupport = SDL_TRUE;
impl->AllowsArbitraryDeviceNames = 1;
return 1; /* this audio target is available. */

View file

@ -33,9 +33,11 @@
#include <CoreAudio/CoreAudio.h>
#include <CoreServices/CoreServices.h>
#else
#include <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
#import <UIKit/UIApplication.h>
#endif
#include <AudioToolbox/AudioToolbox.h>
#include <AudioUnit/AudioUnit.h>
/* Hidden "this" pointer for the audio functions */
@ -43,13 +45,21 @@
struct SDL_PrivateAudioData
{
AudioUnit audioUnit;
int audioUnitOpened;
SDL_Thread *thread;
AudioQueueRef audioQueue;
AudioQueueBufferRef audioBuffer[2];
void *buffer;
UInt32 bufferOffset;
UInt32 bufferSize;
AudioStreamBasicDescription strdesc;
SDL_sem *ready_semaphore;
char *thread_error;
SDL_atomic_t shutdown;
#if MACOSX_COREAUDIO
AudioDeviceID deviceID;
#else
SDL_bool interrupted;
CFTypeRef interruption_listener;
#endif
};

View file

@ -0,0 +1,849 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#if SDL_AUDIO_DRIVER_COREAUDIO
/* !!! FIXME: clean out some of the macro salsa in here. */
#include "SDL_audio.h"
#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 MACOSX_COREAUDIO
static const AudioObjectPropertyAddress devlist_address = {
kAudioHardwarePropertyDevices,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
typedef void (*addDevFn)(const char *name, const int iscapture, AudioDeviceID devId, void *data);
typedef struct AudioDeviceList
{
AudioDeviceID devid;
SDL_bool alive;
struct AudioDeviceList *next;
} AudioDeviceList;
static AudioDeviceList *output_devs = NULL;
static AudioDeviceList *capture_devs = NULL;
static SDL_bool
add_to_internal_dev_list(const int iscapture, AudioDeviceID devId)
{
AudioDeviceList *item = (AudioDeviceList *) SDL_malloc(sizeof (AudioDeviceList));
if (item == NULL) {
return SDL_FALSE;
}
item->devid = devId;
item->alive = SDL_TRUE;
item->next = iscapture ? capture_devs : output_devs;
if (iscapture) {
capture_devs = item;
} else {
output_devs = item;
}
return SDL_TRUE;
}
static void
addToDevList(const char *name, const int iscapture, AudioDeviceID devId, void *data)
{
if (add_to_internal_dev_list(iscapture, devId)) {
SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
}
}
static void
build_device_list(int iscapture, addDevFn addfn, void *addfndata)
{
OSStatus result = noErr;
UInt32 size = 0;
AudioDeviceID *devs = NULL;
UInt32 i = 0;
UInt32 max = 0;
result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
&devlist_address, 0, NULL, &size);
if (result != kAudioHardwareNoError)
return;
devs = (AudioDeviceID *) alloca(size);
if (devs == NULL)
return;
result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
&devlist_address, 0, NULL, &size, devs);
if (result != kAudioHardwareNoError)
return;
max = size / sizeof (AudioDeviceID);
for (i = 0; i < max; i++) {
CFStringRef cfstr = NULL;
char *ptr = NULL;
AudioDeviceID dev = devs[i];
AudioBufferList *buflist = NULL;
int usable = 0;
CFIndex len = 0;
const AudioObjectPropertyAddress addr = {
kAudioDevicePropertyStreamConfiguration,
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster
};
const AudioObjectPropertyAddress nameaddr = {
kAudioObjectPropertyName,
iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster
};
result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size);
if (result != noErr)
continue;
buflist = (AudioBufferList *) SDL_malloc(size);
if (buflist == NULL)
continue;
result = AudioObjectGetPropertyData(dev, &addr, 0, NULL,
&size, buflist);
if (result == noErr) {
UInt32 j;
for (j = 0; j < buflist->mNumberBuffers; j++) {
if (buflist->mBuffers[j].mNumberChannels > 0) {
usable = 1;
break;
}
}
}
SDL_free(buflist);
if (!usable)
continue;
size = sizeof (CFStringRef);
result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr);
if (result != kAudioHardwareNoError)
continue;
len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
kCFStringEncodingUTF8);
ptr = (char *) SDL_malloc(len + 1);
usable = ((ptr != NULL) &&
(CFStringGetCString
(cfstr, ptr, len + 1, kCFStringEncodingUTF8)));
CFRelease(cfstr);
if (usable) {
len = strlen(ptr);
/* Some devices have whitespace at the end...trim it. */
while ((len > 0) && (ptr[len - 1] == ' ')) {
len--;
}
usable = (len > 0);
}
if (usable) {
ptr[len] = '\0';
#if DEBUG_COREAUDIO
printf("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n",
((iscapture) ? "capture" : "output"),
(int) i, ptr, (int) dev);
#endif
addfn(ptr, iscapture, dev, addfndata);
}
SDL_free(ptr); /* addfn() would have copied the string. */
}
}
static void
free_audio_device_list(AudioDeviceList **list)
{
AudioDeviceList *item = *list;
while (item) {
AudioDeviceList *next = item->next;
SDL_free(item);
item = next;
}
*list = NULL;
}
static void
COREAUDIO_DetectDevices(void)
{
build_device_list(SDL_TRUE, addToDevList, NULL);
build_device_list(SDL_FALSE, addToDevList, NULL);
}
static void
build_device_change_list(const char *name, const int iscapture, AudioDeviceID devId, void *data)
{
AudioDeviceList **list = (AudioDeviceList **) data;
AudioDeviceList *item;
for (item = *list; item != NULL; item = item->next) {
if (item->devid == devId) {
item->alive = SDL_TRUE;
return;
}
}
add_to_internal_dev_list(iscapture, devId); /* new device, add it. */
SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
}
static void
reprocess_device_list(const int iscapture, AudioDeviceList **list)
{
AudioDeviceList *item;
AudioDeviceList *prev = NULL;
for (item = *list; item != NULL; item = item->next) {
item->alive = SDL_FALSE;
}
build_device_list(iscapture, build_device_change_list, list);
/* free items in the list that aren't still alive. */
item = *list;
while (item != NULL) {
AudioDeviceList *next = item->next;
if (item->alive) {
prev = item;
} else {
SDL_RemoveAudioDevice(iscapture, (void *) ((size_t) item->devid));
if (prev) {
prev->next = item->next;
} else {
*list = item->next;
}
SDL_free(item);
}
item = next;
}
}
/* this is called when the system's list of available audio devices changes. */
static OSStatus
device_list_changed(AudioObjectID systemObj, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
{
reprocess_device_list(SDL_TRUE, &capture_devs);
reprocess_device_list(SDL_FALSE, &output_devs);
return 0;
}
#endif
static int open_playback_devices = 0;
static int open_capture_devices = 0;
#if !MACOSX_COREAUDIO
static void interruption_begin(_THIS)
{
if (this != NULL && this->hidden->audioQueue != NULL) {
this->hidden->interrupted = SDL_TRUE;
AudioQueuePause(this->hidden->audioQueue);
}
}
static void interruption_end(_THIS)
{
if (this != NULL && this->hidden != NULL && this->hidden->audioQueue != NULL
&& this->hidden->interrupted) {
this->hidden->interrupted = SDL_FALSE;
AudioQueueStart(this->hidden->audioQueue, NULL);
}
}
@interface SDLInterruptionListener : NSObject
@property (nonatomic, assign) SDL_AudioDevice *device;
@end
@implementation SDLInterruptionListener
- (void)audioSessionInterruption:(NSNotification *)note
{
@synchronized (self) {
NSNumber *type = note.userInfo[AVAudioSessionInterruptionTypeKey];
if (type.unsignedIntegerValue == AVAudioSessionInterruptionTypeBegan) {
interruption_begin(self.device);
} else {
interruption_end(self.device);
}
}
}
- (void)applicationBecameActive:(NSNotification *)note
{
@synchronized (self) {
interruption_end(self.device);
}
}
@end
static BOOL update_audio_session(_THIS, SDL_bool open)
{
@autoreleasepool {
AVAudioSession *session = [AVAudioSession sharedInstance];
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
NSString *category;
NSError *err = nil;
if (open_playback_devices && open_capture_devices) {
category = AVAudioSessionCategoryPlayAndRecord;
} else if (open_capture_devices) {
category = AVAudioSessionCategoryRecord;
} else {
/* Set category to ambient so that other music continues playing.
You can change this at runtime in your own code if you need different
behavior. If this is common, we can add an SDL hint for this. */
category = AVAudioSessionCategoryAmbient;
}
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_playback_devices + open_capture_devices == 1) {
if (![session setActive:YES error:&err]) {
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 setActive:NO error:nil];
}
if (open) {
SDLInterruptionListener *listener = [SDLInterruptionListener new];
listener.device = this;
[center addObserver:listener
selector:@selector(audioSessionInterruption:)
name:AVAudioSessionInterruptionNotification
object:session];
/* 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. */
[center addObserver:listener
selector:@selector(applicationBecameActive:)
name:UIApplicationDidBecomeActiveNotification
object:session];
[center addObserver:listener
selector:@selector(applicationBecameActive:)
name:UIApplicationWillEnterForegroundNotification
object:session];
this->hidden->interruption_listener = CFBridgingRetain(listener);
} else {
if (this->hidden->interruption_listener != NULL) {
SDLInterruptionListener *listener = nil;
listener = (SDLInterruptionListener *) CFBridgingRelease(this->hidden->interruption_listener);
@synchronized (listener) {
listener.device = NULL;
}
[center removeObserver:listener];
}
}
}
return YES;
}
#endif
/* The AudioQueue callback */
static void
outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
{
SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
/* Supply silence if audio is enabled and not paused */
SDL_memset(inBuffer->mAudioData, this->spec.silence, inBuffer->mAudioDataBytesCapacity);
} else {
UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
Uint8 *ptr = (Uint8 *) inBuffer->mAudioData;
while (remaining > 0) {
UInt32 len;
if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
/* Generate the data */
SDL_LockMutex(this->mixer_lock);
(*this->spec.callback)(this->spec.userdata,
this->hidden->buffer, this->hidden->bufferSize);
SDL_UnlockMutex(this->mixer_lock);
this->hidden->bufferOffset = 0;
}
len = this->hidden->bufferSize - this->hidden->bufferOffset;
if (len > remaining) {
len = remaining;
}
SDL_memcpy(ptr, (char *)this->hidden->buffer +
this->hidden->bufferOffset, len);
ptr = ptr + len;
remaining -= len;
this->hidden->bufferOffset += len;
}
}
if (!SDL_AtomicGet(&this->hidden->shutdown)) {
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
}
inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity;
}
static void
inputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer,
const AudioTimeStamp *inStartTime, UInt32 inNumberPacketDescriptions,
const AudioStreamPacketDescription *inPacketDescs )
{
SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
if (SDL_AtomicGet(&this->enabled) && !SDL_AtomicGet(&this->paused)) { /* ignore unless we're active. */
const Uint8 *ptr = (const Uint8 *) inBuffer->mAudioData;
UInt32 remaining = inBuffer->mAudioDataByteSize;
while (remaining > 0) {
UInt32 len = this->hidden->bufferSize - this->hidden->bufferOffset;
if (len > remaining) {
len = remaining;
}
SDL_memcpy((char *)this->hidden->buffer + this->hidden->bufferOffset, ptr, len);
ptr += len;
remaining -= len;
this->hidden->bufferOffset += len;
if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
SDL_LockMutex(this->mixer_lock);
(*this->spec.callback)(this->spec.userdata, this->hidden->buffer, this->hidden->bufferSize);
SDL_UnlockMutex(this->mixer_lock);
this->hidden->bufferOffset = 0;
}
}
}
if (!SDL_AtomicGet(&this->hidden->shutdown)) {
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
}
}
#if MACOSX_COREAUDIO
static const AudioObjectPropertyAddress alive_address =
{
kAudioDevicePropertyDeviceIsAlive,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
static OSStatus
device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
{
SDL_AudioDevice *this = (SDL_AudioDevice *) data;
SDL_bool dead = SDL_FALSE;
UInt32 isAlive = 1;
UInt32 size = sizeof (isAlive);
OSStatus error;
if (!SDL_AtomicGet(&this->enabled)) {
return 0; /* already known to be dead. */
}
error = AudioObjectGetPropertyData(this->hidden->deviceID, &alive_address,
0, NULL, &size, &isAlive);
if (error == kAudioHardwareBadDeviceError) {
dead = SDL_TRUE; /* device was unplugged. */
} else if ((error == kAudioHardwareNoError) && (!isAlive)) {
dead = SDL_TRUE; /* device died in some other way. */
}
if (dead) {
SDL_OpenedAudioDeviceDisconnected(this);
}
return 0;
}
#endif
static void
COREAUDIO_CloseDevice(_THIS)
{
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);
#endif
#if !MACOSX_COREAUDIO
update_audio_session(this, SDL_FALSE);
#endif
if (this->hidden->thread) {
SDL_AtomicSet(&this->hidden->shutdown, 1);
SDL_WaitThread(this->hidden->thread, NULL);
}
if (this->hidden->audioQueue) {
for (i = 0; i < SDL_arraysize(this->hidden->audioBuffer); i++) {
if (this->hidden->audioBuffer[i]) {
AudioQueueFreeBuffer(this->hidden->audioQueue, this->hidden->audioBuffer[i]);
}
}
AudioQueueDispose(this->hidden->audioQueue, 1);
}
if (this->hidden->ready_semaphore) {
SDL_DestroySemaphore(this->hidden->ready_semaphore);
}
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
static int
prepare_device(_THIS, void *handle, int iscapture)
{
AudioDeviceID devid = (AudioDeviceID) ((size_t) handle);
OSStatus result = noErr;
UInt32 size = 0;
UInt32 alive = 0;
pid_t pid = 0;
AudioObjectPropertyAddress addr = {
0,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
if (handle == NULL) {
size = sizeof (AudioDeviceID);
addr.mSelector =
((iscapture) ? kAudioHardwarePropertyDefaultInputDevice :
kAudioHardwarePropertyDefaultOutputDevice);
result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr,
0, NULL, &size, &devid);
CHECK_RESULT("AudioHardwareGetProperty (default device)");
}
addr.mSelector = kAudioDevicePropertyDeviceIsAlive;
addr.mScope = iscapture ? kAudioDevicePropertyScopeInput :
kAudioDevicePropertyScopeOutput;
size = sizeof (alive);
result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &alive);
CHECK_RESULT
("AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)");
if (!alive) {
SDL_SetError("CoreAudio: requested device exists, but isn't alive.");
return 0;
}
addr.mSelector = kAudioDevicePropertyHogMode;
size = sizeof (pid);
result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &pid);
/* some devices don't support this property, so errors are fine here. */
if ((result == noErr) && (pid != -1)) {
SDL_SetError("CoreAudio: requested device is being hogged.");
return 0;
}
this->hidden->deviceID = devid;
return 1;
}
#endif
static int
prepare_audioqueue(_THIS)
{
const AudioStreamBasicDescription *strdesc = &this->hidden->strdesc;
const int iscapture = this->iscapture;
OSStatus result;
int i;
SDL_assert(CFRunLoopGetCurrent() != NULL);
if (iscapture) {
result = AudioQueueNewInput(strdesc, inputCallback, this, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &this->hidden->audioQueue);
CHECK_RESULT("AudioQueueNewInput");
} else {
result = AudioQueueNewOutput(strdesc, outputCallback, this, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &this->hidden->audioQueue);
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)");
/* !!! 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
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&this->spec);
/* Allocate a sample buffer */
this->hidden->bufferSize = this->spec.size;
this->hidden->bufferOffset = iscapture ? 0 : this->hidden->bufferSize;
this->hidden->buffer = SDL_malloc(this->hidden->bufferSize);
if (this->hidden->buffer == NULL) {
SDL_OutOfMemory();
return 0;
}
for (i = 0; i < SDL_arraysize(this->hidden->audioBuffer); i++) {
result = AudioQueueAllocateBuffer(this->hidden->audioQueue, this->spec.size, &this->hidden->audioBuffer[i]);
CHECK_RESULT("AudioQueueAllocateBuffer");
SDL_memset(this->hidden->audioBuffer[i]->mAudioData, this->spec.silence, this->hidden->audioBuffer[i]->mAudioDataBytesCapacity);
this->hidden->audioBuffer[i]->mAudioDataByteSize = this->hidden->audioBuffer[i]->mAudioDataBytesCapacity;
result = AudioQueueEnqueueBuffer(this->hidden->audioQueue, this->hidden->audioBuffer[i], 0, NULL);
CHECK_RESULT("AudioQueueEnqueueBuffer");
}
result = AudioQueueStart(this->hidden->audioQueue, NULL);
CHECK_RESULT("AudioQueueStart");
/* We're running! */
return 1;
}
static int
audioqueue_thread(void *arg)
{
SDL_AudioDevice *this = (SDL_AudioDevice *) arg;
const int rc = prepare_audioqueue(this);
if (!rc) {
this->hidden->thread_error = SDL_strdup(SDL_GetError());
SDL_SemPost(this->hidden->ready_semaphore);
return 0;
}
/* 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 (this->iscapture) { /* just stop immediately for capture devices. */
AudioQueueStop(this->hidden->audioQueue, 1);
} else { /* Drain off any pending playback. */
AudioQueueStop(this->hidden->audioQueue, 0);
const CFTimeInterval secs = (((this->spec.size / (SDL_AUDIO_BITSIZE(this->spec.format) / 8)) / this->spec.channels) / ((CFTimeInterval) this->spec.freq)) * 2.0;
CFRunLoopRunInMode(kCFRunLoopDefaultMode, secs, 0);
}
return 0;
}
static int
COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
AudioStreamBasicDescription *strdesc;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
int valid_datatype = 0;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_zerop(this->hidden);
strdesc = &this->hidden->strdesc;
if (iscapture) {
open_capture_devices++;
} else {
open_playback_devices++;
}
#if !MACOSX_COREAUDIO
if (!update_audio_session(this, SDL_TRUE)) {
return -1;
}
#endif
/* Setup a AudioStreamBasicDescription with the requested format */
SDL_zerop(strdesc);
strdesc->mFormatID = kAudioFormatLinearPCM;
strdesc->mFormatFlags = kLinearPCMFormatFlagIsPacked;
strdesc->mChannelsPerFrame = this->spec.channels;
strdesc->mSampleRate = this->spec.freq;
strdesc->mFramesPerPacket = 1;
while ((!valid_datatype) && (test_format)) {
this->spec.format = test_format;
/* Just a list of valid SDL formats, so people don't pass junk here. */
switch (test_format) {
case AUDIO_U8:
case AUDIO_S8:
case AUDIO_U16LSB:
case AUDIO_S16LSB:
case AUDIO_U16MSB:
case AUDIO_S16MSB:
case AUDIO_S32LSB:
case AUDIO_S32MSB:
case AUDIO_F32LSB:
case AUDIO_F32MSB:
valid_datatype = 1;
strdesc->mBitsPerChannel = SDL_AUDIO_BITSIZE(this->spec.format);
if (SDL_AUDIO_ISBIGENDIAN(this->spec.format))
strdesc->mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
if (SDL_AUDIO_ISFLOAT(this->spec.format))
strdesc->mFormatFlags |= kLinearPCMFormatFlagIsFloat;
else if (SDL_AUDIO_ISSIGNED(this->spec.format))
strdesc->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
break;
}
}
if (!valid_datatype) { /* shouldn't happen, but just in case... */
return SDL_SetError("Unsupported audio format");
}
strdesc->mBytesPerFrame = strdesc->mBitsPerChannel * strdesc->mChannelsPerFrame / 8;
strdesc->mBytesPerPacket = strdesc->mBytesPerFrame * strdesc->mFramesPerPacket;
#if MACOSX_COREAUDIO
if (!prepare_device(this, handle, iscapture)) {
return -1;
}
#endif
/* This has to init in a new thread so it can get its own CFRunLoop. :/ */
SDL_AtomicSet(&this->hidden->shutdown, 0);
this->hidden->ready_semaphore = SDL_CreateSemaphore(0);
if (!this->hidden->ready_semaphore) {
return -1; /* oh well. */
}
this->hidden->thread = SDL_CreateThreadInternal(audioqueue_thread, "AudioQueue thread", 512 * 1024, this);
if (!this->hidden->thread) {
return -1;
}
SDL_SemWait(this->hidden->ready_semaphore);
SDL_DestroySemaphore(this->hidden->ready_semaphore);
this->hidden->ready_semaphore = NULL;
if ((this->hidden->thread != NULL) && (this->hidden->thread_error != NULL)) {
SDL_SetError("%s", this->hidden->thread_error);
return -1;
}
return (this->hidden->thread != NULL) ? 0 : -1;
}
static void
COREAUDIO_Deinitialize(void)
{
#if MACOSX_COREAUDIO
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL);
free_audio_device_list(&capture_devs);
free_audio_device_list(&output_devs);
#endif
}
static int
COREAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->OpenDevice = COREAUDIO_OpenDevice;
impl->CloseDevice = COREAUDIO_CloseDevice;
impl->Deinitialize = COREAUDIO_Deinitialize;
#if MACOSX_COREAUDIO
impl->DetectDevices = COREAUDIO_DetectDevices;
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL);
#else
impl->OnlyHasDefaultOutputDevice = 1;
impl->OnlyHasDefaultCaptureDevice = 1;
#endif
impl->ProvidesOwnCallbackThread = 1;
impl->HasCaptureSupport = 1;
return 1; /* this audio target is available. */
}
AudioBootStrap COREAUDIO_bootstrap = {
"coreaudio", "CoreAudio", COREAUDIO_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_COREAUDIO */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -24,6 +24,7 @@
/* Allow access to a raw mixing buffer */
#include "SDL_assert.h"
#include "SDL_timer.h"
#include "SDL_loadso.h"
#include "SDL_audio.h"
@ -36,11 +37,13 @@
/* DirectX function pointers for audio */
static void* DSoundDLL = NULL;
typedef HRESULT(WINAPI*fnDirectSoundCreate8)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN);
typedef HRESULT(WINAPI*fnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
typedef HRESULT(WINAPI*fnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW,LPVOID);
typedef HRESULT (WINAPI *fnDirectSoundCreate8)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN);
typedef HRESULT (WINAPI *fnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
typedef HRESULT (WINAPI *fnDirectSoundCaptureCreate8)(LPCGUID,LPDIRECTSOUNDCAPTURE8 *,LPUNKNOWN);
typedef HRESULT (WINAPI *fnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW,LPVOID);
static fnDirectSoundCreate8 pDirectSoundCreate8 = NULL;
static fnDirectSoundEnumerateW pDirectSoundEnumerateW = NULL;
static fnDirectSoundCaptureCreate8 pDirectSoundCaptureCreate8 = NULL;
static fnDirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW = NULL;
static void
@ -48,6 +51,7 @@ DSOUND_Unload(void)
{
pDirectSoundCreate8 = NULL;
pDirectSoundEnumerateW = NULL;
pDirectSoundCaptureCreate8 = NULL;
pDirectSoundCaptureEnumerateW = NULL;
if (DSoundDLL != NULL) {
@ -76,6 +80,7 @@ DSOUND_Load(void)
loaded = 1; /* will reset if necessary. */
DSOUNDLOAD(DirectSoundCreate8);
DSOUNDLOAD(DirectSoundEnumerateW);
DSOUNDLOAD(DirectSoundCaptureCreate8);
DSOUNDLOAD(DirectSoundCaptureEnumerateW);
#undef DSOUNDLOAD
@ -155,7 +160,7 @@ FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data)
{
const int iscapture = (int) ((size_t) data);
if (guid != NULL) { /* skip default device */
char *str = WIN_StringToUTF8(desc);
char *str = WIN_LookupAudioDeviceName(desc, guid);
if (str != NULL) {
LPGUID cpyguid = (LPGUID) SDL_malloc(sizeof (GUID));
SDL_memcpy(cpyguid, guid, sizeof (GUID));
@ -197,7 +202,7 @@ DSOUND_WaitDevice(_THIS)
return;
}
while ((cursor / this->hidden->mixlen) == this->hidden->lastchunk) {
while ((cursor / this->spec.size) == this->hidden->lastchunk) {
/* FIXME: find out how much time is left and sleep that long */
SDL_Delay(1);
@ -239,9 +244,8 @@ DSOUND_PlayDevice(_THIS)
if (this->hidden->locked_buf) {
IDirectSoundBuffer_Unlock(this->hidden->mixbuf,
this->hidden->locked_buf,
this->hidden->mixlen, NULL, 0);
this->spec.size, NULL, 0);
}
}
static Uint8 *
@ -265,7 +269,7 @@ DSOUND_GetDeviceBuf(_THIS)
SetDSerror("DirectSound GetCurrentPosition", result);
return (NULL);
}
cursor /= this->hidden->mixlen;
cursor /= this->spec.size;
#ifdef DEBUG_SOUND
/* Detect audio dropouts */
{
@ -281,17 +285,17 @@ DSOUND_GetDeviceBuf(_THIS)
#endif
this->hidden->lastchunk = cursor;
cursor = (cursor + 1) % this->hidden->num_buffers;
cursor *= this->hidden->mixlen;
cursor *= this->spec.size;
/* Lock the audio buffer */
result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
this->hidden->mixlen,
this->spec.size,
(LPVOID *) & this->hidden->locked_buf,
&rawlen, NULL, &junk, 0);
if (result == DSERR_BUFFERLOST) {
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
this->hidden->mixlen,
this->spec.size,
(LPVOID *) & this->
hidden->locked_buf, &rawlen, NULL,
&junk, 0);
@ -303,109 +307,106 @@ DSOUND_GetDeviceBuf(_THIS)
return (this->hidden->locked_buf);
}
static void
DSOUND_WaitDone(_THIS)
static int
DSOUND_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
Uint8 *stream = DSOUND_GetDeviceBuf(this);
struct SDL_PrivateAudioData *h = this->hidden;
DWORD junk, cursor, ptr1len, ptr2len;
VOID *ptr1, *ptr2;
/* Wait for the playing chunk to finish */
if (stream != NULL) {
SDL_memset(stream, this->spec.silence, this->hidden->mixlen);
DSOUND_PlayDevice(this);
SDL_assert(buflen == this->spec.size);
while (SDL_TRUE) {
if (SDL_AtomicGet(&this->shutdown)) { /* in case the buffer froze... */
SDL_memset(buffer, this->spec.silence, buflen);
return buflen;
}
if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) != DS_OK) {
return -1;
}
if ((cursor / this->spec.size) == h->lastchunk) {
SDL_Delay(1); /* FIXME: find out how much time is left and sleep that long */
} else {
break;
}
}
DSOUND_WaitDevice(this);
/* Stop the looping sound buffer */
IDirectSoundBuffer_Stop(this->hidden->mixbuf);
if (IDirectSoundCaptureBuffer_Lock(h->capturebuf, h->lastchunk * this->spec.size, this->spec.size, &ptr1, &ptr1len, &ptr2, &ptr2len, 0) != DS_OK) {
return -1;
}
SDL_assert(ptr1len == this->spec.size);
SDL_assert(ptr2 == NULL);
SDL_assert(ptr2len == 0);
SDL_memcpy(buffer, ptr1, ptr1len);
if (IDirectSoundCaptureBuffer_Unlock(h->capturebuf, ptr1, ptr1len, ptr2, ptr2len) != DS_OK) {
return -1;
}
h->lastchunk = (h->lastchunk + 1) % h->num_buffers;
return ptr1len;
}
static void
DSOUND_FlushCapture(_THIS)
{
struct SDL_PrivateAudioData *h = this->hidden;
DWORD junk, cursor;
if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) == DS_OK) {
h->lastchunk = cursor / this->spec.size;
}
}
static void
DSOUND_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
if (this->hidden->sound != NULL) {
if (this->hidden->mixbuf != NULL) {
/* Clean up the audio buffer */
IDirectSoundBuffer_Release(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
IDirectSound_Release(this->hidden->sound);
this->hidden->sound = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
if (this->hidden->mixbuf != NULL) {
IDirectSoundBuffer_Stop(this->hidden->mixbuf);
IDirectSoundBuffer_Release(this->hidden->mixbuf);
}
if (this->hidden->sound != NULL) {
IDirectSound_Release(this->hidden->sound);
}
if (this->hidden->capturebuf != NULL) {
IDirectSoundCaptureBuffer_Stop(this->hidden->capturebuf);
IDirectSoundCaptureBuffer_Release(this->hidden->capturebuf);
}
if (this->hidden->capture != NULL) {
IDirectSoundCapture_Release(this->hidden->capture);
}
SDL_free(this->hidden);
}
/* This function tries to create a secondary audio buffer, and returns the
number of audio chunks available in the created buffer.
number of audio chunks available in the created buffer. This is for
playback devices, not capture.
*/
static int
CreateSecondary(_THIS, HWND focus)
CreateSecondary(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
{
LPDIRECTSOUND sndObj = this->hidden->sound;
LPDIRECTSOUNDBUFFER *sndbuf = &this->hidden->mixbuf;
Uint32 chunksize = this->spec.size;
const int numchunks = 8;
HRESULT result = DS_OK;
DSBUFFERDESC format;
LPVOID pvAudioPtr1, pvAudioPtr2;
DWORD dwAudioBytes1, dwAudioBytes2;
WAVEFORMATEX wfmt;
SDL_zero(wfmt);
if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
} else {
wfmt.wFormatTag = WAVE_FORMAT_PCM;
}
wfmt.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
wfmt.nChannels = this->spec.channels;
wfmt.nSamplesPerSec = this->spec.freq;
wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8);
wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign;
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(&this->spec);
/* Try to set primary mixing privileges */
if (focus) {
result = IDirectSound_SetCooperativeLevel(sndObj,
focus, DSSCL_PRIORITY);
} else {
result = IDirectSound_SetCooperativeLevel(sndObj,
GetDesktopWindow(),
DSSCL_NORMAL);
}
if (result != DS_OK) {
return SetDSerror("DirectSound SetCooperativeLevel", result);
}
/* Try to create the secondary buffer */
SDL_zero(format);
format.dwSize = sizeof(format);
format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
if (!focus) {
format.dwFlags |= DSBCAPS_GLOBALFOCUS;
} else {
format.dwFlags |= DSBCAPS_STICKYFOCUS;
}
format.dwBufferBytes = numchunks * chunksize;
if ((format.dwBufferBytes < DSBSIZE_MIN) ||
(format.dwBufferBytes > DSBSIZE_MAX)) {
return SDL_SetError("Sound buffer size must be between %d and %d",
DSBSIZE_MIN / numchunks, DSBSIZE_MAX / numchunks);
}
format.dwReserved = 0;
format.lpwfxFormat = &wfmt;
format.dwFlags |= DSBCAPS_GLOBALFOCUS;
format.dwBufferBytes = bufsize;
format.lpwfxFormat = wfmt;
result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
if (result != DS_OK) {
return SetDSerror("DirectSound CreateSoundBuffer", result);
}
IDirectSoundBuffer_SetFormat(*sndbuf, &wfmt);
IDirectSoundBuffer_SetFormat(*sndbuf, wfmt);
/* Silence the initial audio buffer */
result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
@ -420,31 +421,90 @@ CreateSecondary(_THIS, HWND focus)
}
/* We're ready to go */
return (numchunks);
return 0;
}
/* This function tries to create a capture buffer, and returns the
number of audio chunks available in the created buffer. This is for
capture devices, not playback.
*/
static int
CreateCaptureBuffer(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
{
LPDIRECTSOUNDCAPTURE capture = this->hidden->capture;
LPDIRECTSOUNDCAPTUREBUFFER *capturebuf = &this->hidden->capturebuf;
DSCBUFFERDESC format;
// DWORD junk, cursor;
HRESULT result;
SDL_zero(format);
format.dwSize = sizeof (format);
format.dwFlags = DSCBCAPS_WAVEMAPPED;
format.dwBufferBytes = bufsize;
format.lpwfxFormat = wfmt;
result = IDirectSoundCapture_CreateCaptureBuffer(capture, &format, capturebuf, NULL);
if (result != DS_OK) {
return SetDSerror("DirectSound CreateCaptureBuffer", result);
}
result = IDirectSoundCaptureBuffer_Start(*capturebuf, DSCBSTART_LOOPING);
if (result != DS_OK) {
IDirectSoundCaptureBuffer_Release(*capturebuf);
return SetDSerror("DirectSound Start", result);
}
#if 0
/* presumably this starts at zero, but just in case... */
result = IDirectSoundCaptureBuffer_GetCurrentPosition(*capturebuf, &junk, &cursor);
if (result != DS_OK) {
IDirectSoundCaptureBuffer_Stop(*capturebuf);
IDirectSoundCaptureBuffer_Release(*capturebuf);
return SetDSerror("DirectSound GetCurrentPosition", result);
}
this->hidden->lastchunk = cursor / this->spec.size;
#endif
return 0;
}
static int
DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
const DWORD numchunks = 8;
HRESULT result;
SDL_bool valid_format = SDL_FALSE;
SDL_bool tried_format = SDL_FALSE;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
LPGUID guid = (LPGUID) handle;
DWORD bufsize;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_zerop(this->hidden);
/* Open the audio device */
result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL);
if (result != DS_OK) {
DSOUND_CloseDevice(this);
return SetDSerror("DirectSoundCreate", result);
if (iscapture) {
result = pDirectSoundCaptureCreate8(guid, &this->hidden->capture, NULL);
if (result != DS_OK) {
return SetDSerror("DirectSoundCaptureCreate8", result);
}
} else {
result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL);
if (result != DS_OK) {
return SetDSerror("DirectSoundCreate8", result);
}
result = IDirectSound_SetCooperativeLevel(this->hidden->sound,
GetDesktopWindow(),
DSSCL_NORMAL);
if (result != DS_OK) {
return SetDSerror("DirectSound SetCooperativeLevel", result);
}
}
while ((!valid_format) && (test_format)) {
@ -454,10 +514,38 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
case AUDIO_S32:
case AUDIO_F32:
tried_format = SDL_TRUE;
this->spec.format = test_format;
this->hidden->num_buffers = CreateSecondary(this, NULL);
if (this->hidden->num_buffers > 0) {
valid_format = SDL_TRUE;
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(&this->spec);
bufsize = numchunks * this->spec.size;
if ((bufsize < DSBSIZE_MIN) || (bufsize > DSBSIZE_MAX)) {
SDL_SetError("Sound buffer size must be between %d and %d",
(DSBSIZE_MIN < numchunks) ? 1 : DSBSIZE_MIN / numchunks,
DSBSIZE_MAX / numchunks);
} else {
int rc;
WAVEFORMATEX wfmt;
SDL_zero(wfmt);
if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
} else {
wfmt.wFormatTag = WAVE_FORMAT_PCM;
}
wfmt.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
wfmt.nChannels = this->spec.channels;
wfmt.nSamplesPerSec = this->spec.freq;
wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8);
wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign;
rc = iscapture ? CreateCaptureBuffer(this, bufsize, &wfmt) : CreateSecondary(this, bufsize, &wfmt);
if (rc == 0) {
this->hidden->num_buffers = numchunks;
valid_format = SDL_TRUE;
}
}
break;
}
@ -465,15 +553,13 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
if (!valid_format) {
DSOUND_CloseDevice(this);
if (tried_format) {
return -1; /* CreateSecondary() should have called SDL_SetError(). */
}
return SDL_SetError("DirectSound: Unsupported audio format");
}
/* The buffer will auto-start playing in DSOUND_WaitDevice() */
this->hidden->mixlen = this->spec.size;
/* Playback buffers will auto-start playing in DSOUND_WaitDevice() */
return 0; /* good to go. */
}
@ -498,13 +584,15 @@ DSOUND_Init(SDL_AudioDriverImpl * impl)
impl->OpenDevice = DSOUND_OpenDevice;
impl->PlayDevice = DSOUND_PlayDevice;
impl->WaitDevice = DSOUND_WaitDevice;
impl->WaitDone = DSOUND_WaitDone;
impl->GetDeviceBuf = DSOUND_GetDeviceBuf;
impl->CaptureFromDevice = DSOUND_CaptureFromDevice;
impl->FlushCapture = DSOUND_FlushCapture;
impl->CloseDevice = DSOUND_CloseDevice;
impl->FreeDeviceHandle = DSOUND_FreeDeviceHandle;
impl->Deinitialize = DSOUND_Deinitialize;
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
}

View file

@ -35,8 +35,9 @@ struct SDL_PrivateAudioData
{
LPDIRECTSOUND sound;
LPDIRECTSOUNDBUFFER mixbuf;
LPDIRECTSOUNDCAPTURE capture;
LPDIRECTSOUNDCAPTUREBUFFER capturebuf;
int num_buffers;
int mixlen;
DWORD lastchunk;
Uint8 *locked_buf;
};

View file

@ -31,46 +31,33 @@
#include "SDL_rwops.h"
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_diskaudio.h"
/* !!! FIXME: these should be SDL hints, not environment variables. */
/* environment variables and defaults. */
#define DISKENVR_OUTFILE "SDL_DISKAUDIOFILE"
#define DISKDEFAULT_OUTFILE "sdlaudio.raw"
#define DISKENVR_WRITEDELAY "SDL_DISKAUDIODELAY"
#define DISKDEFAULT_WRITEDELAY 150
static const char *
DISKAUD_GetOutputFilename(const char *devname)
{
if (devname == NULL) {
devname = SDL_getenv(DISKENVR_OUTFILE);
if (devname == NULL) {
devname = DISKDEFAULT_OUTFILE;
}
}
return devname;
}
#define DISKENVR_INFILE "SDL_DISKAUDIOFILEIN"
#define DISKDEFAULT_INFILE "sdlaudio-in.raw"
#define DISKENVR_IODELAY "SDL_DISKAUDIODELAY"
/* This function waits until it is possible to write a full sound buffer */
static void
DISKAUD_WaitDevice(_THIS)
DISKAUDIO_WaitDevice(_THIS)
{
SDL_Delay(this->hidden->write_delay);
SDL_Delay(this->hidden->io_delay);
}
static void
DISKAUD_PlayDevice(_THIS)
DISKAUDIO_PlayDevice(_THIS)
{
size_t written;
/* Write the audio data */
written = SDL_RWwrite(this->hidden->output,
this->hidden->mixbuf, 1, this->hidden->mixlen);
const size_t written = SDL_RWwrite(this->hidden->io,
this->hidden->mixbuf,
1, this->spec.size);
/* If we couldn't write, assume fatal error for now */
if (written != this->hidden->mixlen) {
if (written != this->spec.size) {
SDL_OpenedAudioDeviceDisconnected(this);
}
#ifdef DEBUG_AUDIO
@ -79,63 +66,105 @@ DISKAUD_PlayDevice(_THIS)
}
static Uint8 *
DISKAUD_GetDeviceBuf(_THIS)
DISKAUDIO_GetDeviceBuf(_THIS)
{
return (this->hidden->mixbuf);
}
static void
DISKAUD_CloseDevice(_THIS)
static int
DISKAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->output != NULL) {
SDL_RWclose(this->hidden->output);
this->hidden->output = NULL;
struct SDL_PrivateAudioData *h = this->hidden;
const int origbuflen = buflen;
SDL_Delay(h->io_delay);
if (h->io) {
const size_t br = SDL_RWread(h->io, buffer, 1, buflen);
buflen -= (int) br;
buffer = ((Uint8 *) buffer) + br;
if (buflen > 0) { /* EOF (or error, but whatever). */
SDL_RWclose(h->io);
h->io = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
}
/* if we ran out of file, just write silence. */
SDL_memset(buffer, this->spec.silence, buflen);
return origbuflen;
}
static void
DISKAUDIO_FlushCapture(_THIS)
{
/* no op...we don't advance the file pointer or anything. */
}
static void
DISKAUDIO_CloseDevice(_THIS)
{
if (this->hidden->io != NULL) {
SDL_RWclose(this->hidden->io);
}
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
}
static const char *
get_filename(const int iscapture, const char *devname)
{
if (devname == NULL) {
devname = SDL_getenv(iscapture ? DISKENVR_INFILE : DISKENVR_OUTFILE);
if (devname == NULL) {
devname = iscapture ? DISKDEFAULT_INFILE : DISKDEFAULT_OUTFILE;
}
}
return devname;
}
static int
DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
DISKAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
/* handle != NULL means "user specified the placeholder name on the fake detected device list" */
const char *fname = DISKAUD_GetOutputFilename(handle ? NULL : devname);
const char *envr = SDL_getenv(DISKENVR_WRITEDELAY);
const char *fname = get_filename(iscapture, handle ? NULL : devname);
const char *envr = SDL_getenv(DISKENVR_IODELAY);
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc(sizeof(*this->hidden));
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, sizeof(*this->hidden));
SDL_zerop(this->hidden);
this->hidden->mixlen = this->spec.size;
this->hidden->write_delay =
(envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY;
if (envr != NULL) {
this->hidden->io_delay = SDL_atoi(envr);
} else {
this->hidden->io_delay = ((this->spec.samples * 1000) / this->spec.freq);
}
/* Open the audio device */
this->hidden->output = SDL_RWFromFile(fname, "wb");
if (this->hidden->output == NULL) {
DISKAUD_CloseDevice(this);
this->hidden->io = SDL_RWFromFile(fname, iscapture ? "rb" : "wb");
if (this->hidden->io == NULL) {
return -1;
}
/* Allocate mixing buffer */
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
DISKAUD_CloseDevice(this);
return -1;
if (!iscapture) {
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size);
if (this->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
#if HAVE_STDIO_H
fprintf(stderr,
"WARNING: You are using the SDL disk writer audio driver!\n"
" Writing to file [%s].\n", fname);
"WARNING: You are using the SDL disk i/o audio driver!\n"
" %s file [%s].\n", iscapture ? "Reading from" : "Writing to",
fname);
#endif
/* We're ready to rock and roll. :-) */
@ -143,30 +172,34 @@ DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
static void
DISKAUD_DetectDevices(void)
DISKAUDIO_DetectDevices(void)
{
/* !!! FIXME: stole this literal string from DEFAULT_OUTPUT_DEVNAME in SDL_audio.c */
SDL_AddAudioDevice(SDL_FALSE, "System audio output device", (void *) 0x1);
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) 0x1);
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) 0x2);
}
static int
DISKAUD_Init(SDL_AudioDriverImpl * impl)
DISKAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->OpenDevice = DISKAUD_OpenDevice;
impl->WaitDevice = DISKAUD_WaitDevice;
impl->PlayDevice = DISKAUD_PlayDevice;
impl->GetDeviceBuf = DISKAUD_GetDeviceBuf;
impl->CloseDevice = DISKAUD_CloseDevice;
impl->DetectDevices = DISKAUD_DetectDevices;
impl->OpenDevice = DISKAUDIO_OpenDevice;
impl->WaitDevice = DISKAUDIO_WaitDevice;
impl->PlayDevice = DISKAUDIO_PlayDevice;
impl->GetDeviceBuf = DISKAUDIO_GetDeviceBuf;
impl->CaptureFromDevice = DISKAUDIO_CaptureFromDevice;
impl->FlushCapture = DISKAUDIO_FlushCapture;
impl->CloseDevice = DISKAUDIO_CloseDevice;
impl->DetectDevices = DISKAUDIO_DetectDevices;
impl->AllowsArbitraryDeviceNames = 1;
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
}
AudioBootStrap DISKAUD_bootstrap = {
"disk", "direct-to-disk audio", DISKAUD_Init, 1
AudioBootStrap DISKAUDIO_bootstrap = {
"disk", "direct-to-disk audio", DISKAUDIO_Init, 1
};
#endif /* SDL_AUDIO_DRIVER_DISK */

View file

@ -32,10 +32,9 @@
struct SDL_PrivateAudioData
{
/* The file descriptor for the audio device */
SDL_RWops *output;
SDL_RWops *io;
Uint32 io_delay;
Uint8 *mixbuf;
Uint32 mixlen;
Uint32 write_delay;
};
#endif /* _SDL_diskaudio_h */

View file

@ -44,7 +44,6 @@
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_dspaudio.h"
@ -60,16 +59,11 @@ DSP_DetectDevices(void)
static void
DSP_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
}
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
}
@ -106,23 +100,20 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_zerop(this->hidden);
/* Open the audio device */
this->hidden->audio_fd = open(devname, flags, 0);
if (this->hidden->audio_fd < 0) {
DSP_CloseDevice(this);
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
}
this->hidden->mixbuf = NULL;
/* Make the file descriptor use blocking writes with fcntl() */
/* Make the file descriptor use blocking i/o with fcntl() */
{
long ctlflags;
ctlflags = fcntl(this->hidden->audio_fd, F_GETFL);
ctlflags &= ~O_NONBLOCK;
if (fcntl(this->hidden->audio_fd, F_SETFL, ctlflags) < 0) {
DSP_CloseDevice(this);
return SDL_SetError("Couldn't set audio blocking mode");
}
}
@ -130,7 +121,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Get a list of supported hardware formats */
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
perror("SNDCTL_DSP_GETFMTS");
DSP_CloseDevice(this);
return SDL_SetError("Couldn't get audio format list");
}
@ -187,7 +177,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
}
if (format == 0) {
DSP_CloseDevice(this);
return SDL_SetError("Couldn't find any hardware audio formats");
}
this->spec.format = test_format;
@ -197,7 +186,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if ((ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
(value != format)) {
perror("SNDCTL_DSP_SETFMT");
DSP_CloseDevice(this);
return SDL_SetError("Couldn't set audio format");
}
@ -205,7 +193,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
value = this->spec.channels;
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
perror("SNDCTL_DSP_CHANNELS");
DSP_CloseDevice(this);
return SDL_SetError("Cannot set the number of channels");
}
this->spec.channels = value;
@ -214,7 +201,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
value = this->spec.freq;
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
perror("SNDCTL_DSP_SPEED");
DSP_CloseDevice(this);
return SDL_SetError("Couldn't set audio frequency");
}
this->spec.freq = value;
@ -225,7 +211,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Determine the power of two of the fragment size */
for (frag_spec = 0; (0x01U << frag_spec) < this->spec.size; ++frag_spec);
if ((0x01U << frag_spec) != this->spec.size) {
DSP_CloseDevice(this);
return SDL_SetError("Fragment size must be a power of two");
}
frag_spec |= 0x00020000; /* two fragments, for low latency */
@ -250,13 +235,14 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
#endif
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
DSP_CloseDevice(this);
return SDL_OutOfMemory();
if (!iscapture) {
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/* We're ready to rock and roll. :-) */
return 0;
@ -266,14 +252,13 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
static void
DSP_PlayDevice(_THIS)
{
const Uint8 *mixbuf = this->hidden->mixbuf;
const int mixlen = this->hidden->mixlen;
if (write(this->hidden->audio_fd, mixbuf, mixlen) == -1) {
struct SDL_PrivateAudioData *h = this->hidden;
if (write(h->audio_fd, h->mixbuf, h->mixlen) == -1) {
perror("Audio write");
SDL_OpenedAudioDeviceDisconnected(this);
}
#ifdef DEBUG_AUDIO
fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen);
fprintf(stderr, "Wrote %d bytes of audio data\n", h->mixlen);
#endif
}
@ -283,6 +268,30 @@ DSP_GetDeviceBuf(_THIS)
return (this->hidden->mixbuf);
}
static int
DSP_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
return (int) read(this->hidden->audio_fd, buffer, buflen);
}
static void
DSP_FlushCapture(_THIS)
{
struct SDL_PrivateAudioData *h = this->hidden;
audio_buf_info info;
if (ioctl(h->audio_fd, SNDCTL_DSP_GETISPACE, &info) == 0) {
while (info.bytes > 0) {
char buf[512];
const size_t len = SDL_min(sizeof (buf), info.bytes);
const ssize_t br = read(h->audio_fd, buf, len);
if (br <= 0) {
break;
}
info.bytes -= br;
}
}
}
static int
DSP_Init(SDL_AudioDriverImpl * impl)
{
@ -292,8 +301,11 @@ DSP_Init(SDL_AudioDriverImpl * impl)
impl->PlayDevice = DSP_PlayDevice;
impl->GetDeviceBuf = DSP_GetDeviceBuf;
impl->CloseDevice = DSP_CloseDevice;
impl->CaptureFromDevice = DSP_CaptureFromDevice;
impl->FlushCapture = DSP_FlushCapture;
impl->AllowsArbitraryDeviceNames = 1;
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
}

View file

@ -22,27 +22,44 @@
/* Output audio to nowhere... */
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
#include "SDL_dummyaudio.h"
static int
DUMMYAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
DUMMYAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
return 0; /* always succeeds. */
}
static int
DUMMYAUD_Init(SDL_AudioDriverImpl * impl)
DUMMYAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
/* Delay to make this sort of simulate real audio input. */
SDL_Delay((this->spec.samples * 1000) / this->spec.freq);
/* always return a full buffer of silence. */
SDL_memset(buffer, this->spec.silence, buflen);
return buflen;
}
static int
DUMMYAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->OpenDevice = DUMMYAUD_OpenDevice;
impl->OpenDevice = DUMMYAUDIO_OpenDevice;
impl->CaptureFromDevice = DUMMYAUDIO_CaptureFromDevice;
impl->OnlyHasDefaultOutputDevice = 1;
impl->OnlyHasDefaultCaptureDevice = 1;
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
}
AudioBootStrap DUMMYAUD_bootstrap = {
"dummy", "SDL dummy audio driver", DUMMYAUD_Init, 1
AudioBootStrap DUMMYAUDIO_bootstrap = {
"dummy", "SDL dummy audio driver", DUMMYAUDIO_Init, 1
};
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -61,16 +61,15 @@ HandleAudioProcess(_THIS)
Uint8 *buf = NULL;
int byte_len = 0;
int bytes = SDL_AUDIO_BITSIZE(this->spec.format) / 8;
int bytes_in = SDL_AUDIO_BITSIZE(this->convert.src_format) / 8;
/* Only do soemthing if audio is enabled */
if (!this->enabled)
return;
if (this->paused)
/* Only do something if audio is enabled */
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
return;
}
if (this->convert.needed) {
const int bytes_in = SDL_AUDIO_BITSIZE(this->convert.src_format) / 8;
if (this->hidden->conv_in_len != 0) {
this->convert.len = this->hidden->conv_in_len * bytes_in * this->spec.channels;
}
@ -128,7 +127,7 @@ HandleAudioProcess(_THIS)
}
for (var j = 0; j < $1; ++j) {
channelData[j] = getValue($0 + (j*numChannels + c)*4, 'float');
channelData[j] = HEAPF32[$0 + ((j*numChannels + c) << 2) >> 2];
}
}
}, buf, byte_len / bytes / this->spec.channels);
@ -136,29 +135,147 @@ HandleAudioProcess(_THIS)
}
static void
Emscripten_CloseDevice(_THIS)
HandleCaptureProcess(_THIS)
{
if (this->hidden != NULL) {
if (this->hidden->mixbuf != NULL) {
/* Clean up the audio buffer */
SDL_free(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
}
Uint8 *buf;
int buflen;
SDL_free(this->hidden);
this->hidden = NULL;
/* Only do something if audio is enabled */
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
return;
}
if (this->convert.needed) {
buf = this->convert.buf;
buflen = this->convert.len_cvt;
} else {
if (!this->hidden->mixbuf) {
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size);
if (!this->hidden->mixbuf) {
return; /* oh well. */
}
}
buf = this->hidden->mixbuf;
buflen = this->spec.size;
}
EM_ASM_ARGS({
var numChannels = SDL2.capture.currentCaptureBuffer.numberOfChannels;
if (numChannels == 1) { /* fastpath this a little for the common (mono) case. */
var channelData = SDL2.capture.currentCaptureBuffer.getChannelData(0);
if (channelData.length != $1) {
throw 'Web Audio capture buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!';
}
for (var j = 0; j < $1; ++j) {
setValue($0 + (j * 4), channelData[j], 'float');
}
} else {
for (var c = 0; c < numChannels; ++c) {
var channelData = SDL2.capture.currentCaptureBuffer.getChannelData(c);
if (channelData.length != $1) {
throw 'Web Audio capture buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!';
}
for (var j = 0; j < $1; ++j) {
setValue($0 + (((j * numChannels) + c) * 4), channelData[j], 'float');
}
}
}
}, buf, (this->spec.size / sizeof (float)) / this->spec.channels);
/* okay, we've got an interleaved float32 array in C now. */
if (this->convert.needed) {
SDL_ConvertAudio(&this->convert);
}
/* Send it to the app. */
(*this->spec.callback) (this->spec.userdata, buf, buflen);
}
static void
EMSCRIPTENAUDIO_CloseDevice(_THIS)
{
EM_ASM_({
if ($0) {
if (SDL2.capture.silenceTimer !== undefined) {
clearTimeout(SDL2.capture.silenceTimer);
}
if (SDL2.capture.stream !== undefined) {
var tracks = SDL2.capture.stream.getAudioTracks();
for (var i = 0; i < tracks.length; i++) {
SDL2.capture.stream.removeTrack(tracks[i]);
}
SDL2.capture.stream = undefined;
}
if (SDL2.capture.scriptProcessorNode !== undefined) {
SDL2.capture.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) {};
SDL2.capture.scriptProcessorNode.disconnect();
SDL2.capture.scriptProcessorNode = undefined;
}
if (SDL2.capture.mediaStreamNode !== undefined) {
SDL2.capture.mediaStreamNode.disconnect();
SDL2.capture.mediaStreamNode = undefined;
}
if (SDL2.capture.silenceBuffer !== undefined) {
SDL2.capture.silenceBuffer = undefined
}
SDL2.capture = undefined;
} else {
if (SDL2.audio.scriptProcessorNode != undefined) {
SDL2.audio.scriptProcessorNode.disconnect();
SDL2.audio.scriptProcessorNode = undefined;
}
SDL2.audio = undefined;
}
if ((SDL2.audioContext !== undefined) && (SDL2.audio === undefined) && (SDL2.capture === undefined)) {
SDL2.audioContext.close();
SDL2.audioContext = undefined;
}
}, this->iscapture);
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
}
static int
Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
SDL_bool valid_format = SDL_FALSE;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
SDL_AudioFormat test_format;
int i;
float f;
int result;
/* based on parts of library_sdl.js */
/* create context (TODO: this puts stuff in the global namespace...)*/
result = EM_ASM_INT({
if(typeof(SDL2) === 'undefined') {
SDL2 = {};
}
if (!$0) {
SDL2.audio = {};
} else {
SDL2.capture = {};
}
if (!SDL2.audioContext) {
if (typeof(AudioContext) !== 'undefined') {
SDL2.audioContext = new AudioContext();
} else if (typeof(webkitAudioContext) !== 'undefined') {
SDL2.audioContext = new webkitAudioContext();
}
}
return SDL2.audioContext === undefined ? -1 : 0;
}, iscapture);
if (result < 0) {
return SDL_SetError("Web Audio API is not available!");
}
test_format = SDL_FirstAudioFormat(this->spec.format);
while ((!valid_format) && (test_format)) {
switch (test_format) {
case AUDIO_F32: /* web audio only supports floats */
@ -181,36 +298,11 @@ Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
/* based on parts of library_sdl.js */
/* create context (TODO: this puts stuff in the global namespace...)*/
result = EM_ASM_INT_V({
if(typeof(SDL2) === 'undefined')
SDL2 = {};
if(typeof(SDL2.audio) === 'undefined')
SDL2.audio = {};
if (!SDL2.audioContext) {
if (typeof(AudioContext) !== 'undefined') {
SDL2.audioContext = new AudioContext();
} else if (typeof(webkitAudioContext) !== 'undefined') {
SDL2.audioContext = new webkitAudioContext();
} else {
return -1;
}
}
return 0;
});
if (result < 0) {
return SDL_SetError("Web Audio API is not available!");
}
SDL_zerop(this->hidden);
/* limit to native freq */
int sampleRate = EM_ASM_INT_V({
return SDL2.audioContext['sampleRate'];
const int sampleRate = EM_ASM_INT_V({
return SDL2.audioContext.sampleRate;
});
if(this->spec.freq != sampleRate) {
@ -227,26 +319,86 @@ Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SDL_CalculateAudioSpec(&this->spec);
/* setup a ScriptProcessorNode */
EM_ASM_ARGS({
SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0);
SDL2.audio.scriptProcessorNode['onaudioprocess'] = function (e) {
SDL2.audio.currentOutputBuffer = e['outputBuffer'];
Runtime.dynCall('vi', $2, [$3]);
};
SDL2.audio.scriptProcessorNode['connect'](SDL2.audioContext['destination']);
}, this->spec.channels, this->spec.samples, HandleAudioProcess, this);
if (iscapture) {
/* The idea is to take the capture media stream, hook it up to an
audio graph where we can pass it through a ScriptProcessorNode
to access the raw PCM samples and push them to the SDL app's
callback. From there, we "process" the audio data into silence
and forget about it. */
/* This should, strictly speaking, use MediaRecorder for capture, but
this API is cleaner to use and better supported, and fires a
callback whenever there's enough data to fire down into the app.
The downside is that we are spending CPU time silencing a buffer
that the audiocontext uselessly mixes into any output. On the
upside, both of those things are not only run in native code in
the browser, they're probably SIMD code, too. MediaRecorder
feels like it's a pretty inefficient tapdance in similar ways,
to be honest. */
EM_ASM_({
var have_microphone = function(stream) {
//console.log('SDL audio capture: we have a microphone! Replacing silence callback.');
if (SDL2.capture.silenceTimer !== undefined) {
clearTimeout(SDL2.capture.silenceTimer);
SDL2.capture.silenceTimer = undefined;
}
SDL2.capture.mediaStreamNode = SDL2.audioContext.createMediaStreamSource(stream);
SDL2.capture.scriptProcessorNode = SDL2.audioContext.createScriptProcessor($1, $0, 1);
SDL2.capture.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) {
if ((SDL2 === undefined) || (SDL2.capture === undefined)) { return; }
audioProcessingEvent.outputBuffer.getChannelData(0).fill(0.0);
SDL2.capture.currentCaptureBuffer = audioProcessingEvent.inputBuffer;
Runtime.dynCall('vi', $2, [$3]);
};
SDL2.capture.mediaStreamNode.connect(SDL2.capture.scriptProcessorNode);
SDL2.capture.scriptProcessorNode.connect(SDL2.audioContext.destination);
SDL2.capture.stream = stream;
};
var no_microphone = function(error) {
//console.log('SDL audio capture: we DO NOT have a microphone! (' + error.name + ')...leaving silence callback running.');
};
/* we write silence to the audio callback until the microphone is available (user approves use, etc). */
SDL2.capture.silenceBuffer = SDL2.audioContext.createBuffer($0, $1, SDL2.audioContext.sampleRate);
SDL2.capture.silenceBuffer.getChannelData(0).fill(0.0);
var silence_callback = function() {
SDL2.capture.currentCaptureBuffer = SDL2.capture.silenceBuffer;
Runtime.dynCall('vi', $2, [$3]);
};
SDL2.capture.silenceTimer = setTimeout(silence_callback, ($1 / SDL2.audioContext.sampleRate) * 1000);
if ((navigator.mediaDevices !== undefined) && (navigator.mediaDevices.getUserMedia !== undefined)) {
navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(have_microphone).catch(no_microphone);
} else if (navigator.webkitGetUserMedia !== undefined) {
navigator.webkitGetUserMedia({ audio: true, video: false }, have_microphone, no_microphone);
}
}, this->spec.channels, this->spec.samples, HandleCaptureProcess, this);
} else {
/* setup a ScriptProcessorNode */
EM_ASM_ARGS({
SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0);
SDL2.audio.scriptProcessorNode['onaudioprocess'] = function (e) {
if ((SDL2 === undefined) || (SDL2.audio === undefined)) { return; }
SDL2.audio.currentOutputBuffer = e['outputBuffer'];
Runtime.dynCall('vi', $2, [$3]);
};
SDL2.audio.scriptProcessorNode['connect'](SDL2.audioContext['destination']);
}, this->spec.channels, this->spec.samples, HandleAudioProcess, this);
}
return 0;
}
static int
Emscripten_Init(SDL_AudioDriverImpl * impl)
EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->OpenDevice = Emscripten_OpenDevice;
impl->CloseDevice = Emscripten_CloseDevice;
impl->OpenDevice = EMSCRIPTENAUDIO_OpenDevice;
impl->CloseDevice = EMSCRIPTENAUDIO_CloseDevice;
/* only one output */
impl->OnlyHasDefaultOutputDevice = 1;
/* no threads here */
@ -254,7 +406,7 @@ Emscripten_Init(SDL_AudioDriverImpl * impl)
impl->ProvidesOwnCallbackThread = 1;
/* check availability */
int available = EM_ASM_INT_V({
const int available = EM_ASM_INT_V({
if (typeof(AudioContext) !== 'undefined') {
return 1;
} else if (typeof(webkitAudioContext) !== 'undefined') {
@ -267,11 +419,23 @@ Emscripten_Init(SDL_AudioDriverImpl * impl)
SDL_SetError("No audio context available");
}
const int capture_available = available && EM_ASM_INT_V({
if ((typeof(navigator.mediaDevices) !== 'undefined') && (typeof(navigator.mediaDevices.getUserMedia) !== 'undefined')) {
return 1;
} else if (typeof(navigator.webkitGetUserMedia) !== 'undefined') {
return 1;
}
return 0;
});
impl->HasCaptureSupport = capture_available ? SDL_TRUE : SDL_FALSE;
impl->OnlyHasDefaultCaptureDevice = capture_available ? SDL_TRUE : SDL_FALSE;
return available;
}
AudioBootStrap EmscriptenAudio_bootstrap = {
"emscripten", "SDL emscripten audio driver", Emscripten_Init, 0
AudioBootStrap EMSCRIPTENAUDIO_bootstrap = {
"emscripten", "SDL emscripten audio driver", EMSCRIPTENAUDIO_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_EMSCRIPTEN */

View file

@ -32,7 +32,6 @@
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_esdaudio.h"
@ -174,17 +173,11 @@ ESD_GetDeviceBuf(_THIS)
static void
ESD_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->audio_fd >= 0) {
SDL_NAME(esd_close) (this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
if (this->hidden->audio_fd >= 0) {
SDL_NAME(esd_close) (this->hidden->audio_fd);
}
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
}
/* Try to get the name of the program */
@ -227,7 +220,7 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_zerop(this->hidden);
this->hidden->audio_fd = -1;
/* Convert audio spec to the ESD audio format */
@ -252,7 +245,6 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
if (!found) {
ESD_CloseDevice(this);
return SDL_SetError("Couldn't find any hardware audio formats");
}
@ -271,7 +263,6 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
get_progname());
if (this->hidden->audio_fd < 0) {
ESD_CloseDevice(this);
return SDL_SetError("Couldn't open ESD connection");
}
@ -283,9 +274,8 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
ESD_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);

View file

@ -22,6 +22,8 @@
#if SDL_AUDIO_DRIVER_FUSIONSOUND
/* !!! FIXME: why is this is SDL_FS_* instead of FUSIONSOUND_*? */
/* Allow access to a raw mixing buffer */
#ifdef HAVE_SIGNAL_H
@ -31,7 +33,6 @@
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_fsaudio.h"
@ -150,13 +151,6 @@ SDL_FS_PlayDevice(_THIS)
#endif
}
static void
SDL_FS_WaitDone(_THIS)
{
this->hidden->stream->Wait(this->hidden->stream,
this->hidden->mixsamples * FUSION_BUFFERS);
}
static Uint8 *
SDL_FS_GetDeviceBuf(_THIS)
@ -168,20 +162,14 @@ SDL_FS_GetDeviceBuf(_THIS)
static void
SDL_FS_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->stream) {
this->hidden->stream->Release(this->hidden->stream);
this->hidden->stream = NULL;
}
if (this->hidden->fs) {
this->hidden->fs->Release(this->hidden->fs);
this->hidden->fs = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
if (this->hidden->stream) {
this->hidden->stream->Release(this->hidden->stream);
}
if (this->hidden->fs) {
this->hidden->fs->Release(this->hidden->fs);
}
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
}
@ -200,7 +188,7 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_zerop(this->hidden);
/* Try for a closest match on audio format */
for (test_format = SDL_FirstAudioFormat(this->spec.format);
@ -239,7 +227,6 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
if (format == 0) {
SDL_FS_CloseDevice(this);
return SDL_SetError("Couldn't find any hardware audio formats");
}
this->spec.format = test_format;
@ -247,7 +234,6 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Retrieve the main sound interface. */
ret = SDL_NAME(FusionSoundCreate) (&this->hidden->fs);
if (ret) {
SDL_FS_CloseDevice(this);
return SDL_SetError("Unable to initialize FusionSound: %d", ret);
}
@ -266,7 +252,6 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
this->hidden->fs->CreateStream(this->hidden->fs, &desc,
&this->hidden->stream);
if (ret) {
SDL_FS_CloseDevice(this);
return SDL_SetError("Unable to create FusionSoundStream: %d", ret);
}
@ -285,9 +270,8 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
SDL_FS_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
@ -328,7 +312,6 @@ SDL_FS_Init(SDL_AudioDriverImpl * impl)
impl->WaitDevice = SDL_FS_WaitDevice;
impl->GetDeviceBuf = SDL_FS_GetDeviceBuf;
impl->CloseDevice = SDL_FS_CloseDevice;
impl->WaitDone = SDL_FS_WaitDone;
impl->Deinitialize = SDL_FS_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1;

View file

@ -49,10 +49,11 @@ FillSound(void *device, void *stream, size_t len,
SDL_AudioDevice *audio = (SDL_AudioDevice *) device;
/* Only do soemthing if audio is enabled */
if (!audio->enabled)
if (!SDL_AtomicGet(&audio->enabled)) {
return;
}
if (!audio->paused) {
if (!SDL_AtomicGet(&audio->paused)) {
if (audio->convert.needed) {
SDL_LockMutex(audio->mixer_lock);
(*audio->spec.callback) (audio->spec.userdata,
@ -73,16 +74,11 @@ FillSound(void *device, void *stream, size_t len,
static void
HAIKUAUDIO_CloseDevice(_THIS)
{
if (_this->hidden != NULL) {
if (_this->hidden->audio_obj) {
_this->hidden->audio_obj->Stop();
delete _this->hidden->audio_obj;
_this->hidden->audio_obj = NULL;
}
delete _this->hidden;
_this->hidden = NULL;
if (_this->hidden->audio_obj) {
_this->hidden->audio_obj->Stop();
delete _this->hidden->audio_obj;
}
delete _this->hidden;
}
@ -122,10 +118,10 @@ HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (_this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(_this->hidden, 0, (sizeof *_this->hidden));
SDL_zerop(_this->hidden);
/* Parse the audio format and fill the Be raw audio format */
SDL_memset(&format, '\0', sizeof(media_raw_audio_format));
SDL_zero(format);
format.byte_order = B_MEDIA_LITTLE_ENDIAN;
format.frame_rate = (float) _this->spec.freq;
format.channel_count = _this->spec.channels; /* !!! FIXME: support > 2? */
@ -176,7 +172,6 @@ HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
if (!valid_datatype) { /* shouldn't happen, but just in case... */
HAIKUAUDIO_CloseDevice(_this);
return SDL_SetError("Unsupported audio format");
}
@ -195,7 +190,6 @@ HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (_this->hidden->audio_obj->Start() == B_NO_ERROR) {
_this->hidden->audio_obj->SetHasData(true);
} else {
HAIKUAUDIO_CloseDevice(_this);
return SDL_SetError("Unable to start Be audio");
}

View file

@ -27,7 +27,6 @@
#include "SDL_audio.h"
#include "SDL_mutex.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
@ -38,22 +37,20 @@
#include "ppapi_simple/ps_event.h"
/* The tag name used by NACL audio */
#define NACLAUD_DRIVER_NAME "nacl"
#define NACLAUDIO_DRIVER_NAME "nacl"
#define SAMPLE_FRAME_COUNT 4096
/* Audio driver functions */
static int NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture);
static void NACLAUD_CloseDevice(_THIS);
static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data);
/* FIXME: Make use of latency if needed */
static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data) {
SDL_AudioDevice* _this = (SDL_AudioDevice*) data;
SDL_LockMutex(private->mutex);
SDL_LockMutex(private->mutex); /* !!! FIXME: is this mutex necessary? */
if (_this->enabled && !_this->paused) {
if (SDL_AtomicGet(&_this->enabled) && !SDL_AtomicGet(&_this->paused)) {
if (_this->convert.needed) {
SDL_LockMutex(_this->mixer_lock);
(*_this->spec.callback) (_this->spec.userdata,
@ -68,13 +65,13 @@ static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelt
SDL_UnlockMutex(_this->mixer_lock);
}
} else {
SDL_memset(samples, 0, buffer_size);
SDL_memset(samples, _this->spec.silence, buffer_size);
}
return;
SDL_UnlockMutex(private->mutex);
}
static void NACLAUD_CloseDevice(SDL_AudioDevice *device) {
static void NACLAUDIO_CloseDevice(SDL_AudioDevice *device) {
const PPB_Core *core = PSInterfaceCore();
const PPB_Audio *ppb_audio = PSInterfaceAudio();
SDL_PrivateAudioData *hidden = (SDL_PrivateAudioData *) device->hidden;
@ -85,7 +82,7 @@ static void NACLAUD_CloseDevice(SDL_AudioDevice *device) {
}
static int
NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) {
NACLAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) {
PP_Instance instance = PSGetInstanceId();
const PPB_Audio *ppb_audio = PSInterfaceAudio();
const PPB_AudioConfig *ppb_audiocfg = PSInterfaceAudioConfig();
@ -121,30 +118,30 @@ NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) {
}
static int
NACLAUD_Init(SDL_AudioDriverImpl * impl)
NACLAUDIO_Init(SDL_AudioDriverImpl * impl)
{
if (PSGetInstanceId() == 0) {
return 0;
}
/* Set the function pointers */
impl->OpenDevice = NACLAUD_OpenDevice;
impl->CloseDevice = NACLAUD_CloseDevice;
impl->OpenDevice = NACLAUDIO_OpenDevice;
impl->CloseDevice = NACLAUDIO_CloseDevice;
impl->OnlyHasDefaultOutputDevice = 1;
impl->ProvidesOwnCallbackThread = 1;
/*
* impl->WaitDevice = NACLAUD_WaitDevice;
* impl->GetDeviceBuf = NACLAUD_GetDeviceBuf;
* impl->PlayDevice = NACLAUD_PlayDevice;
* impl->Deinitialize = NACLAUD_Deinitialize;
* impl->WaitDevice = NACLAUDIO_WaitDevice;
* impl->GetDeviceBuf = NACLAUDIO_GetDeviceBuf;
* impl->PlayDevice = NACLAUDIO_PlayDevice;
* impl->Deinitialize = NACLAUDIO_Deinitialize;
*/
return 1;
}
AudioBootStrap NACLAUD_bootstrap = {
NACLAUD_DRIVER_NAME, "SDL NaCl Audio Driver",
NACLAUD_Init, 0
AudioBootStrap NACLAUDIO_bootstrap = {
NACLAUDIO_DRIVER_NAME, "SDL NaCl Audio Driver",
NACLAUDIO_Init, 0
};
#endif /* SDL_AUDIO_DRIVER_NACL */

View file

@ -30,22 +30,21 @@
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "SDL_loadso.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_nasaudio.h"
static struct SDL_PrivateAudioData *this2 = NULL;
static void (*NAS_AuCloseServer) (AuServer *);
static void (*NAS_AuNextEvent) (AuServer *, AuBool, AuEvent *);
static AuBool(*NAS_AuDispatchEvent) (AuServer *, AuEvent *);
static void (*NAS_AuHandleEvents) (AuServer *);
static AuFlowID(*NAS_AuCreateFlow) (AuServer *, AuStatus *);
static void (*NAS_AuStartFlow) (AuServer *, AuFlowID, AuStatus *);
static void (*NAS_AuSetElements)
(AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *);
static void (*NAS_AuWriteElement)
(AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *);
static AuUint32 (*NAS_AuReadElement)
(AuServer *, AuFlowID, int, AuUint32, AuPointer, AuStatus *);
static AuServer *(*NAS_AuOpenServer)
(_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **);
static AuEventHandlerRec *(*NAS_AuRegisterEventHandler)
@ -80,10 +79,12 @@ load_nas_syms(void)
SDL_NAS_SYM(AuCloseServer);
SDL_NAS_SYM(AuNextEvent);
SDL_NAS_SYM(AuDispatchEvent);
SDL_NAS_SYM(AuHandleEvents);
SDL_NAS_SYM(AuCreateFlow);
SDL_NAS_SYM(AuStartFlow);
SDL_NAS_SYM(AuSetElements);
SDL_NAS_SYM(AuWriteElement);
SDL_NAS_SYM(AuReadElement);
SDL_NAS_SYM(AuOpenServer);
SDL_NAS_SYM(AuRegisterEventHandler);
return 0;
@ -187,19 +188,53 @@ NAS_GetDeviceBuf(_THIS)
return (this->hidden->mixbuf);
}
static int
NAS_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
struct SDL_PrivateAudioData *h = this->hidden;
int retval;
while (SDL_TRUE) {
/* just keep the event queue moving and the server chattering. */
NAS_AuHandleEvents(h->aud);
retval = (int) NAS_AuReadElement(h->aud, h->flow, 1, buflen, buffer, NULL);
/*printf("read %d capture bytes\n", (int) retval);*/
if (retval == 0) {
SDL_Delay(10); /* don't burn the CPU if we're waiting for data. */
} else {
break;
}
}
return retval;
}
static void
NAS_FlushCapture(_THIS)
{
struct SDL_PrivateAudioData *h = this->hidden;
AuUint32 total = 0;
AuUint32 br;
Uint8 buf[512];
do {
/* just keep the event queue moving and the server chattering. */
NAS_AuHandleEvents(h->aud);
br = NAS_AuReadElement(h->aud, h->flow, 1, sizeof (buf), buf, NULL);
/*printf("flushed %d capture bytes\n", (int) br);*/
total += br;
} while ((br == sizeof (buf)) && (total < this->spec.size));
}
static void
NAS_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->aud) {
NAS_AuCloseServer(this->hidden->aud);
this->hidden->aud = 0;
}
SDL_free(this->hidden);
this2 = this->hidden = NULL;
if (this->hidden->aud) {
NAS_AuCloseServer(this->hidden->aud);
}
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
}
static unsigned char
@ -225,6 +260,12 @@ sdlformat_to_auformat(unsigned int fmt)
static AuBool
event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
{
SDL_AudioDevice *this = (SDL_AudioDevice *) hnd->data;
struct SDL_PrivateAudioData *h = this->hidden;
if (this->iscapture) {
return AuTrue; /* we don't (currently) care about any of this for capture devices */
}
switch (ev->type) {
case AuEventTypeElementNotify:
{
@ -232,24 +273,24 @@ event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
switch (event->kind) {
case AuElementNotifyKindLowWater:
if (this2->buf_free >= 0) {
this2->really += event->num_bytes;
gettimeofday(&this2->last_tv, 0);
this2->buf_free += event->num_bytes;
if (h->buf_free >= 0) {
h->really += event->num_bytes;
gettimeofday(&h->last_tv, 0);
h->buf_free += event->num_bytes;
} else {
this2->buf_free = event->num_bytes;
h->buf_free = event->num_bytes;
}
break;
case AuElementNotifyKindState:
switch (event->cur_state) {
case AuStatePause:
if (event->reason != AuReasonUser) {
if (this2->buf_free >= 0) {
this2->really += event->num_bytes;
gettimeofday(&this2->last_tv, 0);
this2->buf_free += event->num_bytes;
if (h->buf_free >= 0) {
h->really += event->num_bytes;
gettimeofday(&h->last_tv, 0);
h->buf_free += event->num_bytes;
} else {
this2->buf_free = event->num_bytes;
h->buf_free = event->num_bytes;
}
}
break;
@ -261,15 +302,29 @@ event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd)
}
static AuDeviceID
find_device(_THIS, int nch)
find_device(_THIS)
{
/* These "Au" things are all macros, not functions... */
struct SDL_PrivateAudioData *h = this->hidden;
const unsigned int devicekind = this->iscapture ? AuComponentKindPhysicalInput : AuComponentKindPhysicalOutput;
const int numdevs = AuServerNumDevices(h->aud);
const int nch = this->spec.channels;
int i;
for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) {
if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) ==
AuComponentKindPhysicalOutput) &&
AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) {
return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i));
/* Try to find exact match on channels first... */
for (i = 0; i < numdevs; i++) {
const AuDeviceAttributes *dev = AuServerDevice(h->aud, i);
if ((AuDeviceKind(dev) == devicekind) && (AuDeviceNumTracks(dev) == nch)) {
return AuDeviceIdentifier(dev);
}
}
/* Take anything, then... */
for (i = 0; i < numdevs; i++) {
const AuDeviceAttributes *dev = AuServerDevice(h->aud, i);
if (AuDeviceKind(dev) == devicekind) {
this->spec.channels = AuDeviceNumTracks(dev);
return AuDeviceIdentifier(dev);
}
}
return AuNone;
@ -288,7 +343,7 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_zerop(this->hidden);
/* Try for a closest match on audio format */
format = 0;
@ -300,21 +355,18 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
}
if (format == 0) {
NAS_CloseDevice(this);
return SDL_SetError("NAS: Couldn't find any hardware audio formats");
}
this->spec.format = test_format;
this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL);
if (this->hidden->aud == 0) {
NAS_CloseDevice(this);
return SDL_SetError("NAS: Couldn't open connection to NAS server");
}
this->hidden->dev = find_device(this, this->spec.channels);
this->hidden->dev = find_device(this);
if ((this->hidden->dev == AuNone)
|| (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) {
NAS_CloseDevice(this);
return SDL_SetError("NAS: Couldn't find a fitting device on NAS server");
}
@ -328,29 +380,38 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Calculate the final parameters for this audio specification */
SDL_CalculateAudioSpec(&this->spec);
this2 = this->hidden;
if (iscapture) {
AuMakeElementImportDevice(elms, this->spec.freq, this->hidden->dev,
AuUnlimitedSamples, 0, NULL);
AuMakeElementExportClient(elms + 1, 0, this->spec.freq, format,
this->spec.channels, AuTrue, buffer_size,
buffer_size, 0, NULL);
} else {
AuMakeElementImportClient(elms, this->spec.freq, format,
this->spec.channels, AuTrue, buffer_size,
buffer_size / 4, 0, NULL);
AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq,
AuUnlimitedSamples, 0, NULL);
}
NAS_AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue,
2, elms, NULL);
AuMakeElementImportClient(elms, this->spec.freq, format,
this->spec.channels, AuTrue, buffer_size,
buffer_size / 4, 0, NULL);
AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq,
AuUnlimitedSamples, 0, NULL);
NAS_AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms,
NULL);
NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0,
this->hidden->flow, event_handler,
(AuPointer) NULL);
(AuPointer) this);
NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL);
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
NAS_CloseDevice(this);
return SDL_OutOfMemory();
if (!iscapture) {
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
/* We're ready to rock and roll. :-) */
return 0;
@ -381,9 +442,14 @@ NAS_Init(SDL_AudioDriverImpl * impl)
impl->PlayDevice = NAS_PlayDevice;
impl->WaitDevice = NAS_WaitDevice;
impl->GetDeviceBuf = NAS_GetDeviceBuf;
impl->CaptureFromDevice = NAS_CaptureFromDevice;
impl->FlushCapture = NAS_FlushCapture;
impl->CloseDevice = NAS_CloseDevice;
impl->Deinitialize = NAS_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: is this true? */
impl->OnlyHasDefaultOutputDevice = 1;
impl->OnlyHasDefaultCaptureDevice = 1;
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
}

View file

@ -35,7 +35,6 @@
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "SDL_stdinc.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_paudio.h"
@ -228,16 +227,11 @@ PAUDIO_GetDeviceBuf(_THIS)
static void
PAUDIO_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
}
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
}
static int
@ -262,13 +256,12 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_zerop(this->hidden);
/* Open the audio device */
fd = OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0);
this->hidden->audio_fd = fd;
if (fd < 0) {
PAUDIO_CloseDevice(this);
return SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno));
}
@ -277,7 +270,6 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
* that we can have.
*/
if (ioctl(fd, AUDIO_BUFFER, &paud_bufinfo) < 0) {
PAUDIO_CloseDevice(this);
return SDL_SetError("Couldn't get audio buffer information");
}
@ -391,7 +383,6 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
#ifdef DEBUG_AUDIO
fprintf(stderr, "Couldn't find any hardware audio formats\n");
#endif
PAUDIO_CloseDevice(this);
return SDL_SetError("Couldn't find any hardware audio formats");
}
this->spec.format = test_format;
@ -449,15 +440,13 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
if (err != NULL) {
PAUDIO_CloseDevice(this);
return SDL_SetError("Paudio: %s", err);
}
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
PAUDIO_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
@ -492,7 +481,6 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
paud_control.ioctl_request = AUDIO_START;
paud_control.position = 0;
if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) {
PAUDIO_CloseDevice(this);
#ifdef DEBUG_AUDIO
fprintf(stderr, "Can't start audio play\n");
#endif

View file

@ -30,7 +30,6 @@
#include "SDL_audio.h"
#include "SDL_error.h"
#include "SDL_timer.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "../SDL_sysaudio.h"
@ -40,10 +39,10 @@
#include <pspthreadman.h>
/* The tag name used by PSP audio */
#define PSPAUD_DRIVER_NAME "psp"
#define PSPAUDIO_DRIVER_NAME "psp"
static int
PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
PSPAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
int format, mixlen, i;
this->hidden = (struct SDL_PrivateAudioData *)
@ -51,7 +50,7 @@ PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, sizeof(*this->hidden));
SDL_zerop(this->hidden);
switch (this->spec.format & 0xff) {
case 8:
case 16:
@ -66,20 +65,7 @@ PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
this->spec.freq = 44100;
/* Update the fragment size as size in bytes. */
/* SDL_CalculateAudioSpec(this->spec); MOD */
switch (this->spec.format) {
case AUDIO_U8:
this->spec.silence = 0x80;
break;
default:
this->spec.silence = 0x00;
break;
}
this->spec.size = SDL_AUDIO_BITSIZE(this->spec.format) / 8;
this->spec.size *= this->spec.channels;
this->spec.size *= this->spec.samples;
/* ========================================== */
SDL_CalculateAudioSpec(&this->spec);
/* Allocate the mixing buffer. Its size and starting address must
be a multiple of 64 bytes. Our sample count is already a multiple of
@ -112,7 +98,7 @@ PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
return 0;
}
static void PSPAUD_PlayDevice(_THIS)
static void PSPAUDIO_PlayDevice(_THIS)
{
Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer];
@ -126,28 +112,25 @@ static void PSPAUD_PlayDevice(_THIS)
}
/* This function waits until it is possible to write a full sound buffer */
static void PSPAUD_WaitDevice(_THIS)
static void PSPAUDIO_WaitDevice(_THIS)
{
/* Because we block when sending audio, there's no need for this function to do anything. */
}
static Uint8 *PSPAUD_GetDeviceBuf(_THIS)
static Uint8 *PSPAUDIO_GetDeviceBuf(_THIS)
{
return this->hidden->mixbufs[this->hidden->next_buffer];
}
static void PSPAUD_CloseDevice(_THIS)
static void PSPAUDIO_CloseDevice(_THIS)
{
if (this->hidden->channel >= 0) {
sceAudioChRelease(this->hidden->channel);
this->hidden->channel = -1;
}
if (this->hidden->rawbuf != NULL) {
free(this->hidden->rawbuf);
this->hidden->rawbuf = NULL;
}
free(this->hidden->rawbuf); /* this uses memalign(), not SDL_malloc(). */
SDL_free(this->hidden);
}
static void PSPAUD_ThreadInit(_THIS)
static void PSPAUDIO_ThreadInit(_THIS)
{
/* Increase the priority of this audio thread by 1 to put it
ahead of other SDL threads. */
@ -162,24 +145,22 @@ static void PSPAUD_ThreadInit(_THIS)
static int
PSPAUD_Init(SDL_AudioDriverImpl * impl)
PSPAUDIO_Init(SDL_AudioDriverImpl * impl)
{
/* Set the function pointers */
impl->OpenDevice = PSPAUD_OpenDevice;
impl->PlayDevice = PSPAUD_PlayDevice;
impl->WaitDevice = PSPAUD_WaitDevice;
impl->GetDeviceBuf = PSPAUD_GetDeviceBuf;
impl->WaitDone = PSPAUD_WaitDevice;
impl->CloseDevice = PSPAUD_CloseDevice;
impl->ThreadInit = PSPAUD_ThreadInit;
impl->OpenDevice = PSPAUDIO_OpenDevice;
impl->PlayDevice = PSPAUDIO_PlayDevice;
impl->WaitDevice = PSPAUDIO_WaitDevice;
impl->GetDeviceBuf = PSPAUDIO_GetDeviceBuf;
impl->CloseDevice = PSPAUDIO_CloseDevice;
impl->ThreadInit = PSPAUDIO_ThreadInit;
/* PSP audio device */
impl->OnlyHasDefaultOutputDevice = 1;
/*
impl->HasCaptureSupport = 1;
impl->OnlyHasDefaultInputDevice = 1;
impl->OnlyHasDefaultCaptureDevice = 1;
*/
/*
impl->DetectDevices = DSOUND_DetectDevices;
@ -188,8 +169,8 @@ PSPAUD_Init(SDL_AudioDriverImpl * impl)
return 1; /* this audio target is available. */
}
AudioBootStrap PSPAUD_bootstrap = {
"psp", "PSP audio driver", PSPAUD_Init, 0
AudioBootStrap PSPAUDIO_bootstrap = {
"psp", "PSP audio driver", PSPAUDIO_Init, 0
};
/* SDL_AUDI */

View file

@ -42,10 +42,10 @@
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_pulseaudio.h"
#include "SDL_loadso.h"
#include "../../thread/SDL_systhread.h"
#if (PA_API_VERSION < 12)
/** Return non-zero if the passed state is one of the connected states */
@ -99,12 +99,19 @@ static pa_stream * (*PULSEAUDIO_pa_stream_new) (pa_context *, const char *,
const pa_sample_spec *, const pa_channel_map *);
static int (*PULSEAUDIO_pa_stream_connect_playback) (pa_stream *, const char *,
const pa_buffer_attr *, pa_stream_flags_t, pa_cvolume *, pa_stream *);
static int (*PULSEAUDIO_pa_stream_connect_record) (pa_stream *, const char *,
const pa_buffer_attr *, pa_stream_flags_t);
static pa_stream_state_t (*PULSEAUDIO_pa_stream_get_state) (pa_stream *);
static size_t (*PULSEAUDIO_pa_stream_writable_size) (pa_stream *);
static size_t (*PULSEAUDIO_pa_stream_readable_size) (pa_stream *);
static int (*PULSEAUDIO_pa_stream_write) (pa_stream *, const void *, size_t,
pa_free_cb_t, int64_t, pa_seek_mode_t);
static pa_operation * (*PULSEAUDIO_pa_stream_drain) (pa_stream *,
pa_stream_success_cb_t, void *);
static int (*PULSEAUDIO_pa_stream_peek) (pa_stream *, const void **, size_t *);
static int (*PULSEAUDIO_pa_stream_drop) (pa_stream *);
static pa_operation * (*PULSEAUDIO_pa_stream_flush) (pa_stream *,
pa_stream_success_cb_t, void *);
static int (*PULSEAUDIO_pa_stream_disconnect) (pa_stream *);
static void (*PULSEAUDIO_pa_stream_unref) (pa_stream *);
@ -205,11 +212,16 @@ load_pulseaudio_syms(void)
SDL_PULSEAUDIO_SYM(pa_context_unref);
SDL_PULSEAUDIO_SYM(pa_stream_new);
SDL_PULSEAUDIO_SYM(pa_stream_connect_playback);
SDL_PULSEAUDIO_SYM(pa_stream_connect_record);
SDL_PULSEAUDIO_SYM(pa_stream_get_state);
SDL_PULSEAUDIO_SYM(pa_stream_writable_size);
SDL_PULSEAUDIO_SYM(pa_stream_readable_size);
SDL_PULSEAUDIO_SYM(pa_stream_write);
SDL_PULSEAUDIO_SYM(pa_stream_drain);
SDL_PULSEAUDIO_SYM(pa_stream_disconnect);
SDL_PULSEAUDIO_SYM(pa_stream_peek);
SDL_PULSEAUDIO_SYM(pa_stream_drop);
SDL_PULSEAUDIO_SYM(pa_stream_flush);
SDL_PULSEAUDIO_SYM(pa_stream_unref);
SDL_PULSEAUDIO_SYM(pa_channel_map_init_auto);
SDL_PULSEAUDIO_SYM(pa_strerror);
@ -238,6 +250,12 @@ getAppName(void)
return "SDL Application"; /* oh well. */
}
static void
stream_operation_complete_no_op(pa_stream *s, int success, void *userdata)
{
/* no-op for pa_stream_drain(), etc, to use for callback. */
}
static void
WaitForPulseOperation(pa_mainloop *mainloop, pa_operation *o)
{
@ -325,7 +343,7 @@ PULSEAUDIO_WaitDevice(_THIS)
{
struct SDL_PrivateAudioData *h = this->hidden;
while (this->enabled) {
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) {
@ -343,41 +361,13 @@ PULSEAUDIO_PlayDevice(_THIS)
{
/* Write the audio data */
struct SDL_PrivateAudioData *h = this->hidden;
if (this->enabled) {
if (SDL_AtomicGet(&this->enabled)) {
if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0) {
SDL_OpenedAudioDeviceDisconnected(this);
}
}
}
static void
stream_drain_complete(pa_stream *s, int success, void *userdata)
{
/* no-op for pa_stream_drain() to use for callback. */
}
static void
PULSEAUDIO_WaitDone(_THIS)
{
if (this->enabled) {
struct SDL_PrivateAudioData *h = this->hidden;
pa_operation *o = PULSEAUDIO_pa_stream_drain(h->stream, stream_drain_complete, NULL);
if (o) {
while (PULSEAUDIO_pa_operation_get_state(o) != PA_OPERATION_DONE) {
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
PULSEAUDIO_pa_operation_cancel(o);
break;
}
}
PULSEAUDIO_pa_operation_unref(o);
}
}
}
static Uint8 *
PULSEAUDIO_GetDeviceBuf(_THIS)
{
@ -385,24 +375,96 @@ PULSEAUDIO_GetDeviceBuf(_THIS)
}
static int
PULSEAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
struct SDL_PrivateAudioData *h = this->hidden;
const void *data = NULL;
size_t nbytes = 0;
while (SDL_AtomicGet(&this->enabled)) {
if (h->capturebuf != NULL) {
const int cpy = SDL_min(buflen, h->capturelen);
SDL_memcpy(buffer, h->capturebuf, cpy);
/*printf("PULSEAUDIO: fed %d captured bytes\n", cpy);*/
h->capturebuf += cpy;
h->capturelen -= cpy;
if (h->capturelen == 0) {
h->capturebuf = NULL;
PULSEAUDIO_pa_stream_drop(h->stream); /* done with this fragment. */
}
return cpy; /* new data, return it. */
}
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
SDL_OpenedAudioDeviceDisconnected(this);
return -1; /* uhoh, pulse failed! */
}
if (PULSEAUDIO_pa_stream_readable_size(h->stream) == 0) {
continue; /* no data available yet. */
}
/* a new fragment is available! */
PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes);
SDL_assert(nbytes > 0);
if (data == NULL) { /* NULL==buffer had a hole. Ignore that. */
PULSEAUDIO_pa_stream_drop(h->stream); /* drop this fragment. */
} else {
/* store this fragment's data, start feeding it to SDL. */
/*printf("PULSEAUDIO: captured %d new bytes\n", (int) nbytes);*/
h->capturebuf = (const Uint8 *) data;
h->capturelen = nbytes;
}
}
return -1; /* not enabled? */
}
static void
PULSEAUDIO_FlushCapture(_THIS)
{
struct SDL_PrivateAudioData *h = this->hidden;
if (h->capturebuf != NULL) {
PULSEAUDIO_pa_stream_drop(h->stream);
h->capturebuf = NULL;
h->capturelen = 0;
}
WaitForPulseOperation(h->mainloop, PULSEAUDIO_pa_stream_flush(h->stream, stream_operation_complete_no_op, NULL));
}
static void
PULSEAUDIO_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
SDL_free(this->hidden->device_name);
if (this->hidden->stream) {
PULSEAUDIO_pa_stream_disconnect(this->hidden->stream);
PULSEAUDIO_pa_stream_unref(this->hidden->stream);
if (this->hidden->stream) {
if (this->hidden->capturebuf != NULL) {
PULSEAUDIO_pa_stream_drop(this->hidden->stream);
}
DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context);
SDL_free(this->hidden);
this->hidden = NULL;
PULSEAUDIO_pa_stream_disconnect(this->hidden->stream);
PULSEAUDIO_pa_stream_unref(this->hidden->stream);
}
DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context);
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden->device_name);
SDL_free(this->hidden);
}
static void
SinkDeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
{
if (i) {
char **devname = (char **) data;
*devname = SDL_strdup(i->name);
}
}
static void
DeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
SourceDeviceNameCallback(pa_context *c, const pa_source_info *i, int is_last, void *data)
{
if (i) {
char **devname = (char **) data;
@ -411,7 +473,7 @@ DeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data
}
static SDL_bool
FindDeviceName(struct SDL_PrivateAudioData *h, void *handle)
FindDeviceName(struct SDL_PrivateAudioData *h, const int iscapture, void *handle)
{
const uint32_t idx = ((uint32_t) ((size_t) handle)) - 1;
@ -419,7 +481,16 @@ FindDeviceName(struct SDL_PrivateAudioData *h, void *handle)
return SDL_TRUE;
}
WaitForPulseOperation(h->mainloop, PULSEAUDIO_pa_context_get_sink_info_by_index(h->context, idx, DeviceNameCallback, &h->device_name));
if (iscapture) {
WaitForPulseOperation(h->mainloop,
PULSEAUDIO_pa_context_get_source_info_by_index(h->context, idx,
SourceDeviceNameCallback, &h->device_name));
} else {
WaitForPulseOperation(h->mainloop,
PULSEAUDIO_pa_context_get_sink_info_by_index(h->context, idx,
SinkDeviceNameCallback, &h->device_name));
}
return (h->device_name != NULL);
}
@ -433,15 +504,15 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
pa_channel_map pacmap;
pa_stream_flags_t flags = 0;
int state = 0;
int rc = 0;
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
h = this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
h = this->hidden;
SDL_zerop(this->hidden);
paspec.format = PA_SAMPLE_INVALID;
@ -482,7 +553,6 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
}
if (paspec.format == PA_SAMPLE_INVALID) {
PULSEAUDIO_CloseDevice(this);
return SDL_SetError("Couldn't find any hardware audio formats");
}
this->spec.format = test_format;
@ -494,13 +564,14 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SDL_CalculateAudioSpec(&this->spec);
/* Allocate mixing buffer */
h->mixlen = this->spec.size;
h->mixbuf = (Uint8 *) SDL_AllocAudioMem(h->mixlen);
if (h->mixbuf == NULL) {
PULSEAUDIO_CloseDevice(this);
return SDL_OutOfMemory();
if (!iscapture) {
h->mixlen = this->spec.size;
h->mixbuf = (Uint8 *) SDL_malloc(h->mixlen);
if (h->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(h->mixbuf, this->spec.silence, this->spec.size);
}
SDL_memset(h->mixbuf, this->spec.silence, this->spec.size);
paspec.channels = this->spec.channels;
paspec.rate = this->spec.freq;
@ -522,13 +593,11 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
#endif
if (ConnectToPulseServer(&h->mainloop, &h->context) < 0) {
PULSEAUDIO_CloseDevice(this);
return SDL_SetError("Could not connect to PulseAudio server");
}
if (!FindDeviceName(h, handle)) {
PULSEAUDIO_CloseDevice(this);
return SDL_SetError("Requested PulseAudio sink missing?");
if (!FindDeviceName(h, iscapture, handle)) {
return SDL_SetError("Requested PulseAudio sink/source missing?");
}
/* The SDL ALSA output hints us that we use Windows' channel mapping */
@ -544,7 +613,6 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
);
if (h->stream == NULL) {
PULSEAUDIO_CloseDevice(this);
return SDL_SetError("Could not set up PulseAudio stream");
}
@ -554,20 +622,22 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
flags |= PA_STREAM_DONT_MOVE;
}
if (PULSEAUDIO_pa_stream_connect_playback(h->stream, h->device_name, &paattr, flags,
NULL, NULL) < 0) {
PULSEAUDIO_CloseDevice(this);
if (iscapture) {
rc = PULSEAUDIO_pa_stream_connect_record(h->stream, h->device_name, &paattr, flags);
} else {
rc = PULSEAUDIO_pa_stream_connect_playback(h->stream, h->device_name, &paattr, flags, NULL, NULL);
}
if (rc < 0) {
return SDL_SetError("Could not connect PulseAudio stream");
}
do {
if (PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
PULSEAUDIO_CloseDevice(this);
return SDL_SetError("pa_mainloop_iterate() failed");
}
state = PULSEAUDIO_pa_stream_get_state(h->stream);
if (!PA_STREAM_IS_GOOD(state)) {
PULSEAUDIO_CloseDevice(this);
return SDL_SetError("Could not connect PulseAudio stream");
}
} while (state != PA_STREAM_READY);
@ -646,7 +716,7 @@ PULSEAUDIO_DetectDevices()
WaitForPulseOperation(hotplug_mainloop, PULSEAUDIO_pa_context_get_source_info_list(hotplug_context, SourceInfoCallback, NULL));
/* ok, we have a sane list, let's set up hotplug notifications now... */
hotplug_thread = SDL_CreateThread(HotplugThread, "PulseHotplug", NULL);
hotplug_thread = SDL_CreateThreadInternal(HotplugThread, "PulseHotplug", 256 * 1024, NULL);
}
static void
@ -684,8 +754,11 @@ PULSEAUDIO_Init(SDL_AudioDriverImpl * impl)
impl->WaitDevice = PULSEAUDIO_WaitDevice;
impl->GetDeviceBuf = PULSEAUDIO_GetDeviceBuf;
impl->CloseDevice = PULSEAUDIO_CloseDevice;
impl->WaitDone = PULSEAUDIO_WaitDone;
impl->Deinitialize = PULSEAUDIO_Deinitialize;
impl->CaptureFromDevice = PULSEAUDIO_CaptureFromDevice;
impl->FlushCapture = PULSEAUDIO_FlushCapture;
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
}

View file

@ -42,6 +42,9 @@ struct SDL_PrivateAudioData
/* Raw mixing buffer */
Uint8 *mixbuf;
int mixlen;
const Uint8 *capturebuf;
int capturelen;
};
#endif /* _SDL_pulseaudio_h */

View file

@ -45,7 +45,6 @@
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_qsa_audio.h"
@ -138,8 +137,7 @@ QSA_ThreadInit(_THIS)
static void
QSA_InitAudioParams(snd_pcm_channel_params_t * cpars)
{
SDL_memset(cpars, 0, sizeof(snd_pcm_channel_params_t));
SDL_zerop(cpars);
cpars->channel = SND_PCM_CHANNEL_PLAYBACK;
cpars->mode = SND_PCM_MODE_BLOCK;
cpars->start_mode = SND_PCM_START_DATA;
@ -229,7 +227,7 @@ QSA_PlayDevice(_THIS)
int towrite;
void *pcmbuffer;
if ((!this->enabled) || (!this->hidden)) {
if (!SDL_AtomicGet(&this->enabled) || !this->hidden) {
return;
}
@ -262,7 +260,7 @@ QSA_PlayDevice(_THIS)
continue;
} else {
if ((errno == EINVAL) || (errno == EIO)) {
SDL_memset(&cstatus, 0, sizeof(cstatus));
SDL_zero(cstatus);
if (!this->hidden->iscapture) {
cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
} else {
@ -305,7 +303,7 @@ QSA_PlayDevice(_THIS)
towrite -= written;
pcmbuffer += written * this->spec.channels;
}
} while ((towrite > 0) && (this->enabled));
} while ((towrite > 0) && SDL_AtomicGet(&this->enabled));
/* If we couldn't write, assume fatal error for now */
if (towrite != 0) {
@ -322,27 +320,21 @@ QSA_GetDeviceBuf(_THIS)
static void
QSA_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
if (this->hidden->audio_handle != NULL) {
if (!this->hidden->iscapture) {
/* Finish playing available samples */
snd_pcm_plugin_flush(this->hidden->audio_handle,
SND_PCM_CHANNEL_PLAYBACK);
} else {
/* Cancel unread samples during capture */
snd_pcm_plugin_flush(this->hidden->audio_handle,
SND_PCM_CHANNEL_CAPTURE);
}
snd_pcm_close(this->hidden->audio_handle);
this->hidden->audio_handle = NULL;
if (this->hidden->audio_handle != NULL) {
if (!this->hidden->iscapture) {
/* Finish playing available samples */
snd_pcm_plugin_flush(this->hidden->audio_handle,
SND_PCM_CHANNEL_PLAYBACK);
} else {
/* Cancel unread samples during capture */
snd_pcm_plugin_flush(this->hidden->audio_handle,
SND_PCM_CHANNEL_CAPTURE);
}
SDL_FreeAudioMem(this->hidden->pcm_buf);
this->hidden->pcm_buf = NULL;
SDL_free(this->hidden);
this->hidden = NULL;
snd_pcm_close(this->hidden->audio_handle);
}
SDL_free(this->hidden->pcm_buf);
SDL_free(this->hidden);
}
static int
@ -365,13 +357,13 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData));
SDL_zerop(this->hidden);
/* Initialize channel transfer parameters to default */
QSA_InitAudioParams(&cparams);
/* Initialize channel direction: capture or playback */
this->hidden->iscapture = iscapture;
this->hidden->iscapture = iscapture ? SDL_TRUE : SDL_FALSE;
if (device != NULL) {
/* Open requested audio device */
@ -391,7 +383,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Check if requested device is opened */
if (status < 0) {
this->hidden->audio_handle = NULL;
QSA_CloseDevice(this);
return QSA_SetError("snd_pcm_open", status);
}
@ -401,7 +392,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
snd_pcm_plugin_set_disable(this->hidden->audio_handle,
PLUGIN_DISABLE_MMAP);
if (status < 0) {
QSA_CloseDevice(this);
return QSA_SetError("snd_pcm_plugin_set_disable", status);
}
}
@ -487,7 +477,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* assumes test_format not 0 on success */
if (test_format == 0) {
QSA_CloseDevice(this);
return SDL_SetError("QSA: Couldn't find any hardware audio formats");
}
@ -505,12 +494,11 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Setup the transfer parameters according to cparams */
status = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams);
if (status < 0) {
QSA_CloseDevice(this);
return QSA_SetError("snd_pcm_channel_params", status);
}
/* Make sure channel is setup right one last time */
SDL_memset(&csetup, 0, sizeof(csetup));
SDL_zero(csetup);
if (!this->hidden->iscapture) {
csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
} else {
@ -519,7 +507,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Setup an audio channel */
if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) {
QSA_CloseDevice(this);
return SDL_SetError("QSA: Unable to setup channel");
}
@ -540,9 +527,8 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
* closest multiple)
*/
this->hidden->pcm_buf =
(Uint8 *) SDL_AllocAudioMem(this->hidden->pcm_len);
(Uint8 *) SDL_malloc(this->hidden->pcm_len);
if (this->hidden->pcm_buf == NULL) {
QSA_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->pcm_buf, this->spec.silence,
@ -560,7 +546,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
if (this->hidden->audio_fd < 0) {
QSA_CloseDevice(this);
return QSA_SetError("snd_pcm_file_descriptor", status);
}
@ -578,7 +563,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
if (status < 0) {
QSA_CloseDevice(this);
return QSA_SetError("snd_pcm_plugin_prepare", status);
}
@ -724,32 +708,13 @@ QSA_DetectDevices(void)
}
}
static void
QSA_WaitDone(_THIS)
{
if (!this->hidden->iscapture) {
if (this->hidden->audio_handle != NULL) {
/* Wait till last fragment is played and stop channel */
snd_pcm_plugin_flush(this->hidden->audio_handle,
SND_PCM_CHANNEL_PLAYBACK);
}
} else {
if (this->hidden->audio_handle != NULL) {
/* Discard all unread data and stop channel */
snd_pcm_plugin_flush(this->hidden->audio_handle,
SND_PCM_CHANNEL_CAPTURE);
}
}
}
static void
QSA_Deinitialize(void)
{
/* Clear devices array on shutdown */
SDL_memset(qsa_playback_device, 0x00,
sizeof(QSA_Device) * QSA_MAX_DEVICES);
SDL_memset(qsa_capture_device, 0x00,
sizeof(QSA_Device) * QSA_MAX_DEVICES);
/* !!! FIXME: we zero these on init...any reason to do it here? */
SDL_zero(qsa_playback_device);
SDL_zero(qsa_capture_device);
qsa_playback_devices = 0;
qsa_capture_devices = 0;
}
@ -761,10 +726,8 @@ QSA_Init(SDL_AudioDriverImpl * impl)
int32_t status = 0;
/* Clear devices array */
SDL_memset(qsa_playback_device, 0x00,
sizeof(QSA_Device) * QSA_MAX_DEVICES);
SDL_memset(qsa_capture_device, 0x00,
sizeof(QSA_Device) * QSA_MAX_DEVICES);
SDL_zero(qsa_playback_device);
SDL_zero(qsa_capture_device);
qsa_playback_devices = 0;
qsa_capture_devices = 0;
@ -778,7 +741,6 @@ QSA_Init(SDL_AudioDriverImpl * impl)
impl->PlayDevice = QSA_PlayDevice;
impl->GetDeviceBuf = QSA_GetDeviceBuf;
impl->CloseDevice = QSA_CloseDevice;
impl->WaitDone = QSA_WaitDone;
impl->Deinitialize = QSA_Deinitialize;
impl->LockDevice = NULL;
impl->UnlockDevice = NULL;
@ -788,7 +750,7 @@ QSA_Init(SDL_AudioDriverImpl * impl)
impl->SkipMixerLock = 0;
impl->HasCaptureSupport = 1;
impl->OnlyHasDefaultOutputDevice = 0;
impl->OnlyHasDefaultInputDevice = 0;
impl->OnlyHasDefaultCaptureDevice = 0;
/* Check if io-audio manager is running or not */
status = snd_cards();

View file

@ -34,7 +34,7 @@
struct SDL_PrivateAudioData
{
/* SDL capture state */
int iscapture;
SDL_bool iscapture;
/* The audio device handle */
int cardno;

View file

@ -36,7 +36,6 @@
#include <unistd.h>
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "SDL_sndioaudio.h"
@ -171,25 +170,15 @@ SNDIO_GetDeviceBuf(_THIS)
return this->hidden->mixbuf;
}
static void
SNDIO_WaitDone(_THIS)
{
SNDIO_sio_stop(this->hidden->dev);
}
static void
SNDIO_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if ( this->hidden->dev != NULL ) {
SNDIO_sio_close(this->hidden->dev);
this->hidden->dev = NULL;
}
SDL_free(this->hidden);
this->hidden = NULL;
if ( this->hidden->dev != NULL ) {
SNDIO_sio_stop(this->hidden->dev);
SNDIO_sio_close(this->hidden->dev);
}
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
}
static int
@ -204,13 +193,12 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, sizeof(*this->hidden));
SDL_zerop(this->hidden);
this->hidden->mixlen = this->spec.size;
/* !!! FIXME: SIO_DEVANY can be a specific device... */
if ((this->hidden->dev = SNDIO_sio_open(SIO_DEVANY, SIO_PLAY, 0)) == NULL) {
SNDIO_CloseDevice(this);
return SDL_SetError("sio_open() failed");
}
@ -233,7 +221,6 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
continue;
}
if (SNDIO_sio_getpar(this->hidden->dev, &par) == 0) {
SNDIO_CloseDevice(this);
return SDL_SetError("sio_getpar() failed");
}
if (par.bps != SIO_BPS(par.bits)) {
@ -248,7 +235,6 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
if (status < 0) {
SNDIO_CloseDevice(this);
return SDL_SetError("sndio: Couldn't find any hardware audio formats");
}
@ -269,7 +255,6 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
else if ((par.bps == 1) && (!par.sig))
this->spec.format = AUDIO_U8;
else {
SNDIO_CloseDevice(this);
return SDL_SetError("sndio: Got unsupported hardware audio format.");
}
@ -282,9 +267,8 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Allocate mixing buffer */
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
SNDIO_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen);
@ -315,7 +299,6 @@ SNDIO_Init(SDL_AudioDriverImpl * impl)
impl->WaitDevice = SNDIO_WaitDevice;
impl->PlayDevice = SNDIO_PlayDevice;
impl->GetDeviceBuf = SNDIO_GetDeviceBuf;
impl->WaitDone = SNDIO_WaitDone;
impl->CloseDevice = SNDIO_CloseDevice;
impl->Deinitialize = SNDIO_Deinitialize;
impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: sndio can handle multiple devices. */

View file

@ -40,7 +40,6 @@
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
#include "SDL_sunaudio.h"
@ -183,18 +182,12 @@ SUNAUDIO_GetDeviceBuf(_THIS)
static void
SUNAUDIO_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
SDL_FreeAudioMem(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
SDL_free(this->hidden->ulaw_buf);
this->hidden->ulaw_buf = NULL;
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
this->hidden->audio_fd = -1;
}
SDL_free(this->hidden);
this->hidden = NULL;
SDL_free(this->hidden->ulaw_buf);
if (this->hidden->audio_fd >= 0) {
close(this->hidden->audio_fd);
}
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
}
static int
@ -219,7 +212,7 @@ SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_zerop(this->hidden);
/* Open the audio device */
this->hidden->audio_fd = open(devname, flags, 0);
@ -340,7 +333,7 @@ SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
SDL_CalculateAudioSpec(&this->spec);
/* Allocate mixing buffer */
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->spec.size);
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size);
if (this->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}

View file

@ -27,6 +27,7 @@
#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"
@ -40,11 +41,11 @@
static void DetectWave##typ##Devs(void) { \
const UINT iscapture = iscap ? 1 : 0; \
const UINT devcount = wave##typ##GetNumDevs(); \
capstyp caps; \
capstyp##2W caps; \
UINT i; \
for (i = 0; i < devcount; i++) { \
if (wave##typ##GetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { \
char *name = WIN_StringToUTF8(caps.szPname); \
if (wave##typ##GetDevCaps(i,(LP##capstyp##W)&caps,sizeof(caps))==MMSYSERR_NOERROR) { \
char *name = WIN_LookupAudioDeviceName(caps.szPname,&caps.NameGuid); \
if (name != NULL) { \
SDL_AddAudioDevice((int) iscapture, name, (void *) ((size_t) i+1)); \
SDL_free(name); \
@ -134,63 +135,87 @@ WINMM_PlayDevice(_THIS)
this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
}
static void
WINMM_WaitDone(_THIS)
static int
WINMM_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
int i, left;
const int nextbuf = this->hidden->next_buffer;
MMRESULT result;
do {
left = NUM_BUFFERS;
for (i = 0; i < NUM_BUFFERS; ++i) {
if (this->hidden->wavebuf[i].dwFlags & WHDR_DONE) {
--left;
}
}
if (left > 0) {
SDL_Delay(100);
}
} while (left > 0);
SDL_assert(buflen == this->spec.size);
/* Wait for an audio chunk to finish */
WaitForSingleObject(this->hidden->audio_sem, INFINITE);
/* Copy it to caller's buffer... */
SDL_memcpy(buffer, this->hidden->wavebuf[nextbuf].lpData, this->spec.size);
/* requeue the buffer that just finished. */
result = waveInAddBuffer(this->hidden->hin,
&this->hidden->wavebuf[nextbuf],
sizeof (this->hidden->wavebuf[nextbuf]));
if (result != MMSYSERR_NOERROR) {
return -1; /* uhoh! Disable the device. */
}
/* queue the next buffer in sequence, next time. */
this->hidden->next_buffer = (nextbuf + 1) % NUM_BUFFERS;
return this->spec.size;
}
static void
WINMM_FlushCapture(_THIS)
{
/* Wait for an audio chunk to finish */
if (WaitForSingleObject(this->hidden->audio_sem, 0) == WAIT_OBJECT_0) {
const int nextbuf = this->hidden->next_buffer;
/* requeue the buffer that just finished without reading from it. */
waveInAddBuffer(this->hidden->hin,
&this->hidden->wavebuf[nextbuf],
sizeof (this->hidden->wavebuf[nextbuf]));
this->hidden->next_buffer = (nextbuf + 1) % NUM_BUFFERS;
}
}
static void
WINMM_CloseDevice(_THIS)
{
/* Close up audio */
if (this->hidden != NULL) {
int i;
int i;
if (this->hidden->audio_sem) {
CloseHandle(this->hidden->audio_sem);
this->hidden->audio_sem = 0;
}
if (this->hidden->hout) {
waveOutReset(this->hidden->hout);
/* Clean up mixing buffers */
for (i = 0; i < NUM_BUFFERS; ++i) {
if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
waveOutUnprepareHeader(this->hidden->hout,
&this->hidden->wavebuf[i],
sizeof(this->hidden->wavebuf[i]));
this->hidden->wavebuf[i].dwUser = 0xFFFF;
sizeof (this->hidden->wavebuf[i]));
}
}
/* Free raw mixing buffer */
SDL_free(this->hidden->mixbuf);
this->hidden->mixbuf = NULL;
if (this->hidden->hin) {
waveInClose(this->hidden->hin);
this->hidden->hin = 0;
}
if (this->hidden->hout) {
waveOutClose(this->hidden->hout);
this->hidden->hout = 0;
}
SDL_free(this->hidden);
this->hidden = NULL;
waveOutClose(this->hidden->hout);
}
if (this->hidden->hin) {
waveInReset(this->hidden->hin);
/* Clean up mixing buffers */
for (i = 0; i < NUM_BUFFERS; ++i) {
if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
waveInUnprepareHeader(this->hidden->hin,
&this->hidden->wavebuf[i],
sizeof (this->hidden->wavebuf[i]));
}
}
waveInClose(this->hidden->hin);
}
if (this->hidden->audio_sem) {
CloseHandle(this->hidden->audio_sem);
}
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
}
static SDL_bool
@ -239,7 +264,7 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
if (this->hidden == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_zerop(this->hidden);
/* Initialize the wavebuf structures for closing */
for (i = 0; i < NUM_BUFFERS; ++i)
@ -269,7 +294,6 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
if (!valid_datatype) {
WINMM_CloseDevice(this);
return SDL_SetError("Unsupported audio format");
}
@ -281,36 +305,45 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
result = waveInOpen(&this->hidden->hin, devId, &waveformat,
(DWORD_PTR) CaptureSound, (DWORD_PTR) this,
CALLBACK_FUNCTION);
if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveInOpen()", result);
}
} else {
result = waveOutOpen(&this->hidden->hout, devId, &waveformat,
(DWORD_PTR) FillSound, (DWORD_PTR) this,
CALLBACK_FUNCTION);
if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveOutOpen()", result);
}
}
if (result != MMSYSERR_NOERROR) {
WINMM_CloseDevice(this);
return SetMMerror("waveOutOpen()", result);
}
#ifdef SOUND_DEBUG
/* Check the sound device we retrieved */
{
WAVEOUTCAPS caps;
result = waveOutGetDevCaps((UINT) this->hidden->hout,
&caps, sizeof(caps));
if (result != MMSYSERR_NOERROR) {
WINMM_CloseDevice(this);
return SetMMerror("waveOutGetDevCaps()", result);
if (iscapture) {
WAVEINCAPS caps;
result = waveInGetDevCaps((UINT) this->hidden->hout,
&caps, sizeof (caps));
if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveInGetDevCaps()", result);
}
printf("Audio device: %s\n", caps.szPname);
} else {
WAVEOUTCAPS caps;
result = waveOutGetDevCaps((UINT) this->hidden->hout,
&caps, sizeof(caps));
if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveOutGetDevCaps()", result);
}
printf("Audio device: %s\n", caps.szPname);
}
printf("Audio device: %s\n", caps.szPname);
}
#endif
/* Create the audio buffer semaphore */
this->hidden->audio_sem =
CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
CreateSemaphore(NULL, iscapture ? 0 : NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
if (this->hidden->audio_sem == NULL) {
WINMM_CloseDevice(this);
return SDL_SetError("Couldn't create semaphore");
}
@ -318,22 +351,44 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
this->hidden->mixbuf =
(Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size);
if (this->hidden->mixbuf == NULL) {
WINMM_CloseDevice(this);
return SDL_OutOfMemory();
}
SDL_zero(this->hidden->wavebuf);
for (i = 0; i < NUM_BUFFERS; ++i) {
SDL_memset(&this->hidden->wavebuf[i], 0,
sizeof(this->hidden->wavebuf[i]));
this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
this->hidden->wavebuf[i].lpData =
(LPSTR) & this->hidden->mixbuf[i * this->spec.size];
result = waveOutPrepareHeader(this->hidden->hout,
&this->hidden->wavebuf[i],
sizeof(this->hidden->wavebuf[i]));
if (iscapture) {
result = waveInPrepareHeader(this->hidden->hin,
&this->hidden->wavebuf[i],
sizeof(this->hidden->wavebuf[i]));
if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveInPrepareHeader()", result);
}
result = waveInAddBuffer(this->hidden->hin,
&this->hidden->wavebuf[i],
sizeof(this->hidden->wavebuf[i]));
if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveInAddBuffer()", result);
}
} else {
result = waveOutPrepareHeader(this->hidden->hout,
&this->hidden->wavebuf[i],
sizeof(this->hidden->wavebuf[i]));
if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveOutPrepareHeader()", result);
}
}
}
if (iscapture) {
result = waveInStart(this->hidden->hin);
if (result != MMSYSERR_NOERROR) {
WINMM_CloseDevice(this);
return SetMMerror("waveOutPrepareHeader()", result);
return SetMMerror("waveInStart()", result);
}
}
@ -349,10 +404,13 @@ WINMM_Init(SDL_AudioDriverImpl * impl)
impl->OpenDevice = WINMM_OpenDevice;
impl->PlayDevice = WINMM_PlayDevice;
impl->WaitDevice = WINMM_WaitDevice;
impl->WaitDone = WINMM_WaitDone;
impl->GetDeviceBuf = WINMM_GetDeviceBuf;
impl->CaptureFromDevice = WINMM_CaptureFromDevice;
impl->FlushCapture = WINMM_FlushCapture;
impl->CloseDevice = WINMM_CloseDevice;
impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
}

View file

@ -195,7 +195,7 @@ XAUDIO2_PlayDevice(_THIS)
IXAudio2SourceVoice *source = this->hidden->source;
HRESULT result = S_OK;
if (!this->enabled) { /* shutting down? */
if (!SDL_AtomicGet(&this->enabled)) { /* shutting down? */
return;
}
@ -226,64 +226,47 @@ XAUDIO2_PlayDevice(_THIS)
static void
XAUDIO2_WaitDevice(_THIS)
{
if (this->enabled) {
if (SDL_AtomicGet(&this->enabled)) {
SDL_SemWait(this->hidden->semaphore);
}
}
static void
XAUDIO2_WaitDone(_THIS)
XAUDIO2_PrepareToClose(_THIS)
{
IXAudio2SourceVoice *source = this->hidden->source;
XAUDIO2_VOICE_STATE state;
SDL_assert(!this->enabled); /* flag that stops playing. */
IXAudio2SourceVoice_Discontinuity(source);
#if SDL_XAUDIO2_WIN8
IXAudio2SourceVoice_GetState(source, &state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
#else
IXAudio2SourceVoice_GetState(source, &state);
#endif
while (state.BuffersQueued > 0) {
SDL_SemWait(this->hidden->semaphore);
#if SDL_XAUDIO2_WIN8
IXAudio2SourceVoice_GetState(source, &state, XAUDIO2_VOICE_NOSAMPLESPLAYED);
#else
IXAudio2SourceVoice_GetState(source, &state);
#endif
if (source) {
IXAudio2SourceVoice_Discontinuity(source);
}
}
static void
XAUDIO2_CloseDevice(_THIS)
{
if (this->hidden != NULL) {
IXAudio2 *ixa2 = this->hidden->ixa2;
IXAudio2SourceVoice *source = this->hidden->source;
IXAudio2MasteringVoice *mastering = this->hidden->mastering;
IXAudio2 *ixa2 = this->hidden->ixa2;
IXAudio2SourceVoice *source = this->hidden->source;
IXAudio2MasteringVoice *mastering = this->hidden->mastering;
if (source != NULL) {
IXAudio2SourceVoice_Stop(source, 0, XAUDIO2_COMMIT_NOW);
IXAudio2SourceVoice_FlushSourceBuffers(source);
IXAudio2SourceVoice_DestroyVoice(source);
}
if (ixa2 != NULL) {
IXAudio2_StopEngine(ixa2);
}
if (mastering != NULL) {
IXAudio2MasteringVoice_DestroyVoice(mastering);
}
if (ixa2 != NULL) {
IXAudio2_Release(ixa2);
}
SDL_free(this->hidden->mixbuf);
if (this->hidden->semaphore != NULL) {
SDL_DestroySemaphore(this->hidden->semaphore);
}
SDL_free(this->hidden);
this->hidden = NULL;
if (source != NULL) {
IXAudio2SourceVoice_Stop(source, 0, XAUDIO2_COMMIT_NOW);
IXAudio2SourceVoice_FlushSourceBuffers(source);
IXAudio2SourceVoice_DestroyVoice(source);
}
if (ixa2 != NULL) {
IXAudio2_StopEngine(ixa2);
}
if (mastering != NULL) {
IXAudio2MasteringVoice_DestroyVoice(mastering);
}
if (ixa2 != NULL) {
IXAudio2_Release(ixa2);
}
if (this->hidden->semaphore != NULL) {
SDL_DestroySemaphore(this->hidden->semaphore);
}
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
}
static int
@ -345,12 +328,11 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
IXAudio2_Release(ixa2);
return SDL_OutOfMemory();
}
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
SDL_zerop(this->hidden);
this->hidden->ixa2 = ixa2;
this->hidden->semaphore = SDL_CreateSemaphore(1);
if (this->hidden->semaphore == NULL) {
XAUDIO2_CloseDevice(this);
return SDL_SetError("XAudio2: CreateSemaphore() failed!");
}
@ -368,7 +350,6 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
if (!valid_format) {
XAUDIO2_CloseDevice(this);
return SDL_SetError("XAudio2: Unsupported audio format");
}
@ -379,11 +360,10 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
this->hidden->mixlen = this->spec.size;
this->hidden->mixbuf = (Uint8 *) SDL_malloc(2 * this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
XAUDIO2_CloseDevice(this);
return SDL_OutOfMemory();
}
this->hidden->nextbuf = this->hidden->mixbuf;
SDL_memset(this->hidden->mixbuf, 0, 2 * this->hidden->mixlen);
SDL_memset(this->hidden->mixbuf, this->spec.silence, 2 * this->hidden->mixlen);
/* We use XAUDIO2_DEFAULT_CHANNELS instead of this->spec.channels. On
Xbox360, this means 5.1 output, but on Windows, it means "figure out
@ -401,7 +381,6 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
this->spec.freq, 0, devId, NULL);
#endif
if (result != S_OK) {
XAUDIO2_CloseDevice(this);
return SDL_SetError("XAudio2: Couldn't create mastering voice");
}
@ -436,7 +415,6 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
#endif
if (result != S_OK) {
XAUDIO2_CloseDevice(this);
return SDL_SetError("XAudio2: Couldn't create source voice");
}
this->hidden->source = source;
@ -444,13 +422,11 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
/* Start everything playing! */
result = IXAudio2_StartEngine(ixa2);
if (result != S_OK) {
XAUDIO2_CloseDevice(this);
return SDL_SetError("XAudio2: Couldn't start engine");
}
result = IXAudio2SourceVoice_Start(source, 0, XAUDIO2_COMMIT_NOW);
if (result != S_OK) {
XAUDIO2_CloseDevice(this);
return SDL_SetError("XAudio2: Couldn't start source voice");
}
@ -499,7 +475,7 @@ XAUDIO2_Init(SDL_AudioDriverImpl * impl)
impl->OpenDevice = XAUDIO2_OpenDevice;
impl->PlayDevice = XAUDIO2_PlayDevice;
impl->WaitDevice = XAUDIO2_WaitDevice;
impl->WaitDone = XAUDIO2_WaitDone;
impl->PrepareToClose = XAUDIO2_PrepareToClose;
impl->GetDeviceBuf = XAUDIO2_GetDeviceBuf;
impl->CloseDevice = XAUDIO2_CloseDevice;
impl->Deinitialize = XAUDIO2_Deinitialize;

View file

@ -71,10 +71,14 @@ static jclass mActivityClass;
/* method signatures */
static jmethodID midGetNativeSurface;
static jmethodID midAudioInit;
static jmethodID midAudioOpen;
static jmethodID midAudioWriteShortBuffer;
static jmethodID midAudioWriteByteBuffer;
static jmethodID midAudioQuit;
static jmethodID midAudioClose;
static jmethodID midCaptureOpen;
static jmethodID midCaptureReadShortBuffer;
static jmethodID midCaptureReadByteBuffer;
static jmethodID midCaptureClose;
static jmethodID midPollInputDevices;
/* Accelerometer data storage */
@ -118,34 +122,45 @@ JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv* mEnv, jclass cls)
midGetNativeSurface = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"getNativeSurface","()Landroid/view/Surface;");
midAudioInit = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"audioInit", "(IZZI)I");
midAudioOpen = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"audioOpen", "(IZZI)I");
midAudioWriteShortBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"audioWriteShortBuffer", "([S)V");
midAudioWriteByteBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"audioWriteByteBuffer", "([B)V");
midAudioQuit = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"audioQuit", "()V");
midAudioClose = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"audioClose", "()V");
midCaptureOpen = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"captureOpen", "(IZZI)I");
midCaptureReadShortBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"captureReadShortBuffer", "([SZ)I");
midCaptureReadByteBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"captureReadByteBuffer", "([BZ)I");
midCaptureClose = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"captureClose", "()V");
midPollInputDevices = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"pollInputDevices", "()V");
bHasNewData = SDL_FALSE;
if (!midGetNativeSurface || !midAudioInit ||
!midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit || !midPollInputDevices) {
if (!midGetNativeSurface ||
!midAudioOpen || !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioClose ||
!midCaptureOpen || !midCaptureReadShortBuffer || !midCaptureReadByteBuffer || !midCaptureClose ||
!midPollInputDevices) {
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly");
}
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init() finished!");
}
/* Drop file */
void Java_org_libsdl_app_SDLActivity_onNativeDropFile(
JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeDropFile(
JNIEnv* env, jclass jcls,
jstring filename)
{
const char *path = (*env)->GetStringUTFChars(env, filename, NULL);
SDL_SendDropFile(path);
SDL_SendDropFile(NULL, path);
(*env)->ReleaseStringUTFChars(env, filename, path);
SDL_SendDropComplete(NULL);
}
/* Resize */
@ -555,11 +570,15 @@ int Android_JNI_SetupThread(void)
static jboolean audioBuffer16Bit = JNI_FALSE;
static jobject audioBuffer = NULL;
static void* audioBufferPinned = NULL;
static jboolean captureBuffer16Bit = JNI_FALSE;
static jobject captureBuffer = NULL;
int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames)
int Android_JNI_OpenAudioDevice(int iscapture, int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames)
{
jboolean audioBufferStereo;
int audioBufferFrames;
jobject jbufobj = NULL;
jboolean isCopy;
JNIEnv *env = Android_JNI_GetEnv();
@ -568,14 +587,24 @@ int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, i
}
Android_JNI_SetupThread();
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device");
audioBuffer16Bit = is16Bit;
audioBufferStereo = channelCount > 1;
if ((*env)->CallStaticIntMethod(env, mActivityClass, midAudioInit, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames) != 0) {
/* Error during audio initialization */
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: error on AudioTrack initialization!");
return 0;
if (iscapture) {
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for capture");
captureBuffer16Bit = is16Bit;
if ((*env)->CallStaticIntMethod(env, mActivityClass, midCaptureOpen, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames) != 0) {
/* Error during audio initialization */
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: error on AudioRecord initialization!");
return 0;
}
} else {
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for output");
audioBuffer16Bit = is16Bit;
if ((*env)->CallStaticIntMethod(env, mActivityClass, midAudioOpen, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames) != 0) {
/* Error during audio initialization */
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: error on AudioTrack initialization!");
return 0;
}
}
/* Allocating the audio buffer from the Java side and passing it as the return value for audioInit no longer works on
@ -584,31 +613,43 @@ int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, i
if (is16Bit) {
jshortArray audioBufferLocal = (*env)->NewShortArray(env, desiredBufferFrames * (audioBufferStereo ? 2 : 1));
if (audioBufferLocal) {
audioBuffer = (*env)->NewGlobalRef(env, audioBufferLocal);
jbufobj = (*env)->NewGlobalRef(env, audioBufferLocal);
(*env)->DeleteLocalRef(env, audioBufferLocal);
}
}
else {
jbyteArray audioBufferLocal = (*env)->NewByteArray(env, desiredBufferFrames * (audioBufferStereo ? 2 : 1));
if (audioBufferLocal) {
audioBuffer = (*env)->NewGlobalRef(env, audioBufferLocal);
jbufobj = (*env)->NewGlobalRef(env, audioBufferLocal);
(*env)->DeleteLocalRef(env, audioBufferLocal);
}
}
if (audioBuffer == NULL) {
if (jbufobj == NULL) {
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: could not allocate an audio buffer!");
return 0;
}
jboolean isCopy = JNI_FALSE;
if (audioBuffer16Bit) {
audioBufferPinned = (*env)->GetShortArrayElements(env, (jshortArray)audioBuffer, &isCopy);
if (iscapture) {
captureBuffer = jbufobj;
} else {
audioBuffer = jbufobj;
}
isCopy = JNI_FALSE;
if (is16Bit) {
if (!iscapture) {
audioBufferPinned = (*env)->GetShortArrayElements(env, (jshortArray)audioBuffer, &isCopy);
}
audioBufferFrames = (*env)->GetArrayLength(env, (jshortArray)audioBuffer);
} else {
audioBufferPinned = (*env)->GetByteArrayElements(env, (jbyteArray)audioBuffer, &isCopy);
if (!iscapture) {
audioBufferPinned = (*env)->GetByteArrayElements(env, (jbyteArray)audioBuffer, &isCopy);
}
audioBufferFrames = (*env)->GetArrayLength(env, (jbyteArray)audioBuffer);
}
if (audioBufferStereo) {
audioBufferFrames /= 2;
}
@ -636,16 +677,71 @@ void Android_JNI_WriteAudioBuffer(void)
/* JNI_COMMIT means the changes are committed to the VM but the buffer remains pinned */
}
void Android_JNI_CloseAudioDevice(void)
int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen)
{
JNIEnv *env = Android_JNI_GetEnv();
jboolean isCopy = JNI_FALSE;
jint br;
if (captureBuffer16Bit) {
SDL_assert((*env)->GetArrayLength(env, (jshortArray)captureBuffer) == (buflen / 2));
br = (*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_TRUE);
if (br > 0) {
jshort *ptr = (*env)->GetShortArrayElements(env, (jshortArray)captureBuffer, &isCopy);
br *= 2;
SDL_memcpy(buffer, ptr, br);
(*env)->ReleaseShortArrayElements(env, (jshortArray)captureBuffer, (jshort *)ptr, JNI_ABORT);
}
} else {
SDL_assert((*env)->GetArrayLength(env, (jshortArray)captureBuffer) == buflen);
br = (*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_TRUE);
if (br > 0) {
jbyte *ptr = (*env)->GetByteArrayElements(env, (jbyteArray)captureBuffer, &isCopy);
SDL_memcpy(buffer, ptr, br);
(*env)->ReleaseByteArrayElements(env, (jbyteArray)captureBuffer, (jbyte *)ptr, JNI_ABORT);
}
}
return (int) br;
}
void Android_JNI_FlushCapturedAudio(void)
{
JNIEnv *env = Android_JNI_GetEnv();
#if 0 /* !!! FIXME: this needs API 23, or it'll do blocking reads and never end. */
if (captureBuffer16Bit) {
const jint len = (*env)->GetArrayLength(env, (jshortArray)captureBuffer);
while ((*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_FALSE) == len) { /* spin */ }
} else {
const jint len = (*env)->GetArrayLength(env, (jbyteArray)captureBuffer);
while ((*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_FALSE) == len) { /* spin */ }
}
#else
if (captureBuffer16Bit) {
(*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_FALSE);
} else {
(*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_FALSE);
}
#endif
}
void Android_JNI_CloseAudioDevice(const int iscapture)
{
JNIEnv *env = Android_JNI_GetEnv();
(*env)->CallStaticVoidMethod(env, mActivityClass, midAudioQuit);
if (audioBuffer) {
(*env)->DeleteGlobalRef(env, audioBuffer);
audioBuffer = NULL;
audioBufferPinned = NULL;
if (iscapture) {
(*env)->CallStaticVoidMethod(env, mActivityClass, midCaptureClose);
if (captureBuffer) {
(*env)->DeleteGlobalRef(env, captureBuffer);
captureBuffer = NULL;
}
} else {
(*env)->CallStaticVoidMethod(env, mActivityClass, midAudioClose);
if (audioBuffer) {
(*env)->DeleteGlobalRef(env, audioBuffer);
audioBuffer = NULL;
audioBufferPinned = NULL;
}
}
}
@ -653,10 +749,12 @@ void Android_JNI_CloseAudioDevice(void)
/* If the parameter silent is truthy then SDL_SetError() will not be called. */
static SDL_bool Android_JNI_ExceptionOccurred(SDL_bool silent)
{
SDL_assert(LocalReferenceHolder_IsActive());
JNIEnv *mEnv = Android_JNI_GetEnv();
jthrowable exception;
jthrowable exception = (*mEnv)->ExceptionOccurred(mEnv);
SDL_assert(LocalReferenceHolder_IsActive());
exception = (*mEnv)->ExceptionOccurred(mEnv);
if (exception != NULL) {
jmethodID mid;
@ -666,13 +764,16 @@ static SDL_bool Android_JNI_ExceptionOccurred(SDL_bool silent)
if (!silent) {
jclass exceptionClass = (*mEnv)->GetObjectClass(mEnv, exception);
jclass classClass = (*mEnv)->FindClass(mEnv, "java/lang/Class");
jstring exceptionName;
const char* exceptionNameUTF8;
jstring exceptionMessage;
mid = (*mEnv)->GetMethodID(mEnv, classClass, "getName", "()Ljava/lang/String;");
jstring exceptionName = (jstring)(*mEnv)->CallObjectMethod(mEnv, exceptionClass, mid);
const char* exceptionNameUTF8 = (*mEnv)->GetStringUTFChars(mEnv, exceptionName, 0);
exceptionName = (jstring)(*mEnv)->CallObjectMethod(mEnv, exceptionClass, mid);
exceptionNameUTF8 = (*mEnv)->GetStringUTFChars(mEnv, exceptionName, 0);
mid = (*mEnv)->GetMethodID(mEnv, exceptionClass, "getMessage", "()Ljava/lang/String;");
jstring exceptionMessage = (jstring)(*mEnv)->CallObjectMethod(mEnv, exception, mid);
exceptionMessage = (jstring)(*mEnv)->CallObjectMethod(mEnv, exception, mid);
if (exceptionMessage != NULL) {
const char* exceptionMessageUTF8 = (*mEnv)->GetStringUTFChars(mEnv, exceptionMessage, 0);
@ -855,6 +956,7 @@ int Android_JNI_FileOpen(SDL_RWops* ctx,
struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
JNIEnv *mEnv = Android_JNI_GetEnv();
int retval;
jstring fileNameJString;
if (!LocalReferenceHolder_Init(&refs, mEnv)) {
LocalReferenceHolder_Cleanup(&refs);
@ -866,7 +968,7 @@ int Android_JNI_FileOpen(SDL_RWops* ctx,
return -1;
}
jstring fileNameJString = (*mEnv)->NewStringUTF(mEnv, fileName);
fileNameJString = (*mEnv)->NewStringUTF(mEnv, fileName);
ctx->hidden.androidio.fileNameRef = (*mEnv)->NewGlobalRef(mEnv, fileNameJString);
ctx->hidden.androidio.inputStreamRef = NULL;
ctx->hidden.androidio.readableByteChannelRef = NULL;
@ -885,10 +987,11 @@ size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer,
if (ctx->hidden.androidio.assetFileDescriptorRef) {
size_t bytesMax = size * maxnum;
size_t result;
if (ctx->hidden.androidio.size != -1 /* UNKNOWN_LENGTH */ && ctx->hidden.androidio.position + bytesMax > ctx->hidden.androidio.size) {
bytesMax = ctx->hidden.androidio.size - ctx->hidden.androidio.position;
}
size_t result = read(ctx->hidden.androidio.fd, buffer, bytesMax );
result = read(ctx->hidden.androidio.fd, buffer, bytesMax );
if (result > 0) {
ctx->hidden.androidio.position += result;
LocalReferenceHolder_Cleanup(&refs);
@ -900,19 +1003,23 @@ size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer,
jlong bytesRemaining = (jlong) (size * maxnum);
jlong bytesMax = (jlong) (ctx->hidden.androidio.size - ctx->hidden.androidio.position);
int bytesRead = 0;
JNIEnv *mEnv;
jobject readableByteChannel;
jmethodID readMethod;
jobject byteBuffer;
/* Don't read more bytes than those that remain in the file, otherwise we get an exception */
if (bytesRemaining > bytesMax) bytesRemaining = bytesMax;
JNIEnv *mEnv = Android_JNI_GetEnv();
mEnv = Android_JNI_GetEnv();
if (!LocalReferenceHolder_Init(&refs, mEnv)) {
LocalReferenceHolder_Cleanup(&refs);
return 0;
}
jobject readableByteChannel = (jobject)ctx->hidden.androidio.readableByteChannelRef;
jmethodID readMethod = (jmethodID)ctx->hidden.androidio.readMethod;
jobject byteBuffer = (*mEnv)->NewDirectByteBuffer(mEnv, buffer, bytesRemaining);
readableByteChannel = (jobject)ctx->hidden.androidio.readableByteChannelRef;
readMethod = (jmethodID)ctx->hidden.androidio.readMethod;
byteBuffer = (*mEnv)->NewDirectByteBuffer(mEnv, buffer, bytesRemaining);
while (bytesRemaining > 0) {
/* result = readableByteChannel.read(...); */
@ -1002,6 +1109,7 @@ Sint64 Android_JNI_FileSize(SDL_RWops* ctx)
Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence)
{
if (ctx->hidden.androidio.assetFileDescriptorRef) {
off_t ret;
switch (whence) {
case RW_SEEK_SET:
if (ctx->hidden.androidio.size != -1 /* UNKNOWN_LENGTH */ && offset > ctx->hidden.androidio.size) offset = ctx->hidden.androidio.size;
@ -1020,11 +1128,12 @@ Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence)
}
whence = SEEK_SET;
off_t ret = lseek(ctx->hidden.androidio.fd, (off_t)offset, SEEK_SET);
ret = lseek(ctx->hidden.androidio.fd, (off_t)offset, SEEK_SET);
if (ret == -1) return -1;
ctx->hidden.androidio.position = ret - ctx->hidden.androidio.offset;
} else {
Sint64 newPosition;
Sint64 movement;
switch (whence) {
case RW_SEEK_SET:
@ -1048,17 +1157,18 @@ Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence)
newPosition = ctx->hidden.androidio.size;
}
Sint64 movement = newPosition - ctx->hidden.androidio.position;
movement = newPosition - ctx->hidden.androidio.position;
if (movement > 0) {
unsigned char buffer[4096];
/* The easy case where we're seeking forwards */
while (movement > 0) {
Sint64 amount = sizeof (buffer);
size_t result;
if (amount > movement) {
amount = movement;
}
size_t result = Android_JNI_FileRead(ctx, buffer, 1, amount);
result = Android_JNI_FileRead(ctx, buffer, 1, amount);
if (result <= 0) {
/* Failed to read/skip the required amount, so fail */
return -1;
@ -1091,21 +1201,23 @@ static jobject Android_JNI_GetSystemServiceObject(const char* name)
struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
JNIEnv* env = Android_JNI_GetEnv();
jobject retval = NULL;
jstring service;
jmethodID mid;
jobject context;
jobject manager;
if (!LocalReferenceHolder_Init(&refs, env)) {
LocalReferenceHolder_Cleanup(&refs);
return NULL;
}
jstring service = (*env)->NewStringUTF(env, name);
jmethodID mid;
service = (*env)->NewStringUTF(env, name);
mid = (*env)->GetStaticMethodID(env, mActivityClass, "getContext", "()Landroid/content/Context;");
jobject context = (*env)->CallStaticObjectMethod(env, mActivityClass, mid);
context = (*env)->CallStaticObjectMethod(env, mActivityClass, mid);
mid = (*env)->GetMethodID(env, mActivityClass, "getSystemServiceFromUiThread", "(Ljava/lang/String;)Ljava/lang/Object;");
jobject manager = (*env)->CallObjectMethod(env, context, mid, service);
manager = (*env)->CallObjectMethod(env, context, mid, service);
(*env)->DeleteLocalRef(env, service);
@ -1117,11 +1229,12 @@ static jobject Android_JNI_GetSystemServiceObject(const char* name)
#define SETUP_CLIPBOARD(error) \
struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); \
JNIEnv* env = Android_JNI_GetEnv(); \
jobject clipboard; \
if (!LocalReferenceHolder_Init(&refs, env)) { \
LocalReferenceHolder_Cleanup(&refs); \
return error; \
} \
jobject clipboard = Android_JNI_GetSystemServiceObject("clipboard"); \
clipboard = Android_JNI_GetSystemServiceObject("clipboard"); \
if (!clipboard) { \
LocalReferenceHolder_Cleanup(&refs); \
return error; \
@ -1132,14 +1245,17 @@ static jobject Android_JNI_GetSystemServiceObject(const char* name)
int Android_JNI_SetClipboardText(const char* text)
{
/* Watch out for C89 scoping rules because of the macro */
SETUP_CLIPBOARD(-1)
jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, clipboard), "setText", "(Ljava/lang/CharSequence;)V");
jstring string = (*env)->NewStringUTF(env, text);
(*env)->CallVoidMethod(env, clipboard, mid, string);
(*env)->DeleteGlobalRef(env, clipboard);
(*env)->DeleteLocalRef(env, string);
/* Nest the following in a scope to avoid C89 declaration rules triggered by the macro */
{
jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, clipboard), "setText", "(Ljava/lang/CharSequence;)V");
jstring string = (*env)->NewStringUTF(env, text);
(*env)->CallVoidMethod(env, clipboard, mid, string);
(*env)->DeleteGlobalRef(env, clipboard);
(*env)->DeleteLocalRef(env, string);
}
CLEANUP_CLIPBOARD();
return 0;
@ -1147,25 +1263,30 @@ int Android_JNI_SetClipboardText(const char* text)
char* Android_JNI_GetClipboardText(void)
{
/* Watch out for C89 scoping rules because of the macro */
SETUP_CLIPBOARD(SDL_strdup(""))
jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, clipboard), "getText", "()Ljava/lang/CharSequence;");
jobject sequence = (*env)->CallObjectMethod(env, clipboard, mid);
(*env)->DeleteGlobalRef(env, clipboard);
if (sequence) {
mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, sequence), "toString", "()Ljava/lang/String;");
jstring string = (jstring)((*env)->CallObjectMethod(env, sequence, mid));
const char* utf = (*env)->GetStringUTFChars(env, string, 0);
if (utf) {
char* text = SDL_strdup(utf);
(*env)->ReleaseStringUTFChars(env, string, utf);
/* Nest the following in a scope to avoid C89 declaration rules triggered by the macro */
{
jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, clipboard), "getText", "()Ljava/lang/CharSequence;");
jobject sequence = (*env)->CallObjectMethod(env, clipboard, mid);
(*env)->DeleteGlobalRef(env, clipboard);
if (sequence) {
jstring string;
const char* utf;
mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, sequence), "toString", "()Ljava/lang/String;");
string = (jstring)((*env)->CallObjectMethod(env, sequence, mid));
utf = (*env)->GetStringUTFChars(env, string, 0);
if (utf) {
char* text = SDL_strdup(utf);
(*env)->ReleaseStringUTFChars(env, string, utf);
CLEANUP_CLIPBOARD();
CLEANUP_CLIPBOARD();
return text;
return text;
}
}
}
CLEANUP_CLIPBOARD();
return SDL_strdup("");
@ -1173,10 +1294,13 @@ char* Android_JNI_GetClipboardText(void)
SDL_bool Android_JNI_HasClipboardText(void)
{
jmethodID mid;
jboolean has;
/* Watch out for C89 scoping rules because of the macro */
SETUP_CLIPBOARD(SDL_FALSE)
jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, clipboard), "hasText", "()Z");
jboolean has = (*env)->CallBooleanMethod(env, clipboard, mid);
mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, clipboard), "hasText", "()Z");
has = (*env)->CallBooleanMethod(env, clipboard, mid);
(*env)->DeleteGlobalRef(env, clipboard);
CLEANUP_CLIPBOARD();
@ -1193,49 +1317,61 @@ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seco
{
struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
JNIEnv* env = Android_JNI_GetEnv();
jmethodID mid;
jobject context;
jstring action;
jclass cls;
jobject filter;
jobject intent;
jstring iname;
jmethodID imid;
jstring bname;
jmethodID bmid;
if (!LocalReferenceHolder_Init(&refs, env)) {
LocalReferenceHolder_Cleanup(&refs);
return -1;
}
jmethodID mid;
mid = (*env)->GetStaticMethodID(env, mActivityClass, "getContext", "()Landroid/content/Context;");
jobject context = (*env)->CallStaticObjectMethod(env, mActivityClass, mid);
context = (*env)->CallStaticObjectMethod(env, mActivityClass, mid);
jstring action = (*env)->NewStringUTF(env, "android.intent.action.BATTERY_CHANGED");
action = (*env)->NewStringUTF(env, "android.intent.action.BATTERY_CHANGED");
jclass cls = (*env)->FindClass(env, "android/content/IntentFilter");
cls = (*env)->FindClass(env, "android/content/IntentFilter");
mid = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/lang/String;)V");
jobject filter = (*env)->NewObject(env, cls, mid, action);
filter = (*env)->NewObject(env, cls, mid, action);
(*env)->DeleteLocalRef(env, action);
mid = (*env)->GetMethodID(env, mActivityClass, "registerReceiver", "(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;");
jobject intent = (*env)->CallObjectMethod(env, context, mid, NULL, filter);
intent = (*env)->CallObjectMethod(env, context, mid, NULL, filter);
(*env)->DeleteLocalRef(env, filter);
cls = (*env)->GetObjectClass(env, intent);
jstring iname;
jmethodID imid = (*env)->GetMethodID(env, cls, "getIntExtra", "(Ljava/lang/String;I)I");
imid = (*env)->GetMethodID(env, cls, "getIntExtra", "(Ljava/lang/String;I)I");
/* Watch out for C89 scoping rules because of the macro */
#define GET_INT_EXTRA(var, key) \
int var; \
iname = (*env)->NewStringUTF(env, key); \
int var = (*env)->CallIntMethod(env, intent, imid, iname, -1); \
var = (*env)->CallIntMethod(env, intent, imid, iname, -1); \
(*env)->DeleteLocalRef(env, iname);
jstring bname;
jmethodID bmid = (*env)->GetMethodID(env, cls, "getBooleanExtra", "(Ljava/lang/String;Z)Z");
bmid = (*env)->GetMethodID(env, cls, "getBooleanExtra", "(Ljava/lang/String;Z)Z");
/* Watch out for C89 scoping rules because of the macro */
#define GET_BOOL_EXTRA(var, key) \
int var; \
bname = (*env)->NewStringUTF(env, key); \
int var = (*env)->CallBooleanMethod(env, intent, bmid, bname, JNI_FALSE); \
var = (*env)->CallBooleanMethod(env, intent, bmid, bname, JNI_FALSE); \
(*env)->DeleteLocalRef(env, bname);
if (plugged) {
/* Watch out for C89 scoping rules because of the macro */
GET_INT_EXTRA(plug, "plugged") /* == BatteryManager.EXTRA_PLUGGED (API 5) */
if (plug == -1) {
LocalReferenceHolder_Cleanup(&refs);
@ -1247,6 +1383,7 @@ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seco
}
if (charged) {
/* Watch out for C89 scoping rules because of the macro */
GET_INT_EXTRA(status, "status") /* == BatteryManager.EXTRA_STATUS (API 5) */
if (status == -1) {
LocalReferenceHolder_Cleanup(&refs);
@ -1266,8 +1403,20 @@ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seco
}
if (percent) {
GET_INT_EXTRA(level, "level") /* == BatteryManager.EXTRA_LEVEL (API 5) */
GET_INT_EXTRA(scale, "scale") /* == BatteryManager.EXTRA_SCALE (API 5) */
int level;
int scale;
/* Watch out for C89 scoping rules because of the macro */
{
GET_INT_EXTRA(level_temp, "level") /* == BatteryManager.EXTRA_LEVEL (API 5) */
level = level_temp;
}
/* Watch out for C89 scoping rules because of the macro */
{
GET_INT_EXTRA(scale_temp, "scale") /* == BatteryManager.EXTRA_SCALE (API 5) */
scale = scale_temp;
}
if ((level == -1) || (scale == -1)) {
LocalReferenceHolder_Cleanup(&refs);
return -1;
@ -1320,14 +1469,16 @@ void Android_JNI_PollInputDevices(void)
int Android_JNI_SendMessage(int command, int param)
{
JNIEnv *env = Android_JNI_GetEnv();
jmethodID mid;
jboolean success;
if (!env) {
return -1;
}
jmethodID mid = (*env)->GetStaticMethodID(env, mActivityClass, "sendMessage", "(II)Z");
mid = (*env)->GetStaticMethodID(env, mActivityClass, "sendMessage", "(II)Z");
if (!mid) {
return -1;
}
jboolean success = (*env)->CallStaticBooleanMethod(env, mActivityClass, mid, command, param);
success = (*env)->CallStaticBooleanMethod(env, mActivityClass, mid, command, param);
return success ? 0 : -1;
}
@ -1339,11 +1490,12 @@ void Android_JNI_SuspendScreenSaver(SDL_bool suspend)
void Android_JNI_ShowTextInput(SDL_Rect *inputRect)
{
JNIEnv *env = Android_JNI_GetEnv();
jmethodID mid;
if (!env) {
return;
}
jmethodID mid = (*env)->GetStaticMethodID(env, mActivityClass, "showTextInput", "(IIII)Z");
mid = (*env)->GetStaticMethodID(env, mActivityClass, "showTextInput", "(IIII)Z");
if (!mid) {
return;
}

View file

@ -40,10 +40,12 @@ extern void Android_JNI_HideTextInput(void);
extern ANativeWindow* Android_JNI_GetNativeWindow(void);
/* Audio support */
extern int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames);
extern int Android_JNI_OpenAudioDevice(int iscapture, int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames);
extern void* Android_JNI_GetAudioBuffer(void);
extern void Android_JNI_WriteAudioBuffer(void);
extern void Android_JNI_CloseAudioDevice(void);
extern int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen);
extern void Android_JNI_FlushCapturedAudio(void);
extern void Android_JNI_CloseAudioDevice(const int iscapture);
#include "SDL_rwops.h"

View file

@ -27,7 +27,7 @@
static const char *dbus_library = "libdbus-1.so.3";
static void *dbus_handle = NULL;
static unsigned int screensaver_cookie = 0;
static SDL_DBusContext dbus = {0};
static SDL_DBusContext dbus;
static int
LoadDBUSSyms(void)

File diff suppressed because it is too large Load diff

View file

@ -27,31 +27,11 @@
#ifdef SDL_INPUT_LINUXEV
#include "SDL_events.h"
#include <sys/stat.h>
typedef struct SDL_evdevlist_item
{
char *path;
int fd;
struct SDL_evdevlist_item *next;
} SDL_evdevlist_item;
typedef struct SDL_EVDEV_PrivateData
{
SDL_evdevlist_item *first;
SDL_evdevlist_item *last;
int numdevices;
int ref_count;
int console_fd;
int kb_mode;
int tty;
} SDL_EVDEV_PrivateData;
extern int SDL_EVDEV_Init(void);
extern void SDL_EVDEV_Quit(void);
extern void SDL_EVDEV_Poll(void);
#endif /* SDL_INPUT_LINUXEV */
#endif /* _SDL_evdev_h */

View file

@ -0,0 +1,553 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#ifdef HAVE_FCITX_FRONTEND_H
#include <fcitx/frontend.h>
#include <unistd.h>
#include "SDL_fcitx.h"
#include "SDL_keycode.h"
#include "SDL_keyboard.h"
#include "../../events/SDL_keyboard_c.h"
#include "SDL_dbus.h"
#include "SDL_syswm.h"
#if SDL_VIDEO_DRIVER_X11
# include "../../video/x11/SDL_x11video.h"
#endif
#include "SDL_hints.h"
#define FCITX_DBUS_SERVICE "org.fcitx.Fcitx"
#define FCITX_IM_DBUS_PATH "/inputmethod"
#define FCITX_IC_DBUS_PATH "/inputcontext_%d"
#define FCITX_IM_DBUS_INTERFACE "org.fcitx.Fcitx.InputMethod"
#define FCITX_IC_DBUS_INTERFACE "org.fcitx.Fcitx.InputContext"
#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];
int id;
SDL_Rect cursor_rect;
} 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()
{
#if defined(__LINUX__) || defined(__FREEBSD__)
char *spot;
char procfile[1024];
char linkfile[1024];
int linksize;
#if defined(__LINUX__)
SDL_snprintf(procfile, sizeof(procfile), "/proc/%d/exe", getpid());
#elif defined(__FREEBSD__)
SDL_snprintf(procfile, sizeof(procfile), "/proc/%d/file", getpid());
#endif
linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1);
if (linksize > 0) {
linkfile[linksize] = '\0';
spot = SDL_strrchr(linkfile, '/');
if (spot) {
return SDL_strdup(spot + 1);
} else {
return SDL_strdup(linkfile);
}
}
#endif /* __LINUX__ || __FREEBSD__ */
return SDL_strdup("SDL_App");
}
/*
* Copied from fcitx source
*/
#define CONT(i) ISUTF8_CB(in[i])
#define VAL(i, s) ((in[i]&0x3f) << s)
static char *
_fcitx_utf8_get_char(const char *i, uint32_t *chr)
{
const unsigned char* in = (const unsigned char *)i;
if (!(in[0] & 0x80)) {
*(chr) = *(in);
return (char *)in + 1;
}
/* 2-byte, 0x80-0x7ff */
if ((in[0] & 0xe0) == 0xc0 && CONT(1)) {
*chr = ((in[0] & 0x1f) << 6) | VAL(1, 0);
return (char *)in + 2;
}
/* 3-byte, 0x800-0xffff */
if ((in[0] & 0xf0) == 0xe0 && CONT(1) && CONT(2)) {
*chr = ((in[0] & 0xf) << 12) | VAL(1, 6) | VAL(2, 0);
return (char *)in + 3;
}
/* 4-byte, 0x10000-0x1FFFFF */
if ((in[0] & 0xf8) == 0xf0 && CONT(1) && CONT(2) && CONT(3)) {
*chr = ((in[0] & 0x7) << 18) | VAL(1, 12) | VAL(2, 6) | VAL(3, 0);
return (char *)in + 4;
}
/* 5-byte, 0x200000-0x3FFFFFF */
if ((in[0] & 0xfc) == 0xf8 && CONT(1) && CONT(2) && CONT(3) && CONT(4)) {
*chr = ((in[0] & 0x3) << 24) | VAL(1, 18) | VAL(2, 12) | VAL(3, 6) | VAL(4, 0);
return (char *)in + 5;
}
/* 6-byte, 0x400000-0x7FFFFFF */
if ((in[0] & 0xfe) == 0xfc && CONT(1) && CONT(2) && CONT(3) && CONT(4) && CONT(5)) {
*chr = ((in[0] & 0x1) << 30) | VAL(1, 24) | VAL(2, 18) | VAL(3, 12) | VAL(4, 6) | VAL(5, 0);
return (char *)in + 6;
}
*chr = *in;
return (char *)in + 1;
}
static size_t
_fcitx_utf8_strlen(const char *s)
{
unsigned int l = 0;
while (*s) {
uint32_t chr;
s = _fcitx_utf8_get_char(s, &chr);
l++;
}
return l;
}
static DBusHandlerResult
DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data)
{
SDL_DBusContext *dbus = (SDL_DBusContext *)data;
if (dbus->message_is_signal(msg, FCITX_IC_DBUS_INTERFACE, "CommitString")) {
DBusMessageIter iter;
const char *text = NULL;
dbus->message_iter_init(msg, &iter);
dbus->message_iter_get_basic(&iter, &text);
if (text)
SDL_SendKeyboardText(text);
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) {
char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
size_t text_bytes = SDL_strlen(text), i = 0;
size_t cursor = 0;
while (i < text_bytes) {
size_t sz = SDL_utf8strlcpy(buf, text + i, sizeof(buf));
size_t chars = _fcitx_utf8_strlen(buf);
SDL_SendEditingText(buf, cursor, chars);
i += sz;
cursor += chars;
}
}
SDL_Fcitx_UpdateTextRect(NULL);
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static DBusMessage*
FcitxClientICNewMethod(FcitxClient *client,
const char *method)
{
SDL_DBusContext *dbus = client->dbus;
return dbus->message_new_method_call(
client->servicename,
client->icname,
FCITX_IC_DBUS_INTERFACE,
method);
}
static void
FcitxClientICCallMethod(FcitxClient *client,
const char *method)
{
SDL_DBusContext *dbus = client->dbus;
DBusMessage *msg = FcitxClientICNewMethod(client, method);
if (msg == NULL)
return ;
if (dbus->connection_send(dbus->session_conn, msg, NULL)) {
dbus->connection_flush(dbus->session_conn);
}
dbus->message_unref(msg);
}
static void
Fcitx_SetCapabilities(void *data,
const char *name,
const char *old_val,
const char *internal_editing)
{
FcitxClient *client = (FcitxClient *)data;
SDL_DBusContext *dbus = client->dbus;
Uint32 caps = CAPACITY_NONE;
DBusMessage *msg = FcitxClientICNewMethod(client, "SetCapacity");
if (msg == NULL)
return ;
if (!(internal_editing && *internal_editing == '1')) {
caps |= CAPACITY_PREEDIT;
}
dbus->message_append_args(msg,
DBUS_TYPE_UINT32, &caps,
DBUS_TYPE_INVALID);
if (dbus->connection_send(dbus->session_conn, msg, NULL)) {
dbus->connection_flush(dbus->session_conn);
}
dbus->message_unref(msg);
}
static void
FcitxClientCreateIC(FcitxClient *client)
{
char *appname = NULL;
pid_t pid = 0;
int id = 0;
SDL_bool enable;
Uint32 arg1, arg2, arg3, arg4;
SDL_DBusContext *dbus = client->dbus;
DBusMessage *reply = NULL;
DBusMessage *msg = dbus->message_new_method_call(
client->servicename,
FCITX_IM_DBUS_PATH,
FCITX_IM_DBUS_INTERFACE,
"CreateICv3"
);
if (msg == NULL)
return ;
appname = GetAppName();
pid = getpid();
dbus->message_append_args(msg,
DBUS_TYPE_STRING, &appname,
DBUS_TYPE_INT32, &pid,
DBUS_TYPE_INVALID);
do {
reply = dbus->connection_send_with_reply_and_block(
dbus->session_conn,
msg,
DBUS_TIMEOUT,
NULL);
if (!reply)
break;
if (!dbus->message_get_args(reply, NULL,
DBUS_TYPE_INT32, &id,
DBUS_TYPE_BOOLEAN, &enable,
DBUS_TYPE_UINT32, &arg1,
DBUS_TYPE_UINT32, &arg2,
DBUS_TYPE_UINT32, &arg3,
DBUS_TYPE_UINT32, &arg4,
DBUS_TYPE_INVALID))
break;
if (id < 0)
break;
client->id = id;
SDL_snprintf(client->icname, IC_NAME_MAX,
FCITX_IC_DBUS_PATH, client->id);
dbus->bus_add_match(dbus->session_conn,
"type='signal', interface='org.fcitx.Fcitx.InputContext'",
NULL);
dbus->connection_add_filter(dbus->session_conn,
&DBus_MessageFilter, dbus,
NULL);
dbus->connection_flush(dbus->session_conn);
SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &Fcitx_SetCapabilities, client);
}
while (0);
if (reply)
dbus->message_unref(reply);
dbus->message_unref(msg);
SDL_free(appname);
}
static Uint32
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;
return fcitx_mods;
}
SDL_bool
SDL_Fcitx_Init()
{
fcitx_client.dbus = SDL_DBus_GetContext();
fcitx_client.cursor_rect.x = -1;
fcitx_client.cursor_rect.y = -1;
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());
FcitxClientCreateIC(&fcitx_client);
return SDL_TRUE;
}
void
SDL_Fcitx_Quit()
{
FcitxClientICCallMethod(&fcitx_client, "DestroyIC");
}
void
SDL_Fcitx_SetFocus(SDL_bool focused)
{
if (focused) {
FcitxClientICCallMethod(&fcitx_client, "FocusIn");
} else {
FcitxClientICCallMethod(&fcitx_client, "FocusOut");
}
}
void
SDL_Fcitx_Reset(void)
{
FcitxClientICCallMethod(&fcitx_client, "Reset");
FcitxClientICCallMethod(&fcitx_client, "CloseIC");
}
SDL_bool
SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
{
DBusMessage *msg = NULL;
DBusMessage *reply = NULL;
SDL_DBusContext *dbus = fcitx_client.dbus;
Uint32 state = 0;
SDL_bool handled = SDL_FALSE;
int type = FCITX_PRESS_KEY;
Uint32 event_time = 0;
msg = FcitxClientICNewMethod(&fcitx_client, "ProcessKeyEvent");
if (msg == NULL)
return SDL_FALSE;
state = Fcitx_ModState();
dbus->message_append_args(msg,
DBUS_TYPE_UINT32, &keysym,
DBUS_TYPE_UINT32, &keycode,
DBUS_TYPE_UINT32, &state,
DBUS_TYPE_INT32, &type,
DBUS_TYPE_UINT32, &event_time,
DBUS_TYPE_INVALID);
reply = dbus->connection_send_with_reply_and_block(dbus->session_conn,
msg,
-1,
NULL);
if (reply) {
dbus->message_get_args(reply,
NULL,
DBUS_TYPE_INT32, &handled,
DBUS_TYPE_INVALID);
dbus->message_unref(reply);
}
if (handled) {
SDL_Fcitx_UpdateTextRect(NULL);
}
return handled;
}
void
SDL_Fcitx_UpdateTextRect(SDL_Rect *rect)
{
SDL_Window *focused_win = NULL;
SDL_SysWMinfo info;
int x = 0, y = 0;
SDL_Rect *cursor = &fcitx_client.cursor_rect;
SDL_DBusContext *dbus = fcitx_client.dbus;
DBusMessage *msg = NULL;
DBusConnection *conn;
if (rect) {
SDL_memcpy(cursor, rect, sizeof(SDL_Rect));
}
focused_win = SDL_GetKeyboardFocus();
if (!focused_win) {
return ;
}
SDL_VERSION(&info.version);
if (!SDL_GetWindowWMInfo(focused_win, &info)) {
return;
}
SDL_GetWindowPosition(focused_win, &x, &y);
#if SDL_VIDEO_DRIVER_X11
if (info.subsystem == SDL_SYSWM_X11) {
SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(focused_win)->driverdata;
Display *x_disp = info.info.x11.display;
Window x_win = info.info.x11.window;
int x_screen = displaydata->screen;
Window unused;
X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &y, &unused);
}
#endif
if (cursor->x == -1 && cursor->y == -1 && cursor->w == 0 && cursor->h == 0) {
// move to bottom left
int w = 0, h = 0;
SDL_GetWindowSize(focused_win, &w, &h);
cursor->x = 0;
cursor->y = h;
}
x += cursor->x;
y += cursor->y;
msg = FcitxClientICNewMethod(&fcitx_client, "SetCursorRect");
if (msg == NULL)
return ;
dbus->message_append_args(msg,
DBUS_TYPE_INT32, &x,
DBUS_TYPE_INT32, &y,
DBUS_TYPE_INT32, &cursor->w,
DBUS_TYPE_INT32, &cursor->h,
DBUS_TYPE_INVALID);
conn = dbus->session_conn;
if (dbus->connection_send(conn, msg, NULL))
dbus->connection_flush(conn);
dbus->message_unref(msg);
}
void
SDL_Fcitx_PumpEvents()
{
SDL_DBusContext *dbus = fcitx_client.dbus;
DBusConnection *conn = dbus->session_conn;
dbus->connection_read_write(conn, 0);
while (dbus->connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS) {
/* Do nothing, actual work happens in DBus_MessageFilter */
usleep(10);
}
}
#endif /* HAVE_FCITX_FRONTEND_H */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -0,0 +1,40 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef _SDL_fcitx_h
#define _SDL_fcitx_h
#include "../../SDL_internal.h"
#include "SDL_stdinc.h"
#include "SDL_rect.h"
extern SDL_bool SDL_Fcitx_Init(void);
extern void SDL_Fcitx_Quit(void);
extern void SDL_Fcitx_SetFocus(SDL_bool focused);
extern void SDL_Fcitx_Reset(void);
extern SDL_bool SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
extern void SDL_Fcitx_UpdateTextRect(SDL_Rect *rect);
extern void SDL_Fcitx_PumpEvents();
#endif /* _SDL_fcitx_h */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -42,7 +42,7 @@ static const char IBUS_INTERFACE[] = "org.freedesktop.IBus";
static const char IBUS_INPUT_INTERFACE[] = "org.freedesktop.IBus.InputContext";
static char *input_ctx_path = NULL;
static SDL_Rect ibus_cursor_rect = {0};
static SDL_Rect ibus_cursor_rect = { 0, 0, 0, 0 };
static DBusConnection *ibus_conn = NULL;
static char *ibus_addr_file = NULL;
int inotify_fd = -1, inotify_wd = -1;
@ -341,7 +341,9 @@ IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr)
const char *path = NULL;
SDL_bool result = SDL_FALSE;
DBusMessage *msg;
DBusObjectPathVTable ibus_vtable = {0};
DBusObjectPathVTable ibus_vtable;
SDL_zero(ibus_vtable);
ibus_vtable.message_function = &IBus_MessageHandler;
ibus_conn = dbus->connection_open_private(addr, NULL);

View file

@ -0,0 +1,138 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_ime.h"
#include "SDL_ibus.h"
#include "SDL_fcitx.h"
typedef SDL_bool (*_SDL_IME_Init)();
typedef void (*_SDL_IME_Quit)();
typedef void (*_SDL_IME_SetFocus)(SDL_bool);
typedef void (*_SDL_IME_Reset)();
typedef SDL_bool (*_SDL_IME_ProcessKeyEvent)(Uint32, Uint32);
typedef void (*_SDL_IME_UpdateTextRect)(SDL_Rect *);
typedef void (*_SDL_IME_PumpEvents)();
static _SDL_IME_Init SDL_IME_Init_Real = NULL;
static _SDL_IME_Quit SDL_IME_Quit_Real = NULL;
static _SDL_IME_SetFocus SDL_IME_SetFocus_Real = NULL;
static _SDL_IME_Reset SDL_IME_Reset_Real = NULL;
static _SDL_IME_ProcessKeyEvent SDL_IME_ProcessKeyEvent_Real = NULL;
static _SDL_IME_UpdateTextRect SDL_IME_UpdateTextRect_Real = NULL;
static _SDL_IME_PumpEvents SDL_IME_PumpEvents_Real = NULL;
static void
InitIME()
{
static SDL_bool inited = SDL_FALSE;
#ifdef HAVE_FCITX_FRONTEND_H
const char *im_module = SDL_getenv("SDL_IM_MODULE");
const char *xmodifiers = SDL_getenv("XMODIFIERS");
#endif
if (inited == SDL_TRUE)
return;
inited = SDL_TRUE;
/* See if fcitx IME support is being requested */
#ifdef HAVE_FCITX_FRONTEND_H
if (!SDL_IME_Init_Real &&
((im_module && SDL_strcmp(im_module, "fcitx") == 0) ||
(!im_module && xmodifiers && SDL_strstr(xmodifiers, "@im=fcitx") != NULL))) {
SDL_IME_Init_Real = SDL_Fcitx_Init;
SDL_IME_Quit_Real = SDL_Fcitx_Quit;
SDL_IME_SetFocus_Real = SDL_Fcitx_SetFocus;
SDL_IME_Reset_Real = SDL_Fcitx_Reset;
SDL_IME_ProcessKeyEvent_Real = SDL_Fcitx_ProcessKeyEvent;
SDL_IME_UpdateTextRect_Real = SDL_Fcitx_UpdateTextRect;
SDL_IME_PumpEvents_Real = SDL_Fcitx_PumpEvents;
}
#endif /* HAVE_FCITX_FRONTEND_H */
/* default to IBus */
#ifdef HAVE_IBUS_IBUS_H
if (!SDL_IME_Init_Real) {
SDL_IME_Init_Real = SDL_IBus_Init;
SDL_IME_Quit_Real = SDL_IBus_Quit;
SDL_IME_SetFocus_Real = SDL_IBus_SetFocus;
SDL_IME_Reset_Real = SDL_IBus_Reset;
SDL_IME_ProcessKeyEvent_Real = SDL_IBus_ProcessKeyEvent;
SDL_IME_UpdateTextRect_Real = SDL_IBus_UpdateTextRect;
SDL_IME_PumpEvents_Real = SDL_IBus_PumpEvents;
}
#endif /* HAVE_IBUS_IBUS_H */
}
SDL_bool
SDL_IME_Init(void)
{
InitIME();
if (SDL_IME_Init_Real)
return SDL_IME_Init_Real();
return SDL_FALSE;
}
void
SDL_IME_Quit(void)
{
if (SDL_IME_Quit_Real)
SDL_IME_Quit_Real();
}
void
SDL_IME_SetFocus(SDL_bool focused)
{
if (SDL_IME_SetFocus_Real)
SDL_IME_SetFocus_Real(focused);
}
void
SDL_IME_Reset(void)
{
if (SDL_IME_Reset_Real)
SDL_IME_Reset_Real();
}
SDL_bool
SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
{
if (SDL_IME_ProcessKeyEvent_Real)
return SDL_IME_ProcessKeyEvent_Real(keysym, keycode);
return SDL_FALSE;
}
void
SDL_IME_UpdateTextRect(SDL_Rect *rect)
{
if (SDL_IME_UpdateTextRect_Real)
SDL_IME_UpdateTextRect_Real(rect);
}
void
SDL_IME_PumpEvents()
{
if (SDL_IME_PumpEvents_Real)
SDL_IME_PumpEvents_Real();
}

View file

@ -0,0 +1,38 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef _SDL_ime_h
#define _SDL_ime_h
#include "../../SDL_internal.h"
#include "SDL_stdinc.h"
#include "SDL_rect.h"
extern SDL_bool SDL_IME_Init();
extern void SDL_IME_Quit();
extern void SDL_IME_SetFocus(SDL_bool focused);
extern void SDL_IME_Reset();
extern SDL_bool SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
extern void SDL_IME_UpdateTextRect(SDL_Rect *rect);
extern void SDL_IME_PumpEvents();
#endif /* _SDL_ime_h */

View file

@ -349,7 +349,9 @@ guess_device_class(struct udev_device *dev)
} else if (test_bit(BTN_MOUSE, bitmask_key)) {
devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */
} else if (test_bit(BTN_TOUCH, bitmask_key)) {
; /* ID_INPUT_TOUCHSCREEN */
/* 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) ||
@ -411,6 +413,11 @@ device_event(SDL_UDEV_deviceevent type, struct udev_device *dev)
if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_MOUSE;
}
val = _this->udev_device_get_property_value(dev, "ID_INPUT_TOUCHSCREEN");
if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_TOUCHSCREEN;
}
/* The undocumented rule is:
- All devices with keys get ID_INPUT_KEY

View file

@ -42,17 +42,19 @@
typedef enum
{
SDL_UDEV_DEVICEADDED = 0x0001,
SDL_UDEV_DEVICEADDED = 1,
SDL_UDEV_DEVICEREMOVED
} SDL_UDEV_deviceevent;
/* 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_SOUND = 0x0008,
SDL_UDEV_DEVICE_TOUCHSCREEN = 0x0010
} SDL_UDEV_deviceclass;
typedef void (*SDL_UDEV_Callback)(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);

View file

@ -124,6 +124,84 @@ BOOL WIN_IsWindowsVistaOrGreater()
#endif
}
/*
WAVExxxCAPS gives you 31 bytes for the device name, and just truncates if it's
longer. However, since WinXP, you can use the WAVExxxCAPS2 structure, which
will give you a name GUID. The full name is in the Windows Registry under
that GUID, located here: HKLM\System\CurrentControlSet\Control\MediaCategories
Note that drivers can report GUID_NULL for the name GUID, in which case,
Windows makes a best effort to fill in those 31 bytes in the usual place.
This info summarized from MSDN:
http://web.archive.org/web/20131027093034/http://msdn.microsoft.com/en-us/library/windows/hardware/ff536382(v=vs.85).aspx
Always look this up in the registry if possible, because the strings are
different! At least on Win10, I see "Yeti Stereo Microphone" in the
Registry, and a unhelpful "Microphone(Yeti Stereo Microph" in winmm. Sigh.
(Also, DirectSound shouldn't be limited to 32 chars, but its device enum
has the same problem.)
*/
char *
WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid)
{
#if __WINRT__
return WIN_StringToUTF8(name); /* No registry access on WinRT/UWP, go with what we've got. */
#else
static const GUID nullguid = { 0 };
const unsigned char *ptr;
char keystr[128];
WCHAR *strw = NULL;
SDL_bool rc;
HKEY hkey;
DWORD len = 0;
char *retval = NULL;
if (SDL_memcmp(guid, &nullguid, sizeof (*guid)) == 0) {
return WIN_StringToUTF8(name); /* No GUID, go with what we've got. */
}
ptr = (const unsigned char *) guid;
SDL_snprintf(keystr, sizeof (keystr),
"System\\CurrentControlSet\\Control\\MediaCategories\\{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
ptr[3], ptr[2], ptr[1], ptr[0], ptr[5], ptr[4], ptr[7], ptr[6],
ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]);
strw = WIN_UTF8ToString(keystr);
rc = (RegOpenKeyExW(HKEY_LOCAL_MACHINE, strw, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS);
SDL_free(strw);
if (!rc) {
return WIN_StringToUTF8(name); /* oh well. */
}
rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, NULL, &len) == ERROR_SUCCESS);
if (!rc) {
RegCloseKey(hkey);
return WIN_StringToUTF8(name); /* oh well. */
}
strw = (WCHAR *) SDL_malloc(len + sizeof (WCHAR));
if (!strw) {
RegCloseKey(hkey);
return WIN_StringToUTF8(name); /* oh well. */
}
rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, (LPBYTE) strw, &len) == ERROR_SUCCESS);
RegCloseKey(hkey);
if (!rc) {
SDL_free(strw);
return WIN_StringToUTF8(name); /* oh well. */
}
strw[len / 2] = 0; /* make sure it's null-terminated. */
retval = WIN_StringToUTF8(strw);
SDL_free(strw);
return retval ? retval : WIN_StringToUTF8(name);
#endif /* if __WINRT__ / else */
}
#endif /* __WIN32__ || __WINRT__ */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -59,6 +59,9 @@ extern void WIN_CoUninitialize(void);
/* Returns SDL_TRUE if we're running on Windows Vista and newer */
extern BOOL WIN_IsWindowsVistaOrGreater();
/* You need to SDL_free() the result of this call. */
extern char *WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid);
#endif /* _INCLUDED_WINDOWS_H */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -254,6 +254,18 @@ void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView)
CoreApplication::Exiting +=
ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnExiting);
#if NTDDI_VERSION >= NTDDI_WIN10
/* HACK ALERT! Xbox One doesn't seem to detect gamepads unless something
gets registered to receive Win10's Windows.Gaming.Input.Gamepad.GamepadAdded
events. We'll register an event handler for these events here, to make
sure that gamepad detection works later on, if requested.
*/
Windows::Gaming::Input::Gamepad::GamepadAdded +=
ref new Windows::Foundation::EventHandler<Windows::Gaming::Input::Gamepad^>(
this, &SDL_WinRTApp::OnGamepadAdded
);
#endif
}
#if NTDDI_VERSION > NTDDI_WIN8
@ -810,11 +822,8 @@ static void WINRT_OnBackButtonPressed(BackButtonEventArgs ^ args)
SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_AC_BACK);
SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_AC_BACK);
const char *hint = SDL_GetHint(SDL_HINT_WINRT_HANDLE_BACK_BUTTON);
if (hint) {
if (*hint == '1') {
args->Handled = true;
}
if (SDL_GetHintBoolean(SDL_HINT_WINRT_HANDLE_BACK_BUTTON, SDL_FALSE)) {
args->Handled = true;
}
}
@ -832,3 +841,15 @@ void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::Phone:
}
#endif
#if NTDDI_VERSION >= NTDDI_WIN10
void SDL_WinRTApp::OnGamepadAdded(Platform::Object ^sender, Windows::Gaming::Input::Gamepad ^gamepad)
{
/* HACK ALERT: Nothing needs to be done here, as this method currently
only exists to allow something to be registered with Win10's
GamepadAdded event, an operation that seems to be necessary to get
Xinput-based detection to work on Xbox One.
*/
}
#endif
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -80,6 +80,10 @@ protected:
void OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args);
#endif
#if NTDDI_VERSION >= NTDDI_WIN10
void OnGamepadAdded(Platform::Object ^sender, Windows::Gaming::Input::Gamepad ^gamepad);
#endif
private:
bool m_windowClosed;
bool m_windowVisible;

View file

@ -293,7 +293,7 @@ SDL_InitDynamicAPI(void)
* SDL_CreateThread() would also call this function before building the
* new thread).
*/
static volatile SDL_bool already_initialized = SDL_FALSE;
static SDL_bool already_initialized = SDL_FALSE;
/* SDL_AtomicLock calls SDL mutex functions to emulate if
SDL_ATOMIC_DISABLED, which we can't do here, so in such a

View file

@ -43,9 +43,15 @@
#include "TargetConditionals.h"
#endif
#if TARGET_OS_IPHONE || __native_client__ || __EMSCRIPTEN__ /* probably not useful on iOS, NACL or Emscripten. */
#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE /* probably not useful on iOS. */
#define SDL_DYNAMIC_API 0
#elif SDL_BUILDING_WINRT /* probaly not useful on WinRT, given current .dll loading restrictions */
#elif defined(__native_client__) && __native_client__ /* probably not useful on NACL. */
#define SDL_DYNAMIC_API 0
#elif defined(__EMSCRIPTEN__) && __EMSCRIPTEN__ /* probably not useful on Emscripten. */
#define SDL_DYNAMIC_API 0
#elif defined(SDL_BUILDING_WINRT) && SDL_BUILDING_WINRT /* probably not useful on WinRT, given current .dll loading restrictions */
#define SDL_DYNAMIC_API 0
#elif defined(__PSP__) && __PSP__
#define SDL_DYNAMIC_API 0
#elif defined(__clang_analyzer__)
#define SDL_DYNAMIC_API 0 /* Turn off for static analysis, so reports are more clear. */

View file

@ -445,6 +445,8 @@
#define SDL_iconv_close SDL_iconv_close_REAL
#define SDL_iconv SDL_iconv_REAL
#define SDL_iconv_string SDL_iconv_string_REAL
#define SDL_CreateRGBSurfaceWithFormat SDL_CreateRGBSurfaceWithFormat_REAL
#define SDL_CreateRGBSurfaceWithFormatFrom SDL_CreateRGBSurfaceWithFormatFrom_REAL
#define SDL_CreateRGBSurface SDL_CreateRGBSurface_REAL
#define SDL_CreateRGBSurfaceFrom SDL_CreateRGBSurfaceFrom_REAL
#define SDL_FreeSurface SDL_FreeSurface_REAL
@ -597,3 +599,16 @@
#define SDL_JoystickCurrentPowerLevel SDL_JoystickCurrentPowerLevel_REAL
#define SDL_GameControllerFromInstanceID SDL_GameControllerFromInstanceID_REAL
#define SDL_JoystickFromInstanceID SDL_JoystickFromInstanceID_REAL
#define SDL_GetDisplayUsableBounds SDL_GetDisplayUsableBounds_REAL
#define SDL_GetWindowBordersSize SDL_GetWindowBordersSize_REAL
#define SDL_SetWindowOpacity SDL_SetWindowOpacity_REAL
#define SDL_GetWindowOpacity SDL_GetWindowOpacity_REAL
#define SDL_SetWindowInputFocus SDL_SetWindowInputFocus_REAL
#define SDL_SetWindowModalFor SDL_SetWindowModalFor_REAL
#define SDL_RenderSetIntegerScale SDL_RenderSetIntegerScale_REAL
#define SDL_RenderGetIntegerScale SDL_RenderGetIntegerScale_REAL
#define SDL_DequeueAudio SDL_DequeueAudio_REAL
#define SDL_SetWindowResizable SDL_SetWindowResizable_REAL
#define SDL_CreateRGBSurfaceWithFormat SDL_CreateRGBSurfaceWithFormat_REAL
#define SDL_CreateRGBSurfaceWithFormatFrom SDL_CreateRGBSurfaceWithFormatFrom_REAL
#define SDL_GetHintBoolean SDL_GetHintBoolean_REAL

View file

@ -631,3 +631,16 @@ SDL_DYNAPI_PROC(int,SDL_GetDisplayDPI,(int a, float *b, float *c, float *d),(a,b
SDL_DYNAPI_PROC(SDL_JoystickPowerLevel,SDL_JoystickCurrentPowerLevel,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(SDL_GameController*,SDL_GameControllerFromInstanceID,(SDL_JoystickID a),(a),return)
SDL_DYNAPI_PROC(SDL_Joystick*,SDL_JoystickFromInstanceID,(SDL_JoystickID a),(a),return)
SDL_DYNAPI_PROC(int,SDL_GetDisplayUsableBounds,(int a, SDL_Rect *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GetWindowBordersSize,(SDL_Window *a, int *b, int *c, int *d, int *e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(int,SDL_SetWindowOpacity,(SDL_Window *a, float b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GetWindowOpacity,(SDL_Window *a, float *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_SetWindowInputFocus,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_SetWindowModalFor,(SDL_Window *a, SDL_Window *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_RenderSetIntegerScale,(SDL_Renderer *a, SDL_bool b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_RenderGetIntegerScale,(SDL_Renderer *a),(a),return)
SDL_DYNAPI_PROC(Uint32,SDL_DequeueAudio,(SDL_AudioDeviceID a, void *b, Uint32 c),(a,b,c),return)
SDL_DYNAPI_PROC(void,SDL_SetWindowResizable,(SDL_Window *a, SDL_bool b),(a,b),)
SDL_DYNAPI_PROC(SDL_Surface*,SDL_CreateRGBSurfaceWithFormat,(Uint32 a, int b, int c, int d, Uint32 e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(SDL_Surface*,SDL_CreateRGBSurfaceWithFormatFrom,(void *a, int b, int c, int d, int e, Uint32 f),(a,b,c,d,e,f),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_GetHintBoolean,(const char *a, SDL_bool b),(a,b),return)

View file

@ -26,21 +26,73 @@
#include "SDL_events_c.h"
#include "SDL_dropevents_c.h"
#include "../video/SDL_sysvideo.h" /* for SDL_Window internals. */
int
SDL_SendDropFile(const char *file)
static int
SDL_SendDrop(SDL_Window *window, const SDL_EventType evtype, const char *data)
{
int posted;
static SDL_bool app_is_dropping = SDL_FALSE;
int posted = 0;
/* Post the event, if desired */
posted = 0;
if (SDL_GetEventState(SDL_DROPFILE) == SDL_ENABLE) {
if (SDL_GetEventState(evtype) == SDL_ENABLE) {
const SDL_bool need_begin = window ? !window->is_dropping : !app_is_dropping;
SDL_Event event;
event.type = SDL_DROPFILE;
event.drop.file = SDL_strdup(file);
if (need_begin) {
SDL_zero(event);
event.type = SDL_DROPBEGIN;
if (window) {
event.drop.windowID = window->id;
}
posted = (SDL_PushEvent(&event) > 0);
if (!posted) {
return 0;
}
if (window) {
window->is_dropping = SDL_TRUE;
} else {
app_is_dropping = SDL_TRUE;
}
}
SDL_zero(event);
event.type = evtype;
event.drop.file = data ? SDL_strdup(data) : NULL;
event.drop.windowID = window ? window->id : 0;
posted = (SDL_PushEvent(&event) > 0);
if (posted && (evtype == SDL_DROPCOMPLETE)) {
if (window) {
window->is_dropping = SDL_FALSE;
} else {
app_is_dropping = SDL_FALSE;
}
}
}
return (posted);
return posted;
}
int
SDL_SendDropFile(SDL_Window *window, const char *file)
{
return SDL_SendDrop(window, SDL_DROPFILE, file);
}
int
SDL_SendDropText(SDL_Window *window, const char *text)
{
return SDL_SendDrop(window, SDL_DROPTEXT, text);
}
int
SDL_SendDropComplete(SDL_Window *window)
{
return SDL_SendDrop(window, SDL_DROPCOMPLETE, NULL);
}
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -23,7 +23,9 @@
#ifndef _SDL_dropevents_c_h
#define _SDL_dropevents_c_h
extern int SDL_SendDropFile(const char *file);
extern int SDL_SendDropFile(SDL_Window *window, const char *file);
extern int SDL_SendDropText(SDL_Window *window, const char *text);
extern int SDL_SendDropComplete(SDL_Window *window);
#endif /* _SDL_dropevents_c_h */

View file

@ -73,15 +73,15 @@ typedef struct _SDL_SysWMEntry
static struct
{
SDL_mutex *lock;
volatile SDL_bool active;
volatile int count;
volatile int max_events_seen;
SDL_atomic_t active;
SDL_atomic_t count;
int max_events_seen;
SDL_EventEntry *head;
SDL_EventEntry *tail;
SDL_EventEntry *free;
SDL_SysWMEntry *wmmsg_used;
SDL_SysWMEntry *wmmsg_free;
} SDL_EventQ = { NULL, SDL_TRUE, 0, 0, NULL, NULL, NULL, NULL, NULL };
} SDL_EventQ = { NULL, { 1 }, { 0 }, 0, NULL, NULL, NULL, NULL, NULL };
/* Public functions */
@ -98,7 +98,7 @@ SDL_StopEventLoop(void)
SDL_LockMutex(SDL_EventQ.lock);
}
SDL_EventQ.active = SDL_FALSE;
SDL_AtomicSet(&SDL_EventQ.active, 0);
if (report && SDL_atoi(report)) {
SDL_Log("SDL EVENT QUEUE: Maximum events in-flight: %d\n",
@ -127,7 +127,7 @@ SDL_StopEventLoop(void)
wmmsg = next;
}
SDL_EventQ.count = 0;
SDL_AtomicSet(&SDL_EventQ.count, 0);
SDL_EventQ.max_events_seen = 0;
SDL_EventQ.head = NULL;
SDL_EventQ.tail = NULL;
@ -171,7 +171,7 @@ SDL_StartEventLoop(void)
SDL_EventQ.lock = SDL_CreateMutex();
}
if (SDL_EventQ.lock == NULL) {
return (-1);
return -1;
}
#endif /* !SDL_THREADS_DISABLED */
@ -180,9 +180,9 @@ SDL_StartEventLoop(void)
SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE);
SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
SDL_EventQ.active = SDL_TRUE;
SDL_AtomicSet(&SDL_EventQ.active, 1);
return (0);
return 0;
}
@ -191,9 +191,11 @@ static int
SDL_AddEvent(SDL_Event * event)
{
SDL_EventEntry *entry;
const int initial_count = SDL_AtomicGet(&SDL_EventQ.count);
int final_count;
if (SDL_EventQ.count >= SDL_MAX_QUEUED_EVENTS) {
SDL_SetError("Event queue is full (%d events)", SDL_EventQ.count);
if (initial_count >= SDL_MAX_QUEUED_EVENTS) {
SDL_SetError("Event queue is full (%d events)", initial_count);
return 0;
}
@ -225,10 +227,10 @@ SDL_AddEvent(SDL_Event * event)
entry->prev = NULL;
entry->next = NULL;
}
++SDL_EventQ.count;
if (SDL_EventQ.count > SDL_EventQ.max_events_seen) {
SDL_EventQ.max_events_seen = SDL_EventQ.count;
final_count = SDL_AtomicAdd(&SDL_EventQ.count, 1) + 1;
if (final_count > SDL_EventQ.max_events_seen) {
SDL_EventQ.max_events_seen = final_count;
}
return 1;
@ -256,8 +258,8 @@ SDL_CutEvent(SDL_EventEntry *entry)
entry->next = SDL_EventQ.free;
SDL_EventQ.free = entry;
SDL_assert(SDL_EventQ.count > 0);
--SDL_EventQ.count;
SDL_assert(SDL_AtomicGet(&SDL_EventQ.count) > 0);
SDL_AtomicAdd(&SDL_EventQ.count, -1);
}
/* Lock the event queue, take a peep at it, and unlock it */
@ -268,7 +270,7 @@ SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
int i, used;
/* Don't look after we've quit */
if (!SDL_EventQ.active) {
if (!SDL_AtomicGet(&SDL_EventQ.active)) {
/* We get a few spurious events at shutdown, so don't warn then */
if (action != SDL_ADDEVENT) {
SDL_SetError("The event system has been shut down");
@ -285,56 +287,54 @@ SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action,
} else {
SDL_EventEntry *entry, *next;
SDL_SysWMEntry *wmmsg, *wmmsg_next;
SDL_Event tmpevent;
Uint32 type;
/* If 'events' is NULL, just see if they exist */
if (events == NULL) {
action = SDL_PEEKEVENT;
numevents = 1;
events = &tmpevent;
if (action == SDL_GETEVENT) {
/* Clean out any used wmmsg data
FIXME: Do we want to retain the data for some period of time?
*/
for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) {
wmmsg_next = wmmsg->next;
wmmsg->next = SDL_EventQ.wmmsg_free;
SDL_EventQ.wmmsg_free = wmmsg;
}
SDL_EventQ.wmmsg_used = NULL;
}
/* Clean out any used wmmsg data
FIXME: Do we want to retain the data for some period of time?
*/
for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) {
wmmsg_next = wmmsg->next;
wmmsg->next = SDL_EventQ.wmmsg_free;
SDL_EventQ.wmmsg_free = wmmsg;
}
SDL_EventQ.wmmsg_used = NULL;
for (entry = SDL_EventQ.head; entry && used < numevents; entry = next) {
for (entry = SDL_EventQ.head; entry && (!events || used < numevents); entry = next) {
next = entry->next;
type = entry->event.type;
if (minType <= type && type <= maxType) {
events[used] = entry->event;
if (entry->event.type == SDL_SYSWMEVENT) {
/* We need to copy the wmmsg somewhere safe.
For now we'll guarantee it's valid at least until
the next call to SDL_PeepEvents()
*/
if (SDL_EventQ.wmmsg_free) {
wmmsg = SDL_EventQ.wmmsg_free;
SDL_EventQ.wmmsg_free = wmmsg->next;
} else {
wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg));
if (events) {
events[used] = entry->event;
if (entry->event.type == SDL_SYSWMEVENT) {
/* We need to copy the wmmsg somewhere safe.
For now we'll guarantee it's valid at least until
the next call to SDL_PeepEvents()
*/
if (SDL_EventQ.wmmsg_free) {
wmmsg = SDL_EventQ.wmmsg_free;
SDL_EventQ.wmmsg_free = wmmsg->next;
} else {
wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg));
}
wmmsg->msg = *entry->event.syswm.msg;
wmmsg->next = SDL_EventQ.wmmsg_used;
SDL_EventQ.wmmsg_used = wmmsg;
events[used].syswm.msg = &wmmsg->msg;
}
if (action == SDL_GETEVENT) {
SDL_CutEvent(entry);
}
wmmsg->msg = *entry->event.syswm.msg;
wmmsg->next = SDL_EventQ.wmmsg_used;
SDL_EventQ.wmmsg_used = wmmsg;
events[used].syswm.msg = &wmmsg->msg;
}
++used;
if (action == SDL_GETEVENT) {
SDL_CutEvent(entry);
}
}
}
}
SDL_UnlockMutex(SDL_EventQ.lock);
if (SDL_EventQ.lock) {
SDL_UnlockMutex(SDL_EventQ.lock);
}
} else {
return SDL_SetError("Couldn't lock event queue");
}
@ -363,7 +363,7 @@ void
SDL_FlushEvents(Uint32 minType, Uint32 maxType)
{
/* Don't look after we've quit */
if (!SDL_EventQ.active) {
if (!SDL_AtomicGet(&SDL_EventQ.active)) {
return;
}
@ -376,7 +376,7 @@ SDL_FlushEvents(Uint32 minType, Uint32 maxType)
#endif
/* Lock the event queue */
if (SDL_LockMutex(SDL_EventQ.lock) == 0) {
if (SDL_EventQ.lock && SDL_LockMutex(SDL_EventQ.lock) == 0) {
SDL_EventEntry *entry, *next;
Uint32 type;
for (entry = SDL_EventQ.head; entry; entry = next) {
@ -437,8 +437,6 @@ SDL_WaitEventTimeout(SDL_Event * event, int timeout)
switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) {
case -1:
return 0;
case 1:
return 1;
case 0:
if (timeout == 0) {
/* Polling and no events, just return */
@ -450,6 +448,9 @@ SDL_WaitEventTimeout(SDL_Event * event, int timeout)
}
SDL_Delay(10);
break;
default:
/* Has events */
return 1;
}
}
}

View file

@ -21,7 +21,7 @@
#include "../SDL_internal.h"
/* General mouse handling code for SDL */
/* General gesture handling code for SDL */
#include "SDL_events.h"
#include "SDL_endian.h"

View file

@ -322,15 +322,13 @@ static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button)
return &mouse->clickstate[button];
}
int
SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
static int
SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button, int clicks)
{
SDL_Mouse *mouse = SDL_GetMouse();
int posted;
Uint32 type;
Uint32 buttonstate = mouse->buttonstate;
SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button);
Uint8 click_count;
/* Figure out which event to perform */
switch (state) {
@ -358,25 +356,28 @@ SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8
}
mouse->buttonstate = buttonstate;
if (clickstate) {
if (state == SDL_PRESSED) {
Uint32 now = SDL_GetTicks();
if (clicks < 0) {
SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button);
if (clickstate) {
if (state == SDL_PRESSED) {
Uint32 now = SDL_GetTicks();
if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + SDL_double_click_time) ||
SDL_abs(mouse->x - clickstate->last_x) > SDL_double_click_radius ||
SDL_abs(mouse->y - clickstate->last_y) > SDL_double_click_radius) {
clickstate->click_count = 0;
}
clickstate->last_timestamp = now;
clickstate->last_x = mouse->x;
clickstate->last_y = mouse->y;
if (clickstate->click_count < 255) {
++clickstate->click_count;
if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + SDL_double_click_time) ||
SDL_abs(mouse->x - clickstate->last_x) > SDL_double_click_radius ||
SDL_abs(mouse->y - clickstate->last_y) > SDL_double_click_radius) {
clickstate->click_count = 0;
}
clickstate->last_timestamp = now;
clickstate->last_x = mouse->x;
clickstate->last_y = mouse->y;
if (clickstate->click_count < 255) {
++clickstate->click_count;
}
}
clicks = clickstate->click_count;
} else {
clicks = 1;
}
click_count = clickstate->click_count;
} else {
click_count = 1;
}
/* Post the event, if desired */
@ -388,7 +389,7 @@ SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8
event.button.which = mouseID;
event.button.state = state;
event.button.button = button;
event.button.clicks = click_count;
event.button.clicks = (Uint8) SDL_min(clicks, 255);
event.button.x = mouse->x;
event.button.y = mouse->y;
posted = (SDL_PushEvent(&event) > 0);
@ -398,10 +399,23 @@ SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8
if (window && state == SDL_RELEASED) {
SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
}
return posted;
}
int
SDL_SendMouseButtonClicks(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button, int clicks)
{
clicks = SDL_max(clicks, 0);
return SDL_PrivateSendMouseButton(window, mouseID, state, button, clicks);
}
int
SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
{
return SDL_PrivateSendMouseButton(window, mouseID, state, button, -1);
}
int
SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y, SDL_MouseWheelDirection direction)
{
@ -550,21 +564,11 @@ SDL_WarpMouseGlobal(int x, int y)
static SDL_bool
ShouldUseRelativeModeWarp(SDL_Mouse *mouse)
{
const char *hint;
if (!mouse->SetRelativeMouseMode) {
return SDL_TRUE;
}
hint = SDL_GetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP);
if (hint) {
if (*hint == '0') {
return SDL_FALSE;
} else {
return SDL_TRUE;
}
}
return SDL_FALSE;
return SDL_GetHintBoolean(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, SDL_FALSE);
}
int

View file

@ -119,6 +119,9 @@ extern int SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int rel
/* Send a mouse button event */
extern int SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button);
/* Send a mouse button event with a click count */
extern int SDL_SendMouseButtonClicks(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button, int clicks);
/* Send a mouse wheel event */
extern int SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y, SDL_MouseWheelDirection direction);

View file

@ -91,9 +91,7 @@ SDL_QuitInit_Internal(void)
int
SDL_QuitInit(void)
{
const char *hint = SDL_GetHint(SDL_HINT_NO_SIGNAL_HANDLERS);
disable_signals = hint && (SDL_atoi(hint) == 1);
if (!disable_signals) {
if (!SDL_GetHintBoolean(SDL_HINT_NO_SIGNAL_HANDLERS, SDL_FALSE)) {
return SDL_QuitInit_Internal();
}
return 0;

View file

@ -70,6 +70,20 @@ RemovePendingMoveEvents(void * userdata, SDL_Event *event)
return 1;
}
static int
RemovePendingExposedEvents(void * userdata, SDL_Event *event)
{
SDL_Event *new_event = (SDL_Event *)userdata;
if (event->type == SDL_WINDOWEVENT &&
event->window.event == SDL_WINDOWEVENT_EXPOSED &&
event->window.windowID == new_event->window.windowID) {
/* We're about to post a new exposed event, drop the old one */
return 0;
}
return 1;
}
int
SDL_SendWindowEvent(SDL_Window * window, Uint8 windowevent, int data1,
int data2)
@ -195,7 +209,9 @@ SDL_SendWindowEvent(SDL_Window * window, Uint8 windowevent, int data1,
if (windowevent == SDL_WINDOWEVENT_MOVED) {
SDL_FilterEvents(RemovePendingMoveEvents, &event);
}
if (windowevent == SDL_WINDOWEVENT_EXPOSED) {
SDL_FilterEvents(RemovePendingExposedEvents, &event);
}
posted = (SDL_PushEvent(&event) > 0);
}

View file

@ -111,7 +111,7 @@ static SDL_Scancode const linux_scancode_table[] = {
/* 82 */ SDL_SCANCODE_KP_0,
/* 83 */ SDL_SCANCODE_KP_PERIOD,
0,
/* 85 */ SDL_SCANCODE_UNKNOWN, /* KEY_ZENKAKUHANKAKU */
/* 85 */ SDL_SCANCODE_LANG5, /* KEY_ZENKAKUHANKAKU */
/* 86 */ SDL_SCANCODE_NONUSBACKSLASH, /* KEY_102ND */
/* 87 */ SDL_SCANCODE_F11,
/* 88 */ SDL_SCANCODE_F12,
@ -153,7 +153,7 @@ static SDL_Scancode const linux_scancode_table[] = {
/* 124 */ SDL_SCANCODE_INTERNATIONAL3, /* KEY_YEN */
/* 125 */ SDL_SCANCODE_LGUI,
/* 126 */ SDL_SCANCODE_RGUI,
/* 127 */ SDL_SCANCODE_UNKNOWN, /* KEY_COMPOSE */
/* 127 */ SDL_SCANCODE_APPLICATION, /* KEY_COMPOSE */
/* 128 */ SDL_SCANCODE_STOP,
/* 129 */ SDL_SCANCODE_AGAIN,
/* 130 */ SDL_SCANCODE_UNKNOWN, /* KEY_PROPS */
@ -174,9 +174,9 @@ static SDL_Scancode const linux_scancode_table[] = {
/* 145 */ SDL_SCANCODE_UNKNOWN, /* KEY_SENDFILE */
/* 146 */ SDL_SCANCODE_UNKNOWN, /* KEY_DELETEFILE */
/* 147 */ SDL_SCANCODE_UNKNOWN, /* KEY_XFER */
/* 148 */ SDL_SCANCODE_UNKNOWN, /* KEY_PROG1 */
/* 149 */ SDL_SCANCODE_UNKNOWN, /* KEY_PROG2 */
/* 150 */ SDL_SCANCODE_UNKNOWN, /* KEY_WWW */
/* 148 */ SDL_SCANCODE_APP1, /* KEY_PROG1 */
/* 149 */ SDL_SCANCODE_APP2, /* KEY_PROG2 */
/* 150 */ SDL_SCANCODE_WWW, /* KEY_WWW */
/* 151 */ SDL_SCANCODE_UNKNOWN, /* KEY_MSDOS */
/* 152 */ SDL_SCANCODE_UNKNOWN, /* KEY_COFFEE */
/* 153 */ SDL_SCANCODE_UNKNOWN, /* KEY_DIRECTION */
@ -192,7 +192,7 @@ static SDL_Scancode const linux_scancode_table[] = {
/* 163 */ SDL_SCANCODE_AUDIONEXT, /* KEY_NEXTSONG */
/* 164 */ SDL_SCANCODE_AUDIOPLAY, /* KEY_PLAYPAUSE */
/* 165 */ SDL_SCANCODE_AUDIOPREV, /* KEY_PREVIOUSSONG */
/* 166 */ SDL_SCANCODE_UNKNOWN, /* KEY_STOPCD */
/* 166 */ SDL_SCANCODE_AUDIOSTOP, /* KEY_STOPCD */
/* 167 */ SDL_SCANCODE_UNKNOWN, /* KEY_RECORD */
/* 168 */ SDL_SCANCODE_UNKNOWN, /* KEY_REWIND */
/* 169 */ SDL_SCANCODE_UNKNOWN, /* KEY_PHONE */
@ -221,7 +221,7 @@ static SDL_Scancode const linux_scancode_table[] = {
/* 192 */ SDL_SCANCODE_F22,
/* 193 */ SDL_SCANCODE_F23,
/* 194 */ SDL_SCANCODE_F24,
0, 0, 0, 0,
0, 0, 0, 0, 0,
/* 200 */ SDL_SCANCODE_UNKNOWN, /* KEY_PLAYCD */
/* 201 */ SDL_SCANCODE_UNKNOWN, /* KEY_PAUSECD */
/* 202 */ SDL_SCANCODE_UNKNOWN, /* KEY_PROG3 */

View file

@ -418,4 +418,89 @@ static const SDL_Scancode xfree86_scancode_table2[] = {
/* 238 */ SDL_SCANCODE_UNKNOWN, /* XF86WLAN */
};
/* Xvnc / Xtightvnc scancodes from xmodmap -pk */
static const SDL_Scancode xvnc_scancode_table[] = {
/* 0 */ SDL_SCANCODE_LCTRL,
/* 1 */ SDL_SCANCODE_RCTRL,
/* 2 */ SDL_SCANCODE_LSHIFT,
/* 3 */ SDL_SCANCODE_RSHIFT,
/* 4 */ SDL_SCANCODE_UNKNOWN, /* Meta_L */
/* 5 */ SDL_SCANCODE_UNKNOWN, /* Meta_R */
/* 6 */ SDL_SCANCODE_LALT,
/* 7 */ SDL_SCANCODE_RALT,
/* 8 */ SDL_SCANCODE_SPACE,
/* 9 */ SDL_SCANCODE_0,
/* 10 */ SDL_SCANCODE_1,
/* 11 */ SDL_SCANCODE_2,
/* 12 */ SDL_SCANCODE_3,
/* 13 */ SDL_SCANCODE_4,
/* 14 */ SDL_SCANCODE_5,
/* 15 */ SDL_SCANCODE_6,
/* 16 */ SDL_SCANCODE_7,
/* 17 */ SDL_SCANCODE_8,
/* 18 */ SDL_SCANCODE_9,
/* 19 */ SDL_SCANCODE_MINUS,
/* 20 */ SDL_SCANCODE_EQUALS,
/* 21 */ SDL_SCANCODE_LEFTBRACKET,
/* 22 */ SDL_SCANCODE_RIGHTBRACKET,
/* 23 */ SDL_SCANCODE_SEMICOLON,
/* 24 */ SDL_SCANCODE_APOSTROPHE,
/* 25 */ SDL_SCANCODE_GRAVE,
/* 26 */ SDL_SCANCODE_COMMA,
/* 27 */ SDL_SCANCODE_PERIOD,
/* 28 */ SDL_SCANCODE_SLASH,
/* 29 */ SDL_SCANCODE_BACKSLASH,
/* 30 */ SDL_SCANCODE_A,
/* 31 */ SDL_SCANCODE_B,
/* 32 */ SDL_SCANCODE_C,
/* 33 */ SDL_SCANCODE_D,
/* 34 */ SDL_SCANCODE_E,
/* 35 */ SDL_SCANCODE_F,
/* 36 */ SDL_SCANCODE_G,
/* 37 */ SDL_SCANCODE_H,
/* 38 */ SDL_SCANCODE_I,
/* 39 */ SDL_SCANCODE_J,
/* 40 */ SDL_SCANCODE_K,
/* 41 */ SDL_SCANCODE_L,
/* 42 */ SDL_SCANCODE_M,
/* 43 */ SDL_SCANCODE_N,
/* 44 */ SDL_SCANCODE_O,
/* 45 */ SDL_SCANCODE_P,
/* 46 */ SDL_SCANCODE_Q,
/* 47 */ SDL_SCANCODE_R,
/* 48 */ SDL_SCANCODE_S,
/* 49 */ SDL_SCANCODE_T,
/* 50 */ SDL_SCANCODE_U,
/* 51 */ SDL_SCANCODE_V,
/* 52 */ SDL_SCANCODE_W,
/* 53 */ SDL_SCANCODE_X,
/* 54 */ SDL_SCANCODE_Y,
/* 55 */ SDL_SCANCODE_Z,
/* 56 */ SDL_SCANCODE_BACKSPACE,
/* 57 */ SDL_SCANCODE_RETURN,
/* 58 */ SDL_SCANCODE_TAB,
/* 59 */ SDL_SCANCODE_ESCAPE,
/* 60 */ SDL_SCANCODE_DELETE,
/* 61 */ SDL_SCANCODE_HOME,
/* 62 */ SDL_SCANCODE_END,
/* 63 */ SDL_SCANCODE_PAGEUP,
/* 64 */ SDL_SCANCODE_PAGEDOWN,
/* 65 */ SDL_SCANCODE_UP,
/* 66 */ SDL_SCANCODE_DOWN,
/* 67 */ SDL_SCANCODE_LEFT,
/* 68 */ SDL_SCANCODE_RIGHT,
/* 69 */ SDL_SCANCODE_F1,
/* 70 */ SDL_SCANCODE_F2,
/* 71 */ SDL_SCANCODE_F3,
/* 72 */ SDL_SCANCODE_F4,
/* 73 */ SDL_SCANCODE_F5,
/* 74 */ SDL_SCANCODE_F6,
/* 75 */ SDL_SCANCODE_F7,
/* 76 */ SDL_SCANCODE_F8,
/* 77 */ SDL_SCANCODE_F9,
/* 78 */ SDL_SCANCODE_F10,
/* 79 */ SDL_SCANCODE_F11,
/* 80 */ SDL_SCANCODE_F12,
};
/* *INDENT-ON* */

View file

@ -20,7 +20,7 @@
*/
#include "../../SDL_internal.h"
#ifdef SDL_FILESYSTEM_DUMMY
#if defined(SDL_FILESYSTEM_DUMMY) || defined(SDL_FILESYSTEM_DISABLED)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* System dependent filesystem routines */
@ -42,6 +42,6 @@ SDL_GetPrefPath(const char *org, const char *app)
return NULL;
}
#endif /* SDL_FILESYSTEM_DUMMY */
#endif /* SDL_FILESYSTEM_DUMMY || SDL_FILESYSTEM_DISABLED */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -33,7 +33,7 @@
#include <sys/types.h>
#include <limits.h>
#ifdef __FREEBSD__
#if defined(__FREEBSD__) || defined(__OPENBSD__)
#include <sys/sysctl.h>
#endif
@ -90,7 +90,26 @@ SDL_GetBasePath(void)
return NULL;
}
}
#elif defined(__SOLARIS__)
#endif
#if defined(__OPENBSD__)
char **retvalargs;
size_t len;
const int mib[] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };
if (sysctl(mib, 4, NULL, &len, NULL, 0) != -1) {
retvalargs = SDL_malloc(len);
if (!retvalargs) {
SDL_OutOfMemory();
return NULL;
}
sysctl(mib, 4, retvalargs, &len, NULL, 0);
retval = SDL_malloc(PATH_MAX + 1);
if (retval)
realpath(retvalargs[0], retval);
SDL_free(retvalargs);
}
#endif
#if defined(__SOLARIS__)
const char *path = getexecname();
if ((path != NULL) && (path[0] == '/')) { /* must be absolute path... */
retval = SDL_strdup(path);

View file

@ -609,7 +609,7 @@ SDL_SYS_HapticQuit(void)
/* Opened and not closed haptics are leaked, this is on purpose.
* Close your haptic devices after usage. */
SDL_free(item->fname);
item->fname = NULL;
SDL_free(item);
}
#if SDL_USE_LIBUDEV
@ -690,7 +690,7 @@ SDL_SYS_ToDirection(Uint16 *dest, SDL_HapticDirection * src)
else if (!src->dir[0])
*dest = (src->dir[1] >= 0 ? 0x8000 : 0);
else {
float f = atan2(src->dir[1], src->dir[0]); /* Ideally we'd use fixed point math instead of floats... */
float f = SDL_atan2(src->dir[1], src->dir[0]); /* Ideally we'd use fixed point math instead of floats... */
/*
atan2 takes the parameters: Y-axis-value and X-axis-value (in that order)
- Y-axis-value is the second coordinate (from center to SOUTH)

View file

@ -325,20 +325,12 @@ SDL_DINPUT_HapticOpenFromDevice(SDL_Haptic * haptic, LPDIRECTINPUTDEVICE8 device
/* Set data format. */
ret = IDirectInputDevice8_SetDataFormat(haptic->hwdata->device,
&c_dfDIJoystick2);
&SDL_c_dfDIJoystick2);
if (FAILED(ret)) {
DI_SetError("Setting data format", ret);
goto acquire_err;
}
/* Get number of axes. */
ret = IDirectInputDevice8_EnumObjects(haptic->hwdata->device,
DI_DeviceObjectCallback,
haptic, DIDFT_AXIS);
if (FAILED(ret)) {
DI_SetError("Getting device axes", ret);
goto acquire_err;
}
/* Acquire the device. */
ret = IDirectInputDevice8_Acquire(haptic->hwdata->device);
@ -348,6 +340,15 @@ SDL_DINPUT_HapticOpenFromDevice(SDL_Haptic * haptic, LPDIRECTINPUTDEVICE8 device
}
}
/* Get number of axes. */
ret = IDirectInputDevice8_EnumObjects(haptic->hwdata->device,
DI_DeviceObjectCallback,
haptic, DIDFT_AXIS);
if (FAILED(ret)) {
DI_SetError("Getting device axes", ret);
goto acquire_err;
}
/* Reset all actuators - just in case. */
ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
DISFFC_RESET);

View file

@ -255,7 +255,7 @@ SDL_SYS_HapticQuit(void)
for (hapticitem = SDL_haptics; hapticitem; hapticitem = hapticitem->next) {
if ((hapticitem->hwdata->bXInputHaptic) && (hapticitem->hwdata->thread)) {
/* we _have_ to stop the thread before we free the XInput DLL! */
hapticitem->hwdata->stopThread = 1;
SDL_AtomicSet(&hapticitem->hwdata->stopThread, 1);
SDL_WaitThread(hapticitem->hwdata->thread, NULL);
hapticitem->hwdata->thread = NULL;
}

View file

@ -42,8 +42,8 @@ struct haptic_hwdata
Uint8 userid; /* XInput userid index for this joystick */
SDL_Thread *thread;
SDL_mutex *mutex;
volatile Uint32 stopTicks;
volatile int stopThread;
Uint32 stopTicks;
SDL_atomic_t stopThread;
};

View file

@ -33,6 +33,7 @@
#include "SDL_xinputhaptic_c.h"
#include "../../core/windows/SDL_xinput.h"
#include "../../joystick/windows/SDL_windowsjoystick_c.h"
#include "../../thread/SDL_systhread.h"
/*
* Internal stuff.
@ -43,8 +44,7 @@ static SDL_bool loaded_xinput = SDL_FALSE;
int
SDL_XINPUT_HapticInit(void)
{
const char *env = SDL_GetHint(SDL_HINT_XINPUT_ENABLED);
if (!env || SDL_atoi(env)) {
if (SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, SDL_TRUE)) {
loaded_xinput = (WIN_LoadXInputDLL() == 0);
}
@ -146,7 +146,7 @@ SDL_RunXInputHaptic(void *arg)
{
struct haptic_hwdata *hwdata = (struct haptic_hwdata *) arg;
while (!hwdata->stopThread) {
while (!SDL_AtomicGet(&hwdata->stopThread)) {
SDL_Delay(50);
SDL_LockMutex(hwdata->mutex);
/* If we're currently running and need to stop... */
@ -205,17 +205,8 @@ SDL_XINPUT_HapticOpenFromUserIndex(SDL_Haptic *haptic, const Uint8 userid)
}
SDL_snprintf(threadName, sizeof(threadName), "SDLXInputDev%d", (int)userid);
haptic->hwdata->thread = SDL_CreateThreadInternal(SDL_RunXInputHaptic, threadName, 64 * 1024, haptic->hwdata);
#if defined(__WIN32__) && !defined(HAVE_LIBC) /* !!! FIXME: this is nasty. */
#undef SDL_CreateThread
#if SDL_DYNAMIC_API
haptic->hwdata->thread = SDL_CreateThread_REAL(SDL_RunXInputHaptic, threadName, haptic->hwdata, NULL, NULL);
#else
haptic->hwdata->thread = SDL_CreateThread(SDL_RunXInputHaptic, threadName, haptic->hwdata, NULL, NULL);
#endif
#else
haptic->hwdata->thread = SDL_CreateThread(SDL_RunXInputHaptic, threadName, haptic->hwdata);
#endif
if (haptic->hwdata->thread == NULL) {
SDL_DestroyMutex(haptic->hwdata->mutex);
SDL_free(haptic->effects);
@ -261,7 +252,7 @@ SDL_XINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
void
SDL_XINPUT_HapticClose(SDL_Haptic * haptic)
{
haptic->hwdata->stopThread = 1;
SDL_AtomicSet(&haptic->hwdata->stopThread, 1);
SDL_WaitThread(haptic->hwdata->thread, NULL);
SDL_DestroyMutex(haptic->hwdata->mutex);
}

View file

@ -45,7 +45,8 @@ struct _SDL_HatMapping
Uint8 mask;
};
#define k_nMaxReverseEntries 20
/* We need 36 entries for Android (as of SDL v2.0.4) */
#define k_nMaxReverseEntries 48
/**
* We are encoding the "HAT" as 0xhm. where h == hat ID and m == mask
@ -105,6 +106,35 @@ struct _SDL_GameController
int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value);
int SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state);
/*
* If there is an existing add event in the queue, it needs to be modified
* to have the right value for which, because the number of controllers in
* the system is now one less.
*/
static void UpdateEventsForDeviceRemoval()
{
int i, num_events;
SDL_Event *events;
num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEADDED);
if (num_events <= 0) {
return;
}
events = SDL_stack_alloc(SDL_Event, num_events);
if (!events) {
return;
}
num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEADDED);
for (i = 0; i < num_events; ++i) {
--events[i].cdevice.which;
}
SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
SDL_stack_free(events);
}
/*
* Event filter to fire controller events from joystick ones
*/
@ -115,7 +145,11 @@ int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event)
{
SDL_GameController *controllerlist;
if (event->jaxis.axis >= k_nMaxReverseEntries) break;
if (event->jaxis.axis >= k_nMaxReverseEntries)
{
SDL_SetError("SDL_GameControllerEventWatcher: Axis index %d too large, ignoring motion", (int)event->jaxis.axis);
break;
}
controllerlist = SDL_gamecontrollers;
while (controllerlist) {
@ -126,8 +160,8 @@ int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event)
switch (axis) {
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
/* Shift it to be 0 - 32767. */
value = value / 2 + 16384;
break;
default:
break;
}
@ -146,7 +180,11 @@ int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event)
{
SDL_GameController *controllerlist;
if (event->jbutton.button >= k_nMaxReverseEntries) break;
if (event->jbutton.button >= k_nMaxReverseEntries)
{
SDL_SetError("SDL_GameControllerEventWatcher: Button index %d too large, ignoring update", (int)event->jbutton.button);
break;
}
controllerlist = SDL_gamecontrollers;
while (controllerlist) {
@ -223,9 +261,12 @@ int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event)
while (controllerlist) {
if (controllerlist->joystick->instance_id == event->jdevice.which) {
SDL_Event deviceevent;
deviceevent.type = SDL_CONTROLLERDEVICEREMOVED;
deviceevent.cdevice.which = event->jdevice.which;
SDL_PushEvent(&deviceevent);
UpdateEventsForDeviceRemoval();
break;
}
controllerlist = controllerlist->next;
@ -861,7 +902,6 @@ SDL_GameControllerInit(void)
{
int i = 0;
const char *pMappingString = NULL;
s_pSupportedControllers = NULL;
pMappingString = s_ControllerMappings[i];
while (pMappingString) {
SDL_GameControllerAddMapping(pMappingString);
@ -971,6 +1011,20 @@ SDL_GameControllerOpen(int device_index)
SDL_PrivateLoadButtonMapping(&gamecontroller->mapping, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping);
/* The triggers are mapped from -32768 to 32767, where -32768 is the 'unpressed' value */
{
int leftTriggerMapping = gamecontroller->mapping.axes[SDL_CONTROLLER_AXIS_TRIGGERLEFT];
int rightTriggerMapping = gamecontroller->mapping.axes[SDL_CONTROLLER_AXIS_TRIGGERRIGHT];
if (leftTriggerMapping >= 0) {
gamecontroller->joystick->axes[leftTriggerMapping] =
gamecontroller->joystick->axes_zero[leftTriggerMapping] = (Sint16)-32768;
}
if (rightTriggerMapping >= 0) {
gamecontroller->joystick->axes[rightTriggerMapping] =
gamecontroller->joystick->axes_zero[rightTriggerMapping] = (Sint16)-32768;
}
}
/* Add joystick to list */
++gamecontroller->ref_count;
/* Link the joystick in the list */
@ -1007,7 +1061,7 @@ SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControlle
switch (axis) {
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
/* Shift it to be 0 - 32767. */
/* Shift it to be 0 - 32767 */
value = value / 2 + 16384;
default:
break;

View file

@ -35,6 +35,7 @@ static const char *s_ControllerMappings [] =
"xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
#endif
#if SDL_JOYSTICK_DINPUT
"10280900000000000000504944564944,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,",
"341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"e8206058000000000000504944564944,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
@ -48,6 +49,7 @@ static const char *s_ControllerMappings [] =
"4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
#endif
#if defined(__MACOSX__)
"10280000000000000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,",
"830500000000000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */
@ -56,11 +58,14 @@ static const char *s_ControllerMappings [] =
"6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* This includes F710 in DInput mode and the "Logitech Cordless RumblePad 2", at the very least. */
"4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
"4c05000000000000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"351200000000000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,",
"11010000000000002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,",
"11010000000000001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,",
"5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
#endif
#if defined(__LINUX__)
"05000000102800000900000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,",
"03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
"03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
@ -71,6 +76,12 @@ static const char *s_ControllerMappings [] =
"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */
"030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000380700008433000011010000,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000380700008483000011010000,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000380700003847000090040000,Mad Catz Wired Xbox 360 Controller (SFIV),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"03000000380700008034000011010000,Mad Catz fightstick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000380700008084000011010000,Mad Catz fightstick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000380700001888000010010000,MadCatz PC USB Wired Stick 8818,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b1,b:b0,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
"050000003620000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,",
@ -78,12 +89,15 @@ static const char *s_ControllerMappings [] =
"03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
"030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
"03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000321500000009000011010000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
"03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"030000005e040000d102000001010000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
#endif
#if defined(__ANDROID__)

View file

@ -142,8 +142,8 @@ SDL_JoystickOpen(int device_index)
joystick->name = NULL;
if (joystick->naxes > 0) {
joystick->axes = (Sint16 *) SDL_malloc
(joystick->naxes * sizeof(Sint16));
joystick->axes = (Sint16 *) SDL_malloc(joystick->naxes * sizeof(Sint16));
joystick->axes_zero = (Sint16 *) SDL_malloc(joystick->naxes * sizeof(Sint16));
}
if (joystick->nhats > 0) {
joystick->hats = (Uint8 *) SDL_malloc
@ -167,6 +167,7 @@ SDL_JoystickOpen(int device_index)
}
if (joystick->axes) {
SDL_memset(joystick->axes, 0, joystick->naxes * sizeof(Sint16));
SDL_memset(joystick->axes_zero, 0, joystick->naxes * sizeof(Sint16));
}
if (joystick->hats) {
SDL_memset(joystick->hats, 0, joystick->nhats * sizeof(Uint8));
@ -497,6 +498,71 @@ SDL_PrivateJoystickShouldIgnoreEvent()
/* These are global for SDL_sysjoystick.c and SDL_events.c */
void SDL_PrivateJoystickAdded(int device_index)
{
#if !SDL_EVENTS_DISABLED
SDL_Event event;
event.type = SDL_JOYDEVICEADDED;
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = device_index;
if ( (SDL_EventOK == NULL) ||
(*SDL_EventOK) (SDL_EventOKParam, &event) ) {
SDL_PushEvent(&event);
}
}
#endif /* !SDL_EVENTS_DISABLED */
}
/*
* If there is an existing add event in the queue, it needs to be modified
* to have the right value for which, because the number of controllers in
* the system is now one less.
*/
static void UpdateEventsForDeviceRemoval()
{
int i, num_events;
SDL_Event *events;
num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
if (num_events <= 0) {
return;
}
events = SDL_stack_alloc(SDL_Event, num_events);
if (!events) {
return;
}
num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
for (i = 0; i < num_events; ++i) {
--events[i].jdevice.which;
}
SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
SDL_stack_free(events);
}
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
{
#if !SDL_EVENTS_DISABLED
SDL_Event event;
event.type = SDL_JOYDEVICEREMOVED;
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = device_instance;
if ( (SDL_EventOK == NULL) ||
(*SDL_EventOK) (SDL_EventOKParam, &event) ) {
SDL_PushEvent(&event);
}
}
UpdateEventsForDeviceRemoval();
#endif /* !SDL_EVENTS_DISABLED */
}
int
SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
{
@ -514,8 +580,8 @@ SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
* events.
*/
if (SDL_PrivateJoystickShouldIgnoreEvent()) {
if ((value > 0 && value >= joystick->axes[axis]) ||
(value < 0 && value <= joystick->axes[axis])) {
if ((value > joystick->axes_zero[axis] && value >= joystick->axes[axis]) ||
(value < joystick->axes_zero[axis] && value <= joystick->axes[axis])) {
return 0;
}
}
@ -688,7 +754,7 @@ SDL_JoystickUpdate(void)
/* Tell the app that everything is centered/unpressed... */
for (i = 0; i < joystick->naxes; i++) {
SDL_PrivateJoystickAxis(joystick, i, 0);
SDL_PrivateJoystickAxis(joystick, i, joystick->axes_zero[i]);
}
for (i = 0; i < joystick->nbuttons; i++) {

View file

@ -33,6 +33,8 @@ extern void SDL_GameControllerQuit(void);
/* Internal event queueing functions */
extern void SDL_PrivateJoystickAdded(int device_index);
extern void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance);
extern int SDL_PrivateJoystickAxis(SDL_Joystick * joystick,
Uint8 axis, Sint16 value);
extern int SDL_PrivateJoystickBall(SDL_Joystick * joystick,
@ -41,8 +43,8 @@ extern int SDL_PrivateJoystickHat(SDL_Joystick * joystick,
Uint8 hat, Uint8 value);
extern int SDL_PrivateJoystickButton(SDL_Joystick * joystick,
Uint8 button, Uint8 state);
extern void SDL_PrivateJoystickBatteryLevel( SDL_Joystick * joystick,
SDL_JoystickPowerLevel ePowerLevel );
extern void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick,
SDL_JoystickPowerLevel ePowerLevel);
/* Internal sanity checking functions */
extern int SDL_PrivateJoystickValid(SDL_Joystick * joystick);

View file

@ -36,6 +36,7 @@ struct _SDL_Joystick
int naxes; /* Number of axis controls on the joystick */
Sint16 *axes; /* Current axis states */
Sint16 *axes_zero; /* Zero point on the axis (-32768 for triggers) */
int nhats; /* Number of hats on the joystick */
Uint8 *hats; /* Current hat states */

View file

@ -27,10 +27,6 @@
#include "SDL_error.h"
#include "SDL_events.h"
#if !SDL_EVENTS_DISABLED
#include "../../events/SDL_events_c.h"
#endif
#include "SDL_joystick.h"
#include "SDL_hints.h"
#include "SDL_assert.h"
@ -191,8 +187,8 @@ Android_OnPadDown(int device_id, int keycode)
item = JoystickByDeviceId(device_id);
if (item && item->joystick) {
SDL_PrivateJoystickButton(item->joystick, button , SDL_PRESSED);
return 0;
}
return 0;
}
return -1;
@ -207,8 +203,8 @@ Android_OnPadUp(int device_id, int keycode)
item = JoystickByDeviceId(device_id);
if (item && item->joystick) {
SDL_PrivateJoystickButton(item->joystick, button, SDL_RELEASED);
return 0;
}
return 0;
}
return -1;
@ -252,9 +248,6 @@ Android_AddJoystick(int device_id, const char *name, SDL_bool is_accelerometer,
{
SDL_JoystickGUID guid;
SDL_joylist_item *item;
#if !SDL_EVENTS_DISABLED
SDL_Event event;
#endif
if(JoystickByDeviceId(device_id) != NULL || name == NULL) {
return -1;
@ -299,17 +292,7 @@ Android_AddJoystick(int device_id, const char *name, SDL_bool is_accelerometer,
/* Need to increment the joystick count before we post the event */
++numjoysticks;
#if !SDL_EVENTS_DISABLED
event.type = SDL_JOYDEVICEADDED;
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = (numjoysticks - 1);
if ( (SDL_EventOK == NULL) ||
(*SDL_EventOK) (SDL_EventOKParam, &event) ) {
SDL_PushEvent(&event);
}
}
#endif /* !SDL_EVENTS_DISABLED */
SDL_PrivateJoystickAdded(numjoysticks - 1);
#ifdef DEBUG_JOYSTICK
SDL_Log("Added joystick %s with device_id %d", name, device_id);
@ -323,9 +306,6 @@ Android_RemoveJoystick(int device_id)
{
SDL_joylist_item *item = SDL_joylist;
SDL_joylist_item *prev = NULL;
#if !SDL_EVENTS_DISABLED
SDL_Event event;
#endif
/* Don't call JoystickByDeviceId here or there'll be an infinite loop! */
while (item != NULL) {
@ -340,7 +320,6 @@ Android_RemoveJoystick(int device_id)
return -1;
}
const int retval = item->device_instance;
if (item->joystick) {
item->joystick->hwdata = NULL;
}
@ -358,17 +337,7 @@ Android_RemoveJoystick(int device_id)
/* Need to decrement the joystick count before we post the event */
--numjoysticks;
#if !SDL_EVENTS_DISABLED
event.type = SDL_JOYDEVICEREMOVED;
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = item->device_instance;
if ( (SDL_EventOK == NULL) ||
(*SDL_EventOK) (SDL_EventOKParam, &event) ) {
SDL_PushEvent(&event);
}
}
#endif /* !SDL_EVENTS_DISABLED */
SDL_PrivateJoystickRemoved(item->device_instance);
#ifdef DEBUG_JOYSTICK
SDL_Log("Removed joystick with device_id %d", device_id);
@ -376,18 +345,16 @@ Android_RemoveJoystick(int device_id)
SDL_free(item->name);
SDL_free(item);
return retval;
return numjoysticks;
}
int
SDL_SYS_JoystickInit(void)
{
const char *hint;
SDL_SYS_JoystickDetect();
hint = SDL_GetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK);
if (!hint || SDL_atoi(hint)) {
if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE)) {
/* Default behavior, accelerometer as joystick */
Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, SDL_TRUE, 0, 3, 0, 0);
}
@ -539,6 +506,10 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
void
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
{
SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
if (item) {
item->joystick = NULL;
}
}
/* Function to perform any system-specific joystick related cleanup */

View file

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

View file

@ -179,7 +179,7 @@ SDL_SYS_JoystickInit(void)
SDL_snprintf(s, SDL_arraysize(s), "/dev/uhid%d", i);
joynames[SDL_SYS_numjoysticks] = strdup(s);
joynames[SDL_SYS_numjoysticks] = SDL_strdup(s);
if (SDL_SYS_JoystickOpen(&nj, SDL_SYS_numjoysticks) == 0) {
SDL_SYS_JoystickClose(&nj);
@ -193,7 +193,7 @@ SDL_SYS_JoystickInit(void)
SDL_snprintf(s, SDL_arraysize(s), "/dev/joy%d", i);
fd = open(s, O_RDONLY);
if (fd != -1) {
joynames[SDL_SYS_numjoysticks++] = strdup(s);
joynames[SDL_SYS_numjoysticks++] = SDL_strdup(s);
close(fd);
}
}
@ -304,14 +304,14 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joy, int device_index)
}
joy->hwdata = hw;
hw->fd = fd;
hw->path = strdup(path);
hw->path = SDL_strdup(path);
if (!SDL_strncmp(path, "/dev/joy", 8)) {
hw->type = BSDJOY_JOY;
joy->naxes = 2;
joy->nbuttons = 2;
joy->nhats = 0;
joy->nballs = 0;
joydevnames[device_index] = strdup("Gameport joystick");
joydevnames[device_index] = SDL_strdup("Gameport joystick");
goto usbend;
} else {
hw->type = BSDJOY_UHID;
@ -363,7 +363,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joy, int device_index)
str[i] = '\0';
asprintf(&new_name, "%s @ %s", str, path);
if (new_name != NULL) {
free(joydevnames[SDL_SYS_numjoysticks]);
SDL_free(joydevnames[SDL_SYS_numjoysticks]);
joydevnames[SDL_SYS_numjoysticks] = new_name;
}
}

View file

@ -34,9 +34,6 @@
#include "SDL_sysjoystick_c.h"
#include "SDL_events.h"
#include "../../haptic/darwin/SDL_syshaptic_c.h" /* For haptic hot plugging */
#if !SDL_EVENTS_DISABLED
#include "../../events/SDL_events_c.h"
#endif
#define SDL_JOYSTICK_RUNLOOP_MODE CFSTR("SDLJoystick")
@ -154,21 +151,7 @@ JoystickDeviceWasRemovedCallback(void *ctx, IOReturn result, void *sender)
MacHaptic_MaybeRemoveDevice(device->ffservice);
#endif
/* !!! FIXME: why isn't there an SDL_PrivateJoyDeviceRemoved()? */
#if !SDL_EVENTS_DISABLED
{
SDL_Event event;
event.type = SDL_JOYDEVICEREMOVED;
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = device->instance_id;
if ((SDL_EventOK == NULL)
|| (*SDL_EventOK) (SDL_EventOKParam, &event)) {
SDL_PushEvent(&event);
}
}
}
#endif /* !SDL_EVENTS_DISABLED */
SDL_PrivateJoystickRemoved(device->instance_id);
}
@ -249,6 +232,7 @@ AddHIDElement(const void *value, void *parameter)
case kHIDUsage_GD_DPadLeft:
case kHIDUsage_GD_Start:
case kHIDUsage_GD_Select:
case kHIDUsage_GD_SystemMainMenu:
if (!ElementAlreadyAdded(cookie, pDevice->firstButton)) {
element = (recElement *) SDL_calloc(1, sizeof (recElement));
if (element) {
@ -422,6 +406,7 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic
{
recDevice *device;
int device_index = 0;
io_service_t ioservice;
if (res != kIOReturnSuccess) {
return;
@ -451,20 +436,11 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic
device->instance_id = ++s_joystick_instance_id;
/* We have to do some storage of the io_service_t for SDL_HapticOpenFromJoystick */
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
if (IOHIDDeviceGetService != NULL) { /* weak reference: available in 10.6 and later. */
#endif
const io_service_t ioservice = IOHIDDeviceGetService(ioHIDDeviceObject);
ioservice = IOHIDDeviceGetService(ioHIDDeviceObject);
#if SDL_HAPTIC_IOKIT
if ((ioservice) && (FFIsForceFeedback(ioservice) == FF_OK)) {
device->ffservice = ioservice;
MacHaptic_MaybeAddDevice(ioservice);
}
#endif
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
if ((ioservice) && (FFIsForceFeedback(ioservice) == FF_OK)) {
device->ffservice = ioservice;
MacHaptic_MaybeAddDevice(ioservice);
}
#endif
@ -483,21 +459,7 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic
++device_index; /* bump by one since we counted by pNext. */
}
/* !!! FIXME: why isn't there an SDL_PrivateJoyDeviceAdded()? */
#if !SDL_EVENTS_DISABLED
{
SDL_Event event;
event.type = SDL_JOYDEVICEADDED;
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = device_index;
if ((SDL_EventOK == NULL)
|| (*SDL_EventOK) (SDL_EventOKParam, &event)) {
SDL_PushEvent(&event);
}
}
}
#endif /* !SDL_EVENTS_DISABLED */
SDL_PrivateJoystickAdded(device_index);
}
static SDL_bool

View file

@ -27,10 +27,6 @@
#include "SDL_error.h"
#include "SDL_events.h"
#if !SDL_EVENTS_DISABLED
#include "../../events/SDL_events_c.h"
#endif
#include "SDL_joystick.h"
#include "SDL_hints.h"
#include "SDL_assert.h"
@ -57,10 +53,6 @@ Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepa
return 1;
}
#if !SDL_EVENTS_DISABLED
SDL_Event event;
#endif
item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
if (item == NULL) {
return 1;
@ -105,20 +97,12 @@ Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepa
}
++numjoysticks;
SDL_PrivateJoystickAdded(numjoysticks - 1);
#ifdef DEBUG_JOYSTICK
SDL_Log("Number of joysticks is %d", numjoysticks);
#endif
#if !SDL_EVENTS_DISABLED
event.type = SDL_JOYDEVICEADDED;
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = numjoysticks - 1;
if ( (SDL_EventOK == NULL) ||
(*SDL_EventOK) (SDL_EventOKParam, &event) ) {
SDL_PushEvent(&event);
}
}
#endif /* !SDL_EVENTS_DISABLED */
#ifdef DEBUG_JOYSTICK
SDL_Log("Added joystick with index %d", item->index);
@ -132,9 +116,6 @@ Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gam
{
SDL_joylist_item *item = SDL_joylist;
SDL_joylist_item *prev = NULL;
#if !SDL_EVENTS_DISABLED
SDL_Event event;
#endif
while (item != NULL) {
if (item->index == gamepadEvent->index) {
@ -165,17 +146,7 @@ Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gam
/* Need to decrement the joystick count before we post the event */
--numjoysticks;
#if !SDL_EVENTS_DISABLED
event.type = SDL_JOYDEVICEREMOVED;
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = item->device_instance;
if ( (SDL_EventOK == NULL) ||
(*SDL_EventOK) (SDL_EventOKParam, &event) ) {
SDL_PushEvent(&event);
}
}
#endif /* !SDL_EVENTS_DISABLED */
SDL_PrivateJoystickRemoved(item->device_instance);
#ifdef DEBUG_JOYSTICK
SDL_Log("Removed joystick with id %d", item->device_instance);
@ -377,6 +348,10 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
void
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
{
SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
if (item) {
item->joystick = NULL;
}
}
/* Function to perform any system-specific joystick related cleanup */

View file

@ -1,23 +1,23 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
Simple DirectMedia Layer
Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
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:
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.
*/
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"

View file

@ -74,8 +74,8 @@ extern "C"
if (joystick.Open(name) != B_ERROR) {
BString stick_name;
joystick.GetControllerName(&stick_name);
SDL_joyport[SDL_SYS_numjoysticks] = strdup(name);
SDL_joyname[SDL_SYS_numjoysticks] = strdup(stick_name.String());
SDL_joyport[SDL_SYS_numjoysticks] = SDL_strdup(name);
SDL_joyname[SDL_SYS_numjoysticks] = SDL_strdup(stick_name.String());
SDL_SYS_numjoysticks++;
joystick.Close();
}

View file

@ -26,6 +26,7 @@
/* needed for SDL_IPHONE_MAX_GFORCE macro */
#include "SDL_config_iphoneos.h"
#include "SDL_events.h"
#include "SDL_joystick.h"
#include "SDL_hints.h"
#include "SDL_stdinc.h"
@ -36,7 +37,9 @@
#include "../../events/SDL_events_c.h"
#endif
#if !TARGET_OS_TV
#import <CoreMotion/CoreMotion.h>
#endif
#ifdef SDL_JOYSTICK_MFI
#import <GameController/GameController.h>
@ -45,8 +48,10 @@ static id connectObserver = nil;
static id disconnectObserver = nil;
#endif /* SDL_JOYSTICK_MFI */
#if !TARGET_OS_TV
static const char *accelerometerName = "iOS Accelerometer";
static CMMotionManager *motionManager = nil;
#endif /* !TARGET_OS_TV */
static SDL_JoystickDeviceItem *deviceList = NULL;
@ -105,6 +110,11 @@ SDL_SYS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *contr
} else if (controller.gamepad) {
device->guid.data[10] = 2;
}
#if TARGET_OS_TV
else if (controller.microGamepad) {
device->guid.data[10] = 3;
}
#endif /* TARGET_OS_TV */
if (controller.extendedGamepad) {
device->naxes = 6; /* 2 thumbsticks and 2 triggers */
@ -115,21 +125,27 @@ SDL_SYS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *contr
device->nhats = 1; /* d-pad */
device->nbuttons = 7; /* ABXY, shoulder buttons, pause button */
}
/* TODO: Handle micro profiles on tvOS. */
#if TARGET_OS_TV
else if (controller.microGamepad) {
device->naxes = 2; /* treat the touch surface as two axes */
device->nhats = 0; /* apparently the touch surface-as-dpad is buggy */
device->nbuttons = 3; /* AX, pause button */
controller.microGamepad.allowsRotation = SDL_GetHintBoolean(SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION, SDL_FALSE);
}
#endif /* TARGET_OS_TV */
/* This will be set when the first button press of the controller is
* detected. */
controller.playerIndex = -1;
#endif
#endif /* SDL_JOYSTICK_MFI */
}
static void
SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer)
{
SDL_JoystickDeviceItem *device = deviceList;
#if !SDL_EVENTS_DISABLED
SDL_Event event;
#endif
while (device != NULL) {
if (device->controller == controller) {
@ -149,6 +165,10 @@ SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer)
device->instance_id = instancecounter++;
if (accelerometer) {
#if TARGET_OS_TV
SDL_free(device);
return;
#else
device->name = SDL_strdup(accelerometerName);
device->naxes = 3; /* Device acceleration in the x, y, and z axes. */
device->nhats = 0;
@ -156,6 +176,7 @@ SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer)
/* Use the accelerometer name as a GUID. */
SDL_memcpy(&device->guid.data, device->name, SDL_min(sizeof(SDL_JoystickGUID), SDL_strlen(device->name)));
#endif /* TARGET_OS_TV */
} else if (controller) {
SDL_SYS_AddMFIJoystickDevice(device, controller);
}
@ -172,17 +193,7 @@ SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer)
++numjoysticks;
#if !SDL_EVENTS_DISABLED
event.type = SDL_JOYDEVICEADDED;
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = numjoysticks - 1;
if ((SDL_EventOK == NULL) ||
(*SDL_EventOK)(SDL_EventOKParam, &event)) {
SDL_PushEvent(&event);
}
}
#endif /* !SDL_EVENTS_DISABLED */
SDL_PrivateJoystickAdded(numjoysticks - 1);
}
static SDL_JoystickDeviceItem *
@ -191,9 +202,6 @@ SDL_SYS_RemoveJoystickDevice(SDL_JoystickDeviceItem *device)
SDL_JoystickDeviceItem *prev = NULL;
SDL_JoystickDeviceItem *next = NULL;
SDL_JoystickDeviceItem *item = deviceList;
#if !SDL_EVENTS_DISABLED
SDL_Event event;
#endif
if (device == NULL) {
return NULL;
@ -234,17 +242,7 @@ SDL_SYS_RemoveJoystickDevice(SDL_JoystickDeviceItem *device)
--numjoysticks;
#if !SDL_EVENTS_DISABLED
event.type = SDL_JOYDEVICEREMOVED;
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = device->instance_id;
if ((SDL_EventOK == NULL) ||
(*SDL_EventOK)(SDL_EventOKParam, &event)) {
SDL_PushEvent(&event);
}
}
#endif /* !SDL_EVENTS_DISABLED */
SDL_PrivateJoystickRemoved(device->instance_id);
SDL_free(device->name);
SDL_free(device);
@ -252,6 +250,22 @@ SDL_SYS_RemoveJoystickDevice(SDL_JoystickDeviceItem *device)
return next;
}
#if TARGET_OS_TV
static void
SDL_AppleTVRemoteRotationHintChanged(void *udata, const char *name, const char *oldValue, const char *newValue)
{
BOOL allowRotation = newValue != NULL && *newValue != '0';
@autoreleasepool {
for (GCController *controller in [GCController controllers]) {
if (controller.microGamepad) {
controller.microGamepad.allowsRotation = allowRotation;
}
}
}
}
#endif /* TARGET_OS_TV */
/* Function to scan the system for joysticks.
* Joystick 0 should be the system default joystick.
* It should return 0, or -1 on an unrecoverable fatal error.
@ -261,12 +275,13 @@ SDL_SYS_JoystickInit(void)
{
@autoreleasepool {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
const char *hint = SDL_GetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK);
if (!hint || SDL_atoi(hint)) {
#if !TARGET_OS_TV
if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE)) {
/* Default behavior, accelerometer as joystick */
SDL_SYS_AddJoystickDevice(nil, SDL_TRUE);
}
#endif /* !TARGET_OS_TV */
#ifdef SDL_JOYSTICK_MFI
/* GameController.framework was added in iOS 7. */
@ -278,6 +293,11 @@ SDL_SYS_JoystickInit(void)
SDL_SYS_AddJoystickDevice(controller, SDL_FALSE);
}
#if TARGET_OS_TV
SDL_AddHintCallback(SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION,
SDL_AppleTVRemoteRotationHintChanged, NULL);
#endif /* TARGET_OS_TV */
connectObserver = [center addObserverForName:GCControllerDidConnectNotification
object:nil
queue:nil
@ -355,6 +375,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
@autoreleasepool {
if (device->accelerometer) {
#if !TARGET_OS_TV
if (motionManager == nil) {
motionManager = [[CMMotionManager alloc] init];
}
@ -362,6 +383,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
/* Shorter times between updates can significantly increase CPU usage. */
motionManager.accelerometerUpdateInterval = 0.1;
[motionManager startAccelerometerUpdates];
#endif /* !TARGET_OS_TV */
} else {
#ifdef SDL_JOYSTICK_MFI
GCController *controller = device->controller;
@ -387,6 +409,7 @@ SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
static void
SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick)
{
#if !TARGET_OS_TV
const float maxgforce = SDL_IPHONE_MAX_GFORCE;
const SInt16 maxsint16 = 0x7FFF;
CMAcceleration accel;
@ -424,6 +447,7 @@ SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick)
SDL_PrivateJoystickAxis(joystick, 0, (accel.x / maxgforce) * maxsint16);
SDL_PrivateJoystickAxis(joystick, 1, -(accel.y / maxgforce) * maxsint16);
SDL_PrivateJoystickAxis(joystick, 2, (accel.z / maxgforce) * maxsint16);
#endif /* !TARGET_OS_TV */
}
#ifdef SDL_JOYSTICK_MFI
@ -455,7 +479,7 @@ SDL_SYS_MFIJoystickHatStateForDPad(GCControllerDirectionPad *dpad)
static void
SDL_SYS_MFIJoystickUpdate(SDL_Joystick * joystick)
{
#ifdef SDL_JOYSTICK_MFI
#if SDL_JOYSTICK_MFI
@autoreleasepool {
GCController *controller = joystick->hwdata->controller;
Uint8 hatstate = SDL_HAT_CENTERED;
@ -517,7 +541,36 @@ SDL_SYS_MFIJoystickUpdate(SDL_Joystick * joystick)
SDL_PrivateJoystickButton(joystick, i, buttons[i]);
}
}
/* TODO: Handle micro profiles on tvOS. */
#if TARGET_OS_TV
else if (controller.microGamepad) {
GCMicroGamepad *gamepad = controller.microGamepad;
Sint16 axes[] = {
(Sint16) (gamepad.dpad.xAxis.value * 32767),
(Sint16) (gamepad.dpad.yAxis.value * -32767),
};
for (i = 0; i < SDL_arraysize(axes); i++) {
updateplayerindex |= (joystick->axes[i] != axes[i]);
SDL_PrivateJoystickAxis(joystick, i, axes[i]);
}
/* Apparently the dpad values are not accurate enough to be useful. */
/* hatstate = SDL_SYS_MFIJoystickHatStateForDPad(gamepad.dpad); */
Uint8 buttons[] = {
gamepad.buttonA.isPressed,
gamepad.buttonX.isPressed,
};
for (i = 0; i < SDL_arraysize(buttons); i++) {
updateplayerindex |= (joystick->buttons[i] != buttons[i]);
SDL_PrivateJoystickButton(joystick, i, buttons[i]);
}
/* TODO: Figure out what to do with reportsAbsoluteDpadValues */
}
#endif /* TARGET_OS_TV */
if (joystick->nhats > 0) {
updateplayerindex |= (joystick->hats[0] != hatstate);
@ -557,7 +610,7 @@ SDL_SYS_MFIJoystickUpdate(SDL_Joystick * joystick)
}
}
}
#endif
#endif /* SDL_JOYSTICK_MFI */
}
/* Function to update the state of a joystick - called as a device poll.
@ -595,7 +648,9 @@ SDL_SYS_JoystickClose(SDL_Joystick * joystick)
@autoreleasepool {
if (device->accelerometer) {
#if !TARGET_OS_TV
[motionManager stopAccelerometerUpdates];
#endif /* !TARGET_OS_TV */
} else if (device->controller) {
#ifdef SDL_JOYSTICK_MFI
GCController *controller = device->controller;
@ -623,13 +678,20 @@ SDL_SYS_JoystickQuit(void)
[center removeObserver:disconnectObserver name:GCControllerDidDisconnectNotification object:nil];
disconnectObserver = nil;
}
#if TARGET_OS_TV
SDL_DelHintCallback(SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION,
SDL_AppleTVRemoteRotationHintChanged, NULL);
#endif /* TARGET_OS_TV */
#endif /* SDL_JOYSTICK_MFI */
while (deviceList != NULL) {
SDL_SYS_RemoveJoystickDevice(deviceList);
}
#if !TARGET_OS_TV
motionManager = nil;
#endif /* !TARGET_OS_TV */
}
numjoysticks = 0;

View file

@ -42,11 +42,6 @@
#include "../SDL_joystick_c.h"
#include "SDL_sysjoystick_c.h"
/* !!! FIXME: move this somewhere else. */
#if !SDL_EVENTS_DISABLED
#include "../../events/SDL_events_c.h"
#endif
/* This isn't defined in older Linux kernel headers */
#ifndef SYN_DROPPED
#define SYN_DROPPED 3
@ -176,9 +171,6 @@ MaybeAddDevice(const char *path)
char namebuf[128];
SDL_JoystickGUID guid;
SDL_joylist_item *item;
#if !SDL_EVENTS_DISABLED
SDL_Event event;
#endif
if (path == NULL) {
return -1;
@ -239,18 +231,7 @@ MaybeAddDevice(const char *path)
/* Need to increment the joystick count before we post the event */
++numjoysticks;
/* !!! FIXME: Move this to an SDL_PrivateJoyDeviceAdded() function? */
#if !SDL_EVENTS_DISABLED
event.type = SDL_JOYDEVICEADDED;
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = (numjoysticks - 1);
if ( (SDL_EventOK == NULL) ||
(*SDL_EventOK) (SDL_EventOKParam, &event) ) {
SDL_PushEvent(&event);
}
}
#endif /* !SDL_EVENTS_DISABLED */
SDL_PrivateJoystickAdded(numjoysticks - 1);
return numjoysticks;
}
@ -262,9 +243,6 @@ MaybeRemoveDevice(const char *path)
{
SDL_joylist_item *item;
SDL_joylist_item *prev = NULL;
#if !SDL_EVENTS_DISABLED
SDL_Event event;
#endif
if (path == NULL) {
return -1;
@ -290,18 +268,7 @@ MaybeRemoveDevice(const char *path)
/* Need to decrement the joystick count before we post the event */
--numjoysticks;
/* !!! FIXME: Move this to an SDL_PrivateJoyDeviceRemoved() function? */
#if !SDL_EVENTS_DISABLED
event.type = SDL_JOYDEVICEREMOVED;
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = item->device_instance;
if ( (SDL_EventOK == NULL) ||
(*SDL_EventOK) (SDL_EventOKParam, &event) ) {
SDL_PushEvent(&event);
}
}
#endif /* !SDL_EVENTS_DISABLED */
SDL_PrivateJoystickRemoved(item->device_instance);
SDL_free(item->path);
SDL_free(item->name);

View file

@ -34,9 +34,9 @@
#include "SDL_events.h"
#include "SDL_error.h"
#include "SDL_thread.h"
#include "SDL_mutex.h"
#include "SDL_timer.h"
#include "../../thread/SDL_systhread.h"
/* Current pad state */
static SceCtrlData pad = { .Lx = 0, .Ly = 0, .Buttons = 0 };
@ -116,7 +116,7 @@ int SDL_SYS_JoystickInit(void)
return SDL_SetError("Can't create input semaphore");
}
running = 1;
if((thread = SDL_CreateThread(JoystickUpdate, "JoySitckThread",NULL)) == NULL) {
if((thread = SDL_CreateThreadInternal(JoystickUpdate, "JoystickThread", 4096, NULL)) == NULL) {
return SDL_SetError("Can't create input thread");
}

View file

@ -214,7 +214,7 @@ static DIOBJECTDATAFORMAT dfDIJoystick2[] = {
{ &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
};
const DIDATAFORMAT c_dfDIJoystick2 = {
const DIDATAFORMAT SDL_c_dfDIJoystick2 = {
sizeof(DIDATAFORMAT),
sizeof(DIOBJECTDATAFORMAT),
DIDF_ABSAXIS,
@ -240,11 +240,23 @@ SDL_IsXInputDevice(const GUID* pGuidProductFromDirectInput)
static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static GUID IID_XOneWiredGamepad = { MAKELONG(0x045E, 0x02FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static GUID IID_XOneWirelessGamepad = { MAKELONG(0x045E, 0x02DD), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static GUID IID_XOneNewWirelessGamepad = { MAKELONG(0x045E, 0x02D1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static GUID IID_XOneSWirelessGamepad = { MAKELONG(0x045E, 0x02EA), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static GUID IID_XOneSBluetoothGamepad = { MAKELONG(0x045E, 0x02E0), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static GUID IID_XOneEliteWirelessGamepad = { MAKELONG(0x045E, 0x02E3), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static const GUID *s_XInputProductGUID[] = {
&IID_ValveStreamingGamepad,
&IID_X360WiredGamepad, /* Microsoft's wired X360 controller for Windows. */
&IID_X360WirelessGamepad /* Microsoft's wireless X360 controller for Windows. */
&IID_X360WiredGamepad, /* Microsoft's wired X360 controller for Windows. */
&IID_X360WirelessGamepad, /* Microsoft's wireless X360 controller for Windows. */
&IID_XOneWiredGamepad, /* Microsoft's wired Xbox One controller for Windows. */
&IID_XOneWirelessGamepad, /* Microsoft's wireless Xbox One controller for Windows. */
&IID_XOneNewWirelessGamepad, /* Microsoft's updated wireless Xbox One controller (w/ 3.5 mm jack) for Windows. */
&IID_XOneSWirelessGamepad, /* Microsoft's wireless Xbox One S controller for Windows. */
&IID_XOneSBluetoothGamepad, /* Microsoft's Bluetooth Xbox One S controller for Windows. */
&IID_XOneEliteWirelessGamepad /* Microsoft's wireless Xbox One Elite controller for Windows. */
};
size_t iDevice;
@ -582,7 +594,7 @@ SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickde
/* Use the extended data structure: DIJOYSTATE2. */
result =
IDirectInputDevice8_SetDataFormat(joystick->hwdata->InputDevice,
&c_dfDIJoystick2);
&SDL_c_dfDIJoystick2);
if (FAILED(result)) {
return SetDIerror("IDirectInputDevice8::SetDataFormat", result);
}

View file

@ -35,16 +35,13 @@
#include "SDL_error.h"
#include "SDL_assert.h"
#include "SDL_events.h"
#include "SDL_thread.h"
#include "SDL_timer.h"
#include "SDL_mutex.h"
#include "SDL_events.h"
#include "SDL_hints.h"
#include "SDL_joystick.h"
#include "../SDL_sysjoystick.h"
#if !SDL_EVENTS_DISABLED
#include "../../events/SDL_events_c.h"
#endif
#include "../../thread/SDL_systhread.h"
#include "../../core/windows/SDL_windows.h"
#if !defined(__WINRT__)
#include <dbt.h>
@ -301,18 +298,9 @@ SDL_SYS_JoystickInit(void)
SDL_SYS_JoystickDetect();
if (!s_threadJoystick) {
s_bJoystickThreadQuit = SDL_FALSE;
/* spin up the thread to detect hotplug of devices */
#if defined(__WIN32__) && !defined(HAVE_LIBC)
#undef SDL_CreateThread
#if SDL_DYNAMIC_API
s_threadJoystick= SDL_CreateThread_REAL(SDL_JoystickThread, "SDL_joystick", NULL, NULL, NULL);
#else
s_threadJoystick= SDL_CreateThread(SDL_JoystickThread, "SDL_joystick", NULL, NULL, NULL);
#endif
#else
s_threadJoystick = SDL_CreateThread(SDL_JoystickThread, "SDL_joystick", NULL);
#endif
s_bJoystickThreadQuit = SDL_FALSE;
s_threadJoystick = SDL_CreateThreadInternal(SDL_JoystickThread, "SDL_joystick", 64 * 1024, NULL);
}
return SDL_SYS_NumJoysticks();
}
@ -336,9 +324,6 @@ void
SDL_SYS_JoystickDetect()
{
JoyStick_DeviceData *pCurList = NULL;
#if !SDL_EVENTS_DISABLED
SDL_Event event;
#endif
/* only enum the devices if the joystick thread told us something changed */
if (!s_bDeviceAdded && !s_bDeviceRemoved) {
@ -370,17 +355,7 @@ SDL_SYS_JoystickDetect()
SDL_DINPUT_MaybeRemoveDevice(&pCurList->dxdevice);
}
#if !SDL_EVENTS_DISABLED
SDL_zero(event);
event.type = SDL_JOYDEVICEREMOVED;
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = pCurList->nInstanceID;
if ((!SDL_EventOK) || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
SDL_PushEvent(&event);
}
}
#endif /* !SDL_EVENTS_DISABLED */
SDL_PrivateJoystickRemoved(pCurList->nInstanceID);
pListNext = pCurList->pNext;
SDL_free(pCurList->joystickname);
@ -401,17 +376,8 @@ SDL_SYS_JoystickDetect()
SDL_DINPUT_MaybeAddDevice(&pNewJoystick->dxdevice);
}
#if !SDL_EVENTS_DISABLED
SDL_zero(event);
event.type = SDL_JOYDEVICEADDED;
SDL_PrivateJoystickAdded(device_index);
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = device_index;
if ((!SDL_EventOK) || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
SDL_PushEvent(&event);
}
}
#endif /* !SDL_EVENTS_DISABLED */
pNewJoystick->send_add_event = SDL_FALSE;
}
device_index++;
@ -543,6 +509,9 @@ SDL_SYS_JoystickQuit(void)
SDL_DINPUT_JoystickQuit();
SDL_XINPUT_JoystickQuit();
s_bDeviceAdded = SDL_FALSE;
s_bDeviceRemoved = SDL_FALSE;
}
/* return the stable device guid for this device index */

View file

@ -83,6 +83,10 @@ struct joystick_hwdata
DWORD dwPacketNumber;
};
#if SDL_JOYSTICK_DINPUT
extern const DIDATAFORMAT SDL_c_dfDIJoystick2;
#endif
extern void SDL_SYS_AddJoystickDevice(JoyStick_DeviceData *device);
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -40,8 +40,7 @@ SDL_XInputUseOldJoystickMapping()
{
static int s_XInputUseOldJoystickMapping = -1;
if (s_XInputUseOldJoystickMapping < 0) {
const char *hint = SDL_GetHint(SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING);
s_XInputUseOldJoystickMapping = (hint && *hint == '1') ? 1 : 0;
s_XInputUseOldJoystickMapping = SDL_GetHintBoolean(SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING, SDL_FALSE);
}
return (s_XInputUseOldJoystickMapping > 0);
}
@ -54,10 +53,7 @@ SDL_bool SDL_XINPUT_Enabled(void)
int
SDL_XINPUT_JoystickInit(void)
{
const char *env = SDL_GetHint(SDL_HINT_XINPUT_ENABLED);
if (env && !SDL_atoi(env)) {
s_bXInputEnabled = SDL_FALSE;
}
s_bXInputEnabled = SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, SDL_TRUE);
if (s_bXInputEnabled && WIN_LoadXInputDLL() < 0) {
s_bXInputEnabled = SDL_FALSE; /* oh well. */
@ -376,7 +372,7 @@ SDL_SYS_IsXInputGamepad_DeviceIndex(int device_index)
for (index = device_index; index > 0; index--)
device = device->pNext;
return (device->SubType == XINPUT_DEVSUBTYPE_GAMEPAD);
return device->bXInputDevice;
}
#else /* !SDL_JOYSTICK_XINPUT */

View file

@ -30,11 +30,25 @@
#include "SDL_loadso.h"
#if SDL_VIDEO_DRIVER_UIKIT
#include "../../video/uikit/SDL_uikitvideo.h"
#endif
void *
SDL_LoadObject(const char *sofile)
{
void *handle = dlopen(sofile, RTLD_NOW|RTLD_LOCAL);
const char *loaderror = (char *) dlerror();
void *handle;
const char *loaderror;
#if SDL_VIDEO_DRIVER_UIKIT
if (!UIKit_IsSystemVersionAtLeast(8.0)) {
SDL_SetError("SDL_LoadObject requires iOS 8+");
return NULL;
}
#endif
handle = dlopen(sofile, RTLD_NOW|RTLD_LOCAL);
loaderror = (char *) dlerror();
if (handle == NULL) {
SDL_SetError("Failed loading %s: %s", sofile, loaderror);
}

View file

@ -16,12 +16,17 @@
/* Called before SDL_main() to initialize JNI bindings in SDL library */
extern void SDL_Android_Init(JNIEnv* env, jclass cls);
/* This prototype is needed to prevent a warning about the missing prototype for global function below */
JNIEXPORT int JNICALL Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject array);
/* Start up the SDL app */
JNIEXPORT int JNICALL Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject array)
{
int i;
int argc;
int status;
int len;
char** argv;
/* This interface could expand with ABI negotiation, callbacks, etc. */
SDL_Android_Init(env, cls);
@ -30,8 +35,8 @@ JNIEXPORT int JNICALL Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jc
/* Prepare the arguments. */
int len = (*env)->GetArrayLength(env, array);
char* argv[1 + len + 1];
len = (*env)->GetArrayLength(env, array);
argv = SDL_stack_alloc(char*, 1 + len + 1);
argc = 0;
/* Use the name "app_process" so PHYSFS_platformCalcBaseDir() works.
https://bitbucket.org/MartinFelis/love-android-sdl2/issue/23/release-build-crash-on-start
@ -66,7 +71,7 @@ JNIEXPORT int JNICALL Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jc
for (i = 0; i < argc; ++i) {
SDL_free(argv[i]);
}
SDL_stack_free(argv);
/* Do not issue an exit or the whole application will terminate instead of just the SDL thread */
/* exit(status); */

View file

@ -193,7 +193,8 @@ public:
if(_current_context)
_current_context->UnlockGL();
_current_context = newContext;
_current_context->LockGL();
if (_current_context)
_current_context->LockGL();
}
private:
/* Event management */
@ -272,6 +273,17 @@ private:
}
BE_SetKeyState(scancode, state);
SDL_SendKeyboardKey(state, BE_GetScancodeFromBeKey(scancode));
if (state == SDL_PRESSED && SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
const int8 *keyUtf8;
ssize_t count;
if (msg->FindData("key-utf8", B_INT8_TYPE, (const void**)&keyUtf8, &count) == B_OK) {
char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
SDL_zero(text);
SDL_memcpy(text, keyUtf8, count);
SDL_SendKeyboardText(text);
}
}
}
void _HandleMouseFocus(BMessage *msg) {

View file

@ -31,7 +31,6 @@
#include "SDL_BApp.h" /* SDL_BApp class definition */
#include "SDL_BeApp.h"
#include "SDL_thread.h"
#include "SDL_timer.h"
#include "SDL_error.h"
@ -40,6 +39,9 @@
#ifdef __cplusplus
extern "C" {
#endif
#include "../../thread/SDL_systhread.h"
/* Flag to tell whether or not the Be application is active or not */
int SDL_BeAppActive = 0;
static SDL_Thread *SDL_AppThread = NULL;
@ -62,7 +64,7 @@ SDL_InitBeApp(void)
{
/* Create the BApplication that handles appserver interaction */
if (SDL_BeAppActive <= 0) {
SDL_AppThread = SDL_CreateThread(StartBeApp, "SDLApplication", NULL);
SDL_AppThread = SDL_CreateThreadInternal(StartBeApp, "SDLApplication", 0, NULL);
if (SDL_AppThread == NULL) {
return SDL_SetError("Couldn't create BApplication thread");
}

View file

@ -126,44 +126,15 @@ main_utf8(int argc, char *argv[])
return SDL_main(argc, argv);
}
/* This is where execution begins [console apps, ansi] */
int
console_ansi_main(int argc, char *argv[])
{
/* !!! FIXME: are these in the system codepage? We need to convert to UTF-8. */
return main_utf8(argc, argv);
}
#if UNICODE
/* This is where execution begins [console apps, unicode] */
int
console_wmain(int argc, wchar_t *wargv[], wchar_t *wenvp)
{
int retval = 0;
char **argv = SDL_stack_alloc(char*, argc);
int i;
for (i = 0; i < argc; ++i) {
argv[i] = WIN_StringToUTF8(wargv[i]);
}
retval = main_utf8(argc, argv);
/* !!! FIXME: we are leaking all the elements of argv we allocated. */
SDL_stack_free(argv);
return retval;
}
#endif
/* This is where execution begins [windowed apps] */
int WINAPI
WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
/* Gets the arguments with GetCommandLine, converts them to argc and argv
and calls main_utf8 */
static int
main_getcmdline()
{
char **argv;
int argc;
char *cmdline;
int retval = 0;
/* Grab the command line */
TCHAR *text = GetCommandLine();
@ -185,15 +156,50 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
}
ParseCommandLine(cmdline, argv);
/* Run the main program */
main_utf8(argc, argv);
retval = main_utf8(argc, argv);
SDL_stack_free(argv);
SDL_free(cmdline);
/* Hush little compiler, don't you cry... */
return 0;
return retval;
}
/* This is where execution begins [console apps, ansi] */
int
console_ansi_main(int argc, char *argv[])
{
return main_getcmdline();
}
#if UNICODE
/* This is where execution begins [console apps, unicode] */
int
console_wmain(int argc, wchar_t *wargv[], wchar_t *wenvp)
{
int retval = 0;
char **argv = SDL_stack_alloc(char*, argc + 1);
int i;
for (i = 0; i < argc; ++i) {
argv[i] = WIN_StringToUTF8(wargv[i]);
}
argv[argc] = NULL;
retval = main_utf8(argc, argv);
/* !!! FIXME: we are leaking all the elements of argv we allocated. */
SDL_stack_free(argv);
return retval;
}
#endif
/* This is where execution begins [windowed apps] */
int WINAPI
WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
{
return main_getcmdline();
}
#endif /* __WIN32__ */

View file

@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,0,4,0
PRODUCTVERSION 2,0,4,0
FILEVERSION 2,0,5,0
PRODUCTVERSION 2,0,5,0
FILEFLAGSMASK 0x3fL
FILEFLAGS 0x0L
FILEOS 0x40004L
@ -23,12 +23,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "\0"
VALUE "FileDescription", "SDL\0"
VALUE "FileVersion", "2, 0, 4, 0\0"
VALUE "FileVersion", "2, 0, 5, 0\0"
VALUE "InternalName", "SDL\0"
VALUE "LegalCopyright", "Copyright © 2016 Sam Lantinga\0"
VALUE "OriginalFilename", "SDL2.dll\0"
VALUE "ProductName", "Simple DirectMedia Layer\0"
VALUE "ProductVersion", "2, 0, 4, 0\0"
VALUE "ProductVersion", "2, 0, 5, 0\0"
END
END
BLOCK "VarFileInfo"

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