mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-14 08:04:40 +00:00
Updates SDL to 2.0.5
This commit is contained in:
parent
00a4a21e3f
commit
1e671bfc7a
274 changed files with 11502 additions and 4656 deletions
|
|
@ -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, ¤t_audio.inputDevices, ¤t_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, ¤t_audio.captureDevicesRemoved);
|
||||
} else {
|
||||
mark_device_removed(handle, current_audio.outputDevices, ¤t_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(¤t_audio.outputDevices, ¤t_audio.outputDeviceCount);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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: */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
849
Engine/lib/sdl/src/audio/coreaudio/SDL_coreaudio.m
Normal file
849
Engine/lib/sdl/src/audio/coreaudio/SDL_coreaudio.m
Normal 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: */
|
||||
|
|
@ -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. */
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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: */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ struct SDL_PrivateAudioData
|
|||
/* Raw mixing buffer */
|
||||
Uint8 *mixbuf;
|
||||
int mixlen;
|
||||
|
||||
const Uint8 *capturebuf;
|
||||
int capturelen;
|
||||
};
|
||||
|
||||
#endif /* _SDL_pulseaudio_h */
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
struct SDL_PrivateAudioData
|
||||
{
|
||||
/* SDL capture state */
|
||||
int iscapture;
|
||||
SDL_bool iscapture;
|
||||
|
||||
/* The audio device handle */
|
||||
int cardno;
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue