mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-05-22 04:38:30 +00:00
Remove _THIS in src/audio/
This commit is contained in:
parent
81ff49f4b5
commit
04e17d4e46
48 changed files with 1352 additions and 1425 deletions
|
@ -27,8 +27,6 @@
|
||||||
#include "../thread/SDL_systhread.h"
|
#include "../thread/SDL_systhread.h"
|
||||||
#include "../SDL_utils_c.h"
|
#include "../SDL_utils_c.h"
|
||||||
|
|
||||||
#define _THIS SDL_AudioDevice *_this
|
|
||||||
|
|
||||||
static SDL_AudioDriver current_audio;
|
static SDL_AudioDriver current_audio;
|
||||||
static SDL_AudioDevice *open_devices[16];
|
static SDL_AudioDevice *open_devices[16];
|
||||||
|
|
||||||
|
@ -137,37 +135,37 @@ static void SDL_AudioDetectDevices_Default(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDL_AudioThreadInit_Default(_THIS)
|
static void SDL_AudioThreadInit_Default(SDL_AudioDevice *_this)
|
||||||
{ /* no-op. */
|
{ /* no-op. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDL_AudioThreadDeinit_Default(_THIS)
|
static void SDL_AudioThreadDeinit_Default(SDL_AudioDevice *_this)
|
||||||
{ /* no-op. */
|
{ /* no-op. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDL_AudioWaitDevice_Default(_THIS)
|
static void SDL_AudioWaitDevice_Default(SDL_AudioDevice *_this)
|
||||||
{ /* no-op. */
|
{ /* no-op. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDL_AudioPlayDevice_Default(_THIS)
|
static void SDL_AudioPlayDevice_Default(SDL_AudioDevice *_this)
|
||||||
{ /* no-op. */
|
{ /* no-op. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *SDL_AudioGetDeviceBuf_Default(_THIS)
|
static Uint8 *SDL_AudioGetDeviceBuf_Default(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int SDL_AudioCaptureFromDevice_Default(_THIS, void *buffer, int buflen)
|
static int SDL_AudioCaptureFromDevice_Default(SDL_AudioDevice *_this, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
return -1; /* just fail immediately. */
|
return -1; /* just fail immediately. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDL_AudioFlushCapture_Default(_THIS)
|
static void SDL_AudioFlushCapture_Default(SDL_AudioDevice *_this)
|
||||||
{ /* no-op. */
|
{ /* no-op. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SDL_AudioCloseDevice_Default(_THIS)
|
static void SDL_AudioCloseDevice_Default(SDL_AudioDevice *_this)
|
||||||
{ /* no-op. */
|
{ /* no-op. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +177,7 @@ static void SDL_AudioFreeDeviceHandle_Default(void *handle)
|
||||||
{ /* no-op. */
|
{ /* no-op. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int SDL_AudioOpenDevice_Default(_THIS, const char *devname)
|
static int SDL_AudioOpenDevice_Default(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
return SDL_Unsupported();
|
return SDL_Unsupported();
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
|
|
||||||
/* The SDL audio driver */
|
/* The SDL audio driver */
|
||||||
typedef struct SDL_AudioDevice SDL_AudioDevice;
|
typedef struct SDL_AudioDevice SDL_AudioDevice;
|
||||||
#define _THIS SDL_AudioDevice *_this
|
|
||||||
|
|
||||||
/* Audio targets should call this as devices are added to the system (such as
|
/* Audio targets should call this as devices are added to the system (such as
|
||||||
a USB headset being plugged in), and should also be called for
|
a USB headset being plugged in), and should also be called for
|
||||||
|
@ -63,17 +62,17 @@ extern void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device);
|
||||||
typedef struct SDL_AudioDriverImpl
|
typedef struct SDL_AudioDriverImpl
|
||||||
{
|
{
|
||||||
void (*DetectDevices)(void);
|
void (*DetectDevices)(void);
|
||||||
int (*OpenDevice)(_THIS, const char *devname);
|
int (*OpenDevice)(SDL_AudioDevice *_this, const char *devname);
|
||||||
void (*ThreadInit)(_THIS); /* Called by audio thread at start */
|
void (*ThreadInit)(SDL_AudioDevice *_this); /* Called by audio thread at start */
|
||||||
void (*ThreadDeinit)(_THIS); /* Called by audio thread at end */
|
void (*ThreadDeinit)(SDL_AudioDevice *_this); /* Called by audio thread at end */
|
||||||
void (*WaitDevice)(_THIS);
|
void (*WaitDevice)(SDL_AudioDevice *_this);
|
||||||
void (*PlayDevice)(_THIS);
|
void (*PlayDevice)(SDL_AudioDevice *_this);
|
||||||
Uint8 *(*GetDeviceBuf)(_THIS);
|
Uint8 *(*GetDeviceBuf)(SDL_AudioDevice *_this);
|
||||||
int (*CaptureFromDevice)(_THIS, void *buffer, int buflen);
|
int (*CaptureFromDevice)(SDL_AudioDevice *_this, void *buffer, int buflen);
|
||||||
void (*FlushCapture)(_THIS);
|
void (*FlushCapture)(SDL_AudioDevice *_this);
|
||||||
void (*CloseDevice)(_THIS);
|
void (*CloseDevice)(SDL_AudioDevice *_this);
|
||||||
void (*LockDevice)(_THIS);
|
void (*LockDevice)(SDL_AudioDevice *_this);
|
||||||
void (*UnlockDevice)(_THIS);
|
void (*UnlockDevice)(SDL_AudioDevice *_this);
|
||||||
void (*FreeDeviceHandle)(void *handle); /**< SDL is done with handle from SDL_AddAudioDevice() */
|
void (*FreeDeviceHandle)(void *handle); /**< SDL is done with handle from SDL_AddAudioDevice() */
|
||||||
void (*Deinitialize)(void);
|
void (*Deinitialize)(void);
|
||||||
int (*GetDefaultAudioInfo)(char **name, SDL_AudioSpec *spec, int iscapture);
|
int (*GetDefaultAudioInfo)(char **name, SDL_AudioSpec *spec, int iscapture);
|
||||||
|
@ -165,7 +164,6 @@ struct SDL_AudioDevice
|
||||||
|
|
||||||
void *handle;
|
void *handle;
|
||||||
};
|
};
|
||||||
#undef _THIS
|
|
||||||
|
|
||||||
typedef struct AudioBootStrap
|
typedef struct AudioBootStrap
|
||||||
{
|
{
|
||||||
|
|
|
@ -65,10 +65,10 @@ void aaudio_errorCallback(AAudioStream *stream, void *userData, aaudio_result_t
|
||||||
|
|
||||||
#define LIB_AAUDIO_SO "libaaudio.so"
|
#define LIB_AAUDIO_SO "libaaudio.so"
|
||||||
|
|
||||||
static int aaudio_OpenDevice(_THIS, const char *devname)
|
static int aaudio_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *private;
|
struct SDL_PrivateAudioData *private;
|
||||||
SDL_bool iscapture = this->iscapture;
|
SDL_bool iscapture = _this->iscapture;
|
||||||
aaudio_result_t res;
|
aaudio_result_t res;
|
||||||
LOGI(__func__);
|
LOGI(__func__);
|
||||||
|
|
||||||
|
@ -79,14 +79,14 @@ static int aaudio_OpenDevice(_THIS, const char *devname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*this->hidden));
|
_this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*_this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
private = this->hidden;
|
private = _this->hidden;
|
||||||
|
|
||||||
ctx.AAudioStreamBuilder_setSampleRate(ctx.builder, this->spec.freq);
|
ctx.AAudioStreamBuilder_setSampleRate(ctx.builder, _this->spec.freq);
|
||||||
ctx.AAudioStreamBuilder_setChannelCount(ctx.builder, this->spec.channels);
|
ctx.AAudioStreamBuilder_setChannelCount(ctx.builder, _this->spec.channels);
|
||||||
if(devname != NULL) {
|
if(devname != NULL) {
|
||||||
int aaudio_device_id = SDL_atoi(devname);
|
int aaudio_device_id = SDL_atoi(devname);
|
||||||
LOGI("Opening device id %d", aaudio_device_id);
|
LOGI("Opening device id %d", aaudio_device_id);
|
||||||
|
@ -98,9 +98,9 @@ static int aaudio_OpenDevice(_THIS, const char *devname)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
aaudio_format_t format = AAUDIO_FORMAT_PCM_FLOAT;
|
aaudio_format_t format = AAUDIO_FORMAT_PCM_FLOAT;
|
||||||
if (this->spec.format == SDL_AUDIO_S16SYS) {
|
if (_this->spec.format == SDL_AUDIO_S16SYS) {
|
||||||
format = AAUDIO_FORMAT_PCM_I16;
|
format = AAUDIO_FORMAT_PCM_I16;
|
||||||
} else if (this->spec.format == SDL_AUDIO_S16SYS) {
|
} else if (_this->spec.format == SDL_AUDIO_S16SYS) {
|
||||||
format = AAUDIO_FORMAT_PCM_FLOAT;
|
format = AAUDIO_FORMAT_PCM_FLOAT;
|
||||||
}
|
}
|
||||||
ctx.AAudioStreamBuilder_setFormat(ctx.builder, format);
|
ctx.AAudioStreamBuilder_setFormat(ctx.builder, format);
|
||||||
|
@ -109,8 +109,8 @@ static int aaudio_OpenDevice(_THIS, const char *devname)
|
||||||
ctx.AAudioStreamBuilder_setErrorCallback(ctx.builder, aaudio_errorCallback, private);
|
ctx.AAudioStreamBuilder_setErrorCallback(ctx.builder, aaudio_errorCallback, private);
|
||||||
|
|
||||||
LOGI("AAudio Try to open %u hz %u bit chan %u %s samples %u",
|
LOGI("AAudio Try to open %u hz %u bit chan %u %s samples %u",
|
||||||
this->spec.freq, SDL_AUDIO_BITSIZE(this->spec.format),
|
_this->spec.freq, SDL_AUDIO_BITSIZE(_this->spec.format),
|
||||||
this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples);
|
_this->spec.channels, (_this->spec.format & 0x1000) ? "BE" : "LE", _this->spec.samples);
|
||||||
|
|
||||||
res = ctx.AAudioStreamBuilder_openStream(ctx.builder, &private->stream);
|
res = ctx.AAudioStreamBuilder_openStream(ctx.builder, &private->stream);
|
||||||
if (res != AAUDIO_OK) {
|
if (res != AAUDIO_OK) {
|
||||||
|
@ -118,34 +118,34 @@ static int aaudio_OpenDevice(_THIS, const char *devname)
|
||||||
return SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
|
return SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
this->spec.freq = ctx.AAudioStream_getSampleRate(private->stream);
|
_this->spec.freq = ctx.AAudioStream_getSampleRate(private->stream);
|
||||||
this->spec.channels = ctx.AAudioStream_getChannelCount(private->stream);
|
_this->spec.channels = ctx.AAudioStream_getChannelCount(private->stream);
|
||||||
{
|
{
|
||||||
aaudio_format_t fmt = ctx.AAudioStream_getFormat(private->stream);
|
aaudio_format_t fmt = ctx.AAudioStream_getFormat(private->stream);
|
||||||
if (fmt == AAUDIO_FORMAT_PCM_I16) {
|
if (fmt == AAUDIO_FORMAT_PCM_I16) {
|
||||||
this->spec.format = SDL_AUDIO_S16SYS;
|
_this->spec.format = SDL_AUDIO_S16SYS;
|
||||||
} else if (fmt == AAUDIO_FORMAT_PCM_FLOAT) {
|
} else if (fmt == AAUDIO_FORMAT_PCM_FLOAT) {
|
||||||
this->spec.format = SDL_AUDIO_F32SYS;
|
_this->spec.format = SDL_AUDIO_F32SYS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("AAudio Try to open %u hz %u bit chan %u %s samples %u",
|
LOGI("AAudio Try to open %u hz %u bit chan %u %s samples %u",
|
||||||
this->spec.freq, SDL_AUDIO_BITSIZE(this->spec.format),
|
_this->spec.freq, SDL_AUDIO_BITSIZE(_this->spec.format),
|
||||||
this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples);
|
_this->spec.channels, (_this->spec.format & 0x1000) ? "BE" : "LE", _this->spec.samples);
|
||||||
|
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
if (!iscapture) {
|
if (!iscapture) {
|
||||||
private->mixlen = this->spec.size;
|
private->mixlen = _this->spec.size;
|
||||||
private->mixbuf = (Uint8 *)SDL_malloc(private->mixlen);
|
private->mixbuf = (Uint8 *)SDL_malloc(private->mixlen);
|
||||||
if (private->mixbuf == NULL) {
|
if (private->mixbuf == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(private->mixbuf, this->spec.silence, this->spec.size);
|
SDL_memset(private->mixbuf, _this->spec.silence, _this->spec.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
private->frame_size = this->spec.channels * (SDL_AUDIO_BITSIZE(this->spec.format) / 8);
|
private->frame_size = _this->spec.channels * (SDL_AUDIO_BITSIZE(_this->spec.format) / 8);
|
||||||
|
|
||||||
res = ctx.AAudioStream_requestStart(private->stream);
|
res = ctx.AAudioStream_requestStart(private->stream);
|
||||||
if (res != AAUDIO_OK) {
|
if (res != AAUDIO_OK) {
|
||||||
|
@ -157,9 +157,9 @@ static int aaudio_OpenDevice(_THIS, const char *devname)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aaudio_CloseDevice(_THIS)
|
static void aaudio_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *private = this->hidden;
|
struct SDL_PrivateAudioData *private = _this->hidden;
|
||||||
aaudio_result_t res;
|
aaudio_result_t res;
|
||||||
LOGI(__func__);
|
LOGI(__func__);
|
||||||
|
|
||||||
|
@ -179,19 +179,19 @@ static void aaudio_CloseDevice(_THIS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_free(this->hidden->mixbuf);
|
SDL_free(_this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(_this->hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *aaudio_GetDeviceBuf(_THIS)
|
static Uint8 *aaudio_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *private = this->hidden;
|
struct SDL_PrivateAudioData *private = _this->hidden;
|
||||||
return private->mixbuf;
|
return private->mixbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aaudio_PlayDevice(_THIS)
|
static void aaudio_PlayDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *private = this->hidden;
|
struct SDL_PrivateAudioData *private = _this->hidden;
|
||||||
aaudio_result_t res;
|
aaudio_result_t res;
|
||||||
int64_t timeoutNanoseconds = 1 * 1000 * 1000; /* 8 ms */
|
int64_t timeoutNanoseconds = 1 * 1000 * 1000; /* 8 ms */
|
||||||
res = ctx.AAudioStream_write(private->stream, private->mixbuf, private->mixlen / private->frame_size, timeoutNanoseconds);
|
res = ctx.AAudioStream_write(private->stream, private->mixbuf, private->mixlen / private->frame_size, timeoutNanoseconds);
|
||||||
|
@ -214,9 +214,9 @@ static void aaudio_PlayDevice(_THIS)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int aaudio_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
static int aaudio_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *private = this->hidden;
|
struct SDL_PrivateAudioData *private = _this->hidden;
|
||||||
aaudio_result_t res;
|
aaudio_result_t res;
|
||||||
int64_t timeoutNanoseconds = 8 * 1000 * 1000; /* 8 ms */
|
int64_t timeoutNanoseconds = 8 * 1000 * 1000; /* 8 ms */
|
||||||
res = ctx.AAudioStream_read(private->stream, buffer, buflen / private->frame_size, timeoutNanoseconds);
|
res = ctx.AAudioStream_read(private->stream, buffer, buflen / private->frame_size, timeoutNanoseconds);
|
||||||
|
@ -328,18 +328,18 @@ void aaudio_PauseDevices(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < get_max_num_audio_dev(); i++) {
|
for (i = 0; i < get_max_num_audio_dev(); i++) {
|
||||||
SDL_AudioDevice *this = get_audio_dev(i);
|
SDL_AudioDevice *_this = get_audio_dev(i);
|
||||||
SDL_AudioDevice *audioDevice = NULL;
|
SDL_AudioDevice *audioDevice = NULL;
|
||||||
SDL_AudioDevice *captureDevice = NULL;
|
SDL_AudioDevice *captureDevice = NULL;
|
||||||
|
|
||||||
if (this == NULL) {
|
if (_this == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->iscapture) {
|
if (_this->iscapture) {
|
||||||
captureDevice = this;
|
captureDevice = _this;
|
||||||
} else {
|
} else {
|
||||||
audioDevice = this;
|
audioDevice = _this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audioDevice != NULL && audioDevice->hidden != NULL) {
|
if (audioDevice != NULL && audioDevice->hidden != NULL) {
|
||||||
|
@ -399,18 +399,18 @@ void aaudio_ResumeDevices(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < get_max_num_audio_dev(); i++) {
|
for (i = 0; i < get_max_num_audio_dev(); i++) {
|
||||||
SDL_AudioDevice *this = get_audio_dev(i);
|
SDL_AudioDevice *_this = get_audio_dev(i);
|
||||||
SDL_AudioDevice *audioDevice = NULL;
|
SDL_AudioDevice *audioDevice = NULL;
|
||||||
SDL_AudioDevice *captureDevice = NULL;
|
SDL_AudioDevice *captureDevice = NULL;
|
||||||
|
|
||||||
if (this == NULL) {
|
if (_this == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->iscapture) {
|
if (_this->iscapture) {
|
||||||
captureDevice = this;
|
captureDevice = _this;
|
||||||
} else {
|
} else {
|
||||||
audioDevice = this;
|
audioDevice = _this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audioDevice != NULL && audioDevice->hidden != NULL) {
|
if (audioDevice != NULL && audioDevice->hidden != NULL) {
|
||||||
|
@ -466,18 +466,18 @@ SDL_bool aaudio_DetectBrokenPlayState(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < get_max_num_audio_dev(); i++) {
|
for (i = 0; i < get_max_num_audio_dev(); i++) {
|
||||||
SDL_AudioDevice *this = get_audio_dev(i);
|
SDL_AudioDevice *_this = get_audio_dev(i);
|
||||||
SDL_AudioDevice *audioDevice = NULL;
|
SDL_AudioDevice *audioDevice = NULL;
|
||||||
SDL_AudioDevice *captureDevice = NULL;
|
SDL_AudioDevice *captureDevice = NULL;
|
||||||
|
|
||||||
if (this == NULL) {
|
if (_this == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->iscapture) {
|
if (_this->iscapture) {
|
||||||
captureDevice = this;
|
captureDevice = _this;
|
||||||
} else {
|
} else {
|
||||||
audioDevice = this;
|
audioDevice = _this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audioDevice != NULL && audioDevice->hidden != NULL) {
|
if (audioDevice != NULL && audioDevice->hidden != NULL) {
|
||||||
|
|
|
@ -27,9 +27,6 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <aaudio/AAudio.h>
|
#include <aaudio/AAudio.h>
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
AAudioStream *stream;
|
AAudioStream *stream;
|
||||||
|
|
|
@ -225,20 +225,20 @@ static const char *get_audio_device(void *handle, const int channels)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function waits until it is possible to write a full sound buffer */
|
/* This function waits until it is possible to write a full sound buffer */
|
||||||
static void ALSA_WaitDevice(_THIS)
|
static void ALSA_WaitDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
#if SDL_ALSA_NON_BLOCKING
|
#if SDL_ALSA_NON_BLOCKING
|
||||||
const snd_pcm_sframes_t needed = (snd_pcm_sframes_t)this->spec.samples;
|
const snd_pcm_sframes_t needed = (snd_pcm_sframes_t)_this->spec.samples;
|
||||||
while (SDL_AtomicGet(&this->enabled)) {
|
while (SDL_AtomicGet(&_this->enabled)) {
|
||||||
const snd_pcm_sframes_t rc = ALSA_snd_pcm_avail(this->hidden->pcm_handle);
|
const snd_pcm_sframes_t rc = ALSA_snd_pcm_avail(_this->hidden->pcm_handle);
|
||||||
if ((rc < 0) && (rc != -EAGAIN)) {
|
if ((rc < 0) && (rc != -EAGAIN)) {
|
||||||
/* Hmm, not much we can do - abort */
|
/* Hmm, not much we can do - abort */
|
||||||
fprintf(stderr, "ALSA snd_pcm_avail failed (unrecoverable): %s\n",
|
fprintf(stderr, "ALSA snd_pcm_avail failed (unrecoverable): %s\n",
|
||||||
ALSA_snd_strerror(rc));
|
ALSA_snd_strerror(rc));
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||||
return;
|
return;
|
||||||
} else if (rc < needed) {
|
} else if (rc < needed) {
|
||||||
const Uint32 delay = ((needed - (SDL_max(rc, 0))) * 1000) / this->spec.freq;
|
const Uint32 delay = ((needed - (SDL_max(rc, 0))) * 1000) / _this->spec.freq;
|
||||||
SDL_Delay(SDL_max(delay, 10));
|
SDL_Delay(SDL_max(delay, 10));
|
||||||
} else {
|
} else {
|
||||||
break; /* ready to go! */
|
break; /* ready to go! */
|
||||||
|
@ -311,15 +311,15 @@ CHANNEL_SWIZZLE(SWIZ8)
|
||||||
#undef SWIZ8
|
#undef SWIZ8
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called right before feeding this->hidden->mixbuf to the hardware. Swizzle
|
* Called right before feeding _this->hidden->mixbuf to the hardware. Swizzle
|
||||||
* channels from Windows/Mac order to the format alsalib will want.
|
* channels from Windows/Mac order to the format alsalib will want.
|
||||||
*/
|
*/
|
||||||
static void swizzle_alsa_channels(_THIS, void *buffer, Uint32 bufferlen)
|
static void swizzle_alsa_channels(SDL_AudioDevice *_this, void *buffer, Uint32 bufferlen)
|
||||||
{
|
{
|
||||||
switch (this->spec.channels) {
|
switch (_this->spec.channels) {
|
||||||
#define CHANSWIZ(chans) \
|
#define CHANSWIZ(chans) \
|
||||||
case chans: \
|
case chans: \
|
||||||
switch ((this->spec.format & (0xFF))) { \
|
switch ((_this->spec.format & (0xFF))) { \
|
||||||
case 8: \
|
case 8: \
|
||||||
swizzle_alsa_channels_##chans##_Uint8(buffer, bufferlen); \
|
swizzle_alsa_channels_##chans##_Uint8(buffer, bufferlen); \
|
||||||
break; \
|
break; \
|
||||||
|
@ -348,22 +348,22 @@ static void swizzle_alsa_channels(_THIS, void *buffer, Uint32 bufferlen)
|
||||||
|
|
||||||
#ifdef SND_CHMAP_API_VERSION
|
#ifdef SND_CHMAP_API_VERSION
|
||||||
/* Some devices have the right channel map, no swizzling necessary */
|
/* Some devices have the right channel map, no swizzling necessary */
|
||||||
static void no_swizzle(_THIS, void *buffer, Uint32 bufferlen)
|
static void no_swizzle(SDL_AudioDevice *_this, void *buffer, Uint32 bufferlen)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif /* SND_CHMAP_API_VERSION */
|
#endif /* SND_CHMAP_API_VERSION */
|
||||||
|
|
||||||
static void ALSA_PlayDevice(_THIS)
|
static void ALSA_PlayDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
const Uint8 *sample_buf = (const Uint8 *)this->hidden->mixbuf;
|
const Uint8 *sample_buf = (const Uint8 *)_this->hidden->mixbuf;
|
||||||
const int frame_size = ((SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
|
const int frame_size = ((SDL_AUDIO_BITSIZE(_this->spec.format)) / 8) *
|
||||||
this->spec.channels;
|
_this->spec.channels;
|
||||||
snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t)this->spec.samples);
|
snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t)_this->spec.samples);
|
||||||
|
|
||||||
this->hidden->swizzle_func(this, this->hidden->mixbuf, frames_left);
|
_this->hidden->swizzle_func(_this, _this->hidden->mixbuf, frames_left);
|
||||||
|
|
||||||
while (frames_left > 0 && SDL_AtomicGet(&this->enabled)) {
|
while (frames_left > 0 && SDL_AtomicGet(&_this->enabled)) {
|
||||||
int status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
|
int status = ALSA_snd_pcm_writei(_this->hidden->pcm_handle,
|
||||||
sample_buf, frames_left);
|
sample_buf, frames_left);
|
||||||
|
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
|
@ -373,20 +373,20 @@ static void ALSA_PlayDevice(_THIS)
|
||||||
SDL_Delay(1);
|
SDL_Delay(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
|
status = ALSA_snd_pcm_recover(_this->hidden->pcm_handle, status, 0);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
/* Hmm, not much we can do - abort */
|
/* Hmm, not much we can do - abort */
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
|
SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
|
||||||
"ALSA write failed (unrecoverable): %s\n",
|
"ALSA write failed (unrecoverable): %s\n",
|
||||||
ALSA_snd_strerror(status));
|
ALSA_snd_strerror(status));
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
} else if (status == 0) {
|
} else if (status == 0) {
|
||||||
/* No frames were written (no available space in pcm device).
|
/* No frames were written (no available space in pcm device).
|
||||||
Allow other threads to catch up. */
|
Allow other threads to catch up. */
|
||||||
Uint32 delay = (frames_left / 2 * 1000) / this->spec.freq;
|
Uint32 delay = (frames_left / 2 * 1000) / _this->spec.freq;
|
||||||
SDL_Delay(delay);
|
SDL_Delay(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,34 +395,34 @@ static void ALSA_PlayDevice(_THIS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *ALSA_GetDeviceBuf(_THIS)
|
static Uint8 *ALSA_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
return this->hidden->mixbuf;
|
return _this->hidden->mixbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ALSA_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
static int ALSA_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
Uint8 *sample_buf = (Uint8 *)buffer;
|
Uint8 *sample_buf = (Uint8 *)buffer;
|
||||||
const int frame_size = ((SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
|
const int frame_size = ((SDL_AUDIO_BITSIZE(_this->spec.format)) / 8) *
|
||||||
this->spec.channels;
|
_this->spec.channels;
|
||||||
const int total_frames = buflen / frame_size;
|
const int total_frames = buflen / frame_size;
|
||||||
snd_pcm_uframes_t frames_left = total_frames;
|
snd_pcm_uframes_t frames_left = total_frames;
|
||||||
snd_pcm_uframes_t wait_time = frame_size / 2;
|
snd_pcm_uframes_t wait_time = frame_size / 2;
|
||||||
|
|
||||||
SDL_assert((buflen % frame_size) == 0);
|
SDL_assert((buflen % frame_size) == 0);
|
||||||
|
|
||||||
while (frames_left > 0 && SDL_AtomicGet(&this->enabled)) {
|
while (frames_left > 0 && SDL_AtomicGet(&_this->enabled)) {
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
status = ALSA_snd_pcm_readi(this->hidden->pcm_handle,
|
status = ALSA_snd_pcm_readi(_this->hidden->pcm_handle,
|
||||||
sample_buf, frames_left);
|
sample_buf, frames_left);
|
||||||
|
|
||||||
if (status == -EAGAIN) {
|
if (status == -EAGAIN) {
|
||||||
ALSA_snd_pcm_wait(this->hidden->pcm_handle, wait_time);
|
ALSA_snd_pcm_wait(_this->hidden->pcm_handle, wait_time);
|
||||||
status = 0;
|
status = 0;
|
||||||
} else if (status < 0) {
|
} else if (status < 0) {
|
||||||
/*printf("ALSA: capture error %d\n", status);*/
|
/*printf("ALSA: capture error %d\n", status);*/
|
||||||
status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0);
|
status = ALSA_snd_pcm_recover(_this->hidden->pcm_handle, status, 0);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
/* Hmm, not much we can do - abort */
|
/* Hmm, not much we can do - abort */
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
|
SDL_LogError(SDL_LOG_CATEGORY_AUDIO,
|
||||||
|
@ -438,32 +438,32 @@ static int ALSA_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
frames_left -= status;
|
frames_left -= status;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->swizzle_func(this, buffer, total_frames - frames_left);
|
_this->hidden->swizzle_func(_this, buffer, total_frames - frames_left);
|
||||||
|
|
||||||
return (total_frames - frames_left) * frame_size;
|
return (total_frames - frames_left) * frame_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ALSA_FlushCapture(_THIS)
|
static void ALSA_FlushCapture(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
ALSA_snd_pcm_reset(this->hidden->pcm_handle);
|
ALSA_snd_pcm_reset(_this->hidden->pcm_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ALSA_CloseDevice(_THIS)
|
static void ALSA_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (this->hidden->pcm_handle) {
|
if (_this->hidden->pcm_handle) {
|
||||||
/* Wait for the submitted audio to drain
|
/* Wait for the submitted audio to drain
|
||||||
ALSA_snd_pcm_drop() can hang, so don't use that.
|
ALSA_snd_pcm_drop() can hang, so don't use that.
|
||||||
*/
|
*/
|
||||||
Uint32 delay = ((this->spec.samples * 1000) / this->spec.freq) * 2;
|
Uint32 delay = ((_this->spec.samples * 1000) / _this->spec.freq) * 2;
|
||||||
SDL_Delay(delay);
|
SDL_Delay(delay);
|
||||||
|
|
||||||
ALSA_snd_pcm_close(this->hidden->pcm_handle);
|
ALSA_snd_pcm_close(_this->hidden->pcm_handle);
|
||||||
}
|
}
|
||||||
SDL_free(this->hidden->mixbuf);
|
SDL_free(_this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(_this->hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params)
|
static int ALSA_set_buffer_size(SDL_AudioDevice *_this, snd_pcm_hw_params_t *params)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
snd_pcm_hw_params_t *hwparams;
|
snd_pcm_hw_params_t *hwparams;
|
||||||
|
@ -475,9 +475,9 @@ static int ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params)
|
||||||
ALSA_snd_pcm_hw_params_copy(hwparams, params);
|
ALSA_snd_pcm_hw_params_copy(hwparams, params);
|
||||||
|
|
||||||
/* Attempt to match the period size to the requested buffer size */
|
/* Attempt to match the period size to the requested buffer size */
|
||||||
persize = this->spec.samples;
|
persize = _this->spec.samples;
|
||||||
status = ALSA_snd_pcm_hw_params_set_period_size_near(
|
status = ALSA_snd_pcm_hw_params_set_period_size_near(
|
||||||
this->hidden->pcm_handle, hwparams, &persize, NULL);
|
_this->hidden->pcm_handle, hwparams, &persize, NULL);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -485,24 +485,24 @@ static int ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params)
|
||||||
/* Need to at least double buffer */
|
/* Need to at least double buffer */
|
||||||
periods = 2;
|
periods = 2;
|
||||||
status = ALSA_snd_pcm_hw_params_set_periods_min(
|
status = ALSA_snd_pcm_hw_params_set_periods_min(
|
||||||
this->hidden->pcm_handle, hwparams, &periods, NULL);
|
_this->hidden->pcm_handle, hwparams, &periods, NULL);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = ALSA_snd_pcm_hw_params_set_periods_first(
|
status = ALSA_snd_pcm_hw_params_set_periods_first(
|
||||||
this->hidden->pcm_handle, hwparams, &periods, NULL);
|
_this->hidden->pcm_handle, hwparams, &periods, NULL);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* "set" the hardware with the desired parameters */
|
/* "set" the hardware with the desired parameters */
|
||||||
status = ALSA_snd_pcm_hw_params(this->hidden->pcm_handle, hwparams);
|
status = ALSA_snd_pcm_hw_params(_this->hidden->pcm_handle, hwparams);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->spec.samples = persize;
|
_this->spec.samples = persize;
|
||||||
|
|
||||||
/* This is useful for debugging */
|
/* This is useful for debugging */
|
||||||
if (SDL_getenv("SDL_AUDIO_ALSA_DEBUG")) {
|
if (SDL_getenv("SDL_AUDIO_ALSA_DEBUG")) {
|
||||||
|
@ -518,10 +518,10 @@ static int ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ALSA_OpenDevice(_THIS, const char *devname)
|
static int ALSA_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
int status = 0;
|
int status = 0;
|
||||||
SDL_bool iscapture = this->iscapture;
|
SDL_bool iscapture = _this->iscapture;
|
||||||
snd_pcm_t *pcm_handle = NULL;
|
snd_pcm_t *pcm_handle = NULL;
|
||||||
snd_pcm_hw_params_t *hwparams = NULL;
|
snd_pcm_hw_params_t *hwparams = NULL;
|
||||||
snd_pcm_sw_params_t *swparams = NULL;
|
snd_pcm_sw_params_t *swparams = NULL;
|
||||||
|
@ -536,16 +536,16 @@ static int ALSA_OpenDevice(_THIS, const char *devname)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Initialize all variables that we clean on shutdown */
|
/* Initialize all variables that we clean on shutdown */
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*this->hidden));
|
_this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*_this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_zerop(this->hidden);
|
SDL_zerop(_this->hidden);
|
||||||
|
|
||||||
/* Open the audio device */
|
/* Open the audio device */
|
||||||
/* Name of device should depend on # channels in spec */
|
/* Name of device should depend on # channels in spec */
|
||||||
status = ALSA_snd_pcm_open(&pcm_handle,
|
status = ALSA_snd_pcm_open(&pcm_handle,
|
||||||
get_audio_device(this->handle, this->spec.channels),
|
get_audio_device(_this->handle, _this->spec.channels),
|
||||||
iscapture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
|
iscapture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
|
||||||
SND_PCM_NONBLOCK);
|
SND_PCM_NONBLOCK);
|
||||||
|
|
||||||
|
@ -553,7 +553,7 @@ static int ALSA_OpenDevice(_THIS, const char *devname)
|
||||||
return SDL_SetError("ALSA: Couldn't open audio device: %s", ALSA_snd_strerror(status));
|
return SDL_SetError("ALSA: Couldn't open audio device: %s", ALSA_snd_strerror(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->pcm_handle = pcm_handle;
|
_this->hidden->pcm_handle = pcm_handle;
|
||||||
|
|
||||||
/* Figure out what the hardware is capable of */
|
/* Figure out what the hardware is capable of */
|
||||||
snd_pcm_hw_params_alloca(&hwparams);
|
snd_pcm_hw_params_alloca(&hwparams);
|
||||||
|
@ -570,7 +570,7 @@ static int ALSA_OpenDevice(_THIS, const char *devname)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try for a closest match on audio format */
|
/* Try for a closest match on audio format */
|
||||||
closefmts = SDL_ClosestAudioFormats(this->spec.format);
|
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
|
||||||
while ((test_format = *(closefmts++)) != 0) {
|
while ((test_format = *(closefmts++)) != 0) {
|
||||||
switch (test_format) {
|
switch (test_format) {
|
||||||
case SDL_AUDIO_U8:
|
case SDL_AUDIO_U8:
|
||||||
|
@ -607,19 +607,19 @@ static int ALSA_OpenDevice(_THIS, const char *devname)
|
||||||
if (!test_format) {
|
if (!test_format) {
|
||||||
return SDL_SetError("%s: Unsupported audio format", "alsa");
|
return SDL_SetError("%s: Unsupported audio format", "alsa");
|
||||||
}
|
}
|
||||||
this->spec.format = test_format;
|
_this->spec.format = test_format;
|
||||||
|
|
||||||
/* Validate number of channels and determine if swizzling is necessary
|
/* Validate number of channels and determine if swizzling is necessary
|
||||||
* Assume original swizzling, until proven otherwise.
|
* Assume original swizzling, until proven otherwise.
|
||||||
*/
|
*/
|
||||||
this->hidden->swizzle_func = swizzle_alsa_channels;
|
_this->hidden->swizzle_func = swizzle_alsa_channels;
|
||||||
#ifdef SND_CHMAP_API_VERSION
|
#ifdef SND_CHMAP_API_VERSION
|
||||||
chmap = ALSA_snd_pcm_get_chmap(pcm_handle);
|
chmap = ALSA_snd_pcm_get_chmap(pcm_handle);
|
||||||
if (chmap) {
|
if (chmap) {
|
||||||
if (ALSA_snd_pcm_chmap_print(chmap, sizeof(chmap_str), chmap_str) > 0) {
|
if (ALSA_snd_pcm_chmap_print(chmap, sizeof(chmap_str), chmap_str) > 0) {
|
||||||
if (SDL_strcmp("FL FR FC LFE RL RR", chmap_str) == 0 ||
|
if (SDL_strcmp("FL FR FC LFE RL RR", chmap_str) == 0 ||
|
||||||
SDL_strcmp("FL FR FC LFE SL SR", chmap_str) == 0) {
|
SDL_strcmp("FL FR FC LFE SL SR", chmap_str) == 0) {
|
||||||
this->hidden->swizzle_func = no_swizzle;
|
_this->hidden->swizzle_func = no_swizzle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(chmap);
|
free(chmap);
|
||||||
|
@ -628,27 +628,27 @@ static int ALSA_OpenDevice(_THIS, const char *devname)
|
||||||
|
|
||||||
/* Set the number of channels */
|
/* Set the number of channels */
|
||||||
status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
|
status = ALSA_snd_pcm_hw_params_set_channels(pcm_handle, hwparams,
|
||||||
this->spec.channels);
|
_this->spec.channels);
|
||||||
channels = this->spec.channels;
|
channels = _this->spec.channels;
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
status = ALSA_snd_pcm_hw_params_get_channels(hwparams, &channels);
|
status = ALSA_snd_pcm_hw_params_get_channels(hwparams, &channels);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
return SDL_SetError("ALSA: Couldn't set audio channels");
|
return SDL_SetError("ALSA: Couldn't set audio channels");
|
||||||
}
|
}
|
||||||
this->spec.channels = channels;
|
_this->spec.channels = channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the audio rate */
|
/* Set the audio rate */
|
||||||
rate = this->spec.freq;
|
rate = _this->spec.freq;
|
||||||
status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
|
status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams,
|
||||||
&rate, NULL);
|
&rate, NULL);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
return SDL_SetError("ALSA: Couldn't set audio frequency: %s", ALSA_snd_strerror(status));
|
return SDL_SetError("ALSA: Couldn't set audio frequency: %s", ALSA_snd_strerror(status));
|
||||||
}
|
}
|
||||||
this->spec.freq = rate;
|
_this->spec.freq = rate;
|
||||||
|
|
||||||
/* Set the buffer size, in samples */
|
/* Set the buffer size, in samples */
|
||||||
status = ALSA_set_buffer_size(this, hwparams);
|
status = ALSA_set_buffer_size(_this, hwparams);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
return SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status));
|
return SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status));
|
||||||
}
|
}
|
||||||
|
@ -659,7 +659,7 @@ static int ALSA_OpenDevice(_THIS, const char *devname)
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
return SDL_SetError("ALSA: Couldn't get software config: %s", ALSA_snd_strerror(status));
|
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);
|
status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, _this->spec.samples);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
return SDL_SetError("Couldn't set minimum available samples: %s", ALSA_snd_strerror(status));
|
return SDL_SetError("Couldn't set minimum available samples: %s", ALSA_snd_strerror(status));
|
||||||
}
|
}
|
||||||
|
@ -674,16 +674,16 @@ static int ALSA_OpenDevice(_THIS, const char *devname)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate the final parameters for this audio specification */
|
/* Calculate the final parameters for this audio specification */
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
if (!iscapture) {
|
if (!iscapture) {
|
||||||
this->hidden->mixlen = this->spec.size;
|
_this->hidden->mixlen = _this->spec.size;
|
||||||
this->hidden->mixbuf = (Uint8 *)SDL_malloc(this->hidden->mixlen);
|
_this->hidden->mixbuf = (Uint8 *)SDL_malloc(_this->hidden->mixlen);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (_this->hidden->mixbuf == NULL) {
|
||||||
return SDL_OutOfMemory();
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !SDL_ALSA_NON_BLOCKING
|
#if !SDL_ALSA_NON_BLOCKING
|
||||||
|
|
|
@ -27,9 +27,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
/* The audio device handle */
|
/* The audio device handle */
|
||||||
|
@ -40,7 +37,7 @@ struct SDL_PrivateAudioData
|
||||||
int mixlen;
|
int mixlen;
|
||||||
|
|
||||||
/* swizzle function */
|
/* swizzle function */
|
||||||
void (*swizzle_func)(_THIS, void *buffer, Uint32 bufferlen);
|
void (*swizzle_func)(SDL_AudioDevice *_this, void *buffer, Uint32 bufferlen);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* SDL_ALSA_audio_h_ */
|
#endif /* SDL_ALSA_audio_h_ */
|
||||||
|
|
|
@ -35,11 +35,11 @@ static SDL_AudioDevice *audioDevice = NULL;
|
||||||
static SDL_AudioDevice *captureDevice = NULL;
|
static SDL_AudioDevice *captureDevice = NULL;
|
||||||
|
|
||||||
|
|
||||||
static int ANDROIDAUDIO_OpenDevice(_THIS, const char *devname)
|
static int ANDROIDAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
SDL_AudioFormat test_format;
|
SDL_AudioFormat test_format;
|
||||||
const SDL_AudioFormat *closefmts;
|
const SDL_AudioFormat *closefmts;
|
||||||
SDL_bool iscapture = this->iscapture;
|
SDL_bool iscapture = _this->iscapture;
|
||||||
|
|
||||||
if (iscapture) {
|
if (iscapture) {
|
||||||
if (captureDevice) {
|
if (captureDevice) {
|
||||||
|
@ -54,22 +54,22 @@ static int ANDROIDAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iscapture) {
|
if (iscapture) {
|
||||||
captureDevice = this;
|
captureDevice = _this;
|
||||||
} else {
|
} else {
|
||||||
audioDevice = this;
|
audioDevice = _this;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*this->hidden));
|
_this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*_this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
closefmts = SDL_ClosestAudioFormats(this->spec.format);
|
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
|
||||||
while ((test_format = *(closefmts++)) != 0) {
|
while ((test_format = *(closefmts++)) != 0) {
|
||||||
if ((test_format == SDL_AUDIO_U8) ||
|
if ((test_format == SDL_AUDIO_U8) ||
|
||||||
(test_format == SDL_AUDIO_S16) ||
|
(test_format == SDL_AUDIO_S16) ||
|
||||||
(test_format == SDL_AUDIO_F32)) {
|
(test_format == SDL_AUDIO_F32)) {
|
||||||
this->spec.format = test_format;
|
_this->spec.format = test_format;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,50 +84,50 @@ static int ANDROIDAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
if (devname != NULL) {
|
if (devname != NULL) {
|
||||||
audio_device_id = SDL_atoi(devname);
|
audio_device_id = SDL_atoi(devname);
|
||||||
}
|
}
|
||||||
if (Android_JNI_OpenAudioDevice(iscapture, audio_device_id, &this->spec) < 0) {
|
if (Android_JNI_OpenAudioDevice(iscapture, audio_device_id, &_this->spec) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ANDROIDAUDIO_PlayDevice(_THIS)
|
static void ANDROIDAUDIO_PlayDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
Android_JNI_WriteAudioBuffer();
|
Android_JNI_WriteAudioBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *ANDROIDAUDIO_GetDeviceBuf(_THIS)
|
static Uint8 *ANDROIDAUDIO_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
return Android_JNI_GetAudioBuffer();
|
return Android_JNI_GetAudioBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ANDROIDAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
static int ANDROIDAUDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
return Android_JNI_CaptureAudioBuffer(buffer, buflen);
|
return Android_JNI_CaptureAudioBuffer(buffer, buflen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ANDROIDAUDIO_FlushCapture(_THIS)
|
static void ANDROIDAUDIO_FlushCapture(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
Android_JNI_FlushCapturedAudio();
|
Android_JNI_FlushCapturedAudio();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ANDROIDAUDIO_CloseDevice(_THIS)
|
static void ANDROIDAUDIO_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
/* At this point SDL_CloseAudioDevice via close_audio_device took care of terminating the audio thread
|
/* 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
|
so it's safe to terminate the Java side buffer and AudioTrack
|
||||||
*/
|
*/
|
||||||
Android_JNI_CloseAudioDevice(this->iscapture);
|
Android_JNI_CloseAudioDevice(_this->iscapture);
|
||||||
if (this->iscapture) {
|
if (_this->iscapture) {
|
||||||
SDL_assert(captureDevice == this);
|
SDL_assert(captureDevice == _this);
|
||||||
captureDevice = NULL;
|
captureDevice = NULL;
|
||||||
} else {
|
} else {
|
||||||
SDL_assert(audioDevice == this);
|
SDL_assert(audioDevice == _this);
|
||||||
audioDevice = NULL;
|
audioDevice = NULL;
|
||||||
}
|
}
|
||||||
SDL_free(this->hidden);
|
SDL_free(_this->hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_bool ANDROIDAUDIO_Init(SDL_AudioDriverImpl *impl)
|
static SDL_bool ANDROIDAUDIO_Init(SDL_AudioDriverImpl *impl)
|
||||||
|
|
|
@ -25,9 +25,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
/* Resume device if it was paused automatically */
|
/* Resume device if it was paused automatically */
|
||||||
|
|
|
@ -47,9 +47,6 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
SDL_Thread *thread;
|
SDL_Thread *thread;
|
||||||
|
|
|
@ -323,18 +323,18 @@ static void resume_audio_devices()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void interruption_begin(_THIS)
|
static void interruption_begin(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (this != NULL && this->hidden->audioQueue != NULL) {
|
if (_this != NULL && _this->hidden->audioQueue != NULL) {
|
||||||
this->hidden->interrupted = SDL_TRUE;
|
_this->hidden->interrupted = SDL_TRUE;
|
||||||
AudioQueuePause(this->hidden->audioQueue);
|
AudioQueuePause(_this->hidden->audioQueue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void interruption_end(_THIS)
|
static void interruption_end(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (this != NULL && this->hidden != NULL && this->hidden->audioQueue != NULL && this->hidden->interrupted && AudioQueueStart(this->hidden->audioQueue, NULL) == AVAudioSessionErrorCodeNone) {
|
if (_this != NULL && _this->hidden != NULL && _this->hidden->audioQueue != NULL && _this->hidden->interrupted && AudioQueueStart(_this->hidden->audioQueue, NULL) == AVAudioSessionErrorCodeNone) {
|
||||||
this->hidden->interrupted = SDL_FALSE;
|
_this->hidden->interrupted = SDL_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,7 +367,7 @@ static void interruption_end(_THIS)
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
static BOOL update_audio_session(_THIS, SDL_bool open, SDL_bool allow_playandrecord)
|
static BOOL update_audio_session(SDL_AudioDevice *_this, SDL_bool open, SDL_bool allow_playandrecord)
|
||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
AVAudioSession *session = [AVAudioSession sharedInstance];
|
AVAudioSession *session = [AVAudioSession sharedInstance];
|
||||||
|
@ -455,7 +455,7 @@ static BOOL update_audio_session(_THIS, SDL_bool open, SDL_bool allow_playandrec
|
||||||
if (![session setActive:YES error:&err]) {
|
if (![session setActive:YES error:&err]) {
|
||||||
if ([err code] == AVAudioSessionErrorCodeResourceNotAvailable &&
|
if ([err code] == AVAudioSessionErrorCodeResourceNotAvailable &&
|
||||||
category == AVAudioSessionCategoryPlayAndRecord) {
|
category == AVAudioSessionCategoryPlayAndRecord) {
|
||||||
return update_audio_session(this, open, SDL_FALSE);
|
return update_audio_session(_this, open, SDL_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *desc = err.description;
|
NSString *desc = err.description;
|
||||||
|
@ -472,7 +472,7 @@ static BOOL update_audio_session(_THIS, SDL_bool open, SDL_bool allow_playandrec
|
||||||
|
|
||||||
if (open) {
|
if (open) {
|
||||||
SDLInterruptionListener *listener = [SDLInterruptionListener new];
|
SDLInterruptionListener *listener = [SDLInterruptionListener new];
|
||||||
listener.device = this;
|
listener.device = _this;
|
||||||
|
|
||||||
[center addObserver:listener
|
[center addObserver:listener
|
||||||
selector:@selector(audioSessionInterruption:)
|
selector:@selector(audioSessionInterruption:)
|
||||||
|
@ -493,10 +493,10 @@ static BOOL update_audio_session(_THIS, SDL_bool open, SDL_bool allow_playandrec
|
||||||
name:UIApplicationWillEnterForegroundNotification
|
name:UIApplicationWillEnterForegroundNotification
|
||||||
object:nil];
|
object:nil];
|
||||||
|
|
||||||
this->hidden->interruption_listener = CFBridgingRetain(listener);
|
_this->hidden->interruption_listener = CFBridgingRetain(listener);
|
||||||
} else {
|
} else {
|
||||||
SDLInterruptionListener *listener = nil;
|
SDLInterruptionListener *listener = nil;
|
||||||
listener = (SDLInterruptionListener *)CFBridgingRelease(this->hidden->interruption_listener);
|
listener = (SDLInterruptionListener *)CFBridgingRelease(_this->hidden->interruption_listener);
|
||||||
[center removeObserver:listener];
|
[center removeObserver:listener];
|
||||||
@synchronized(listener) {
|
@synchronized(listener) {
|
||||||
listener.device = NULL;
|
listener.device = NULL;
|
||||||
|
@ -511,47 +511,47 @@ static BOOL update_audio_session(_THIS, SDL_bool open, SDL_bool allow_playandrec
|
||||||
/* The AudioQueue callback */
|
/* The AudioQueue callback */
|
||||||
static void outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
|
static void outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
|
||||||
{
|
{
|
||||||
SDL_AudioDevice *this = (SDL_AudioDevice *)inUserData;
|
SDL_AudioDevice *_this = (SDL_AudioDevice *)inUserData;
|
||||||
|
|
||||||
/* This flag is set before this->mixer_lock is destroyed during
|
/* This flag is set before _this->mixer_lock is destroyed during
|
||||||
shutdown, so check it before grabbing the mutex, and then check it
|
shutdown, so check it before grabbing the mutex, and then check it
|
||||||
again _after_ in case we blocked waiting on the lock. */
|
again _after_ in case we blocked waiting on the lock. */
|
||||||
if (SDL_AtomicGet(&this->shutdown)) {
|
if (SDL_AtomicGet(&_this->shutdown)) {
|
||||||
return; /* don't do anything, since we don't even want to enqueue this buffer again. */
|
return; /* don't do anything, since we don't even want to enqueue this buffer again. */
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_LockMutex(this->mixer_lock);
|
SDL_LockMutex(_this->mixer_lock);
|
||||||
|
|
||||||
if (SDL_AtomicGet(&this->shutdown)) {
|
if (SDL_AtomicGet(&_this->shutdown)) {
|
||||||
SDL_UnlockMutex(this->mixer_lock);
|
SDL_UnlockMutex(_this->mixer_lock);
|
||||||
return; /* don't do anything, since we don't even want to enqueue this buffer again. */
|
return; /* don't do anything, since we don't even want to enqueue this buffer again. */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
|
if (!SDL_AtomicGet(&_this->enabled) || SDL_AtomicGet(&_this->paused)) {
|
||||||
/* Supply silence if audio is not enabled or paused */
|
/* Supply silence if audio is not enabled or paused */
|
||||||
SDL_memset(inBuffer->mAudioData, this->spec.silence, inBuffer->mAudioDataBytesCapacity);
|
SDL_memset(inBuffer->mAudioData, _this->spec.silence, inBuffer->mAudioDataBytesCapacity);
|
||||||
} else if (this->stream) {
|
} else if (_this->stream) {
|
||||||
UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
|
UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
|
||||||
Uint8 *ptr = (Uint8 *)inBuffer->mAudioData;
|
Uint8 *ptr = (Uint8 *)inBuffer->mAudioData;
|
||||||
|
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
if (SDL_GetAudioStreamAvailable(this->stream) == 0) {
|
if (SDL_GetAudioStreamAvailable(_this->stream) == 0) {
|
||||||
/* Generate the data */
|
/* Generate the data */
|
||||||
(*this->callbackspec.callback)(this->callbackspec.userdata,
|
(*_this->callbackspec.callback)(_this->callbackspec.userdata,
|
||||||
this->hidden->buffer, this->hidden->bufferSize);
|
_this->hidden->buffer, _this->hidden->bufferSize);
|
||||||
this->hidden->bufferOffset = 0;
|
_this->hidden->bufferOffset = 0;
|
||||||
SDL_PutAudioStreamData(this->stream, this->hidden->buffer, this->hidden->bufferSize);
|
SDL_PutAudioStreamData(_this->stream, _this->hidden->buffer, _this->hidden->bufferSize);
|
||||||
}
|
}
|
||||||
if (SDL_GetAudioStreamAvailable(this->stream) > 0) {
|
if (SDL_GetAudioStreamAvailable(_this->stream) > 0) {
|
||||||
int got;
|
int got;
|
||||||
UInt32 len = SDL_GetAudioStreamAvailable(this->stream);
|
UInt32 len = SDL_GetAudioStreamAvailable(_this->stream);
|
||||||
if (len > remaining) {
|
if (len > remaining) {
|
||||||
len = remaining;
|
len = remaining;
|
||||||
}
|
}
|
||||||
got = SDL_GetAudioStreamData(this->stream, ptr, len);
|
got = SDL_GetAudioStreamData(_this->stream, ptr, len);
|
||||||
SDL_assert((got < 0) || (got == len));
|
SDL_assert((got < 0) || (got == len));
|
||||||
if (got != len) {
|
if (got != len) {
|
||||||
SDL_memset(ptr, this->spec.silence, len);
|
SDL_memset(ptr, _this->spec.silence, len);
|
||||||
}
|
}
|
||||||
ptr = ptr + len;
|
ptr = ptr + len;
|
||||||
remaining -= len;
|
remaining -= len;
|
||||||
|
@ -563,66 +563,66 @@ static void outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBuffe
|
||||||
|
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
UInt32 len;
|
UInt32 len;
|
||||||
if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
|
if (_this->hidden->bufferOffset >= _this->hidden->bufferSize) {
|
||||||
/* Generate the data */
|
/* Generate the data */
|
||||||
(*this->callbackspec.callback)(this->callbackspec.userdata,
|
(*_this->callbackspec.callback)(_this->callbackspec.userdata,
|
||||||
this->hidden->buffer, this->hidden->bufferSize);
|
_this->hidden->buffer, _this->hidden->bufferSize);
|
||||||
this->hidden->bufferOffset = 0;
|
_this->hidden->bufferOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = this->hidden->bufferSize - this->hidden->bufferOffset;
|
len = _this->hidden->bufferSize - _this->hidden->bufferOffset;
|
||||||
if (len > remaining) {
|
if (len > remaining) {
|
||||||
len = remaining;
|
len = remaining;
|
||||||
}
|
}
|
||||||
SDL_memcpy(ptr, (char *)this->hidden->buffer + this->hidden->bufferOffset, len);
|
SDL_memcpy(ptr, (char *)_this->hidden->buffer + _this->hidden->bufferOffset, len);
|
||||||
ptr = ptr + len;
|
ptr = ptr + len;
|
||||||
remaining -= len;
|
remaining -= len;
|
||||||
this->hidden->bufferOffset += len;
|
_this->hidden->bufferOffset += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
|
AudioQueueEnqueueBuffer(_this->hidden->audioQueue, inBuffer, 0, NULL);
|
||||||
|
|
||||||
inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity;
|
inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity;
|
||||||
|
|
||||||
SDL_UnlockMutex(this->mixer_lock);
|
SDL_UnlockMutex(_this->mixer_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer,
|
static void inputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer,
|
||||||
const AudioTimeStamp *inStartTime, UInt32 inNumberPacketDescriptions,
|
const AudioTimeStamp *inStartTime, UInt32 inNumberPacketDescriptions,
|
||||||
const AudioStreamPacketDescription *inPacketDescs)
|
const AudioStreamPacketDescription *inPacketDescs)
|
||||||
{
|
{
|
||||||
SDL_AudioDevice *this = (SDL_AudioDevice *)inUserData;
|
SDL_AudioDevice *_this = (SDL_AudioDevice *)inUserData;
|
||||||
|
|
||||||
if (SDL_AtomicGet(&this->shutdown)) {
|
if (SDL_AtomicGet(&_this->shutdown)) {
|
||||||
return; /* don't do anything. */
|
return; /* don't do anything. */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ignore unless we're active. */
|
/* ignore unless we're active. */
|
||||||
if (!SDL_AtomicGet(&this->paused) && SDL_AtomicGet(&this->enabled)) {
|
if (!SDL_AtomicGet(&_this->paused) && SDL_AtomicGet(&_this->enabled)) {
|
||||||
const Uint8 *ptr = (const Uint8 *)inBuffer->mAudioData;
|
const Uint8 *ptr = (const Uint8 *)inBuffer->mAudioData;
|
||||||
UInt32 remaining = inBuffer->mAudioDataByteSize;
|
UInt32 remaining = inBuffer->mAudioDataByteSize;
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
UInt32 len = this->hidden->bufferSize - this->hidden->bufferOffset;
|
UInt32 len = _this->hidden->bufferSize - _this->hidden->bufferOffset;
|
||||||
if (len > remaining) {
|
if (len > remaining) {
|
||||||
len = remaining;
|
len = remaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_memcpy((char *)this->hidden->buffer + this->hidden->bufferOffset, ptr, len);
|
SDL_memcpy((char *)_this->hidden->buffer + _this->hidden->bufferOffset, ptr, len);
|
||||||
ptr += len;
|
ptr += len;
|
||||||
remaining -= len;
|
remaining -= len;
|
||||||
this->hidden->bufferOffset += len;
|
_this->hidden->bufferOffset += len;
|
||||||
|
|
||||||
if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
|
if (_this->hidden->bufferOffset >= _this->hidden->bufferSize) {
|
||||||
SDL_LockMutex(this->mixer_lock);
|
SDL_LockMutex(_this->mixer_lock);
|
||||||
(*this->callbackspec.callback)(this->callbackspec.userdata, this->hidden->buffer, this->hidden->bufferSize);
|
(*_this->callbackspec.callback)(_this->callbackspec.userdata, _this->hidden->buffer, _this->hidden->bufferSize);
|
||||||
SDL_UnlockMutex(this->mixer_lock);
|
SDL_UnlockMutex(_this->mixer_lock);
|
||||||
this->hidden->bufferOffset = 0;
|
_this->hidden->bufferOffset = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
|
AudioQueueEnqueueBuffer(_this->hidden->audioQueue, inBuffer, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MACOSX_COREAUDIO
|
#ifdef MACOSX_COREAUDIO
|
||||||
|
@ -634,17 +634,17 @@ static const AudioObjectPropertyAddress alive_address = {
|
||||||
|
|
||||||
static OSStatus device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
|
static OSStatus device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
|
||||||
{
|
{
|
||||||
SDL_AudioDevice *this = (SDL_AudioDevice *)data;
|
SDL_AudioDevice *_this = (SDL_AudioDevice *)data;
|
||||||
SDL_bool dead = SDL_FALSE;
|
SDL_bool dead = SDL_FALSE;
|
||||||
UInt32 isAlive = 1;
|
UInt32 isAlive = 1;
|
||||||
UInt32 size = sizeof(isAlive);
|
UInt32 size = sizeof(isAlive);
|
||||||
OSStatus error;
|
OSStatus error;
|
||||||
|
|
||||||
if (!SDL_AtomicGet(&this->enabled)) {
|
if (!SDL_AtomicGet(&_this->enabled)) {
|
||||||
return 0; /* already known to be dead. */
|
return 0; /* already known to be dead. */
|
||||||
}
|
}
|
||||||
|
|
||||||
error = AudioObjectGetPropertyData(this->hidden->deviceID, &alive_address,
|
error = AudioObjectGetPropertyData(_this->hidden->deviceID, &alive_address,
|
||||||
0, NULL, &size, &isAlive);
|
0, NULL, &size, &isAlive);
|
||||||
|
|
||||||
if (error == kAudioHardwareBadDeviceError) {
|
if (error == kAudioHardwareBadDeviceError) {
|
||||||
|
@ -654,7 +654,7 @@ static OSStatus device_unplugged(AudioObjectID devid, UInt32 num_addr, const Aud
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dead) {
|
if (dead) {
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -663,41 +663,41 @@ static OSStatus device_unplugged(AudioObjectID devid, UInt32 num_addr, const Aud
|
||||||
/* macOS calls this when the default device changed (if we have a default device open). */
|
/* macOS calls this when the default device changed (if we have a default device open). */
|
||||||
static OSStatus default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inUserData)
|
static OSStatus default_device_changed(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inUserData)
|
||||||
{
|
{
|
||||||
SDL_AudioDevice *this = (SDL_AudioDevice *)inUserData;
|
SDL_AudioDevice *_this = (SDL_AudioDevice *)inUserData;
|
||||||
#if DEBUG_COREAUDIO
|
#if DEBUG_COREAUDIO
|
||||||
printf("COREAUDIO: default device changed for SDL audio device %p!\n", this);
|
printf("COREAUDIO: default device changed for SDL audio device %p!\n", _this);
|
||||||
#endif
|
#endif
|
||||||
SDL_AtomicSet(&this->hidden->device_change_flag, 1); /* let the audioqueue thread pick up on this when safe to do so. */
|
SDL_AtomicSet(&_this->hidden->device_change_flag, 1); /* let the audioqueue thread pick up on this when safe to do so. */
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void COREAUDIO_CloseDevice(_THIS)
|
static void COREAUDIO_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
const SDL_bool iscapture = this->iscapture;
|
const SDL_bool iscapture = _this->iscapture;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */
|
/* !!! 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?) */
|
/* !!! FIXME: (we only do a "default" device on iOS right now...can we do more?) */
|
||||||
#ifdef MACOSX_COREAUDIO
|
#ifdef MACOSX_COREAUDIO
|
||||||
if (this->handle != NULL) { /* we don't register this listener for default devices. */
|
if (_this->handle != NULL) { /* we don't register this listener for default devices. */
|
||||||
AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
|
AudioObjectRemovePropertyListener(_this->hidden->deviceID, &alive_address, device_unplugged, _this);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* if callback fires again, feed silence; don't call into the app. */
|
/* if callback fires again, feed silence; don't call into the app. */
|
||||||
SDL_AtomicSet(&this->paused, 1);
|
SDL_AtomicSet(&_this->paused, 1);
|
||||||
|
|
||||||
/* dispose of the audio queue before waiting on the thread, or it might stall for a long time! */
|
/* dispose of the audio queue before waiting on the thread, or it might stall for a long time! */
|
||||||
if (this->hidden->audioQueue) {
|
if (_this->hidden->audioQueue) {
|
||||||
AudioQueueFlush(this->hidden->audioQueue);
|
AudioQueueFlush(_this->hidden->audioQueue);
|
||||||
AudioQueueStop(this->hidden->audioQueue, 0);
|
AudioQueueStop(_this->hidden->audioQueue, 0);
|
||||||
AudioQueueDispose(this->hidden->audioQueue, 0);
|
AudioQueueDispose(_this->hidden->audioQueue, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->thread) {
|
if (_this->hidden->thread) {
|
||||||
SDL_assert(SDL_AtomicGet(&this->shutdown) != 0); /* should have been set by SDL_audio.c */
|
SDL_assert(SDL_AtomicGet(&_this->shutdown) != 0); /* should have been set by SDL_audio.c */
|
||||||
SDL_WaitThread(this->hidden->thread, NULL);
|
SDL_WaitThread(_this->hidden->thread, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iscapture) {
|
if (iscapture) {
|
||||||
|
@ -707,11 +707,11 @@ static void COREAUDIO_CloseDevice(_THIS)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef MACOSX_COREAUDIO
|
#ifndef MACOSX_COREAUDIO
|
||||||
update_audio_session(this, SDL_FALSE, SDL_TRUE);
|
update_audio_session(_this, SDL_FALSE, SDL_TRUE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (i = 0; i < num_open_devices; ++i) {
|
for (i = 0; i < num_open_devices; ++i) {
|
||||||
if (open_devices[i] == this) {
|
if (open_devices[i] == _this) {
|
||||||
--num_open_devices;
|
--num_open_devices;
|
||||||
if (i < num_open_devices) {
|
if (i < num_open_devices) {
|
||||||
SDL_memmove(&open_devices[i], &open_devices[i + 1], sizeof(open_devices[i]) * (num_open_devices - i));
|
SDL_memmove(&open_devices[i], &open_devices[i + 1], sizeof(open_devices[i]) * (num_open_devices - i));
|
||||||
|
@ -724,22 +724,22 @@ static void COREAUDIO_CloseDevice(_THIS)
|
||||||
open_devices = NULL;
|
open_devices = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->ready_semaphore) {
|
if (_this->hidden->ready_semaphore) {
|
||||||
SDL_DestroySemaphore(this->hidden->ready_semaphore);
|
SDL_DestroySemaphore(_this->hidden->ready_semaphore);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* AudioQueueDispose() frees the actual buffer objects. */
|
/* AudioQueueDispose() frees the actual buffer objects. */
|
||||||
SDL_free(this->hidden->audioBuffer);
|
SDL_free(_this->hidden->audioBuffer);
|
||||||
SDL_free(this->hidden->thread_error);
|
SDL_free(_this->hidden->thread_error);
|
||||||
SDL_free(this->hidden->buffer);
|
SDL_free(_this->hidden->buffer);
|
||||||
SDL_free(this->hidden);
|
SDL_free(_this->hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MACOSX_COREAUDIO
|
#ifdef MACOSX_COREAUDIO
|
||||||
static int prepare_device(_THIS)
|
static int prepare_device(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
void *handle = this->handle;
|
void *handle = _this->handle;
|
||||||
SDL_bool iscapture = this->iscapture;
|
SDL_bool iscapture = _this->iscapture;
|
||||||
AudioDeviceID devid = (AudioDeviceID)((size_t)handle);
|
AudioDeviceID devid = (AudioDeviceID)((size_t)handle);
|
||||||
OSStatus result = noErr;
|
OSStatus result = noErr;
|
||||||
UInt32 size = 0;
|
UInt32 size = 0;
|
||||||
|
@ -783,73 +783,73 @@ static int prepare_device(_THIS)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->deviceID = devid;
|
_this->hidden->deviceID = devid;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int assign_device_to_audioqueue(_THIS)
|
static int assign_device_to_audioqueue(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
const AudioObjectPropertyAddress prop = {
|
const AudioObjectPropertyAddress prop = {
|
||||||
kAudioDevicePropertyDeviceUID,
|
kAudioDevicePropertyDeviceUID,
|
||||||
this->iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
_this->iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
|
||||||
kAudioObjectPropertyElementMain
|
kAudioObjectPropertyElementMain
|
||||||
};
|
};
|
||||||
|
|
||||||
OSStatus result;
|
OSStatus result;
|
||||||
CFStringRef devuid;
|
CFStringRef devuid;
|
||||||
UInt32 devuidsize = sizeof(devuid);
|
UInt32 devuidsize = sizeof(devuid);
|
||||||
result = AudioObjectGetPropertyData(this->hidden->deviceID, &prop, 0, NULL, &devuidsize, &devuid);
|
result = AudioObjectGetPropertyData(_this->hidden->deviceID, &prop, 0, NULL, &devuidsize, &devuid);
|
||||||
CHECK_RESULT("AudioObjectGetPropertyData (kAudioDevicePropertyDeviceUID)");
|
CHECK_RESULT("AudioObjectGetPropertyData (kAudioDevicePropertyDeviceUID)");
|
||||||
result = AudioQueueSetProperty(this->hidden->audioQueue, kAudioQueueProperty_CurrentDevice, &devuid, devuidsize);
|
result = AudioQueueSetProperty(_this->hidden->audioQueue, kAudioQueueProperty_CurrentDevice, &devuid, devuidsize);
|
||||||
CHECK_RESULT("AudioQueueSetProperty (kAudioQueueProperty_CurrentDevice)");
|
CHECK_RESULT("AudioQueueSetProperty (kAudioQueueProperty_CurrentDevice)");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int prepare_audioqueue(_THIS)
|
static int prepare_audioqueue(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
const AudioStreamBasicDescription *strdesc = &this->hidden->strdesc;
|
const AudioStreamBasicDescription *strdesc = &_this->hidden->strdesc;
|
||||||
const int iscapture = this->iscapture;
|
const int iscapture = _this->iscapture;
|
||||||
OSStatus result;
|
OSStatus result;
|
||||||
int i, numAudioBuffers = 2;
|
int i, numAudioBuffers = 2;
|
||||||
AudioChannelLayout layout;
|
AudioChannelLayout layout;
|
||||||
double MINIMUM_AUDIO_BUFFER_TIME_MS;
|
double MINIMUM_AUDIO_BUFFER_TIME_MS;
|
||||||
const double msecs = (this->spec.samples / ((double)this->spec.freq)) * 1000.0;
|
const double msecs = (_this->spec.samples / ((double)_this->spec.freq)) * 1000.0;
|
||||||
;
|
;
|
||||||
|
|
||||||
SDL_assert(CFRunLoopGetCurrent() != NULL);
|
SDL_assert(CFRunLoopGetCurrent() != NULL);
|
||||||
|
|
||||||
if (iscapture) {
|
if (iscapture) {
|
||||||
result = AudioQueueNewInput(strdesc, inputCallback, this, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &this->hidden->audioQueue);
|
result = AudioQueueNewInput(strdesc, inputCallback, _this, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &_this->hidden->audioQueue);
|
||||||
CHECK_RESULT("AudioQueueNewInput");
|
CHECK_RESULT("AudioQueueNewInput");
|
||||||
} else {
|
} else {
|
||||||
result = AudioQueueNewOutput(strdesc, outputCallback, this, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &this->hidden->audioQueue);
|
result = AudioQueueNewOutput(strdesc, outputCallback, _this, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &_this->hidden->audioQueue);
|
||||||
CHECK_RESULT("AudioQueueNewOutput");
|
CHECK_RESULT("AudioQueueNewOutput");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MACOSX_COREAUDIO
|
#ifdef MACOSX_COREAUDIO
|
||||||
if (!assign_device_to_audioqueue(this)) {
|
if (!assign_device_to_audioqueue(_this)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* only listen for unplugging on specific devices, not the default device, as that should
|
/* only listen for unplugging on specific devices, not the default device, as that should
|
||||||
switch to a different device (or hang out silently if there _is_ no other device). */
|
switch to a different device (or hang out silently if there _is_ no other device). */
|
||||||
if (this->handle != NULL) {
|
if (_this->handle != NULL) {
|
||||||
/* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */
|
/* !!! 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?) */
|
/* !!! 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). */
|
/* Fire a callback if the device stops being "alive" (disconnected, etc). */
|
||||||
/* If this fails, oh well, we won't notice a device had an extraordinary event take place. */
|
/* If this fails, oh well, we won't notice a device had an extraordinary event take place. */
|
||||||
AudioObjectAddPropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this);
|
AudioObjectAddPropertyListener(_this->hidden->deviceID, &alive_address, device_unplugged, _this);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Calculate the final parameters for this audio specification */
|
/* Calculate the final parameters for this audio specification */
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
/* Set the channel layout for the audio queue */
|
/* Set the channel layout for the audio queue */
|
||||||
SDL_zero(layout);
|
SDL_zero(layout);
|
||||||
switch (this->spec.channels) {
|
switch (_this->spec.channels) {
|
||||||
case 1:
|
case 1:
|
||||||
layout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
|
layout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
|
||||||
break;
|
break;
|
||||||
|
@ -877,16 +877,16 @@ static int prepare_audioqueue(_THIS)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (layout.mChannelLayoutTag != 0) {
|
if (layout.mChannelLayoutTag != 0) {
|
||||||
result = AudioQueueSetProperty(this->hidden->audioQueue, kAudioQueueProperty_ChannelLayout, &layout, sizeof(layout));
|
result = AudioQueueSetProperty(_this->hidden->audioQueue, kAudioQueueProperty_ChannelLayout, &layout, sizeof(layout));
|
||||||
CHECK_RESULT("AudioQueueSetProperty(kAudioQueueProperty_ChannelLayout)");
|
CHECK_RESULT("AudioQueueSetProperty(kAudioQueueProperty_ChannelLayout)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate a sample buffer */
|
/* Allocate a sample buffer */
|
||||||
this->hidden->bufferSize = this->spec.size;
|
_this->hidden->bufferSize = _this->spec.size;
|
||||||
this->hidden->bufferOffset = iscapture ? 0 : this->hidden->bufferSize;
|
_this->hidden->bufferOffset = iscapture ? 0 : _this->hidden->bufferSize;
|
||||||
|
|
||||||
this->hidden->buffer = SDL_malloc(this->hidden->bufferSize);
|
_this->hidden->buffer = SDL_malloc(_this->hidden->bufferSize);
|
||||||
if (this->hidden->buffer == NULL) {
|
if (_this->hidden->buffer == NULL) {
|
||||||
SDL_OutOfMemory();
|
SDL_OutOfMemory();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -903,9 +903,9 @@ static int prepare_audioqueue(_THIS)
|
||||||
numAudioBuffers = ((int)SDL_ceil(MINIMUM_AUDIO_BUFFER_TIME_MS / msecs) * 2);
|
numAudioBuffers = ((int)SDL_ceil(MINIMUM_AUDIO_BUFFER_TIME_MS / msecs) * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->numAudioBuffers = numAudioBuffers;
|
_this->hidden->numAudioBuffers = numAudioBuffers;
|
||||||
this->hidden->audioBuffer = SDL_calloc(1, sizeof(AudioQueueBufferRef) * numAudioBuffers);
|
_this->hidden->audioBuffer = SDL_calloc(1, sizeof(AudioQueueBufferRef) * numAudioBuffers);
|
||||||
if (this->hidden->audioBuffer == NULL) {
|
if (_this->hidden->audioBuffer == NULL) {
|
||||||
SDL_OutOfMemory();
|
SDL_OutOfMemory();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -915,16 +915,16 @@ static int prepare_audioqueue(_THIS)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (i = 0; i < numAudioBuffers; i++) {
|
for (i = 0; i < numAudioBuffers; i++) {
|
||||||
result = AudioQueueAllocateBuffer(this->hidden->audioQueue, this->spec.size, &this->hidden->audioBuffer[i]);
|
result = AudioQueueAllocateBuffer(_this->hidden->audioQueue, _this->spec.size, &_this->hidden->audioBuffer[i]);
|
||||||
CHECK_RESULT("AudioQueueAllocateBuffer");
|
CHECK_RESULT("AudioQueueAllocateBuffer");
|
||||||
SDL_memset(this->hidden->audioBuffer[i]->mAudioData, this->spec.silence, this->hidden->audioBuffer[i]->mAudioDataBytesCapacity);
|
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;
|
_this->hidden->audioBuffer[i]->mAudioDataByteSize = _this->hidden->audioBuffer[i]->mAudioDataBytesCapacity;
|
||||||
/* !!! FIXME: should we use AudioQueueEnqueueBufferWithParameters and specify all frames be "trimmed" so these are immediately ready to refill with SDL callback data? */
|
/* !!! FIXME: should we use AudioQueueEnqueueBufferWithParameters and specify all frames be "trimmed" so these are immediately ready to refill with SDL callback data? */
|
||||||
result = AudioQueueEnqueueBuffer(this->hidden->audioQueue, this->hidden->audioBuffer[i], 0, NULL);
|
result = AudioQueueEnqueueBuffer(_this->hidden->audioQueue, _this->hidden->audioBuffer[i], 0, NULL);
|
||||||
CHECK_RESULT("AudioQueueEnqueueBuffer");
|
CHECK_RESULT("AudioQueueEnqueueBuffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
result = AudioQueueStart(this->hidden->audioQueue, NULL);
|
result = AudioQueueStart(_this->hidden->audioQueue, NULL);
|
||||||
CHECK_RESULT("AudioQueueStart");
|
CHECK_RESULT("AudioQueueStart");
|
||||||
|
|
||||||
/* We're running! */
|
/* We're running! */
|
||||||
|
@ -933,41 +933,41 @@ static int prepare_audioqueue(_THIS)
|
||||||
|
|
||||||
static int audioqueue_thread(void *arg)
|
static int audioqueue_thread(void *arg)
|
||||||
{
|
{
|
||||||
SDL_AudioDevice *this = (SDL_AudioDevice *)arg;
|
SDL_AudioDevice *_this = (SDL_AudioDevice *)arg;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
#ifdef MACOSX_COREAUDIO
|
#ifdef MACOSX_COREAUDIO
|
||||||
const AudioObjectPropertyAddress default_device_address = {
|
const AudioObjectPropertyAddress default_device_address = {
|
||||||
this->iscapture ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice,
|
_this->iscapture ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice,
|
||||||
kAudioObjectPropertyScopeGlobal,
|
kAudioObjectPropertyScopeGlobal,
|
||||||
kAudioObjectPropertyElementMain
|
kAudioObjectPropertyElementMain
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this->handle == NULL) { /* opened the default device? Register to know if the user picks a new default. */
|
if (_this->handle == NULL) { /* opened the default device? Register to know if the user picks a new default. */
|
||||||
/* we don't care if this fails; we just won't change to new default devices, but we still otherwise function in this case. */
|
/* we don't care if this fails; we just won't change to new default devices, but we still otherwise function in this case. */
|
||||||
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &default_device_address, default_device_changed, this);
|
AudioObjectAddPropertyListener(kAudioObjectSystemObject, &default_device_address, default_device_changed, _this);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
rc = prepare_audioqueue(this);
|
rc = prepare_audioqueue(_this);
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
this->hidden->thread_error = SDL_strdup(SDL_GetError());
|
_this->hidden->thread_error = SDL_strdup(SDL_GetError());
|
||||||
SDL_PostSemaphore(this->hidden->ready_semaphore);
|
SDL_PostSemaphore(_this->hidden->ready_semaphore);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
|
SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
|
||||||
|
|
||||||
/* init was successful, alert parent thread and start running... */
|
/* init was successful, alert parent thread and start running... */
|
||||||
SDL_PostSemaphore(this->hidden->ready_semaphore);
|
SDL_PostSemaphore(_this->hidden->ready_semaphore);
|
||||||
|
|
||||||
while (!SDL_AtomicGet(&this->shutdown)) {
|
while (!SDL_AtomicGet(&_this->shutdown)) {
|
||||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
|
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
|
||||||
|
|
||||||
#ifdef MACOSX_COREAUDIO
|
#ifdef MACOSX_COREAUDIO
|
||||||
if ((this->handle == NULL) && SDL_AtomicGet(&this->hidden->device_change_flag)) {
|
if ((_this->handle == NULL) && SDL_AtomicGet(&_this->hidden->device_change_flag)) {
|
||||||
const AudioDeviceID prev_devid = this->hidden->deviceID;
|
const AudioDeviceID prev_devid = _this->hidden->deviceID;
|
||||||
SDL_AtomicSet(&this->hidden->device_change_flag, 0);
|
SDL_AtomicSet(&_this->hidden->device_change_flag, 0);
|
||||||
|
|
||||||
#if DEBUG_COREAUDIO
|
#if DEBUG_COREAUDIO
|
||||||
printf("COREAUDIO: audioqueue_thread is trying to switch to new default device!\n");
|
printf("COREAUDIO: audioqueue_thread is trying to switch to new default device!\n");
|
||||||
|
@ -976,53 +976,53 @@ static int audioqueue_thread(void *arg)
|
||||||
/* if any of this fails, there's not much to do but wait to see if the user gives up
|
/* if any of this fails, there's not much to do but wait to see if the user gives up
|
||||||
and quits (flagging the audioqueue for shutdown), or toggles to some other system
|
and quits (flagging the audioqueue for shutdown), or toggles to some other system
|
||||||
output device (in which case we'll try again). */
|
output device (in which case we'll try again). */
|
||||||
if (prepare_device(this) && (prev_devid != this->hidden->deviceID)) {
|
if (prepare_device(_this) && (prev_devid != _this->hidden->deviceID)) {
|
||||||
AudioQueueStop(this->hidden->audioQueue, 1);
|
AudioQueueStop(_this->hidden->audioQueue, 1);
|
||||||
if (assign_device_to_audioqueue(this)) {
|
if (assign_device_to_audioqueue(_this)) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < this->hidden->numAudioBuffers; i++) {
|
for (i = 0; i < _this->hidden->numAudioBuffers; i++) {
|
||||||
SDL_memset(this->hidden->audioBuffer[i]->mAudioData, this->spec.silence, this->hidden->audioBuffer[i]->mAudioDataBytesCapacity);
|
SDL_memset(_this->hidden->audioBuffer[i]->mAudioData, _this->spec.silence, _this->hidden->audioBuffer[i]->mAudioDataBytesCapacity);
|
||||||
/* !!! FIXME: should we use AudioQueueEnqueueBufferWithParameters and specify all frames be "trimmed" so these are immediately ready to refill with SDL callback data? */
|
/* !!! FIXME: should we use AudioQueueEnqueueBufferWithParameters and specify all frames be "trimmed" so these are immediately ready to refill with SDL callback data? */
|
||||||
AudioQueueEnqueueBuffer(this->hidden->audioQueue, this->hidden->audioBuffer[i], 0, NULL);
|
AudioQueueEnqueueBuffer(_this->hidden->audioQueue, _this->hidden->audioBuffer[i], 0, NULL);
|
||||||
}
|
}
|
||||||
AudioQueueStart(this->hidden->audioQueue, NULL);
|
AudioQueueStart(_this->hidden->audioQueue, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->iscapture) { /* Drain off any pending playback. */
|
if (!_this->iscapture) { /* Drain off any pending playback. */
|
||||||
const CFTimeInterval secs = (((this->spec.size / (SDL_AUDIO_BITSIZE(this->spec.format) / 8.0)) / this->spec.channels) / ((CFTimeInterval)this->spec.freq)) * 2.0;
|
const CFTimeInterval secs = (((_this->spec.size / (SDL_AUDIO_BITSIZE(_this->spec.format) / 8.0)) / _this->spec.channels) / ((CFTimeInterval)_this->spec.freq)) * 2.0;
|
||||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, secs, 0);
|
CFRunLoopRunInMode(kCFRunLoopDefaultMode, secs, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MACOSX_COREAUDIO
|
#ifdef MACOSX_COREAUDIO
|
||||||
if (this->handle == NULL) {
|
if (_this->handle == NULL) {
|
||||||
/* we don't care if this fails; we just won't change to new default devices, but we still otherwise function in this case. */
|
/* we don't care if this fails; we just won't change to new default devices, but we still otherwise function in this case. */
|
||||||
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &default_device_address, default_device_changed, this);
|
AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &default_device_address, default_device_changed, _this);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int COREAUDIO_OpenDevice(_THIS, const char *devname)
|
static int COREAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
AudioStreamBasicDescription *strdesc;
|
AudioStreamBasicDescription *strdesc;
|
||||||
const SDL_AudioFormat *closefmts;
|
const SDL_AudioFormat *closefmts;
|
||||||
SDL_AudioFormat test_format;
|
SDL_AudioFormat test_format;
|
||||||
SDL_bool iscapture = this->iscapture;
|
SDL_bool iscapture = _this->iscapture;
|
||||||
SDL_AudioDevice **new_open_devices;
|
SDL_AudioDevice **new_open_devices;
|
||||||
|
|
||||||
/* Initialize all variables that we clean on shutdown */
|
/* Initialize all variables that we clean on shutdown */
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*this->hidden));
|
_this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*_this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_zerop(this->hidden);
|
SDL_zerop(_this->hidden);
|
||||||
|
|
||||||
strdesc = &this->hidden->strdesc;
|
strdesc = &_this->hidden->strdesc;
|
||||||
|
|
||||||
if (iscapture) {
|
if (iscapture) {
|
||||||
open_capture_devices++;
|
open_capture_devices++;
|
||||||
|
@ -1033,26 +1033,26 @@ static int COREAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
new_open_devices = (SDL_AudioDevice **)SDL_realloc(open_devices, sizeof(open_devices[0]) * (num_open_devices + 1));
|
new_open_devices = (SDL_AudioDevice **)SDL_realloc(open_devices, sizeof(open_devices[0]) * (num_open_devices + 1));
|
||||||
if (new_open_devices) {
|
if (new_open_devices) {
|
||||||
open_devices = new_open_devices;
|
open_devices = new_open_devices;
|
||||||
open_devices[num_open_devices++] = this;
|
open_devices[num_open_devices++] = _this;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef MACOSX_COREAUDIO
|
#ifndef MACOSX_COREAUDIO
|
||||||
if (!update_audio_session(this, SDL_TRUE, SDL_TRUE)) {
|
if (!update_audio_session(_this, SDL_TRUE, SDL_TRUE)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stop CoreAudio from doing expensive audio rate conversion */
|
/* Stop CoreAudio from doing expensive audio rate conversion */
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
AVAudioSession *session = [AVAudioSession sharedInstance];
|
AVAudioSession *session = [AVAudioSession sharedInstance];
|
||||||
[session setPreferredSampleRate:this->spec.freq error:nil];
|
[session setPreferredSampleRate:_this->spec.freq error:nil];
|
||||||
this->spec.freq = (int)session.sampleRate;
|
_this->spec.freq = (int)session.sampleRate;
|
||||||
#if TARGET_OS_TV
|
#if TARGET_OS_TV
|
||||||
if (iscapture) {
|
if (iscapture) {
|
||||||
[session setPreferredInputNumberOfChannels:this->spec.channels error:nil];
|
[session setPreferredInputNumberOfChannels:_this->spec.channels error:nil];
|
||||||
this->spec.channels = session.preferredInputNumberOfChannels;
|
_this->spec.channels = session.preferredInputNumberOfChannels;
|
||||||
} else {
|
} else {
|
||||||
[session setPreferredOutputNumberOfChannels:this->spec.channels error:nil];
|
[session setPreferredOutputNumberOfChannels:_this->spec.channels error:nil];
|
||||||
this->spec.channels = session.preferredOutputNumberOfChannels;
|
_this->spec.channels = session.preferredOutputNumberOfChannels;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* Calling setPreferredOutputNumberOfChannels seems to break audio output on iOS */
|
/* Calling setPreferredOutputNumberOfChannels seems to break audio output on iOS */
|
||||||
|
@ -1064,11 +1064,11 @@ static int COREAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
SDL_zerop(strdesc);
|
SDL_zerop(strdesc);
|
||||||
strdesc->mFormatID = kAudioFormatLinearPCM;
|
strdesc->mFormatID = kAudioFormatLinearPCM;
|
||||||
strdesc->mFormatFlags = kLinearPCMFormatFlagIsPacked;
|
strdesc->mFormatFlags = kLinearPCMFormatFlagIsPacked;
|
||||||
strdesc->mChannelsPerFrame = this->spec.channels;
|
strdesc->mChannelsPerFrame = _this->spec.channels;
|
||||||
strdesc->mSampleRate = this->spec.freq;
|
strdesc->mSampleRate = _this->spec.freq;
|
||||||
strdesc->mFramesPerPacket = 1;
|
strdesc->mFramesPerPacket = 1;
|
||||||
|
|
||||||
closefmts = SDL_ClosestAudioFormats(this->spec.format);
|
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
|
||||||
while ((test_format = *(closefmts++)) != 0) {
|
while ((test_format = *(closefmts++)) != 0) {
|
||||||
/* CoreAudio handles most of SDL's formats natively. */
|
/* CoreAudio handles most of SDL's formats natively. */
|
||||||
switch (test_format) {
|
switch (test_format) {
|
||||||
|
@ -1091,7 +1091,7 @@ static int COREAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
if (!test_format) { /* shouldn't happen, but just in case... */
|
if (!test_format) { /* shouldn't happen, but just in case... */
|
||||||
return SDL_SetError("%s: Unsupported audio format", "coreaudio");
|
return SDL_SetError("%s: Unsupported audio format", "coreaudio");
|
||||||
}
|
}
|
||||||
this->spec.format = test_format;
|
_this->spec.format = test_format;
|
||||||
strdesc->mBitsPerChannel = SDL_AUDIO_BITSIZE(test_format);
|
strdesc->mBitsPerChannel = SDL_AUDIO_BITSIZE(test_format);
|
||||||
if (SDL_AUDIO_ISBIGENDIAN(test_format)) {
|
if (SDL_AUDIO_ISBIGENDIAN(test_format)) {
|
||||||
strdesc->mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
|
strdesc->mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
|
||||||
|
@ -1107,31 +1107,31 @@ static int COREAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
strdesc->mBytesPerPacket = strdesc->mBytesPerFrame * strdesc->mFramesPerPacket;
|
strdesc->mBytesPerPacket = strdesc->mBytesPerFrame * strdesc->mFramesPerPacket;
|
||||||
|
|
||||||
#ifdef MACOSX_COREAUDIO
|
#ifdef MACOSX_COREAUDIO
|
||||||
if (!prepare_device(this)) {
|
if (!prepare_device(_this)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This has to init in a new thread so it can get its own CFRunLoop. :/ */
|
/* This has to init in a new thread so it can get its own CFRunLoop. :/ */
|
||||||
this->hidden->ready_semaphore = SDL_CreateSemaphore(0);
|
_this->hidden->ready_semaphore = SDL_CreateSemaphore(0);
|
||||||
if (!this->hidden->ready_semaphore) {
|
if (!_this->hidden->ready_semaphore) {
|
||||||
return -1; /* oh well. */
|
return -1; /* oh well. */
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->thread = SDL_CreateThreadInternal(audioqueue_thread, "AudioQueue thread", 512 * 1024, this);
|
_this->hidden->thread = SDL_CreateThreadInternal(audioqueue_thread, "AudioQueue thread", 512 * 1024, _this);
|
||||||
if (!this->hidden->thread) {
|
if (!_this->hidden->thread) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_WaitSemaphore(this->hidden->ready_semaphore);
|
SDL_WaitSemaphore(_this->hidden->ready_semaphore);
|
||||||
SDL_DestroySemaphore(this->hidden->ready_semaphore);
|
SDL_DestroySemaphore(_this->hidden->ready_semaphore);
|
||||||
this->hidden->ready_semaphore = NULL;
|
_this->hidden->ready_semaphore = NULL;
|
||||||
|
|
||||||
if ((this->hidden->thread != NULL) && (this->hidden->thread_error != NULL)) {
|
if ((_this->hidden->thread != NULL) && (_this->hidden->thread_error != NULL)) {
|
||||||
return SDL_SetError("%s", this->hidden->thread_error);
|
return SDL_SetError("%s", _this->hidden->thread_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (this->hidden->thread != NULL) ? 0 : -1;
|
return (_this->hidden->thread != NULL) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef MACOSX_COREAUDIO
|
#ifndef MACOSX_COREAUDIO
|
||||||
|
|
|
@ -198,7 +198,7 @@ static void DSOUND_DetectDevices(void)
|
||||||
#endif /* HAVE_MMDEVICEAPI_H*/
|
#endif /* HAVE_MMDEVICEAPI_H*/
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DSOUND_WaitDevice(_THIS)
|
static void DSOUND_WaitDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
DWORD status = 0;
|
DWORD status = 0;
|
||||||
DWORD cursor = 0;
|
DWORD cursor = 0;
|
||||||
|
@ -208,11 +208,11 @@ static void DSOUND_WaitDevice(_THIS)
|
||||||
/* Semi-busy wait, since we have no way of getting play notification
|
/* Semi-busy wait, since we have no way of getting play notification
|
||||||
on a primary mixing buffer located in hardware (DirectX 5.0)
|
on a primary mixing buffer located in hardware (DirectX 5.0)
|
||||||
*/
|
*/
|
||||||
result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
|
result = IDirectSoundBuffer_GetCurrentPosition(_this->hidden->mixbuf,
|
||||||
&junk, &cursor);
|
&junk, &cursor);
|
||||||
if (result != DS_OK) {
|
if (result != DS_OK) {
|
||||||
if (result == DSERR_BUFFERLOST) {
|
if (result == DSERR_BUFFERLOST) {
|
||||||
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
|
IDirectSoundBuffer_Restore(_this->hidden->mixbuf);
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_SOUND
|
#ifdef DEBUG_SOUND
|
||||||
SetDSerror("DirectSound GetCurrentPosition", result);
|
SetDSerror("DirectSound GetCurrentPosition", result);
|
||||||
|
@ -220,21 +220,21 @@ static void DSOUND_WaitDevice(_THIS)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((cursor / this->spec.size) == this->hidden->lastchunk) {
|
while ((cursor / _this->spec.size) == _this->hidden->lastchunk) {
|
||||||
/* FIXME: find out how much time is left and sleep that long */
|
/* FIXME: find out how much time is left and sleep that long */
|
||||||
SDL_Delay(1);
|
SDL_Delay(1);
|
||||||
|
|
||||||
/* Try to restore a lost sound buffer */
|
/* Try to restore a lost sound buffer */
|
||||||
IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
|
IDirectSoundBuffer_GetStatus(_this->hidden->mixbuf, &status);
|
||||||
if (status & DSBSTATUS_BUFFERLOST) {
|
if (status & DSBSTATUS_BUFFERLOST) {
|
||||||
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
|
IDirectSoundBuffer_Restore(_this->hidden->mixbuf);
|
||||||
IDirectSoundBuffer_GetStatus(this->hidden->mixbuf, &status);
|
IDirectSoundBuffer_GetStatus(_this->hidden->mixbuf, &status);
|
||||||
if (status & DSBSTATUS_BUFFERLOST) {
|
if (status & DSBSTATUS_BUFFERLOST) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!(status & DSBSTATUS_PLAYING)) {
|
if (!(status & DSBSTATUS_PLAYING)) {
|
||||||
result = IDirectSoundBuffer_Play(this->hidden->mixbuf, 0, 0,
|
result = IDirectSoundBuffer_Play(_this->hidden->mixbuf, 0, 0,
|
||||||
DSBPLAY_LOOPING);
|
DSBPLAY_LOOPING);
|
||||||
if (result == DS_OK) {
|
if (result == DS_OK) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -246,7 +246,7 @@ static void DSOUND_WaitDevice(_THIS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find out where we are playing */
|
/* Find out where we are playing */
|
||||||
result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
|
result = IDirectSoundBuffer_GetCurrentPosition(_this->hidden->mixbuf,
|
||||||
&junk, &cursor);
|
&junk, &cursor);
|
||||||
if (result != DS_OK) {
|
if (result != DS_OK) {
|
||||||
SetDSerror("DirectSound GetCurrentPosition", result);
|
SetDSerror("DirectSound GetCurrentPosition", result);
|
||||||
|
@ -255,17 +255,17 @@ static void DSOUND_WaitDevice(_THIS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DSOUND_PlayDevice(_THIS)
|
static void DSOUND_PlayDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
/* Unlock the buffer, allowing it to play */
|
/* Unlock the buffer, allowing it to play */
|
||||||
if (this->hidden->locked_buf) {
|
if (_this->hidden->locked_buf) {
|
||||||
IDirectSoundBuffer_Unlock(this->hidden->mixbuf,
|
IDirectSoundBuffer_Unlock(_this->hidden->mixbuf,
|
||||||
this->hidden->locked_buf,
|
_this->hidden->locked_buf,
|
||||||
this->spec.size, NULL, 0);
|
_this->spec.size, NULL, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *DSOUND_GetDeviceBuf(_THIS)
|
static Uint8 *DSOUND_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
DWORD cursor = 0;
|
DWORD cursor = 0;
|
||||||
DWORD junk = 0;
|
DWORD junk = 0;
|
||||||
|
@ -273,84 +273,84 @@ static Uint8 *DSOUND_GetDeviceBuf(_THIS)
|
||||||
DWORD rawlen = 0;
|
DWORD rawlen = 0;
|
||||||
|
|
||||||
/* Figure out which blocks to fill next */
|
/* Figure out which blocks to fill next */
|
||||||
this->hidden->locked_buf = NULL;
|
_this->hidden->locked_buf = NULL;
|
||||||
result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
|
result = IDirectSoundBuffer_GetCurrentPosition(_this->hidden->mixbuf,
|
||||||
&junk, &cursor);
|
&junk, &cursor);
|
||||||
if (result == DSERR_BUFFERLOST) {
|
if (result == DSERR_BUFFERLOST) {
|
||||||
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
|
IDirectSoundBuffer_Restore(_this->hidden->mixbuf);
|
||||||
result = IDirectSoundBuffer_GetCurrentPosition(this->hidden->mixbuf,
|
result = IDirectSoundBuffer_GetCurrentPosition(_this->hidden->mixbuf,
|
||||||
&junk, &cursor);
|
&junk, &cursor);
|
||||||
}
|
}
|
||||||
if (result != DS_OK) {
|
if (result != DS_OK) {
|
||||||
SetDSerror("DirectSound GetCurrentPosition", result);
|
SetDSerror("DirectSound GetCurrentPosition", result);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
cursor /= this->spec.size;
|
cursor /= _this->spec.size;
|
||||||
#ifdef DEBUG_SOUND
|
#ifdef DEBUG_SOUND
|
||||||
/* Detect audio dropouts */
|
/* Detect audio dropouts */
|
||||||
{
|
{
|
||||||
DWORD spot = cursor;
|
DWORD spot = cursor;
|
||||||
if (spot < this->hidden->lastchunk) {
|
if (spot < _this->hidden->lastchunk) {
|
||||||
spot += this->hidden->num_buffers;
|
spot += _this->hidden->num_buffers;
|
||||||
}
|
}
|
||||||
if (spot > this->hidden->lastchunk + 1) {
|
if (spot > _this->hidden->lastchunk + 1) {
|
||||||
fprintf(stderr, "Audio dropout, missed %d fragments\n",
|
fprintf(stderr, "Audio dropout, missed %d fragments\n",
|
||||||
(spot - (this->hidden->lastchunk + 1)));
|
(spot - (_this->hidden->lastchunk + 1)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
this->hidden->lastchunk = cursor;
|
_this->hidden->lastchunk = cursor;
|
||||||
cursor = (cursor + 1) % this->hidden->num_buffers;
|
cursor = (cursor + 1) % _this->hidden->num_buffers;
|
||||||
cursor *= this->spec.size;
|
cursor *= _this->spec.size;
|
||||||
|
|
||||||
/* Lock the audio buffer */
|
/* Lock the audio buffer */
|
||||||
result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
|
result = IDirectSoundBuffer_Lock(_this->hidden->mixbuf, cursor,
|
||||||
this->spec.size,
|
_this->spec.size,
|
||||||
(LPVOID *)&this->hidden->locked_buf,
|
(LPVOID *)&_this->hidden->locked_buf,
|
||||||
&rawlen, NULL, &junk, 0);
|
&rawlen, NULL, &junk, 0);
|
||||||
if (result == DSERR_BUFFERLOST) {
|
if (result == DSERR_BUFFERLOST) {
|
||||||
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
|
IDirectSoundBuffer_Restore(_this->hidden->mixbuf);
|
||||||
result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
|
result = IDirectSoundBuffer_Lock(_this->hidden->mixbuf, cursor,
|
||||||
this->spec.size,
|
_this->spec.size,
|
||||||
(LPVOID *)&this->hidden->locked_buf, &rawlen, NULL,
|
(LPVOID *)&_this->hidden->locked_buf, &rawlen, NULL,
|
||||||
&junk, 0);
|
&junk, 0);
|
||||||
}
|
}
|
||||||
if (result != DS_OK) {
|
if (result != DS_OK) {
|
||||||
SetDSerror("DirectSound Lock", result);
|
SetDSerror("DirectSound Lock", result);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return this->hidden->locked_buf;
|
return _this->hidden->locked_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int DSOUND_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
static int DSOUND_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *h = this->hidden;
|
struct SDL_PrivateAudioData *h = _this->hidden;
|
||||||
DWORD junk, cursor, ptr1len, ptr2len;
|
DWORD junk, cursor, ptr1len, ptr2len;
|
||||||
VOID *ptr1, *ptr2;
|
VOID *ptr1, *ptr2;
|
||||||
|
|
||||||
SDL_assert((Uint32)buflen == this->spec.size);
|
SDL_assert((Uint32)buflen == _this->spec.size);
|
||||||
|
|
||||||
while (SDL_TRUE) {
|
while (SDL_TRUE) {
|
||||||
if (SDL_AtomicGet(&this->shutdown)) { /* in case the buffer froze... */
|
if (SDL_AtomicGet(&_this->shutdown)) { /* in case the buffer froze... */
|
||||||
SDL_memset(buffer, this->spec.silence, buflen);
|
SDL_memset(buffer, _this->spec.silence, buflen);
|
||||||
return buflen;
|
return buflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) != DS_OK) {
|
if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) != DS_OK) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ((cursor / this->spec.size) == h->lastchunk) {
|
if ((cursor / _this->spec.size) == h->lastchunk) {
|
||||||
SDL_Delay(1); /* FIXME: find out how much time is left and sleep that long */
|
SDL_Delay(1); /* FIXME: find out how much time is left and sleep that long */
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IDirectSoundCaptureBuffer_Lock(h->capturebuf, h->lastchunk * this->spec.size, this->spec.size, &ptr1, &ptr1len, &ptr2, &ptr2len, 0) != DS_OK) {
|
if (IDirectSoundCaptureBuffer_Lock(h->capturebuf, h->lastchunk * _this->spec.size, _this->spec.size, &ptr1, &ptr1len, &ptr2, &ptr2len, 0) != DS_OK) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_assert(ptr1len == this->spec.size);
|
SDL_assert(ptr1len == _this->spec.size);
|
||||||
SDL_assert(ptr2 == NULL);
|
SDL_assert(ptr2 == NULL);
|
||||||
SDL_assert(ptr2len == 0);
|
SDL_assert(ptr2len == 0);
|
||||||
|
|
||||||
|
@ -365,42 +365,42 @@ static int DSOUND_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
return ptr1len;
|
return ptr1len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DSOUND_FlushCapture(_THIS)
|
static void DSOUND_FlushCapture(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *h = this->hidden;
|
struct SDL_PrivateAudioData *h = _this->hidden;
|
||||||
DWORD junk, cursor;
|
DWORD junk, cursor;
|
||||||
if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) == DS_OK) {
|
if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) == DS_OK) {
|
||||||
h->lastchunk = cursor / this->spec.size;
|
h->lastchunk = cursor / _this->spec.size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DSOUND_CloseDevice(_THIS)
|
static void DSOUND_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (this->hidden->mixbuf != NULL) {
|
if (_this->hidden->mixbuf != NULL) {
|
||||||
IDirectSoundBuffer_Stop(this->hidden->mixbuf);
|
IDirectSoundBuffer_Stop(_this->hidden->mixbuf);
|
||||||
IDirectSoundBuffer_Release(this->hidden->mixbuf);
|
IDirectSoundBuffer_Release(_this->hidden->mixbuf);
|
||||||
}
|
}
|
||||||
if (this->hidden->sound != NULL) {
|
if (_this->hidden->sound != NULL) {
|
||||||
IDirectSound_Release(this->hidden->sound);
|
IDirectSound_Release(_this->hidden->sound);
|
||||||
}
|
}
|
||||||
if (this->hidden->capturebuf != NULL) {
|
if (_this->hidden->capturebuf != NULL) {
|
||||||
IDirectSoundCaptureBuffer_Stop(this->hidden->capturebuf);
|
IDirectSoundCaptureBuffer_Stop(_this->hidden->capturebuf);
|
||||||
IDirectSoundCaptureBuffer_Release(this->hidden->capturebuf);
|
IDirectSoundCaptureBuffer_Release(_this->hidden->capturebuf);
|
||||||
}
|
}
|
||||||
if (this->hidden->capture != NULL) {
|
if (_this->hidden->capture != NULL) {
|
||||||
IDirectSoundCapture_Release(this->hidden->capture);
|
IDirectSoundCapture_Release(_this->hidden->capture);
|
||||||
}
|
}
|
||||||
SDL_free(this->hidden);
|
SDL_free(_this->hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function tries to create a secondary audio buffer, and returns the
|
/* This function tries to create a secondary audio buffer, and returns the
|
||||||
number of audio chunks available in the created buffer. This is for
|
number of audio chunks available in the created buffer. This is for
|
||||||
playback devices, not capture.
|
playback devices, not capture.
|
||||||
*/
|
*/
|
||||||
static int CreateSecondary(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
|
static int CreateSecondary(SDL_AudioDevice *_this, const DWORD bufsize, WAVEFORMATEX *wfmt)
|
||||||
{
|
{
|
||||||
LPDIRECTSOUND sndObj = this->hidden->sound;
|
LPDIRECTSOUND sndObj = _this->hidden->sound;
|
||||||
LPDIRECTSOUNDBUFFER *sndbuf = &this->hidden->mixbuf;
|
LPDIRECTSOUNDBUFFER *sndbuf = &_this->hidden->mixbuf;
|
||||||
HRESULT result = DS_OK;
|
HRESULT result = DS_OK;
|
||||||
DSBUFFERDESC format;
|
DSBUFFERDESC format;
|
||||||
LPVOID pvAudioPtr1, pvAudioPtr2;
|
LPVOID pvAudioPtr1, pvAudioPtr2;
|
||||||
|
@ -425,7 +425,7 @@ static int CreateSecondary(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
|
||||||
(LPVOID *)&pvAudioPtr2, &dwAudioBytes2,
|
(LPVOID *)&pvAudioPtr2, &dwAudioBytes2,
|
||||||
DSBLOCK_ENTIREBUFFER);
|
DSBLOCK_ENTIREBUFFER);
|
||||||
if (result == DS_OK) {
|
if (result == DS_OK) {
|
||||||
SDL_memset(pvAudioPtr1, this->spec.silence, dwAudioBytes1);
|
SDL_memset(pvAudioPtr1, _this->spec.silence, dwAudioBytes1);
|
||||||
IDirectSoundBuffer_Unlock(*sndbuf,
|
IDirectSoundBuffer_Unlock(*sndbuf,
|
||||||
(LPVOID)pvAudioPtr1, dwAudioBytes1,
|
(LPVOID)pvAudioPtr1, dwAudioBytes1,
|
||||||
(LPVOID)pvAudioPtr2, dwAudioBytes2);
|
(LPVOID)pvAudioPtr2, dwAudioBytes2);
|
||||||
|
@ -439,10 +439,10 @@ static int CreateSecondary(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
|
||||||
number of audio chunks available in the created buffer. This is for
|
number of audio chunks available in the created buffer. This is for
|
||||||
capture devices, not playback.
|
capture devices, not playback.
|
||||||
*/
|
*/
|
||||||
static int CreateCaptureBuffer(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
|
static int CreateCaptureBuffer(SDL_AudioDevice *_this, const DWORD bufsize, WAVEFORMATEX *wfmt)
|
||||||
{
|
{
|
||||||
LPDIRECTSOUNDCAPTURE capture = this->hidden->capture;
|
LPDIRECTSOUNDCAPTURE capture = _this->hidden->capture;
|
||||||
LPDIRECTSOUNDCAPTUREBUFFER *capturebuf = &this->hidden->capturebuf;
|
LPDIRECTSOUNDCAPTUREBUFFER *capturebuf = &_this->hidden->capturebuf;
|
||||||
DSCBUFFERDESC format;
|
DSCBUFFERDESC format;
|
||||||
HRESULT result;
|
HRESULT result;
|
||||||
|
|
||||||
|
@ -472,42 +472,42 @@ static int CreateCaptureBuffer(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
|
||||||
return SetDSerror("DirectSound GetCurrentPosition", result);
|
return SetDSerror("DirectSound GetCurrentPosition", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->lastchunk = cursor / this->spec.size;
|
_this->hidden->lastchunk = cursor / _this->spec.size;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int DSOUND_OpenDevice(_THIS, const char *devname)
|
static int DSOUND_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
const DWORD numchunks = 8;
|
const DWORD numchunks = 8;
|
||||||
HRESULT result;
|
HRESULT result;
|
||||||
SDL_bool tried_format = SDL_FALSE;
|
SDL_bool tried_format = SDL_FALSE;
|
||||||
SDL_bool iscapture = this->iscapture;
|
SDL_bool iscapture = _this->iscapture;
|
||||||
SDL_AudioFormat test_format;
|
SDL_AudioFormat test_format;
|
||||||
const SDL_AudioFormat *closefmts;
|
const SDL_AudioFormat *closefmts;
|
||||||
LPGUID guid = (LPGUID)this->handle;
|
LPGUID guid = (LPGUID)_this->handle;
|
||||||
DWORD bufsize;
|
DWORD bufsize;
|
||||||
|
|
||||||
/* Initialize all variables that we clean on shutdown */
|
/* Initialize all variables that we clean on shutdown */
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*this->hidden));
|
_this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*_this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_zerop(this->hidden);
|
SDL_zerop(_this->hidden);
|
||||||
|
|
||||||
/* Open the audio device */
|
/* Open the audio device */
|
||||||
if (iscapture) {
|
if (iscapture) {
|
||||||
result = pDirectSoundCaptureCreate8(guid, &this->hidden->capture, NULL);
|
result = pDirectSoundCaptureCreate8(guid, &_this->hidden->capture, NULL);
|
||||||
if (result != DS_OK) {
|
if (result != DS_OK) {
|
||||||
return SetDSerror("DirectSoundCaptureCreate8", result);
|
return SetDSerror("DirectSoundCaptureCreate8", result);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL);
|
result = pDirectSoundCreate8(guid, &_this->hidden->sound, NULL);
|
||||||
if (result != DS_OK) {
|
if (result != DS_OK) {
|
||||||
return SetDSerror("DirectSoundCreate8", result);
|
return SetDSerror("DirectSoundCreate8", result);
|
||||||
}
|
}
|
||||||
result = IDirectSound_SetCooperativeLevel(this->hidden->sound,
|
result = IDirectSound_SetCooperativeLevel(_this->hidden->sound,
|
||||||
GetDesktopWindow(),
|
GetDesktopWindow(),
|
||||||
DSSCL_NORMAL);
|
DSSCL_NORMAL);
|
||||||
if (result != DS_OK) {
|
if (result != DS_OK) {
|
||||||
|
@ -515,7 +515,7 @@ static int DSOUND_OpenDevice(_THIS, const char *devname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closefmts = SDL_ClosestAudioFormats(this->spec.format);
|
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
|
||||||
while ((test_format = *(closefmts++)) != 0) {
|
while ((test_format = *(closefmts++)) != 0) {
|
||||||
switch (test_format) {
|
switch (test_format) {
|
||||||
case SDL_AUDIO_U8:
|
case SDL_AUDIO_U8:
|
||||||
|
@ -524,12 +524,12 @@ static int DSOUND_OpenDevice(_THIS, const char *devname)
|
||||||
case SDL_AUDIO_F32:
|
case SDL_AUDIO_F32:
|
||||||
tried_format = SDL_TRUE;
|
tried_format = SDL_TRUE;
|
||||||
|
|
||||||
this->spec.format = test_format;
|
_this->spec.format = test_format;
|
||||||
|
|
||||||
/* Update the fragment size as size in bytes */
|
/* Update the fragment size as size in bytes */
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
bufsize = numchunks * this->spec.size;
|
bufsize = numchunks * _this->spec.size;
|
||||||
if ((bufsize < DSBSIZE_MIN) || (bufsize > DSBSIZE_MAX)) {
|
if ((bufsize < DSBSIZE_MIN) || (bufsize > DSBSIZE_MAX)) {
|
||||||
SDL_SetError("Sound buffer size must be between %d and %d",
|
SDL_SetError("Sound buffer size must be between %d and %d",
|
||||||
(int)((DSBSIZE_MIN < numchunks) ? 1 : DSBSIZE_MIN / numchunks),
|
(int)((DSBSIZE_MIN < numchunks) ? 1 : DSBSIZE_MIN / numchunks),
|
||||||
|
@ -538,18 +538,18 @@ static int DSOUND_OpenDevice(_THIS, const char *devname)
|
||||||
int rc;
|
int rc;
|
||||||
WAVEFORMATEXTENSIBLE wfmt;
|
WAVEFORMATEXTENSIBLE wfmt;
|
||||||
SDL_zero(wfmt);
|
SDL_zero(wfmt);
|
||||||
if (this->spec.channels > 2) {
|
if (_this->spec.channels > 2) {
|
||||||
wfmt.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
wfmt.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||||
wfmt.Format.cbSize = sizeof(wfmt) - sizeof(WAVEFORMATEX);
|
wfmt.Format.cbSize = sizeof(wfmt) - sizeof(WAVEFORMATEX);
|
||||||
|
|
||||||
if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
|
if (SDL_AUDIO_ISFLOAT(_this->spec.format)) {
|
||||||
SDL_memcpy(&wfmt.SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID));
|
SDL_memcpy(&wfmt.SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID));
|
||||||
} else {
|
} else {
|
||||||
SDL_memcpy(&wfmt.SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID));
|
SDL_memcpy(&wfmt.SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID));
|
||||||
}
|
}
|
||||||
wfmt.Samples.wValidBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
|
wfmt.Samples.wValidBitsPerSample = SDL_AUDIO_BITSIZE(_this->spec.format);
|
||||||
|
|
||||||
switch (this->spec.channels) {
|
switch (_this->spec.channels) {
|
||||||
case 3: /* 3.0 (or 2.1) */
|
case 3: /* 3.0 (or 2.1) */
|
||||||
wfmt.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER;
|
wfmt.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER;
|
||||||
break;
|
break;
|
||||||
|
@ -572,21 +572,21 @@ static int DSOUND_OpenDevice(_THIS, const char *devname)
|
||||||
SDL_assert(0 && "Unsupported channel count!");
|
SDL_assert(0 && "Unsupported channel count!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
|
} else if (SDL_AUDIO_ISFLOAT(_this->spec.format)) {
|
||||||
wfmt.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
|
wfmt.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
|
||||||
} else {
|
} else {
|
||||||
wfmt.Format.wFormatTag = WAVE_FORMAT_PCM;
|
wfmt.Format.wFormatTag = WAVE_FORMAT_PCM;
|
||||||
}
|
}
|
||||||
|
|
||||||
wfmt.Format.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
|
wfmt.Format.wBitsPerSample = SDL_AUDIO_BITSIZE(_this->spec.format);
|
||||||
wfmt.Format.nChannels = this->spec.channels;
|
wfmt.Format.nChannels = _this->spec.channels;
|
||||||
wfmt.Format.nSamplesPerSec = this->spec.freq;
|
wfmt.Format.nSamplesPerSec = _this->spec.freq;
|
||||||
wfmt.Format.nBlockAlign = wfmt.Format.nChannels * (wfmt.Format.wBitsPerSample / 8);
|
wfmt.Format.nBlockAlign = wfmt.Format.nChannels * (wfmt.Format.wBitsPerSample / 8);
|
||||||
wfmt.Format.nAvgBytesPerSec = wfmt.Format.nSamplesPerSec * wfmt.Format.nBlockAlign;
|
wfmt.Format.nAvgBytesPerSec = wfmt.Format.nSamplesPerSec * wfmt.Format.nBlockAlign;
|
||||||
|
|
||||||
rc = iscapture ? CreateCaptureBuffer(this, bufsize, (WAVEFORMATEX *)&wfmt) : CreateSecondary(this, bufsize, (WAVEFORMATEX *)&wfmt);
|
rc = iscapture ? CreateCaptureBuffer(_this, bufsize, (WAVEFORMATEX *)&wfmt) : CreateSecondary(_this, bufsize, (WAVEFORMATEX *)&wfmt);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
this->hidden->num_buffers = numchunks;
|
_this->hidden->num_buffers = numchunks;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
/* The DirectSound objects */
|
/* The DirectSound objects */
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,12 +40,12 @@
|
||||||
#define DISKENVR_IODELAY "SDL_DISKAUDIODELAY"
|
#define DISKENVR_IODELAY "SDL_DISKAUDIODELAY"
|
||||||
|
|
||||||
/* This function waits until it is possible to write a full sound buffer */
|
/* This function waits until it is possible to write a full sound buffer */
|
||||||
static void DISKAUDIO_WaitDevice(_THIS)
|
static void DISKAUDIO_WaitDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
SDL_Delay(_this->hidden->io_delay);
|
SDL_Delay(_this->hidden->io_delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DISKAUDIO_PlayDevice(_THIS)
|
static void DISKAUDIO_PlayDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
const Sint64 written = SDL_RWwrite(_this->hidden->io,
|
const Sint64 written = SDL_RWwrite(_this->hidden->io,
|
||||||
_this->hidden->mixbuf,
|
_this->hidden->mixbuf,
|
||||||
|
@ -60,12 +60,12 @@ static void DISKAUDIO_PlayDevice(_THIS)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *DISKAUDIO_GetDeviceBuf(_THIS)
|
static Uint8 *DISKAUDIO_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
return _this->hidden->mixbuf;
|
return _this->hidden->mixbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int DISKAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
static int DISKAUDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *h = _this->hidden;
|
struct SDL_PrivateAudioData *h = _this->hidden;
|
||||||
const int origbuflen = buflen;
|
const int origbuflen = buflen;
|
||||||
|
@ -88,12 +88,12 @@ static int DISKAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
return origbuflen;
|
return origbuflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DISKAUDIO_FlushCapture(_THIS)
|
static void DISKAUDIO_FlushCapture(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
/* no op...we don't advance the file pointer or anything. */
|
/* no op...we don't advance the file pointer or anything. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DISKAUDIO_CloseDevice(_THIS)
|
static void DISKAUDIO_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (_this->hidden->io != NULL) {
|
if (_this->hidden->io != NULL) {
|
||||||
SDL_RWclose(_this->hidden->io);
|
SDL_RWclose(_this->hidden->io);
|
||||||
|
@ -113,7 +113,7 @@ static const char *get_filename(const SDL_bool iscapture, const char *devname)
|
||||||
return devname;
|
return devname;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int DISKAUDIO_OpenDevice(_THIS, const char *devname)
|
static int DISKAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
void *handle = _this->handle;
|
void *handle = _this->handle;
|
||||||
/* handle != NULL means "user specified the placeholder name on the fake detected device list" */
|
/* handle != NULL means "user specified the placeholder name on the fake detected device list" */
|
||||||
|
|
|
@ -25,9 +25,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *_this
|
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
/* The file descriptor for the audio device */
|
/* The file descriptor for the audio device */
|
||||||
|
|
|
@ -45,18 +45,18 @@ static void DSP_DetectDevices(void)
|
||||||
SDL_EnumUnixAudioDevices(0, NULL);
|
SDL_EnumUnixAudioDevices(0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DSP_CloseDevice(_THIS)
|
static void DSP_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (this->hidden->audio_fd >= 0) {
|
if (_this->hidden->audio_fd >= 0) {
|
||||||
close(this->hidden->audio_fd);
|
close(_this->hidden->audio_fd);
|
||||||
}
|
}
|
||||||
SDL_free(this->hidden->mixbuf);
|
SDL_free(_this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(_this->hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int DSP_OpenDevice(_THIS, const char *devname)
|
static int DSP_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
SDL_bool iscapture = this->iscapture;
|
SDL_bool iscapture = _this->iscapture;
|
||||||
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
|
const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
|
||||||
int format = 0;
|
int format = 0;
|
||||||
int value;
|
int value;
|
||||||
|
@ -75,45 +75,45 @@ static int DSP_OpenDevice(_THIS, const char *devname)
|
||||||
|
|
||||||
/* Make sure fragment size stays a power of 2, or OSS fails. */
|
/* Make sure fragment size stays a power of 2, or OSS fails. */
|
||||||
/* I don't know which of these are actually legal values, though... */
|
/* I don't know which of these are actually legal values, though... */
|
||||||
if (this->spec.channels > 8) {
|
if (_this->spec.channels > 8) {
|
||||||
this->spec.channels = 8;
|
_this->spec.channels = 8;
|
||||||
} else if (this->spec.channels > 4) {
|
} else if (_this->spec.channels > 4) {
|
||||||
this->spec.channels = 4;
|
_this->spec.channels = 4;
|
||||||
} else if (this->spec.channels > 2) {
|
} else if (_this->spec.channels > 2) {
|
||||||
this->spec.channels = 2;
|
_this->spec.channels = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize all variables that we clean on shutdown */
|
/* Initialize all variables that we clean on shutdown */
|
||||||
this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*this->hidden));
|
_this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*_this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_zerop(this->hidden);
|
SDL_zerop(_this->hidden);
|
||||||
|
|
||||||
/* Open the audio device */
|
/* Open the audio device */
|
||||||
this->hidden->audio_fd = open(devname, flags | O_CLOEXEC, 0);
|
_this->hidden->audio_fd = open(devname, flags | O_CLOEXEC, 0);
|
||||||
if (this->hidden->audio_fd < 0) {
|
if (_this->hidden->audio_fd < 0) {
|
||||||
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
|
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make the file descriptor use blocking i/o with fcntl() */
|
/* Make the file descriptor use blocking i/o with fcntl() */
|
||||||
{
|
{
|
||||||
long ctlflags;
|
long ctlflags;
|
||||||
ctlflags = fcntl(this->hidden->audio_fd, F_GETFL);
|
ctlflags = fcntl(_this->hidden->audio_fd, F_GETFL);
|
||||||
ctlflags &= ~O_NONBLOCK;
|
ctlflags &= ~O_NONBLOCK;
|
||||||
if (fcntl(this->hidden->audio_fd, F_SETFL, ctlflags) < 0) {
|
if (fcntl(_this->hidden->audio_fd, F_SETFL, ctlflags) < 0) {
|
||||||
return SDL_SetError("Couldn't set audio blocking mode");
|
return SDL_SetError("Couldn't set audio blocking mode");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get a list of supported hardware formats */
|
/* Get a list of supported hardware formats */
|
||||||
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
|
if (ioctl(_this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) {
|
||||||
perror("SNDCTL_DSP_GETFMTS");
|
perror("SNDCTL_DSP_GETFMTS");
|
||||||
return SDL_SetError("Couldn't get audio format list");
|
return SDL_SetError("Couldn't get audio format list");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try for a closest match on audio format */
|
/* Try for a closest match on audio format */
|
||||||
closefmts = SDL_ClosestAudioFormats(this->spec.format);
|
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
|
||||||
while ((test_format = *(closefmts++)) != 0) {
|
while ((test_format = *(closefmts++)) != 0) {
|
||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
|
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
|
||||||
|
@ -153,39 +153,39 @@ static int DSP_OpenDevice(_THIS, const char *devname)
|
||||||
if (format == 0) {
|
if (format == 0) {
|
||||||
return SDL_SetError("Couldn't find any hardware audio formats");
|
return SDL_SetError("Couldn't find any hardware audio formats");
|
||||||
}
|
}
|
||||||
this->spec.format = test_format;
|
_this->spec.format = test_format;
|
||||||
|
|
||||||
/* Set the audio format */
|
/* Set the audio format */
|
||||||
value = format;
|
value = format;
|
||||||
if ((ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
|
if ((ioctl(_this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) ||
|
||||||
(value != format)) {
|
(value != format)) {
|
||||||
perror("SNDCTL_DSP_SETFMT");
|
perror("SNDCTL_DSP_SETFMT");
|
||||||
return SDL_SetError("Couldn't set audio format");
|
return SDL_SetError("Couldn't set audio format");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the number of channels of output */
|
/* Set the number of channels of output */
|
||||||
value = this->spec.channels;
|
value = _this->spec.channels;
|
||||||
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
|
if (ioctl(_this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) {
|
||||||
perror("SNDCTL_DSP_CHANNELS");
|
perror("SNDCTL_DSP_CHANNELS");
|
||||||
return SDL_SetError("Cannot set the number of channels");
|
return SDL_SetError("Cannot set the number of channels");
|
||||||
}
|
}
|
||||||
this->spec.channels = value;
|
_this->spec.channels = value;
|
||||||
|
|
||||||
/* Set the DSP frequency */
|
/* Set the DSP frequency */
|
||||||
value = this->spec.freq;
|
value = _this->spec.freq;
|
||||||
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
|
if (ioctl(_this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) {
|
||||||
perror("SNDCTL_DSP_SPEED");
|
perror("SNDCTL_DSP_SPEED");
|
||||||
return SDL_SetError("Couldn't set audio frequency");
|
return SDL_SetError("Couldn't set audio frequency");
|
||||||
}
|
}
|
||||||
this->spec.freq = value;
|
_this->spec.freq = value;
|
||||||
|
|
||||||
/* Calculate the final parameters for this audio specification */
|
/* Calculate the final parameters for this audio specification */
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
/* Determine the power of two of the fragment size */
|
/* Determine the power of two of the fragment size */
|
||||||
for (frag_spec = 0; (0x01U << frag_spec) < this->spec.size; ++frag_spec) {
|
for (frag_spec = 0; (0x01U << frag_spec) < _this->spec.size; ++frag_spec) {
|
||||||
}
|
}
|
||||||
if ((0x01U << frag_spec) != this->spec.size) {
|
if ((0x01U << frag_spec) != _this->spec.size) {
|
||||||
return SDL_SetError("Fragment size must be a power of two");
|
return SDL_SetError("Fragment size must be a power of two");
|
||||||
}
|
}
|
||||||
frag_spec |= 0x00020000; /* two fragments, for low latency */
|
frag_spec |= 0x00020000; /* two fragments, for low latency */
|
||||||
|
@ -195,13 +195,13 @@ static int DSP_OpenDevice(_THIS, const char *devname)
|
||||||
fprintf(stderr, "Requesting %d fragments of size %d\n",
|
fprintf(stderr, "Requesting %d fragments of size %d\n",
|
||||||
(frag_spec >> 16), 1 << (frag_spec & 0xFFFF));
|
(frag_spec >> 16), 1 << (frag_spec & 0xFFFF));
|
||||||
#endif
|
#endif
|
||||||
if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
|
if (ioctl(_this->hidden->audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag_spec) < 0) {
|
||||||
perror("SNDCTL_DSP_SETFRAGMENT");
|
perror("SNDCTL_DSP_SETFRAGMENT");
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
{
|
{
|
||||||
audio_buf_info info;
|
audio_buf_info info;
|
||||||
ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETOSPACE, &info);
|
ioctl(_this->hidden->audio_fd, SNDCTL_DSP_GETOSPACE, &info);
|
||||||
fprintf(stderr, "fragments = %d\n", info.fragments);
|
fprintf(stderr, "fragments = %d\n", info.fragments);
|
||||||
fprintf(stderr, "fragstotal = %d\n", info.fragstotal);
|
fprintf(stderr, "fragstotal = %d\n", info.fragstotal);
|
||||||
fprintf(stderr, "fragsize = %d\n", info.fragsize);
|
fprintf(stderr, "fragsize = %d\n", info.fragsize);
|
||||||
|
@ -211,43 +211,43 @@ static int DSP_OpenDevice(_THIS, const char *devname)
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
if (!iscapture) {
|
if (!iscapture) {
|
||||||
this->hidden->mixlen = this->spec.size;
|
_this->hidden->mixlen = _this->spec.size;
|
||||||
this->hidden->mixbuf = (Uint8 *)SDL_malloc(this->hidden->mixlen);
|
_this->hidden->mixbuf = (Uint8 *)SDL_malloc(_this->hidden->mixlen);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (_this->hidden->mixbuf == NULL) {
|
||||||
return SDL_OutOfMemory();
|
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. :-) */
|
/* We're ready to rock and roll. :-) */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DSP_PlayDevice(_THIS)
|
static void DSP_PlayDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *h = this->hidden;
|
struct SDL_PrivateAudioData *h = _this->hidden;
|
||||||
if (write(h->audio_fd, h->mixbuf, h->mixlen) == -1) {
|
if (write(h->audio_fd, h->mixbuf, h->mixlen) == -1) {
|
||||||
perror("Audio write");
|
perror("Audio write");
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
fprintf(stderr, "Wrote %d bytes of audio data\n", h->mixlen);
|
fprintf(stderr, "Wrote %d bytes of audio data\n", h->mixlen);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *DSP_GetDeviceBuf(_THIS)
|
static Uint8 *DSP_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
return this->hidden->mixbuf;
|
return _this->hidden->mixbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int DSP_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
static int DSP_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
return (int)read(this->hidden->audio_fd, buffer, buflen);
|
return (int)read(_this->hidden->audio_fd, buffer, buflen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DSP_FlushCapture(_THIS)
|
static void DSP_FlushCapture(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *h = this->hidden;
|
struct SDL_PrivateAudioData *h = _this->hidden;
|
||||||
audio_buf_info info;
|
audio_buf_info info;
|
||||||
if (ioctl(h->audio_fd, SNDCTL_DSP_GETISPACE, &info) == 0) {
|
if (ioctl(h->audio_fd, SNDCTL_DSP_GETISPACE, &info) == 0) {
|
||||||
while (info.bytes > 0) {
|
while (info.bytes > 0) {
|
||||||
|
|
|
@ -25,9 +25,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
/* The file descriptor for the audio device */
|
/* The file descriptor for the audio device */
|
||||||
|
|
|
@ -25,14 +25,14 @@
|
||||||
#include "../SDL_audio_c.h"
|
#include "../SDL_audio_c.h"
|
||||||
#include "SDL_dummyaudio.h"
|
#include "SDL_dummyaudio.h"
|
||||||
|
|
||||||
static int DUMMYAUDIO_OpenDevice(_THIS, const char *devname)
|
static int DUMMYAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
_this->hidden = (void *)0x1; /* just something non-NULL */
|
_this->hidden = (void *)0x1; /* just something non-NULL */
|
||||||
|
|
||||||
return 0; /* always succeeds. */
|
return 0; /* always succeeds. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int DUMMYAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
static int DUMMYAUDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
/* Delay to make this sort of simulate real audio input. */
|
/* Delay to make this sort of simulate real audio input. */
|
||||||
SDL_Delay((_this->spec.samples * 1000) / _this->spec.freq);
|
SDL_Delay((_this->spec.samples * 1000) / _this->spec.freq);
|
||||||
|
|
|
@ -25,9 +25,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *_this
|
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
/* The file descriptor for the audio device */
|
/* The file descriptor for the audio device */
|
||||||
|
|
|
@ -32,9 +32,9 @@
|
||||||
!!! FIXME: true always once pthread support becomes widespread. Revisit this code
|
!!! FIXME: true always once pthread support becomes widespread. Revisit this code
|
||||||
!!! FIXME: at some point and see what needs to be done for that! */
|
!!! FIXME: at some point and see what needs to be done for that! */
|
||||||
|
|
||||||
static void FeedAudioDevice(_THIS, const void *buf, const int buflen)
|
static void FeedAudioDevice(SDL_AudioDevice *_this, const void *buf, const int buflen)
|
||||||
{
|
{
|
||||||
const int framelen = (SDL_AUDIO_BITSIZE(this->spec.format) / 8) * this->spec.channels;
|
const int framelen = (SDL_AUDIO_BITSIZE(_this->spec.format) / 8) * _this->spec.channels;
|
||||||
/* *INDENT-OFF* */ /* clang-format off */
|
/* *INDENT-OFF* */ /* clang-format off */
|
||||||
MAIN_THREAD_EM_ASM({
|
MAIN_THREAD_EM_ASM({
|
||||||
var SDL3 = Module['SDL3'];
|
var SDL3 = Module['SDL3'];
|
||||||
|
@ -53,54 +53,54 @@ static void FeedAudioDevice(_THIS, const void *buf, const int buflen)
|
||||||
/* *INDENT-ON* */ /* clang-format on */
|
/* *INDENT-ON* */ /* clang-format on */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HandleAudioProcess(_THIS)
|
static void HandleAudioProcess(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
SDL_AudioCallback callback = this->callbackspec.callback;
|
SDL_AudioCallback callback = _this->callbackspec.callback;
|
||||||
const int stream_len = this->callbackspec.size;
|
const int stream_len = _this->callbackspec.size;
|
||||||
|
|
||||||
/* Only do something if audio is enabled */
|
/* Only do something if audio is enabled */
|
||||||
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
|
if (!SDL_AtomicGet(&_this->enabled) || SDL_AtomicGet(&_this->paused)) {
|
||||||
if (this->stream) {
|
if (_this->stream) {
|
||||||
SDL_ClearAudioStream(this->stream);
|
SDL_ClearAudioStream(_this->stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_memset(this->work_buffer, this->spec.silence, this->spec.size);
|
SDL_memset(_this->work_buffer, _this->spec.silence, _this->spec.size);
|
||||||
FeedAudioDevice(this, this->work_buffer, this->spec.size);
|
FeedAudioDevice(_this, _this->work_buffer, _this->spec.size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->stream == NULL) { /* no conversion necessary. */
|
if (_this->stream == NULL) { /* no conversion necessary. */
|
||||||
SDL_assert(this->spec.size == stream_len);
|
SDL_assert(_this->spec.size == stream_len);
|
||||||
callback(this->callbackspec.userdata, this->work_buffer, stream_len);
|
callback(_this->callbackspec.userdata, _this->work_buffer, stream_len);
|
||||||
} else { /* streaming/converting */
|
} else { /* streaming/converting */
|
||||||
int got;
|
int got;
|
||||||
while (SDL_GetAudioStreamAvailable(this->stream) < ((int)this->spec.size)) {
|
while (SDL_GetAudioStreamAvailable(_this->stream) < ((int)_this->spec.size)) {
|
||||||
callback(this->callbackspec.userdata, this->work_buffer, stream_len);
|
callback(_this->callbackspec.userdata, _this->work_buffer, stream_len);
|
||||||
if (SDL_PutAudioStreamData(this->stream, this->work_buffer, stream_len) == -1) {
|
if (SDL_PutAudioStreamData(_this->stream, _this->work_buffer, stream_len) == -1) {
|
||||||
SDL_ClearAudioStream(this->stream);
|
SDL_ClearAudioStream(_this->stream);
|
||||||
SDL_AtomicSet(&this->enabled, 0);
|
SDL_AtomicSet(&_this->enabled, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
got = SDL_GetAudioStreamData(this->stream, this->work_buffer, this->spec.size);
|
got = SDL_GetAudioStreamData(_this->stream, _this->work_buffer, _this->spec.size);
|
||||||
SDL_assert((got < 0) || (got == this->spec.size));
|
SDL_assert((got < 0) || (got == _this->spec.size));
|
||||||
if (got != this->spec.size) {
|
if (got != _this->spec.size) {
|
||||||
SDL_memset(this->work_buffer, this->spec.silence, this->spec.size);
|
SDL_memset(_this->work_buffer, _this->spec.silence, _this->spec.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FeedAudioDevice(this, this->work_buffer, this->spec.size);
|
FeedAudioDevice(_this, _this->work_buffer, _this->spec.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HandleCaptureProcess(_THIS)
|
static void HandleCaptureProcess(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
SDL_AudioCallback callback = this->callbackspec.callback;
|
SDL_AudioCallback callback = _this->callbackspec.callback;
|
||||||
const int stream_len = this->callbackspec.size;
|
const int stream_len = _this->callbackspec.size;
|
||||||
|
|
||||||
/* Only do something if audio is enabled */
|
/* Only do something if audio is enabled */
|
||||||
if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
|
if (!SDL_AtomicGet(&_this->enabled) || SDL_AtomicGet(&_this->paused)) {
|
||||||
SDL_ClearAudioStream(this->stream);
|
SDL_ClearAudioStream(_this->stream);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,31 +124,31 @@ static void HandleCaptureProcess(_THIS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, this->work_buffer, (this->spec.size / sizeof(float)) / this->spec.channels);
|
}, _this->work_buffer, (_this->spec.size / sizeof(float)) / _this->spec.channels);
|
||||||
/* *INDENT-ON* */ /* clang-format on */
|
/* *INDENT-ON* */ /* clang-format on */
|
||||||
|
|
||||||
/* okay, we've got an interleaved float32 array in C now. */
|
/* okay, we've got an interleaved float32 array in C now. */
|
||||||
|
|
||||||
if (this->stream == NULL) { /* no conversion necessary. */
|
if (_this->stream == NULL) { /* no conversion necessary. */
|
||||||
SDL_assert(this->spec.size == stream_len);
|
SDL_assert(_this->spec.size == stream_len);
|
||||||
callback(this->callbackspec.userdata, this->work_buffer, stream_len);
|
callback(_this->callbackspec.userdata, _this->work_buffer, stream_len);
|
||||||
} else { /* streaming/converting */
|
} else { /* streaming/converting */
|
||||||
if (SDL_PutAudioStreamData(this->stream, this->work_buffer, this->spec.size) == -1) {
|
if (SDL_PutAudioStreamData(_this->stream, _this->work_buffer, _this->spec.size) == -1) {
|
||||||
SDL_AtomicSet(&this->enabled, 0);
|
SDL_AtomicSet(&_this->enabled, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (SDL_GetAudioStreamAvailable(this->stream) >= stream_len) {
|
while (SDL_GetAudioStreamAvailable(_this->stream) >= stream_len) {
|
||||||
const int got = SDL_GetAudioStreamData(this->stream, this->work_buffer, stream_len);
|
const int got = SDL_GetAudioStreamData(_this->stream, _this->work_buffer, stream_len);
|
||||||
SDL_assert((got < 0) || (got == stream_len));
|
SDL_assert((got < 0) || (got == stream_len));
|
||||||
if (got != stream_len) {
|
if (got != stream_len) {
|
||||||
SDL_memset(this->work_buffer, this->callbackspec.silence, stream_len);
|
SDL_memset(_this->work_buffer, _this->callbackspec.silence, stream_len);
|
||||||
}
|
}
|
||||||
callback(this->callbackspec.userdata, this->work_buffer, stream_len); /* Send it to the app. */
|
callback(_this->callbackspec.userdata, _this->work_buffer, stream_len); /* Send it to the app. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EMSCRIPTENAUDIO_CloseDevice(_THIS)
|
static void EMSCRIPTENAUDIO_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
/* *INDENT-OFF* */ /* clang-format off */
|
/* *INDENT-OFF* */ /* clang-format off */
|
||||||
MAIN_THREAD_EM_ASM({
|
MAIN_THREAD_EM_ASM({
|
||||||
|
@ -188,19 +188,19 @@ static void EMSCRIPTENAUDIO_CloseDevice(_THIS)
|
||||||
SDL3.audioContext.close();
|
SDL3.audioContext.close();
|
||||||
SDL3.audioContext = undefined;
|
SDL3.audioContext = undefined;
|
||||||
}
|
}
|
||||||
}, this->iscapture);
|
}, _this->iscapture);
|
||||||
/* *INDENT-ON* */ /* clang-format on */
|
/* *INDENT-ON* */ /* clang-format on */
|
||||||
|
|
||||||
#if 0 /* !!! FIXME: currently not used. Can we move some stuff off the SDL3 namespace? --ryan. */
|
#if 0 /* !!! FIXME: currently not used. Can we move some stuff off the SDL3 namespace? --ryan. */
|
||||||
SDL_free(this->hidden);
|
SDL_free(_this->hidden);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname)
|
static int EMSCRIPTENAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
SDL_AudioFormat test_format;
|
SDL_AudioFormat test_format;
|
||||||
const SDL_AudioFormat *closefmts;
|
const SDL_AudioFormat *closefmts;
|
||||||
SDL_bool iscapture = this->iscapture;
|
SDL_bool iscapture = _this->iscapture;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
/* based on parts of library_sdl.js */
|
/* based on parts of library_sdl.js */
|
||||||
|
@ -236,7 +236,7 @@ static int EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
return SDL_SetError("Web Audio API is not available!");
|
return SDL_SetError("Web Audio API is not available!");
|
||||||
}
|
}
|
||||||
|
|
||||||
closefmts = SDL_ClosestAudioFormats(this->spec.format);
|
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
|
||||||
while ((test_format = *(closefmts++)) != 0) {
|
while ((test_format = *(closefmts++)) != 0) {
|
||||||
switch (test_format) {
|
switch (test_format) {
|
||||||
case SDL_AUDIO_F32: /* web audio only supports floats */
|
case SDL_AUDIO_F32: /* web audio only supports floats */
|
||||||
|
@ -251,25 +251,25 @@ static int EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
/* Didn't find a compatible format :( */
|
/* Didn't find a compatible format :( */
|
||||||
return SDL_SetError("%s: Unsupported audio format", "emscripten");
|
return SDL_SetError("%s: Unsupported audio format", "emscripten");
|
||||||
}
|
}
|
||||||
this->spec.format = test_format;
|
_this->spec.format = test_format;
|
||||||
|
|
||||||
/* Initialize all variables that we clean on shutdown */
|
/* Initialize all variables that we clean on shutdown */
|
||||||
#if 0 /* !!! FIXME: currently not used. Can we move some stuff off the SDL3 namespace? --ryan. */
|
#if 0 /* !!! FIXME: currently not used. Can we move some stuff off the SDL3 namespace? --ryan. */
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*this->hidden));
|
_this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*_this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_zerop(this->hidden);
|
SDL_zerop(_this->hidden);
|
||||||
#endif
|
#endif
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)0x1;
|
_this->hidden = (struct SDL_PrivateAudioData *)0x1;
|
||||||
|
|
||||||
/* limit to native freq */
|
/* limit to native freq */
|
||||||
this->spec.freq = EM_ASM_INT({
|
_this->spec.freq = EM_ASM_INT({
|
||||||
var SDL3 = Module['SDL3'];
|
var SDL3 = Module['SDL3'];
|
||||||
return SDL3.audioContext.sampleRate;
|
return SDL3.audioContext.sampleRate;
|
||||||
});
|
});
|
||||||
|
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
/* *INDENT-OFF* */ /* clang-format off */
|
/* *INDENT-OFF* */ /* clang-format off */
|
||||||
if (iscapture) {
|
if (iscapture) {
|
||||||
|
@ -329,7 +329,7 @@ static int EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
} else if (navigator.webkitGetUserMedia !== undefined) {
|
} else if (navigator.webkitGetUserMedia !== undefined) {
|
||||||
navigator.webkitGetUserMedia({ audio: true, video: false }, have_microphone, no_microphone);
|
navigator.webkitGetUserMedia({ audio: true, video: false }, have_microphone, no_microphone);
|
||||||
}
|
}
|
||||||
}, this->spec.channels, this->spec.samples, HandleCaptureProcess, this);
|
}, _this->spec.channels, _this->spec.samples, HandleCaptureProcess, _this);
|
||||||
} else {
|
} else {
|
||||||
/* setup a ScriptProcessorNode */
|
/* setup a ScriptProcessorNode */
|
||||||
MAIN_THREAD_EM_ASM({
|
MAIN_THREAD_EM_ASM({
|
||||||
|
@ -341,7 +341,7 @@ static int EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
dynCall('vi', $2, [$3]);
|
dynCall('vi', $2, [$3]);
|
||||||
};
|
};
|
||||||
SDL3.audio.scriptProcessorNode['connect'](SDL3.audioContext['destination']);
|
SDL3.audio.scriptProcessorNode['connect'](SDL3.audioContext['destination']);
|
||||||
}, this->spec.channels, this->spec.samples, HandleAudioProcess, this);
|
}, _this->spec.channels, _this->spec.samples, HandleAudioProcess, _this);
|
||||||
}
|
}
|
||||||
/* *INDENT-ON* */ /* clang-format on */
|
/* *INDENT-ON* */ /* clang-format on */
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
int unused;
|
int unused;
|
||||||
|
|
|
@ -83,7 +83,7 @@ static void FillSound(void *device, void *stream, size_t len,
|
||||||
SDL_UnlockMutex(audio->mixer_lock);
|
SDL_UnlockMutex(audio->mixer_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HAIKUAUDIO_CloseDevice(_THIS)
|
static void HAIKUAUDIO_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (_this->hidden->audio_obj) {
|
if (_this->hidden->audio_obj) {
|
||||||
_this->hidden->audio_obj->Stop();
|
_this->hidden->audio_obj->Stop();
|
||||||
|
@ -115,7 +115,7 @@ static inline void UnmaskSignals(sigset_t * omask)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int HAIKUAUDIO_OpenDevice(_THIS, const char *devname)
|
static int HAIKUAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
media_raw_audio_format format;
|
media_raw_audio_format format;
|
||||||
SDL_AudioFormat test_format;
|
SDL_AudioFormat test_format;
|
||||||
|
|
|
@ -25,9 +25,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *_this
|
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
BSoundPlayer *audio_obj;
|
BSoundPlayer *audio_obj;
|
||||||
|
|
|
@ -135,9 +135,9 @@ static int load_jack_syms(void)
|
||||||
|
|
||||||
static void jackShutdownCallback(void *arg) /* JACK went away; device is lost. */
|
static void jackShutdownCallback(void *arg) /* JACK went away; device is lost. */
|
||||||
{
|
{
|
||||||
SDL_AudioDevice *this = (SDL_AudioDevice *)arg;
|
SDL_AudioDevice *_this = (SDL_AudioDevice *)arg;
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||||
SDL_PostSemaphore(this->hidden->iosem); /* unblock the SDL thread. */
|
SDL_PostSemaphore(_this->hidden->iosem); /* unblock the SDL thread. */
|
||||||
}
|
}
|
||||||
|
|
||||||
// !!! FIXME: implement and register these!
|
// !!! FIXME: implement and register these!
|
||||||
|
@ -146,21 +146,21 @@ static void jackShutdownCallback(void *arg) /* JACK went away; device is lost. *
|
||||||
|
|
||||||
static int jackProcessPlaybackCallback(jack_nframes_t nframes, void *arg)
|
static int jackProcessPlaybackCallback(jack_nframes_t nframes, void *arg)
|
||||||
{
|
{
|
||||||
SDL_AudioDevice *this = (SDL_AudioDevice *)arg;
|
SDL_AudioDevice *_this = (SDL_AudioDevice *)arg;
|
||||||
jack_port_t **ports = this->hidden->sdlports;
|
jack_port_t **ports = _this->hidden->sdlports;
|
||||||
const int total_channels = this->spec.channels;
|
const int total_channels = _this->spec.channels;
|
||||||
const int total_frames = this->spec.samples;
|
const int total_frames = _this->spec.samples;
|
||||||
int channelsi;
|
int channelsi;
|
||||||
|
|
||||||
if (!SDL_AtomicGet(&this->enabled)) {
|
if (!SDL_AtomicGet(&_this->enabled)) {
|
||||||
/* silence the buffer to avoid repeats and corruption. */
|
/* silence the buffer to avoid repeats and corruption. */
|
||||||
SDL_memset(this->hidden->iobuffer, '\0', this->spec.size);
|
SDL_memset(_this->hidden->iobuffer, '\0', _this->spec.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (channelsi = 0; channelsi < total_channels; channelsi++) {
|
for (channelsi = 0; channelsi < total_channels; channelsi++) {
|
||||||
float *dst = (float *)JACK_jack_port_get_buffer(ports[channelsi], nframes);
|
float *dst = (float *)JACK_jack_port_get_buffer(ports[channelsi], nframes);
|
||||||
if (dst) {
|
if (dst) {
|
||||||
const float *src = this->hidden->iobuffer + channelsi;
|
const float *src = _this->hidden->iobuffer + channelsi;
|
||||||
int framesi;
|
int framesi;
|
||||||
for (framesi = 0; framesi < total_frames; framesi++) {
|
for (framesi = 0; framesi < total_frames; framesi++) {
|
||||||
*(dst++) = *src;
|
*(dst++) = *src;
|
||||||
|
@ -169,38 +169,38 @@ static int jackProcessPlaybackCallback(jack_nframes_t nframes, void *arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_PostSemaphore(this->hidden->iosem); /* tell SDL thread we're done; refill the buffer. */
|
SDL_PostSemaphore(_this->hidden->iosem); /* tell SDL thread we're done; refill the buffer. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function waits until it is possible to write a full sound buffer */
|
/* This function waits until it is possible to write a full sound buffer */
|
||||||
static void JACK_WaitDevice(_THIS)
|
static void JACK_WaitDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (SDL_AtomicGet(&this->enabled)) {
|
if (SDL_AtomicGet(&_this->enabled)) {
|
||||||
if (SDL_WaitSemaphore(this->hidden->iosem) == -1) {
|
if (SDL_WaitSemaphore(_this->hidden->iosem) == -1) {
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *JACK_GetDeviceBuf(_THIS)
|
static Uint8 *JACK_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
return (Uint8 *)this->hidden->iobuffer;
|
return (Uint8 *)_this->hidden->iobuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jackProcessCaptureCallback(jack_nframes_t nframes, void *arg)
|
static int jackProcessCaptureCallback(jack_nframes_t nframes, void *arg)
|
||||||
{
|
{
|
||||||
SDL_AudioDevice *this = (SDL_AudioDevice *)arg;
|
SDL_AudioDevice *_this = (SDL_AudioDevice *)arg;
|
||||||
if (SDL_AtomicGet(&this->enabled)) {
|
if (SDL_AtomicGet(&_this->enabled)) {
|
||||||
jack_port_t **ports = this->hidden->sdlports;
|
jack_port_t **ports = _this->hidden->sdlports;
|
||||||
const int total_channels = this->spec.channels;
|
const int total_channels = _this->spec.channels;
|
||||||
const int total_frames = this->spec.samples;
|
const int total_frames = _this->spec.samples;
|
||||||
int channelsi;
|
int channelsi;
|
||||||
|
|
||||||
for (channelsi = 0; channelsi < total_channels; channelsi++) {
|
for (channelsi = 0; channelsi < total_channels; channelsi++) {
|
||||||
const float *src = (const float *)JACK_jack_port_get_buffer(ports[channelsi], nframes);
|
const float *src = (const float *)JACK_jack_port_get_buffer(ports[channelsi], nframes);
|
||||||
if (src) {
|
if (src) {
|
||||||
float *dst = this->hidden->iobuffer + channelsi;
|
float *dst = _this->hidden->iobuffer + channelsi;
|
||||||
int framesi;
|
int framesi;
|
||||||
for (framesi = 0; framesi < total_frames; framesi++) {
|
for (framesi = 0; framesi < total_frames; framesi++) {
|
||||||
*dst = *(src++);
|
*dst = *(src++);
|
||||||
|
@ -210,60 +210,60 @@ static int jackProcessCaptureCallback(jack_nframes_t nframes, void *arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_PostSemaphore(this->hidden->iosem); /* tell SDL thread we're done; new buffer is ready! */
|
SDL_PostSemaphore(_this->hidden->iosem); /* tell SDL thread we're done; new buffer is ready! */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int JACK_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
static int JACK_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
SDL_assert(buflen == this->spec.size); /* we always fill a full buffer. */
|
SDL_assert(buflen == _this->spec.size); /* we always fill a full buffer. */
|
||||||
|
|
||||||
/* Wait for JACK to fill the iobuffer */
|
/* Wait for JACK to fill the iobuffer */
|
||||||
if (SDL_WaitSemaphore(this->hidden->iosem) == -1) {
|
if (SDL_WaitSemaphore(_this->hidden->iosem) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_memcpy(buffer, this->hidden->iobuffer, buflen);
|
SDL_memcpy(buffer, _this->hidden->iobuffer, buflen);
|
||||||
return buflen;
|
return buflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void JACK_FlushCapture(_THIS)
|
static void JACK_FlushCapture(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
SDL_WaitSemaphore(this->hidden->iosem);
|
SDL_WaitSemaphore(_this->hidden->iosem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void JACK_CloseDevice(_THIS)
|
static void JACK_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (this->hidden->client) {
|
if (_this->hidden->client) {
|
||||||
JACK_jack_deactivate(this->hidden->client);
|
JACK_jack_deactivate(_this->hidden->client);
|
||||||
|
|
||||||
if (this->hidden->sdlports) {
|
if (_this->hidden->sdlports) {
|
||||||
const int channels = this->spec.channels;
|
const int channels = _this->spec.channels;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < channels; i++) {
|
for (i = 0; i < channels; i++) {
|
||||||
JACK_jack_port_unregister(this->hidden->client, this->hidden->sdlports[i]);
|
JACK_jack_port_unregister(_this->hidden->client, _this->hidden->sdlports[i]);
|
||||||
}
|
}
|
||||||
SDL_free(this->hidden->sdlports);
|
SDL_free(_this->hidden->sdlports);
|
||||||
}
|
}
|
||||||
|
|
||||||
JACK_jack_client_close(this->hidden->client);
|
JACK_jack_client_close(_this->hidden->client);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->iosem) {
|
if (_this->hidden->iosem) {
|
||||||
SDL_DestroySemaphore(this->hidden->iosem);
|
SDL_DestroySemaphore(_this->hidden->iosem);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_free(this->hidden->iobuffer);
|
SDL_free(_this->hidden->iobuffer);
|
||||||
SDL_free(this->hidden);
|
SDL_free(_this->hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int JACK_OpenDevice(_THIS, const char *devname)
|
static int JACK_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
/* Note that JACK uses "output" for capture devices (they output audio
|
/* Note that JACK uses "output" for capture devices (they output audio
|
||||||
data to us) and "input" for playback (we input audio data to them).
|
data to us) and "input" for playback (we input audio data to them).
|
||||||
Likewise, SDL's playback port will be "output" (we write data out)
|
Likewise, SDL's playback port will be "output" (we write data out)
|
||||||
and capture will be "input" (we read data in). */
|
and capture will be "input" (we read data in). */
|
||||||
SDL_bool iscapture = this->iscapture;
|
SDL_bool iscapture = _this->iscapture;
|
||||||
const unsigned long sysportflags = iscapture ? JackPortIsOutput : JackPortIsInput;
|
const unsigned long sysportflags = iscapture ? JackPortIsOutput : JackPortIsInput;
|
||||||
const unsigned long sdlportflags = iscapture ? JackPortIsInput : JackPortIsOutput;
|
const unsigned long sdlportflags = iscapture ? JackPortIsInput : JackPortIsOutput;
|
||||||
const JackProcessCallback callback = iscapture ? jackProcessCaptureCallback : jackProcessPlaybackCallback;
|
const JackProcessCallback callback = iscapture ? jackProcessCaptureCallback : jackProcessPlaybackCallback;
|
||||||
|
@ -277,14 +277,14 @@ static int JACK_OpenDevice(_THIS, const char *devname)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Initialize all variables that we clean on shutdown */
|
/* Initialize all variables that we clean on shutdown */
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*this->hidden));
|
_this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*_this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* !!! FIXME: we _still_ need an API to specify an app name */
|
/* !!! FIXME: we _still_ need an API to specify an app name */
|
||||||
client = JACK_jack_client_open("SDL", JackNoStartServer, &status, NULL);
|
client = JACK_jack_client_open("SDL", JackNoStartServer, &status, NULL);
|
||||||
this->hidden->client = client;
|
_this->hidden->client = client;
|
||||||
if (client == NULL) {
|
if (client == NULL) {
|
||||||
return SDL_SetError("Can't open JACK client");
|
return SDL_SetError("Can't open JACK client");
|
||||||
}
|
}
|
||||||
|
@ -317,28 +317,28 @@ static int JACK_OpenDevice(_THIS, const char *devname)
|
||||||
/* !!! FIXME: docs say about buffer size: "This size may change, clients that depend on it must register a bufsize_callback so they will be notified if it does." */
|
/* !!! FIXME: docs say about buffer size: "This size may change, clients that depend on it must register a bufsize_callback so they will be notified if it does." */
|
||||||
|
|
||||||
/* Jack pretty much demands what it wants. */
|
/* Jack pretty much demands what it wants. */
|
||||||
this->spec.format = SDL_AUDIO_F32SYS;
|
_this->spec.format = SDL_AUDIO_F32SYS;
|
||||||
this->spec.freq = JACK_jack_get_sample_rate(client);
|
_this->spec.freq = JACK_jack_get_sample_rate(client);
|
||||||
this->spec.channels = channels;
|
_this->spec.channels = channels;
|
||||||
this->spec.samples = JACK_jack_get_buffer_size(client);
|
_this->spec.samples = JACK_jack_get_buffer_size(client);
|
||||||
|
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
this->hidden->iosem = SDL_CreateSemaphore(0);
|
_this->hidden->iosem = SDL_CreateSemaphore(0);
|
||||||
if (!this->hidden->iosem) {
|
if (!_this->hidden->iosem) {
|
||||||
SDL_free(audio_ports);
|
SDL_free(audio_ports);
|
||||||
return -1; /* error was set by SDL_CreateSemaphore */
|
return -1; /* error was set by SDL_CreateSemaphore */
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->iobuffer = (float *)SDL_calloc(1, this->spec.size);
|
_this->hidden->iobuffer = (float *)SDL_calloc(1, _this->spec.size);
|
||||||
if (!this->hidden->iobuffer) {
|
if (!_this->hidden->iobuffer) {
|
||||||
SDL_free(audio_ports);
|
SDL_free(audio_ports);
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build SDL's ports, which we will connect to the device ports. */
|
/* Build SDL's ports, which we will connect to the device ports. */
|
||||||
this->hidden->sdlports = (jack_port_t **)SDL_calloc(channels, sizeof(jack_port_t *));
|
_this->hidden->sdlports = (jack_port_t **)SDL_calloc(channels, sizeof(jack_port_t *));
|
||||||
if (this->hidden->sdlports == NULL) {
|
if (_this->hidden->sdlports == NULL) {
|
||||||
SDL_free(audio_ports);
|
SDL_free(audio_ports);
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
|
@ -346,19 +346,19 @@ static int JACK_OpenDevice(_THIS, const char *devname)
|
||||||
for (i = 0; i < channels; i++) {
|
for (i = 0; i < channels; i++) {
|
||||||
char portname[32];
|
char portname[32];
|
||||||
(void)SDL_snprintf(portname, sizeof(portname), "sdl_jack_%s_%d", sdlportstr, i);
|
(void)SDL_snprintf(portname, sizeof(portname), "sdl_jack_%s_%d", sdlportstr, i);
|
||||||
this->hidden->sdlports[i] = JACK_jack_port_register(client, portname, JACK_DEFAULT_AUDIO_TYPE, sdlportflags, 0);
|
_this->hidden->sdlports[i] = JACK_jack_port_register(client, portname, JACK_DEFAULT_AUDIO_TYPE, sdlportflags, 0);
|
||||||
if (this->hidden->sdlports[i] == NULL) {
|
if (_this->hidden->sdlports[i] == NULL) {
|
||||||
SDL_free(audio_ports);
|
SDL_free(audio_ports);
|
||||||
return SDL_SetError("jack_port_register failed");
|
return SDL_SetError("jack_port_register failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JACK_jack_set_process_callback(client, callback, this) != 0) {
|
if (JACK_jack_set_process_callback(client, callback, _this) != 0) {
|
||||||
SDL_free(audio_ports);
|
SDL_free(audio_ports);
|
||||||
return SDL_SetError("JACK: Couldn't set process callback");
|
return SDL_SetError("JACK: Couldn't set process callback");
|
||||||
}
|
}
|
||||||
|
|
||||||
JACK_jack_on_shutdown(client, jackShutdownCallback, this);
|
JACK_jack_on_shutdown(client, jackShutdownCallback, _this);
|
||||||
|
|
||||||
if (JACK_jack_activate(client) != 0) {
|
if (JACK_jack_activate(client) != 0) {
|
||||||
SDL_free(audio_ports);
|
SDL_free(audio_ports);
|
||||||
|
@ -367,7 +367,7 @@ static int JACK_OpenDevice(_THIS, const char *devname)
|
||||||
|
|
||||||
/* once activated, we can connect all the ports. */
|
/* once activated, we can connect all the ports. */
|
||||||
for (i = 0; i < channels; i++) {
|
for (i = 0; i < channels; i++) {
|
||||||
const char *sdlport = JACK_jack_port_name(this->hidden->sdlports[i]);
|
const char *sdlport = JACK_jack_port_name(_this->hidden->sdlports[i]);
|
||||||
const char *srcport = iscapture ? devports[audio_ports[i]] : sdlport;
|
const char *srcport = iscapture ? devports[audio_ports[i]] : sdlport;
|
||||||
const char *dstport = iscapture ? sdlport : devports[audio_ports[i]];
|
const char *dstport = iscapture ? sdlport : devports[audio_ports[i]];
|
||||||
if (JACK_jack_connect(client, srcport, dstport) != 0) {
|
if (JACK_jack_connect(client, srcport, dstport) != 0) {
|
||||||
|
|
|
@ -25,9 +25,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
jack_client_t *client;
|
jack_client_t *client;
|
||||||
|
|
|
@ -32,27 +32,27 @@
|
||||||
static dspHookCookie dsp_hook;
|
static dspHookCookie dsp_hook;
|
||||||
static SDL_AudioDevice *audio_device;
|
static SDL_AudioDevice *audio_device;
|
||||||
|
|
||||||
static void FreePrivateData(_THIS);
|
static void FreePrivateData(SDL_AudioDevice *_this);
|
||||||
static int FindAudioFormat(_THIS);
|
static int FindAudioFormat(SDL_AudioDevice *_this);
|
||||||
|
|
||||||
static SDL_INLINE void contextLock(_THIS)
|
static SDL_INLINE void contextLock(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
LightLock_Lock(&this->hidden->lock);
|
LightLock_Lock(&_this->hidden->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_INLINE void contextUnlock(_THIS)
|
static SDL_INLINE void contextUnlock(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
LightLock_Unlock(&this->hidden->lock);
|
LightLock_Unlock(&_this->hidden->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void N3DSAUD_LockAudio(_THIS)
|
static void N3DSAUD_LockAudio(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
contextLock(this);
|
contextLock(_this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void N3DSAUD_UnlockAudio(_THIS)
|
static void N3DSAUD_UnlockAudio(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
contextUnlock(this);
|
contextUnlock(_this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void N3DSAUD_DspHook(DSP_HookType hook)
|
static void N3DSAUD_DspHook(DSP_HookType hook)
|
||||||
|
@ -70,32 +70,32 @@ static void AudioFrameFinished(void *device)
|
||||||
{
|
{
|
||||||
bool shouldBroadcast = false;
|
bool shouldBroadcast = false;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
SDL_AudioDevice *this = (SDL_AudioDevice *)device;
|
SDL_AudioDevice *_this = (SDL_AudioDevice *)device;
|
||||||
|
|
||||||
contextLock(this);
|
contextLock(_this);
|
||||||
|
|
||||||
for (i = 0; i < NUM_BUFFERS; i++) {
|
for (i = 0; i < NUM_BUFFERS; i++) {
|
||||||
if (this->hidden->waveBuf[i].status == NDSP_WBUF_DONE) {
|
if (_this->hidden->waveBuf[i].status == NDSP_WBUF_DONE) {
|
||||||
this->hidden->waveBuf[i].status = NDSP_WBUF_FREE;
|
_this->hidden->waveBuf[i].status = NDSP_WBUF_FREE;
|
||||||
shouldBroadcast = SDL_TRUE;
|
shouldBroadcast = SDL_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldBroadcast) {
|
if (shouldBroadcast) {
|
||||||
CondVar_Broadcast(&this->hidden->cv);
|
CondVar_Broadcast(&_this->hidden->cv);
|
||||||
}
|
}
|
||||||
|
|
||||||
contextUnlock(this);
|
contextUnlock(_this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int N3DSAUDIO_OpenDevice(_THIS, const char *devname)
|
static int N3DSAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
Result ndsp_init_res;
|
Result ndsp_init_res;
|
||||||
Uint8 *data_vaddr;
|
Uint8 *data_vaddr;
|
||||||
float mix[12];
|
float mix[12];
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*this->hidden));
|
_this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*_this->hidden));
|
||||||
|
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,145 +111,145 @@ static int N3DSAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialise internal state */
|
/* Initialise internal state */
|
||||||
LightLock_Init(&this->hidden->lock);
|
LightLock_Init(&_this->hidden->lock);
|
||||||
CondVar_Init(&this->hidden->cv);
|
CondVar_Init(&_this->hidden->cv);
|
||||||
|
|
||||||
if (this->spec.channels > 2) {
|
if (_this->spec.channels > 2) {
|
||||||
this->spec.channels = 2;
|
_this->spec.channels = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Should not happen but better be safe. */
|
/* Should not happen but better be safe. */
|
||||||
if (FindAudioFormat(this) < 0) {
|
if (FindAudioFormat(_this) < 0) {
|
||||||
return SDL_SetError("No supported audio format found.");
|
return SDL_SetError("No supported audio format found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the fragment size as size in bytes */
|
/* Update the fragment size as size in bytes */
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
if (this->spec.size >= SDL_MAX_UINT32 / 2) {
|
if (_this->spec.size >= SDL_MAX_UINT32 / 2) {
|
||||||
return SDL_SetError("Mixing buffer is too large.");
|
return SDL_SetError("Mixing buffer is too large.");
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->mixlen = this->spec.size;
|
_this->hidden->mixlen = _this->spec.size;
|
||||||
this->hidden->mixbuf = (Uint8 *)SDL_malloc(this->spec.size);
|
_this->hidden->mixbuf = (Uint8 *)SDL_malloc(_this->spec.size);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (_this->hidden->mixbuf == NULL) {
|
||||||
return SDL_OutOfMemory();
|
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);
|
||||||
|
|
||||||
data_vaddr = (Uint8 *)linearAlloc(this->hidden->mixlen * NUM_BUFFERS);
|
data_vaddr = (Uint8 *)linearAlloc(_this->hidden->mixlen * NUM_BUFFERS);
|
||||||
if (data_vaddr == NULL) {
|
if (data_vaddr == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_memset(data_vaddr, 0, this->hidden->mixlen * NUM_BUFFERS);
|
SDL_memset(data_vaddr, 0, _this->hidden->mixlen * NUM_BUFFERS);
|
||||||
DSP_FlushDataCache(data_vaddr, this->hidden->mixlen * NUM_BUFFERS);
|
DSP_FlushDataCache(data_vaddr, _this->hidden->mixlen * NUM_BUFFERS);
|
||||||
|
|
||||||
this->hidden->nextbuf = 0;
|
_this->hidden->nextbuf = 0;
|
||||||
this->hidden->channels = this->spec.channels;
|
_this->hidden->channels = _this->spec.channels;
|
||||||
this->hidden->samplerate = this->spec.freq;
|
_this->hidden->samplerate = _this->spec.freq;
|
||||||
|
|
||||||
ndspChnReset(0);
|
ndspChnReset(0);
|
||||||
|
|
||||||
ndspChnSetInterp(0, NDSP_INTERP_LINEAR);
|
ndspChnSetInterp(0, NDSP_INTERP_LINEAR);
|
||||||
ndspChnSetRate(0, this->spec.freq);
|
ndspChnSetRate(0, _this->spec.freq);
|
||||||
ndspChnSetFormat(0, this->hidden->format);
|
ndspChnSetFormat(0, _this->hidden->format);
|
||||||
|
|
||||||
SDL_memset(mix, 0, sizeof(mix));
|
SDL_memset(mix, 0, sizeof(mix));
|
||||||
mix[0] = 1.0;
|
mix[0] = 1.0;
|
||||||
mix[1] = 1.0;
|
mix[1] = 1.0;
|
||||||
ndspChnSetMix(0, mix);
|
ndspChnSetMix(0, mix);
|
||||||
|
|
||||||
SDL_memset(this->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
|
SDL_memset(_this->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
|
||||||
|
|
||||||
for (unsigned i = 0; i < NUM_BUFFERS; i++) {
|
for (unsigned i = 0; i < NUM_BUFFERS; i++) {
|
||||||
this->hidden->waveBuf[i].data_vaddr = data_vaddr;
|
_this->hidden->waveBuf[i].data_vaddr = data_vaddr;
|
||||||
this->hidden->waveBuf[i].nsamples = this->hidden->mixlen / this->hidden->bytePerSample;
|
_this->hidden->waveBuf[i].nsamples = _this->hidden->mixlen / _this->hidden->bytePerSample;
|
||||||
data_vaddr += this->hidden->mixlen;
|
data_vaddr += _this->hidden->mixlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup callback */
|
/* Setup callback */
|
||||||
audio_device = this;
|
audio_device = _this;
|
||||||
ndspSetCallback(AudioFrameFinished, this);
|
ndspSetCallback(AudioFrameFinished, _this);
|
||||||
dspHook(&dsp_hook, N3DSAUD_DspHook);
|
dspHook(&dsp_hook, N3DSAUD_DspHook);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int N3DSAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
static int N3DSAUDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
/* Delay to make this sort of simulate real audio input. */
|
/* Delay to make this sort of simulate real audio input. */
|
||||||
SDL_Delay((this->spec.samples * 1000) / this->spec.freq);
|
SDL_Delay((_this->spec.samples * 1000) / _this->spec.freq);
|
||||||
|
|
||||||
/* always return a full buffer of silence. */
|
/* always return a full buffer of silence. */
|
||||||
SDL_memset(buffer, this->spec.silence, buflen);
|
SDL_memset(buffer, _this->spec.silence, buflen);
|
||||||
return buflen;
|
return buflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void N3DSAUDIO_PlayDevice(_THIS)
|
static void N3DSAUDIO_PlayDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
size_t nextbuf;
|
size_t nextbuf;
|
||||||
size_t sampleLen;
|
size_t sampleLen;
|
||||||
contextLock(this);
|
contextLock(_this);
|
||||||
|
|
||||||
nextbuf = this->hidden->nextbuf;
|
nextbuf = _this->hidden->nextbuf;
|
||||||
sampleLen = this->hidden->mixlen;
|
sampleLen = _this->hidden->mixlen;
|
||||||
|
|
||||||
if (this->hidden->isCancelled ||
|
if (_this->hidden->isCancelled ||
|
||||||
this->hidden->waveBuf[nextbuf].status != NDSP_WBUF_FREE) {
|
_this->hidden->waveBuf[nextbuf].status != NDSP_WBUF_FREE) {
|
||||||
contextUnlock(this);
|
contextUnlock(_this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->nextbuf = (nextbuf + 1) % NUM_BUFFERS;
|
_this->hidden->nextbuf = (nextbuf + 1) % NUM_BUFFERS;
|
||||||
|
|
||||||
contextUnlock(this);
|
contextUnlock(_this);
|
||||||
|
|
||||||
memcpy((void *)this->hidden->waveBuf[nextbuf].data_vaddr,
|
memcpy((void *)_this->hidden->waveBuf[nextbuf].data_vaddr,
|
||||||
this->hidden->mixbuf, sampleLen);
|
_this->hidden->mixbuf, sampleLen);
|
||||||
DSP_FlushDataCache(this->hidden->waveBuf[nextbuf].data_vaddr, sampleLen);
|
DSP_FlushDataCache(_this->hidden->waveBuf[nextbuf].data_vaddr, sampleLen);
|
||||||
|
|
||||||
ndspChnWaveBufAdd(0, &this->hidden->waveBuf[nextbuf]);
|
ndspChnWaveBufAdd(0, &_this->hidden->waveBuf[nextbuf]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void N3DSAUDIO_WaitDevice(_THIS)
|
static void N3DSAUDIO_WaitDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
contextLock(this);
|
contextLock(_this);
|
||||||
while (!this->hidden->isCancelled &&
|
while (!_this->hidden->isCancelled &&
|
||||||
this->hidden->waveBuf[this->hidden->nextbuf].status != NDSP_WBUF_FREE) {
|
_this->hidden->waveBuf[_this->hidden->nextbuf].status != NDSP_WBUF_FREE) {
|
||||||
CondVar_Wait(&this->hidden->cv, &this->hidden->lock);
|
CondVar_Wait(&_this->hidden->cv, &_this->hidden->lock);
|
||||||
}
|
}
|
||||||
contextUnlock(this);
|
contextUnlock(_this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *N3DSAUDIO_GetDeviceBuf(_THIS)
|
static Uint8 *N3DSAUDIO_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
return this->hidden->mixbuf;
|
return _this->hidden->mixbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void N3DSAUDIO_CloseDevice(_THIS)
|
static void N3DSAUDIO_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
contextLock(this);
|
contextLock(_this);
|
||||||
|
|
||||||
dspUnhook(&dsp_hook);
|
dspUnhook(&dsp_hook);
|
||||||
ndspSetCallback(NULL, NULL);
|
ndspSetCallback(NULL, NULL);
|
||||||
|
|
||||||
if (!this->hidden->isCancelled) {
|
if (!_this->hidden->isCancelled) {
|
||||||
ndspChnReset(0);
|
ndspChnReset(0);
|
||||||
memset(this->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
|
memset(_this->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
|
||||||
CondVar_Broadcast(&this->hidden->cv);
|
CondVar_Broadcast(&_this->hidden->cv);
|
||||||
}
|
}
|
||||||
|
|
||||||
contextUnlock(this);
|
contextUnlock(_this);
|
||||||
|
|
||||||
ndspExit();
|
ndspExit();
|
||||||
|
|
||||||
FreePrivateData(this);
|
FreePrivateData(_this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void N3DSAUDIO_ThreadInit(_THIS)
|
static void N3DSAUDIO_ThreadInit(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
s32 current_priority;
|
s32 current_priority;
|
||||||
svcGetThreadPriority(¤t_priority, CUR_THREAD_HANDLE);
|
svcGetThreadPriority(¤t_priority, CUR_THREAD_HANDLE);
|
||||||
|
@ -289,43 +289,43 @@ AudioBootStrap N3DSAUDIO_bootstrap = {
|
||||||
/**
|
/**
|
||||||
* Cleans up all allocated memory, safe to call with null pointers
|
* Cleans up all allocated memory, safe to call with null pointers
|
||||||
*/
|
*/
|
||||||
static void FreePrivateData(_THIS)
|
static void FreePrivateData(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (!this->hidden) {
|
if (!_this->hidden) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->waveBuf[0].data_vaddr) {
|
if (_this->hidden->waveBuf[0].data_vaddr) {
|
||||||
linearFree((void *)this->hidden->waveBuf[0].data_vaddr);
|
linearFree((void *)_this->hidden->waveBuf[0].data_vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->mixbuf) {
|
if (_this->hidden->mixbuf) {
|
||||||
SDL_free(this->hidden->mixbuf);
|
SDL_free(_this->hidden->mixbuf);
|
||||||
this->hidden->mixbuf = NULL;
|
_this->hidden->mixbuf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_free(this->hidden);
|
SDL_free(_this->hidden);
|
||||||
this->hidden = NULL;
|
_this->hidden = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int FindAudioFormat(_THIS)
|
static int FindAudioFormat(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
SDL_AudioFormat test_format;
|
SDL_AudioFormat test_format;
|
||||||
const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(this->spec.format);
|
const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(_this->spec.format);
|
||||||
while ((test_format = *(closefmts++)) != 0) {
|
while ((test_format = *(closefmts++)) != 0) {
|
||||||
this->spec.format = test_format;
|
_this->spec.format = test_format;
|
||||||
switch (test_format) {
|
switch (test_format) {
|
||||||
case SDL_AUDIO_S8:
|
case SDL_AUDIO_S8:
|
||||||
/* Signed 8-bit audio supported */
|
/* Signed 8-bit audio supported */
|
||||||
this->hidden->format = (this->spec.channels == 2) ? NDSP_FORMAT_STEREO_PCM8 : NDSP_FORMAT_MONO_PCM8;
|
_this->hidden->format = (_this->spec.channels == 2) ? NDSP_FORMAT_STEREO_PCM8 : NDSP_FORMAT_MONO_PCM8;
|
||||||
this->hidden->isSigned = 1;
|
_this->hidden->isSigned = 1;
|
||||||
this->hidden->bytePerSample = this->spec.channels;
|
_this->hidden->bytePerSample = _this->spec.channels;
|
||||||
return 0;
|
return 0;
|
||||||
case SDL_AUDIO_S16:
|
case SDL_AUDIO_S16:
|
||||||
/* Signed 16-bit audio supported */
|
/* Signed 16-bit audio supported */
|
||||||
this->hidden->format = (this->spec.channels == 2) ? NDSP_FORMAT_STEREO_PCM16 : NDSP_FORMAT_MONO_PCM16;
|
_this->hidden->format = (_this->spec.channels == 2) ? NDSP_FORMAT_STEREO_PCM16 : NDSP_FORMAT_MONO_PCM16;
|
||||||
this->hidden->isSigned = 1;
|
_this->hidden->isSigned = 1;
|
||||||
this->hidden->bytePerSample = this->spec.channels * 2;
|
_this->hidden->bytePerSample = _this->spec.channels * 2;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,6 @@
|
||||||
|
|
||||||
#include <3ds.h>
|
#include <3ds.h>
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
#define NUM_BUFFERS 2 /* -- Don't lower this! */
|
#define NUM_BUFFERS 2 /* -- Don't lower this! */
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
|
|
|
@ -48,19 +48,19 @@ static void NETBSDAUDIO_DetectDevices(void)
|
||||||
SDL_EnumUnixAudioDevices(0, NULL);
|
SDL_EnumUnixAudioDevices(0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NETBSDAUDIO_Status(_THIS)
|
static void NETBSDAUDIO_Status(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
/* *INDENT-OFF* */ /* clang-format off */
|
/* *INDENT-OFF* */ /* clang-format off */
|
||||||
audio_info_t info;
|
audio_info_t info;
|
||||||
const struct audio_prinfo *prinfo;
|
const struct audio_prinfo *prinfo;
|
||||||
|
|
||||||
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
|
if (ioctl(_this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
|
||||||
fprintf(stderr, "AUDIO_GETINFO failed.\n");
|
fprintf(stderr, "AUDIO_GETINFO failed.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
prinfo = this->iscapture ? &info.record : &info.play;
|
prinfo = _this->iscapture ? &info.record : &info.play;
|
||||||
|
|
||||||
fprintf(stderr, "\n"
|
fprintf(stderr, "\n"
|
||||||
"[%s info]\n"
|
"[%s info]\n"
|
||||||
|
@ -77,7 +77,7 @@ static void NETBSDAUDIO_Status(_THIS)
|
||||||
"waiting : %s\n"
|
"waiting : %s\n"
|
||||||
"active : %s\n"
|
"active : %s\n"
|
||||||
"",
|
"",
|
||||||
this->iscapture ? "record" : "play",
|
_this->iscapture ? "record" : "play",
|
||||||
prinfo->buffer_size,
|
prinfo->buffer_size,
|
||||||
prinfo->sample_rate,
|
prinfo->sample_rate,
|
||||||
prinfo->channels,
|
prinfo->channels,
|
||||||
|
@ -111,23 +111,23 @@ static void NETBSDAUDIO_Status(_THIS)
|
||||||
"format : 0x%x\n"
|
"format : 0x%x\n"
|
||||||
"size : %u\n"
|
"size : %u\n"
|
||||||
"",
|
"",
|
||||||
this->spec.format,
|
_this->spec.format,
|
||||||
this->spec.size);
|
_this->spec.size);
|
||||||
/* *INDENT-ON* */ /* clang-format on */
|
/* *INDENT-ON* */ /* clang-format on */
|
||||||
|
|
||||||
#endif /* DEBUG_AUDIO */
|
#endif /* DEBUG_AUDIO */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NETBSDAUDIO_PlayDevice(_THIS)
|
static void NETBSDAUDIO_PlayDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *h = this->hidden;
|
struct SDL_PrivateAudioData *h = _this->hidden;
|
||||||
int written;
|
int written;
|
||||||
|
|
||||||
/* Write the audio data */
|
/* Write the audio data */
|
||||||
written = write(h->audio_fd, h->mixbuf, h->mixlen);
|
written = write(h->audio_fd, h->mixbuf, h->mixlen);
|
||||||
if (written == -1) {
|
if (written == -1) {
|
||||||
/* Non recoverable error has occurred. It should be reported!!! */
|
/* Non recoverable error has occurred. It should be reported!!! */
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||||
perror("audio");
|
perror("audio");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -137,17 +137,17 @@ static void NETBSDAUDIO_PlayDevice(_THIS)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *NETBSDAUDIO_GetDeviceBuf(_THIS)
|
static Uint8 *NETBSDAUDIO_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
return this->hidden->mixbuf;
|
return _this->hidden->mixbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int NETBSDAUDIO_CaptureFromDevice(_THIS, void *_buffer, int buflen)
|
static int NETBSDAUDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *_buffer, int buflen)
|
||||||
{
|
{
|
||||||
Uint8 *buffer = (Uint8 *)_buffer;
|
Uint8 *buffer = (Uint8 *)_buffer;
|
||||||
int br;
|
int br;
|
||||||
|
|
||||||
br = read(this->hidden->audio_fd, buffer, buflen);
|
br = read(_this->hidden->audio_fd, buffer, buflen);
|
||||||
if (br == -1) {
|
if (br == -1) {
|
||||||
/* Non recoverable error has occurred. It should be reported!!! */
|
/* Non recoverable error has occurred. It should be reported!!! */
|
||||||
perror("audio");
|
perror("audio");
|
||||||
|
@ -160,20 +160,20 @@ static int NETBSDAUDIO_CaptureFromDevice(_THIS, void *_buffer, int buflen)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NETBSDAUDIO_FlushCapture(_THIS)
|
static void NETBSDAUDIO_FlushCapture(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
audio_info_t info;
|
audio_info_t info;
|
||||||
size_t remain;
|
size_t remain;
|
||||||
Uint8 buf[512];
|
Uint8 buf[512];
|
||||||
|
|
||||||
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
|
if (ioctl(_this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
|
||||||
return; /* oh well. */
|
return; /* oh well. */
|
||||||
}
|
}
|
||||||
|
|
||||||
remain = (size_t)(info.record.samples * (SDL_AUDIO_BITSIZE(this->spec.format) / 8));
|
remain = (size_t)(info.record.samples * (SDL_AUDIO_BITSIZE(_this->spec.format) / 8));
|
||||||
while (remain > 0) {
|
while (remain > 0) {
|
||||||
const size_t len = SDL_min(sizeof(buf), remain);
|
const size_t len = SDL_min(sizeof(buf), remain);
|
||||||
const int br = read(this->hidden->audio_fd, buf, len);
|
const int br = read(_this->hidden->audio_fd, buf, len);
|
||||||
if (br <= 0) {
|
if (br <= 0) {
|
||||||
return; /* oh well. */
|
return; /* oh well. */
|
||||||
}
|
}
|
||||||
|
@ -181,18 +181,18 @@ static void NETBSDAUDIO_FlushCapture(_THIS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void NETBSDAUDIO_CloseDevice(_THIS)
|
static void NETBSDAUDIO_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (this->hidden->audio_fd >= 0) {
|
if (_this->hidden->audio_fd >= 0) {
|
||||||
close(this->hidden->audio_fd);
|
close(_this->hidden->audio_fd);
|
||||||
}
|
}
|
||||||
SDL_free(this->hidden->mixbuf);
|
SDL_free(_this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(_this->hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int NETBSDAUDIO_OpenDevice(_THIS, const char *devname)
|
static int NETBSDAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
SDL_bool iscapture = this->iscapture;
|
SDL_bool iscapture = _this->iscapture;
|
||||||
SDL_AudioFormat test_format;
|
SDL_AudioFormat test_format;
|
||||||
const SDL_AudioFormat *closefmts;
|
const SDL_AudioFormat *closefmts;
|
||||||
int encoding = AUDIO_ENCODING_NONE;
|
int encoding = AUDIO_ENCODING_NONE;
|
||||||
|
@ -209,34 +209,34 @@ static int NETBSDAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize all variables that we clean on shutdown */
|
/* Initialize all variables that we clean on shutdown */
|
||||||
this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*this->hidden));
|
_this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*_this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_zerop(this->hidden);
|
SDL_zerop(_this->hidden);
|
||||||
|
|
||||||
/* Open the audio device */
|
/* Open the audio device */
|
||||||
this->hidden->audio_fd = open(devname, (iscapture ? O_RDONLY : O_WRONLY) | O_CLOEXEC);
|
_this->hidden->audio_fd = open(devname, (iscapture ? O_RDONLY : O_WRONLY) | O_CLOEXEC);
|
||||||
if (this->hidden->audio_fd < 0) {
|
if (_this->hidden->audio_fd < 0) {
|
||||||
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
|
return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
AUDIO_INITINFO(&info);
|
AUDIO_INITINFO(&info);
|
||||||
|
|
||||||
#ifdef AUDIO_GETFORMAT /* Introduced in NetBSD 9.0 */
|
#ifdef AUDIO_GETFORMAT /* Introduced in NetBSD 9.0 */
|
||||||
if (ioctl(this->hidden->audio_fd, AUDIO_GETFORMAT, &hwinfo) != -1) {
|
if (ioctl(_this->hidden->audio_fd, AUDIO_GETFORMAT, &hwinfo) != -1) {
|
||||||
/*
|
/*
|
||||||
* Use the device's native sample rate so the kernel doesn't have to
|
* Use the device's native sample rate so the kernel doesn't have to
|
||||||
* resample.
|
* resample.
|
||||||
*/
|
*/
|
||||||
this->spec.freq = iscapture ? hwinfo.record.sample_rate : hwinfo.play.sample_rate;
|
_this->spec.freq = iscapture ? hwinfo.record.sample_rate : hwinfo.play.sample_rate;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
prinfo->sample_rate = this->spec.freq;
|
prinfo->sample_rate = _this->spec.freq;
|
||||||
prinfo->channels = this->spec.channels;
|
prinfo->channels = _this->spec.channels;
|
||||||
|
|
||||||
closefmts = SDL_ClosestAudioFormats(this->spec.format);
|
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
|
||||||
while ((test_format = *(closefmts++)) != 0) {
|
while ((test_format = *(closefmts++)) != 0) {
|
||||||
switch (test_format) {
|
switch (test_format) {
|
||||||
case SDL_AUDIO_U8:
|
case SDL_AUDIO_U8:
|
||||||
|
@ -271,32 +271,32 @@ static int NETBSDAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
|
|
||||||
info.hiwat = 5;
|
info.hiwat = 5;
|
||||||
info.lowat = 3;
|
info.lowat = 3;
|
||||||
if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
|
if (ioctl(_this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
|
||||||
return SDL_SetError("AUDIO_SETINFO failed for %s: %s", devname, strerror(errno));
|
return SDL_SetError("AUDIO_SETINFO failed for %s: %s", devname, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
|
if (ioctl(_this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
|
||||||
return SDL_SetError("AUDIO_GETINFO failed for %s: %s", devname, strerror(errno));
|
return SDL_SetError("AUDIO_GETINFO failed for %s: %s", devname, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Final spec used for the device. */
|
/* Final spec used for the device. */
|
||||||
this->spec.format = test_format;
|
_this->spec.format = test_format;
|
||||||
this->spec.freq = prinfo->sample_rate;
|
_this->spec.freq = prinfo->sample_rate;
|
||||||
this->spec.channels = prinfo->channels;
|
_this->spec.channels = prinfo->channels;
|
||||||
|
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
if (!iscapture) {
|
if (!iscapture) {
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
this->hidden->mixlen = this->spec.size;
|
_this->hidden->mixlen = _this->spec.size;
|
||||||
this->hidden->mixbuf = (Uint8 *)SDL_malloc(this->hidden->mixlen);
|
_this->hidden->mixbuf = (Uint8 *)SDL_malloc(_this->hidden->mixlen);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (_this->hidden->mixbuf == NULL) {
|
||||||
return SDL_OutOfMemory();
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
NETBSDAUDIO_Status(this);
|
NETBSDAUDIO_Status(_this);
|
||||||
|
|
||||||
/* We're ready to rock and roll. :-) */
|
/* We're ready to rock and roll. :-) */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -25,8 +25,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
/* The file descriptor for the audio device */
|
/* The file descriptor for the audio device */
|
||||||
|
|
|
@ -189,9 +189,9 @@ static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
|
||||||
SDL_PostSemaphore(audiodata->playsem);
|
SDL_PostSemaphore(audiodata->playsem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void openslES_DestroyPCMRecorder(_THIS)
|
static void openslES_DestroyPCMRecorder(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
struct SDL_PrivateAudioData *audiodata = _this->hidden;
|
||||||
SLresult result;
|
SLresult result;
|
||||||
|
|
||||||
/* stop recording */
|
/* stop recording */
|
||||||
|
@ -220,9 +220,9 @@ static void openslES_DestroyPCMRecorder(_THIS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int openslES_CreatePCMRecorder(_THIS)
|
static int openslES_CreatePCMRecorder(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
struct SDL_PrivateAudioData *audiodata = _this->hidden;
|
||||||
SLDataFormat_PCM format_pcm;
|
SLDataFormat_PCM format_pcm;
|
||||||
SLDataLocator_AndroidSimpleBufferQueue loc_bufq;
|
SLDataLocator_AndroidSimpleBufferQueue loc_bufq;
|
||||||
SLDataSink audioSnk;
|
SLDataSink audioSnk;
|
||||||
|
@ -239,16 +239,16 @@ static int openslES_CreatePCMRecorder(_THIS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Just go with signed 16-bit audio as it's the most compatible */
|
/* Just go with signed 16-bit audio as it's the most compatible */
|
||||||
this->spec.format = SDL_AUDIO_S16SYS;
|
_this->spec.format = SDL_AUDIO_S16SYS;
|
||||||
this->spec.channels = 1;
|
_this->spec.channels = 1;
|
||||||
/*this->spec.freq = SL_SAMPLINGRATE_16 / 1000;*/
|
/*_this->spec.freq = SL_SAMPLINGRATE_16 / 1000;*/
|
||||||
|
|
||||||
/* Update the fragment size as size in bytes */
|
/* Update the fragment size as size in bytes */
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
LOGI("Try to open %u hz %u bit chan %u %s samples %u",
|
LOGI("Try to open %u hz %u bit chan %u %s samples %u",
|
||||||
this->spec.freq, SDL_AUDIO_BITSIZE(this->spec.format),
|
_this->spec.freq, SDL_AUDIO_BITSIZE(_this->spec.format),
|
||||||
this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples);
|
_this->spec.channels, (_this->spec.format & 0x1000) ? "BE" : "LE", _this->spec.samples);
|
||||||
|
|
||||||
/* configure audio source */
|
/* configure audio source */
|
||||||
loc_dev.locatorType = SL_DATALOCATOR_IODEVICE;
|
loc_dev.locatorType = SL_DATALOCATOR_IODEVICE;
|
||||||
|
@ -263,10 +263,10 @@ static int openslES_CreatePCMRecorder(_THIS)
|
||||||
loc_bufq.numBuffers = NUM_BUFFERS;
|
loc_bufq.numBuffers = NUM_BUFFERS;
|
||||||
|
|
||||||
format_pcm.formatType = SL_DATAFORMAT_PCM;
|
format_pcm.formatType = SL_DATAFORMAT_PCM;
|
||||||
format_pcm.numChannels = this->spec.channels;
|
format_pcm.numChannels = _this->spec.channels;
|
||||||
format_pcm.samplesPerSec = this->spec.freq * 1000; /* / kilo Hz to milli Hz */
|
format_pcm.samplesPerSec = _this->spec.freq * 1000; /* / kilo Hz to milli Hz */
|
||||||
format_pcm.bitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
|
format_pcm.bitsPerSample = SDL_AUDIO_BITSIZE(_this->spec.format);
|
||||||
format_pcm.containerSize = SDL_AUDIO_BITSIZE(this->spec.format);
|
format_pcm.containerSize = SDL_AUDIO_BITSIZE(_this->spec.format);
|
||||||
format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
||||||
format_pcm.channelMask = SL_SPEAKER_FRONT_CENTER;
|
format_pcm.channelMask = SL_SPEAKER_FRONT_CENTER;
|
||||||
|
|
||||||
|
@ -303,8 +303,8 @@ static int openslES_CreatePCMRecorder(_THIS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* register callback on the buffer queue */
|
/* register callback on the buffer queue */
|
||||||
/* context is '(SDL_PrivateAudioData *)this->hidden' */
|
/* context is '(SDL_PrivateAudioData *)_this->hidden' */
|
||||||
result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback, this->hidden);
|
result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback, _this->hidden);
|
||||||
if (SL_RESULT_SUCCESS != result) {
|
if (SL_RESULT_SUCCESS != result) {
|
||||||
LOGE("RegisterCallback failed: %d", result);
|
LOGE("RegisterCallback failed: %d", result);
|
||||||
goto failed;
|
goto failed;
|
||||||
|
@ -318,14 +318,14 @@ static int openslES_CreatePCMRecorder(_THIS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the sound buffers */
|
/* Create the sound buffers */
|
||||||
audiodata->mixbuff = (Uint8 *)SDL_malloc(NUM_BUFFERS * this->spec.size);
|
audiodata->mixbuff = (Uint8 *)SDL_malloc(NUM_BUFFERS * _this->spec.size);
|
||||||
if (audiodata->mixbuff == NULL) {
|
if (audiodata->mixbuff == NULL) {
|
||||||
LOGE("mixbuffer allocate - out of memory");
|
LOGE("mixbuffer allocate - out of memory");
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < NUM_BUFFERS; i++) {
|
for (i = 0; i < NUM_BUFFERS; i++) {
|
||||||
audiodata->pmixbuff[i] = audiodata->mixbuff + i * this->spec.size;
|
audiodata->pmixbuff[i] = audiodata->mixbuff + i * _this->spec.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* in case already recording, stop recording and clear buffer queue */
|
/* in case already recording, stop recording and clear buffer queue */
|
||||||
|
@ -337,7 +337,7 @@ static int openslES_CreatePCMRecorder(_THIS)
|
||||||
|
|
||||||
/* enqueue empty buffers to be filled by the recorder */
|
/* enqueue empty buffers to be filled by the recorder */
|
||||||
for (i = 0; i < NUM_BUFFERS; i++) {
|
for (i = 0; i < NUM_BUFFERS; i++) {
|
||||||
result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[i], this->spec.size);
|
result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[i], _this->spec.size);
|
||||||
if (SL_RESULT_SUCCESS != result) {
|
if (SL_RESULT_SUCCESS != result) {
|
||||||
LOGE("Record enqueue buffers failed: %d", result);
|
LOGE("Record enqueue buffers failed: %d", result);
|
||||||
goto failed;
|
goto failed;
|
||||||
|
@ -366,9 +366,9 @@ static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
|
||||||
SDL_PostSemaphore(audiodata->playsem);
|
SDL_PostSemaphore(audiodata->playsem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void openslES_DestroyPCMPlayer(_THIS)
|
static void openslES_DestroyPCMPlayer(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
struct SDL_PrivateAudioData *audiodata = _this->hidden;
|
||||||
SLresult result;
|
SLresult result;
|
||||||
|
|
||||||
/* set the player's state to 'stopped' */
|
/* set the player's state to 'stopped' */
|
||||||
|
@ -398,9 +398,9 @@ static void openslES_DestroyPCMPlayer(_THIS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int openslES_CreatePCMPlayer(_THIS)
|
static int openslES_CreatePCMPlayer(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
struct SDL_PrivateAudioData *audiodata = _this->hidden;
|
||||||
SLDataLocator_AndroidSimpleBufferQueue loc_bufq;
|
SLDataLocator_AndroidSimpleBufferQueue loc_bufq;
|
||||||
SLDataFormat_PCM format_pcm;
|
SLDataFormat_PCM format_pcm;
|
||||||
SLAndroidDataFormat_PCM_EX format_pcm_ex;
|
SLAndroidDataFormat_PCM_EX format_pcm_ex;
|
||||||
|
@ -417,7 +417,7 @@ static int openslES_CreatePCMPlayer(_THIS)
|
||||||
https://developer.android.com/ndk/guides/audio/opensl/android-extensions.html#floating-point
|
https://developer.android.com/ndk/guides/audio/opensl/android-extensions.html#floating-point
|
||||||
*/
|
*/
|
||||||
if (SDL_GetAndroidSDKVersion() >= 21) {
|
if (SDL_GetAndroidSDKVersion() >= 21) {
|
||||||
const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(this->spec.format);
|
const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(_this->spec.format);
|
||||||
SDL_AudioFormat test_format;
|
SDL_AudioFormat test_format;
|
||||||
while ((test_format = *(closefmts++)) != 0) {
|
while ((test_format = *(closefmts++)) != 0) {
|
||||||
if (SDL_AUDIO_ISSIGNED(test_format)) {
|
if (SDL_AUDIO_ISSIGNED(test_format)) {
|
||||||
|
@ -430,36 +430,36 @@ static int openslES_CreatePCMPlayer(_THIS)
|
||||||
LOGI("No compatible audio format, using signed 16-bit audio");
|
LOGI("No compatible audio format, using signed 16-bit audio");
|
||||||
test_format = SDL_AUDIO_S16SYS;
|
test_format = SDL_AUDIO_S16SYS;
|
||||||
}
|
}
|
||||||
this->spec.format = test_format;
|
_this->spec.format = test_format;
|
||||||
} else {
|
} else {
|
||||||
/* Just go with signed 16-bit audio as it's the most compatible */
|
/* Just go with signed 16-bit audio as it's the most compatible */
|
||||||
this->spec.format = SDL_AUDIO_S16SYS;
|
_this->spec.format = SDL_AUDIO_S16SYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the fragment size as size in bytes */
|
/* Update the fragment size as size in bytes */
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
LOGI("Try to open %u hz %s %u bit chan %u %s samples %u",
|
LOGI("Try to open %u hz %s %u bit chan %u %s samples %u",
|
||||||
this->spec.freq, SDL_AUDIO_ISFLOAT(this->spec.format) ? "float" : "pcm", SDL_AUDIO_BITSIZE(this->spec.format),
|
_this->spec.freq, SDL_AUDIO_ISFLOAT(_this->spec.format) ? "float" : "pcm", SDL_AUDIO_BITSIZE(_this->spec.format),
|
||||||
this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples);
|
_this->spec.channels, (_this->spec.format & 0x1000) ? "BE" : "LE", _this->spec.samples);
|
||||||
|
|
||||||
/* configure audio source */
|
/* configure audio source */
|
||||||
loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
|
loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
|
||||||
loc_bufq.numBuffers = NUM_BUFFERS;
|
loc_bufq.numBuffers = NUM_BUFFERS;
|
||||||
|
|
||||||
format_pcm.formatType = SL_DATAFORMAT_PCM;
|
format_pcm.formatType = SL_DATAFORMAT_PCM;
|
||||||
format_pcm.numChannels = this->spec.channels;
|
format_pcm.numChannels = _this->spec.channels;
|
||||||
format_pcm.samplesPerSec = this->spec.freq * 1000; /* / kilo Hz to milli Hz */
|
format_pcm.samplesPerSec = _this->spec.freq * 1000; /* / kilo Hz to milli Hz */
|
||||||
format_pcm.bitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
|
format_pcm.bitsPerSample = SDL_AUDIO_BITSIZE(_this->spec.format);
|
||||||
format_pcm.containerSize = SDL_AUDIO_BITSIZE(this->spec.format);
|
format_pcm.containerSize = SDL_AUDIO_BITSIZE(_this->spec.format);
|
||||||
|
|
||||||
if (SDL_AUDIO_ISBIGENDIAN(this->spec.format)) {
|
if (SDL_AUDIO_ISBIGENDIAN(_this->spec.format)) {
|
||||||
format_pcm.endianness = SL_BYTEORDER_BIGENDIAN;
|
format_pcm.endianness = SL_BYTEORDER_BIGENDIAN;
|
||||||
} else {
|
} else {
|
||||||
format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (this->spec.channels) {
|
switch (_this->spec.channels) {
|
||||||
case 1:
|
case 1:
|
||||||
format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT;
|
format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT;
|
||||||
break;
|
break;
|
||||||
|
@ -486,12 +486,12 @@ static int openslES_CreatePCMPlayer(_THIS)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* Unknown number of channels, fall back to stereo */
|
/* Unknown number of channels, fall back to stereo */
|
||||||
this->spec.channels = 2;
|
_this->spec.channels = 2;
|
||||||
format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
|
format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
|
if (SDL_AUDIO_ISFLOAT(_this->spec.format)) {
|
||||||
/* Copy all setup into PCM EX structure */
|
/* Copy all setup into PCM EX structure */
|
||||||
format_pcm_ex.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
|
format_pcm_ex.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
|
||||||
format_pcm_ex.endianness = format_pcm.endianness;
|
format_pcm_ex.endianness = format_pcm.endianness;
|
||||||
|
@ -504,7 +504,7 @@ static int openslES_CreatePCMPlayer(_THIS)
|
||||||
}
|
}
|
||||||
|
|
||||||
audioSrc.pLocator = &loc_bufq;
|
audioSrc.pLocator = &loc_bufq;
|
||||||
audioSrc.pFormat = SDL_AUDIO_ISFLOAT(this->spec.format) ? (void *)&format_pcm_ex : (void *)&format_pcm;
|
audioSrc.pFormat = SDL_AUDIO_ISFLOAT(_this->spec.format) ? (void *)&format_pcm_ex : (void *)&format_pcm;
|
||||||
|
|
||||||
/* configure audio sink */
|
/* configure audio sink */
|
||||||
loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
|
loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
|
||||||
|
@ -541,8 +541,8 @@ static int openslES_CreatePCMPlayer(_THIS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* register callback on the buffer queue */
|
/* register callback on the buffer queue */
|
||||||
/* context is '(SDL_PrivateAudioData *)this->hidden' */
|
/* context is '(SDL_PrivateAudioData *)_this->hidden' */
|
||||||
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, this->hidden);
|
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, _this->hidden);
|
||||||
if (SL_RESULT_SUCCESS != result) {
|
if (SL_RESULT_SUCCESS != result) {
|
||||||
LOGE("RegisterCallback failed: %d", result);
|
LOGE("RegisterCallback failed: %d", result);
|
||||||
goto failed;
|
goto failed;
|
||||||
|
@ -565,14 +565,14 @@ static int openslES_CreatePCMPlayer(_THIS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the sound buffers */
|
/* Create the sound buffers */
|
||||||
audiodata->mixbuff = (Uint8 *)SDL_malloc(NUM_BUFFERS * this->spec.size);
|
audiodata->mixbuff = (Uint8 *)SDL_malloc(NUM_BUFFERS * _this->spec.size);
|
||||||
if (audiodata->mixbuff == NULL) {
|
if (audiodata->mixbuff == NULL) {
|
||||||
LOGE("mixbuffer allocate - out of memory");
|
LOGE("mixbuffer allocate - out of memory");
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < NUM_BUFFERS; i++) {
|
for (i = 0; i < NUM_BUFFERS; i++) {
|
||||||
audiodata->pmixbuff[i] = audiodata->mixbuff + i * this->spec.size;
|
audiodata->pmixbuff[i] = audiodata->mixbuff + i * _this->spec.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set the player's state to playing */
|
/* set the player's state to playing */
|
||||||
|
@ -588,26 +588,26 @@ failed:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int openslES_OpenDevice(_THIS, const char *devname)
|
static int openslES_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*this->hidden));
|
_this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*_this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->iscapture) {
|
if (_this->iscapture) {
|
||||||
LOGI("openslES_OpenDevice() %s for capture", devname);
|
LOGI("openslES_OpenDevice() %s for capture", devname);
|
||||||
return openslES_CreatePCMRecorder(this);
|
return openslES_CreatePCMRecorder(_this);
|
||||||
} else {
|
} else {
|
||||||
int ret;
|
int ret;
|
||||||
LOGI("openslES_OpenDevice() %s for playing", devname);
|
LOGI("openslES_OpenDevice() %s for playing", devname);
|
||||||
ret = openslES_CreatePCMPlayer(this);
|
ret = openslES_CreatePCMPlayer(_this);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
/* Another attempt to open the device with a lower frequency */
|
/* Another attempt to open the device with a lower frequency */
|
||||||
if (this->spec.freq > 48000) {
|
if (_this->spec.freq > 48000) {
|
||||||
openslES_DestroyPCMPlayer(this);
|
openslES_DestroyPCMPlayer(_this);
|
||||||
this->spec.freq = 48000;
|
_this->spec.freq = 48000;
|
||||||
ret = openslES_CreatePCMPlayer(this);
|
ret = openslES_CreatePCMPlayer(_this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,9 +619,9 @@ static int openslES_OpenDevice(_THIS, const char *devname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void openslES_WaitDevice(_THIS)
|
static void openslES_WaitDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
struct SDL_PrivateAudioData *audiodata = _this->hidden;
|
||||||
|
|
||||||
LOGV("openslES_WaitDevice()");
|
LOGV("openslES_WaitDevice()");
|
||||||
|
|
||||||
|
@ -629,15 +629,15 @@ static void openslES_WaitDevice(_THIS)
|
||||||
SDL_WaitSemaphore(audiodata->playsem);
|
SDL_WaitSemaphore(audiodata->playsem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void openslES_PlayDevice(_THIS)
|
static void openslES_PlayDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
struct SDL_PrivateAudioData *audiodata = _this->hidden;
|
||||||
SLresult result;
|
SLresult result;
|
||||||
|
|
||||||
LOGV("======openslES_PlayDevice()======");
|
LOGV("======openslES_PlayDevice()======");
|
||||||
|
|
||||||
/* Queue it up */
|
/* Queue it up */
|
||||||
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
|
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], _this->spec.size);
|
||||||
|
|
||||||
audiodata->next_buffer++;
|
audiodata->next_buffer++;
|
||||||
if (audiodata->next_buffer >= NUM_BUFFERS) {
|
if (audiodata->next_buffer >= NUM_BUFFERS) {
|
||||||
|
@ -663,28 +663,28 @@ static void openslES_PlayDevice(_THIS)
|
||||||
/* */
|
/* */
|
||||||
/* okay.. */
|
/* okay.. */
|
||||||
|
|
||||||
static Uint8 *openslES_GetDeviceBuf(_THIS)
|
static Uint8 *openslES_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
struct SDL_PrivateAudioData *audiodata = _this->hidden;
|
||||||
|
|
||||||
LOGV("openslES_GetDeviceBuf()");
|
LOGV("openslES_GetDeviceBuf()");
|
||||||
return audiodata->pmixbuff[audiodata->next_buffer];
|
return audiodata->pmixbuff[audiodata->next_buffer];
|
||||||
}
|
}
|
||||||
|
|
||||||
static int openslES_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
static int openslES_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *audiodata = this->hidden;
|
struct SDL_PrivateAudioData *audiodata = _this->hidden;
|
||||||
SLresult result;
|
SLresult result;
|
||||||
|
|
||||||
/* Wait for new recorded data */
|
/* Wait for new recorded data */
|
||||||
SDL_WaitSemaphore(audiodata->playsem);
|
SDL_WaitSemaphore(audiodata->playsem);
|
||||||
|
|
||||||
/* Copy it to the output buffer */
|
/* Copy it to the output buffer */
|
||||||
SDL_assert(buflen == this->spec.size);
|
SDL_assert(buflen == _this->spec.size);
|
||||||
SDL_memcpy(buffer, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
|
SDL_memcpy(buffer, audiodata->pmixbuff[audiodata->next_buffer], _this->spec.size);
|
||||||
|
|
||||||
/* Re-enqueue the buffer */
|
/* Re-enqueue the buffer */
|
||||||
result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], this->spec.size);
|
result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], _this->spec.size);
|
||||||
if (SL_RESULT_SUCCESS != result) {
|
if (SL_RESULT_SUCCESS != result) {
|
||||||
LOGE("Record enqueue buffers failed: %d", result);
|
LOGE("Record enqueue buffers failed: %d", result);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -695,22 +695,22 @@ static int openslES_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
audiodata->next_buffer = 0;
|
audiodata->next_buffer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this->spec.size;
|
return _this->spec.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void openslES_CloseDevice(_THIS)
|
static void openslES_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
/* struct SDL_PrivateAudioData *audiodata = this->hidden; */
|
/* struct SDL_PrivateAudioData *audiodata = _this->hidden; */
|
||||||
|
|
||||||
if (this->iscapture) {
|
if (_this->iscapture) {
|
||||||
LOGI("openslES_CloseDevice() for capture");
|
LOGI("openslES_CloseDevice() for capture");
|
||||||
openslES_DestroyPCMRecorder(this);
|
openslES_DestroyPCMRecorder(_this);
|
||||||
} else {
|
} else {
|
||||||
LOGI("openslES_CloseDevice() for playing");
|
LOGI("openslES_CloseDevice() for playing");
|
||||||
openslES_DestroyPCMPlayer(this);
|
openslES_DestroyPCMPlayer(_this);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_free(this->hidden);
|
SDL_free(_this->hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_bool openslES_Init(SDL_AudioDriverImpl *impl)
|
static SDL_bool openslES_Init(SDL_AudioDriverImpl *impl)
|
||||||
|
|
|
@ -25,9 +25,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
#define NUM_BUFFERS 2 /* -- Don't lower this! */
|
#define NUM_BUFFERS 2 /* -- Don't lower this! */
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
|
|
|
@ -942,11 +942,11 @@ static void output_callback(void *data)
|
||||||
struct spa_buffer *spa_buf;
|
struct spa_buffer *spa_buf;
|
||||||
Uint8 *dst;
|
Uint8 *dst;
|
||||||
|
|
||||||
_THIS = (SDL_AudioDevice *)data;
|
SDL_AudioDevice *_this = (SDL_AudioDevice *)data;
|
||||||
struct pw_stream *stream = this->hidden->stream;
|
struct pw_stream *stream = _this->hidden->stream;
|
||||||
|
|
||||||
/* Shutting down, don't do anything */
|
/* Shutting down, don't do anything */
|
||||||
if (SDL_AtomicGet(&this->shutdown)) {
|
if (SDL_AtomicGet(&_this->shutdown)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -967,37 +967,37 @@ static void output_callback(void *data)
|
||||||
* and run the callback with the work buffer to keep the callback
|
* and run the callback with the work buffer to keep the callback
|
||||||
* firing regularly in case the audio is being used as a timer.
|
* firing regularly in case the audio is being used as a timer.
|
||||||
*/
|
*/
|
||||||
SDL_LockMutex(this->mixer_lock);
|
SDL_LockMutex(_this->mixer_lock);
|
||||||
if (!SDL_AtomicGet(&this->paused)) {
|
if (!SDL_AtomicGet(&_this->paused)) {
|
||||||
if (SDL_AtomicGet(&this->enabled)) {
|
if (SDL_AtomicGet(&_this->enabled)) {
|
||||||
dst = spa_buf->datas[0].data;
|
dst = spa_buf->datas[0].data;
|
||||||
} else {
|
} else {
|
||||||
dst = this->work_buffer;
|
dst = _this->work_buffer;
|
||||||
SDL_memset(spa_buf->datas[0].data, this->spec.silence, this->spec.size);
|
SDL_memset(spa_buf->datas[0].data, _this->spec.silence, _this->spec.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->stream) {
|
if (!_this->stream) {
|
||||||
this->callbackspec.callback(this->callbackspec.userdata, dst, this->callbackspec.size);
|
_this->callbackspec.callback(_this->callbackspec.userdata, dst, _this->callbackspec.size);
|
||||||
} else {
|
} else {
|
||||||
int got;
|
int got;
|
||||||
|
|
||||||
/* Fire the callback until we have enough to fill a buffer */
|
/* Fire the callback until we have enough to fill a buffer */
|
||||||
while (SDL_GetAudioStreamAvailable(this->stream) < this->spec.size) {
|
while (SDL_GetAudioStreamAvailable(_this->stream) < _this->spec.size) {
|
||||||
this->callbackspec.callback(this->callbackspec.userdata, this->work_buffer, this->callbackspec.size);
|
_this->callbackspec.callback(_this->callbackspec.userdata, _this->work_buffer, _this->callbackspec.size);
|
||||||
SDL_PutAudioStreamData(this->stream, this->work_buffer, this->callbackspec.size);
|
SDL_PutAudioStreamData(_this->stream, _this->work_buffer, _this->callbackspec.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
got = SDL_GetAudioStreamData(this->stream, dst, this->spec.size);
|
got = SDL_GetAudioStreamData(_this->stream, dst, _this->spec.size);
|
||||||
SDL_assert(got == this->spec.size);
|
SDL_assert(got == _this->spec.size);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SDL_memset(spa_buf->datas[0].data, this->spec.silence, this->spec.size);
|
SDL_memset(spa_buf->datas[0].data, _this->spec.silence, _this->spec.size);
|
||||||
}
|
}
|
||||||
SDL_UnlockMutex(this->mixer_lock);
|
SDL_UnlockMutex(_this->mixer_lock);
|
||||||
|
|
||||||
spa_buf->datas[0].chunk->offset = 0;
|
spa_buf->datas[0].chunk->offset = 0;
|
||||||
spa_buf->datas[0].chunk->stride = this->hidden->stride;
|
spa_buf->datas[0].chunk->stride = _this->hidden->stride;
|
||||||
spa_buf->datas[0].chunk->size = this->spec.size;
|
spa_buf->datas[0].chunk->size = _this->spec.size;
|
||||||
|
|
||||||
PIPEWIRE_pw_stream_queue_buffer(stream, pw_buf);
|
PIPEWIRE_pw_stream_queue_buffer(stream, pw_buf);
|
||||||
}
|
}
|
||||||
|
@ -1007,11 +1007,11 @@ static void input_callback(void *data)
|
||||||
struct pw_buffer *pw_buf;
|
struct pw_buffer *pw_buf;
|
||||||
struct spa_buffer *spa_buf;
|
struct spa_buffer *spa_buf;
|
||||||
Uint8 *src;
|
Uint8 *src;
|
||||||
_THIS = (SDL_AudioDevice *)data;
|
SDL_AudioDevice *_this = (SDL_AudioDevice *)data;
|
||||||
struct pw_stream *stream = this->hidden->stream;
|
struct pw_stream *stream = _this->hidden->stream;
|
||||||
|
|
||||||
/* Shutting down, don't do anything */
|
/* Shutting down, don't do anything */
|
||||||
if (SDL_AtomicGet(&this->shutdown)) {
|
if (SDL_AtomicGet(&_this->shutdown)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1026,7 +1026,7 @@ static void input_callback(void *data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SDL_AtomicGet(&this->paused)) {
|
if (!SDL_AtomicGet(&_this->paused)) {
|
||||||
/* Calculate the offset and data size */
|
/* Calculate the offset and data size */
|
||||||
const Uint32 offset = SPA_MIN(spa_buf->datas[0].chunk->offset, spa_buf->datas[0].maxsize);
|
const Uint32 offset = SPA_MIN(spa_buf->datas[0].chunk->offset, spa_buf->datas[0].maxsize);
|
||||||
const Uint32 size = SPA_MIN(spa_buf->datas[0].chunk->size, spa_buf->datas[0].maxsize - offset);
|
const Uint32 size = SPA_MIN(spa_buf->datas[0].chunk->size, spa_buf->datas[0].maxsize - offset);
|
||||||
|
@ -1034,23 +1034,23 @@ static void input_callback(void *data)
|
||||||
src += offset;
|
src += offset;
|
||||||
|
|
||||||
/* Fill the buffer with silence if the stream is disabled. */
|
/* Fill the buffer with silence if the stream is disabled. */
|
||||||
if (!SDL_AtomicGet(&this->enabled)) {
|
if (!SDL_AtomicGet(&_this->enabled)) {
|
||||||
SDL_memset(src, this->callbackspec.silence, size);
|
SDL_memset(src, _this->callbackspec.silence, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pipewire can vary the latency, so buffer all incoming data */
|
/* Pipewire can vary the latency, so buffer all incoming data */
|
||||||
SDL_WriteToDataQueue(this->hidden->buffer, src, size);
|
SDL_WriteToDataQueue(_this->hidden->buffer, src, size);
|
||||||
|
|
||||||
while (SDL_GetDataQueueSize(this->hidden->buffer) >= this->callbackspec.size) {
|
while (SDL_GetDataQueueSize(_this->hidden->buffer) >= _this->callbackspec.size) {
|
||||||
SDL_ReadFromDataQueue(this->hidden->buffer, this->work_buffer, this->callbackspec.size);
|
SDL_ReadFromDataQueue(_this->hidden->buffer, _this->work_buffer, _this->callbackspec.size);
|
||||||
|
|
||||||
SDL_LockMutex(this->mixer_lock);
|
SDL_LockMutex(_this->mixer_lock);
|
||||||
this->callbackspec.callback(this->callbackspec.userdata, this->work_buffer, this->callbackspec.size);
|
_this->callbackspec.callback(_this->callbackspec.userdata, _this->work_buffer, _this->callbackspec.size);
|
||||||
SDL_UnlockMutex(this->mixer_lock);
|
SDL_UnlockMutex(_this->mixer_lock);
|
||||||
}
|
}
|
||||||
} else if (this->hidden->buffer) { /* Flush the buffer when paused */
|
} else if (_this->hidden->buffer) { /* Flush the buffer when paused */
|
||||||
if (SDL_GetDataQueueSize(this->hidden->buffer) != 0) {
|
if (SDL_GetDataQueueSize(_this->hidden->buffer) != 0) {
|
||||||
SDL_ClearDataQueue(this->hidden->buffer, this->hidden->input_buffer_packet_size);
|
SDL_ClearDataQueue(_this->hidden->buffer, _this->hidden->input_buffer_packet_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1059,18 +1059,18 @@ static void input_callback(void *data)
|
||||||
|
|
||||||
static void stream_add_buffer_callback(void *data, struct pw_buffer *buffer)
|
static void stream_add_buffer_callback(void *data, struct pw_buffer *buffer)
|
||||||
{
|
{
|
||||||
_THIS = data;
|
SDL_AudioDevice *_this = data;
|
||||||
|
|
||||||
if (this->iscapture == SDL_FALSE) {
|
if (_this->iscapture == SDL_FALSE) {
|
||||||
/*
|
/*
|
||||||
* Clamp the output spec samples and size to the max size of the Pipewire buffer.
|
* Clamp the output spec samples and size to the max size of the Pipewire buffer.
|
||||||
* If they exceed the maximum size of the Pipewire buffer, double buffering will be used.
|
* If they exceed the maximum size of the Pipewire buffer, double buffering will be used.
|
||||||
*/
|
*/
|
||||||
if (this->spec.size > buffer->buffer->datas[0].maxsize) {
|
if (_this->spec.size > buffer->buffer->datas[0].maxsize) {
|
||||||
this->spec.samples = buffer->buffer->datas[0].maxsize / this->hidden->stride;
|
_this->spec.samples = buffer->buffer->datas[0].maxsize / _this->hidden->stride;
|
||||||
this->spec.size = buffer->buffer->datas[0].maxsize;
|
_this->spec.size = buffer->buffer->datas[0].maxsize;
|
||||||
}
|
}
|
||||||
} else if (this->hidden->buffer == NULL) {
|
} else if (_this->hidden->buffer == NULL) {
|
||||||
/*
|
/*
|
||||||
* The latency of source nodes can change, so buffering is always required.
|
* The latency of source nodes can change, so buffering is always required.
|
||||||
*
|
*
|
||||||
|
@ -1079,24 +1079,24 @@ static void stream_add_buffer_callback(void *data, struct pw_buffer *buffer)
|
||||||
*
|
*
|
||||||
* A packet size of 2 periods should be more than is ever needed.
|
* A packet size of 2 periods should be more than is ever needed.
|
||||||
*/
|
*/
|
||||||
this->hidden->input_buffer_packet_size = SPA_MAX(this->spec.size, buffer->buffer->datas[0].maxsize) * 2;
|
_this->hidden->input_buffer_packet_size = SPA_MAX(_this->spec.size, buffer->buffer->datas[0].maxsize) * 2;
|
||||||
this->hidden->buffer = SDL_CreateDataQueue(this->hidden->input_buffer_packet_size, this->hidden->input_buffer_packet_size);
|
_this->hidden->buffer = SDL_CreateDataQueue(_this->hidden->input_buffer_packet_size, _this->hidden->input_buffer_packet_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->stream_init_status |= PW_READY_FLAG_BUFFER_ADDED;
|
_this->hidden->stream_init_status |= PW_READY_FLAG_BUFFER_ADDED;
|
||||||
PIPEWIRE_pw_thread_loop_signal(this->hidden->loop, false);
|
PIPEWIRE_pw_thread_loop_signal(_this->hidden->loop, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stream_state_changed_callback(void *data, enum pw_stream_state old, enum pw_stream_state state, const char *error)
|
static void stream_state_changed_callback(void *data, enum pw_stream_state old, enum pw_stream_state state, const char *error)
|
||||||
{
|
{
|
||||||
_THIS = data;
|
SDL_AudioDevice *_this = data;
|
||||||
|
|
||||||
if (state == PW_STREAM_STATE_STREAMING) {
|
if (state == PW_STREAM_STATE_STREAMING) {
|
||||||
this->hidden->stream_init_status |= PW_READY_FLAG_STREAM_READY;
|
_this->hidden->stream_init_status |= PW_READY_FLAG_STREAM_READY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == PW_STREAM_STATE_STREAMING || state == PW_STREAM_STATE_ERROR) {
|
if (state == PW_STREAM_STATE_STREAMING || state == PW_STREAM_STATE_ERROR) {
|
||||||
PIPEWIRE_pw_thread_loop_signal(this->hidden->loop, false);
|
PIPEWIRE_pw_thread_loop_signal(_this->hidden->loop, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1109,7 +1109,7 @@ static const struct pw_stream_events stream_input_events = { PW_VERSION_STREAM_E
|
||||||
.add_buffer = stream_add_buffer_callback,
|
.add_buffer = stream_add_buffer_callback,
|
||||||
.process = input_callback };
|
.process = input_callback };
|
||||||
|
|
||||||
static int PIPEWIRE_OpenDevice(_THIS, const char *devname)
|
static int PIPEWIRE_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* NOTE: The PW_STREAM_FLAG_RT_PROCESS flag can be set to call the stream
|
* NOTE: The PW_STREAM_FLAG_RT_PROCESS flag can be set to call the stream
|
||||||
|
@ -1128,12 +1128,12 @@ static int PIPEWIRE_OpenDevice(_THIS, const char *devname)
|
||||||
struct SDL_PrivateAudioData *priv;
|
struct SDL_PrivateAudioData *priv;
|
||||||
struct pw_properties *props;
|
struct pw_properties *props;
|
||||||
const char *app_name, *stream_name, *stream_role, *error;
|
const char *app_name, *stream_name, *stream_role, *error;
|
||||||
Uint32 node_id = this->handle == NULL ? PW_ID_ANY : PW_HANDLE_TO_ID(this->handle);
|
Uint32 node_id = _this->handle == NULL ? PW_ID_ANY : PW_HANDLE_TO_ID(_this->handle);
|
||||||
SDL_bool iscapture = this->iscapture;
|
SDL_bool iscapture = _this->iscapture;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
/* Clamp the period size to sane values */
|
/* Clamp the period size to sane values */
|
||||||
const int min_period = PW_MIN_SAMPLES * SPA_MAX(this->spec.freq / PW_BASE_CLOCK_RATE, 1);
|
const int min_period = PW_MIN_SAMPLES * SPA_MAX(_this->spec.freq / PW_BASE_CLOCK_RATE, 1);
|
||||||
|
|
||||||
/* Get the hints for the application name, stream name and role */
|
/* Get the hints for the application name, stream name and role */
|
||||||
app_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME);
|
app_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME);
|
||||||
|
@ -1159,27 +1159,27 @@ static int PIPEWIRE_OpenDevice(_THIS, const char *devname)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the Pipewire stream info from the SDL audio spec */
|
/* Initialize the Pipewire stream info from the SDL audio spec */
|
||||||
initialize_spa_info(&this->spec, &spa_info);
|
initialize_spa_info(&_this->spec, &spa_info);
|
||||||
params = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &spa_info);
|
params = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &spa_info);
|
||||||
if (params == NULL) {
|
if (params == NULL) {
|
||||||
return SDL_SetError("Pipewire: Failed to set audio format parameters");
|
return SDL_SetError("Pipewire: Failed to set audio format parameters");
|
||||||
}
|
}
|
||||||
|
|
||||||
priv = SDL_calloc(1, sizeof(struct SDL_PrivateAudioData));
|
priv = SDL_calloc(1, sizeof(struct SDL_PrivateAudioData));
|
||||||
this->hidden = priv;
|
_this->hidden = priv;
|
||||||
if (priv == NULL) {
|
if (priv == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Size of a single audio frame in bytes */
|
/* Size of a single audio frame in bytes */
|
||||||
priv->stride = (SDL_AUDIO_BITSIZE(this->spec.format) >> 3) * this->spec.channels;
|
priv->stride = (SDL_AUDIO_BITSIZE(_this->spec.format) >> 3) * _this->spec.channels;
|
||||||
|
|
||||||
if (this->spec.samples < min_period) {
|
if (_this->spec.samples < min_period) {
|
||||||
this->spec.samples = min_period;
|
_this->spec.samples = min_period;
|
||||||
this->spec.size = this->spec.samples * priv->stride;
|
_this->spec.size = _this->spec.samples * priv->stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)SDL_snprintf(thread_name, sizeof(thread_name), "SDLAudio%c%ld", (iscapture) ? 'C' : 'P', (long)this->handle);
|
(void)SDL_snprintf(thread_name, sizeof(thread_name), "SDLAudio%c%ld", (iscapture) ? 'C' : 'P', (long)_this->handle);
|
||||||
priv->loop = PIPEWIRE_pw_thread_loop_new(thread_name, NULL);
|
priv->loop = PIPEWIRE_pw_thread_loop_new(thread_name, NULL);
|
||||||
if (priv->loop == NULL) {
|
if (priv->loop == NULL) {
|
||||||
return SDL_SetError("Pipewire: Failed to create stream loop (%i)", errno);
|
return SDL_SetError("Pipewire: Failed to create stream loop (%i)", errno);
|
||||||
|
@ -1207,8 +1207,8 @@ static int PIPEWIRE_OpenDevice(_THIS, const char *devname)
|
||||||
PIPEWIRE_pw_properties_set(props, PW_KEY_APP_NAME, app_name);
|
PIPEWIRE_pw_properties_set(props, PW_KEY_APP_NAME, app_name);
|
||||||
PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_NAME, stream_name);
|
PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_NAME, stream_name);
|
||||||
PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, stream_name);
|
PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, stream_name);
|
||||||
PIPEWIRE_pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%i", this->spec.samples, this->spec.freq);
|
PIPEWIRE_pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%i", _this->spec.samples, _this->spec.freq);
|
||||||
PIPEWIRE_pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", this->spec.freq);
|
PIPEWIRE_pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", _this->spec.freq);
|
||||||
PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_ALWAYS_PROCESS, "true");
|
PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_ALWAYS_PROCESS, "true");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1234,7 +1234,7 @@ static int PIPEWIRE_OpenDevice(_THIS, const char *devname)
|
||||||
|
|
||||||
/* Create the new stream */
|
/* Create the new stream */
|
||||||
priv->stream = PIPEWIRE_pw_stream_new_simple(PIPEWIRE_pw_thread_loop_get_loop(priv->loop), stream_name, props,
|
priv->stream = PIPEWIRE_pw_stream_new_simple(PIPEWIRE_pw_thread_loop_get_loop(priv->loop), stream_name, props,
|
||||||
iscapture ? &stream_input_events : &stream_output_events, this);
|
iscapture ? &stream_input_events : &stream_output_events, _this);
|
||||||
if (priv->stream == NULL) {
|
if (priv->stream == NULL) {
|
||||||
return SDL_SetError("Pipewire: Failed to create stream (%i)", errno);
|
return SDL_SetError("Pipewire: Failed to create stream (%i)", errno);
|
||||||
}
|
}
|
||||||
|
@ -1270,29 +1270,29 @@ static int PIPEWIRE_OpenDevice(_THIS, const char *devname)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PIPEWIRE_CloseDevice(_THIS)
|
static void PIPEWIRE_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (this->hidden->loop) {
|
if (_this->hidden->loop) {
|
||||||
PIPEWIRE_pw_thread_loop_stop(this->hidden->loop);
|
PIPEWIRE_pw_thread_loop_stop(_this->hidden->loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->stream) {
|
if (_this->hidden->stream) {
|
||||||
PIPEWIRE_pw_stream_destroy(this->hidden->stream);
|
PIPEWIRE_pw_stream_destroy(_this->hidden->stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->context) {
|
if (_this->hidden->context) {
|
||||||
PIPEWIRE_pw_context_destroy(this->hidden->context);
|
PIPEWIRE_pw_context_destroy(_this->hidden->context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->loop) {
|
if (_this->hidden->loop) {
|
||||||
PIPEWIRE_pw_thread_loop_destroy(this->hidden->loop);
|
PIPEWIRE_pw_thread_loop_destroy(_this->hidden->loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->buffer) {
|
if (_this->hidden->buffer) {
|
||||||
SDL_DestroyDataQueue(this->hidden->buffer);
|
SDL_DestroyDataQueue(_this->hidden->buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_free(this->hidden);
|
SDL_free(_this->hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PIPEWIRE_GetDefaultAudioInfo(char **name, SDL_AudioSpec *spec, int iscapture)
|
static int PIPEWIRE_GetDefaultAudioInfo(char **name, SDL_AudioSpec *spec, int iscapture)
|
||||||
|
|
|
@ -27,9 +27,6 @@
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
#include <pipewire/pipewire.h>
|
#include <pipewire/pipewire.h>
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
struct pw_thread_loop *loop;
|
struct pw_thread_loop *loop;
|
||||||
|
|
|
@ -33,20 +33,20 @@
|
||||||
/* The tag name used by PS2 audio */
|
/* The tag name used by PS2 audio */
|
||||||
#define PS2AUDIO_DRIVER_NAME "ps2"
|
#define PS2AUDIO_DRIVER_NAME "ps2"
|
||||||
|
|
||||||
static int PS2AUDIO_OpenDevice(_THIS, const char *devname)
|
static int PS2AUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
int i, mixlen;
|
int i, mixlen;
|
||||||
struct audsrv_fmt_t format;
|
struct audsrv_fmt_t format;
|
||||||
|
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)
|
_this->hidden = (struct SDL_PrivateAudioData *)
|
||||||
SDL_malloc(sizeof(*this->hidden));
|
SDL_malloc(sizeof(*_this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_zerop(this->hidden);
|
SDL_zerop(_this->hidden);
|
||||||
|
|
||||||
/* These are the native supported audio PS2 configs */
|
/* These are the native supported audio PS2 configs */
|
||||||
switch (this->spec.freq) {
|
switch (_this->spec.freq) {
|
||||||
case 11025:
|
case 11025:
|
||||||
case 12000:
|
case 12000:
|
||||||
case 22050:
|
case 22050:
|
||||||
|
@ -54,86 +54,86 @@ static int PS2AUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
case 32000:
|
case 32000:
|
||||||
case 44100:
|
case 44100:
|
||||||
case 48000:
|
case 48000:
|
||||||
this->spec.freq = this->spec.freq;
|
_this->spec.freq = _this->spec.freq;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this->spec.freq = 48000;
|
_this->spec.freq = 48000;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->spec.samples = 512;
|
_this->spec.samples = 512;
|
||||||
this->spec.channels = this->spec.channels == 1 ? 1 : 2;
|
_this->spec.channels = _this->spec.channels == 1 ? 1 : 2;
|
||||||
this->spec.format = this->spec.format == SDL_AUDIO_S8 ? SDL_AUDIO_S8 : SDL_AUDIO_S16;
|
_this->spec.format = _this->spec.format == SDL_AUDIO_S8 ? SDL_AUDIO_S8 : SDL_AUDIO_S16;
|
||||||
|
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
format.bits = this->spec.format == SDL_AUDIO_S8 ? 8 : 16;
|
format.bits = _this->spec.format == SDL_AUDIO_S8 ? 8 : 16;
|
||||||
format.freq = this->spec.freq;
|
format.freq = _this->spec.freq;
|
||||||
format.channels = this->spec.channels;
|
format.channels = _this->spec.channels;
|
||||||
|
|
||||||
this->hidden->channel = audsrv_set_format(&format);
|
_this->hidden->channel = audsrv_set_format(&format);
|
||||||
audsrv_set_volume(MAX_VOLUME);
|
audsrv_set_volume(MAX_VOLUME);
|
||||||
|
|
||||||
if (this->hidden->channel < 0) {
|
if (_this->hidden->channel < 0) {
|
||||||
free(this->hidden->rawbuf);
|
free(_this->hidden->rawbuf);
|
||||||
this->hidden->rawbuf = NULL;
|
_this->hidden->rawbuf = NULL;
|
||||||
return SDL_SetError("Couldn't reserve hardware channel");
|
return SDL_SetError("Couldn't reserve hardware channel");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the fragment size as size in bytes. */
|
/* Update the fragment size as size in bytes. */
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
/* Allocate the mixing buffer. Its size and starting address must
|
/* Allocate the mixing buffer. Its size and starting address must
|
||||||
be a multiple of 64 bytes. Our sample count is already a multiple of
|
be a multiple of 64 bytes. Our sample count is already a multiple of
|
||||||
64, so spec->size should be a multiple of 64 as well. */
|
64, so spec->size should be a multiple of 64 as well. */
|
||||||
mixlen = this->spec.size * NUM_BUFFERS;
|
mixlen = _this->spec.size * NUM_BUFFERS;
|
||||||
this->hidden->rawbuf = (Uint8 *)memalign(64, mixlen);
|
_this->hidden->rawbuf = (Uint8 *)memalign(64, mixlen);
|
||||||
if (this->hidden->rawbuf == NULL) {
|
if (_this->hidden->rawbuf == NULL) {
|
||||||
return SDL_SetError("Couldn't allocate mixing buffer");
|
return SDL_SetError("Couldn't allocate mixing buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_memset(this->hidden->rawbuf, 0, mixlen);
|
SDL_memset(_this->hidden->rawbuf, 0, mixlen);
|
||||||
for (i = 0; i < NUM_BUFFERS; i++) {
|
for (i = 0; i < NUM_BUFFERS; i++) {
|
||||||
this->hidden->mixbufs[i] = &this->hidden->rawbuf[i * this->spec.size];
|
_this->hidden->mixbufs[i] = &_this->hidden->rawbuf[i * _this->spec.size];
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->next_buffer = 0;
|
_this->hidden->next_buffer = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PS2AUDIO_PlayDevice(_THIS)
|
static void PS2AUDIO_PlayDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
uint8_t *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer];
|
uint8_t *mixbuf = _this->hidden->mixbufs[_this->hidden->next_buffer];
|
||||||
audsrv_play_audio((char *)mixbuf, this->spec.size);
|
audsrv_play_audio((char *)mixbuf, _this->spec.size);
|
||||||
|
|
||||||
this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
|
_this->hidden->next_buffer = (_this->hidden->next_buffer + 1) % NUM_BUFFERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function waits until it is possible to write a full sound buffer */
|
/* This function waits until it is possible to write a full sound buffer */
|
||||||
static void PS2AUDIO_WaitDevice(_THIS)
|
static void PS2AUDIO_WaitDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
audsrv_wait_audio(this->spec.size);
|
audsrv_wait_audio(_this->spec.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *PS2AUDIO_GetDeviceBuf(_THIS)
|
static Uint8 *PS2AUDIO_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
return this->hidden->mixbufs[this->hidden->next_buffer];
|
return _this->hidden->mixbufs[_this->hidden->next_buffer];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PS2AUDIO_CloseDevice(_THIS)
|
static void PS2AUDIO_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (this->hidden->channel >= 0) {
|
if (_this->hidden->channel >= 0) {
|
||||||
audsrv_stop_audio();
|
audsrv_stop_audio();
|
||||||
this->hidden->channel = -1;
|
_this->hidden->channel = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->rawbuf != NULL) {
|
if (_this->hidden->rawbuf != NULL) {
|
||||||
free(this->hidden->rawbuf);
|
free(_this->hidden->rawbuf);
|
||||||
this->hidden->rawbuf = NULL;
|
_this->hidden->rawbuf = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PS2AUDIO_ThreadInit(_THIS)
|
static void PS2AUDIO_ThreadInit(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
/* Increase the priority of this audio thread by 1 to put it
|
/* Increase the priority of this audio thread by 1 to put it
|
||||||
ahead of other SDL threads. */
|
ahead of other SDL threads. */
|
||||||
|
|
|
@ -25,9 +25,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
#define NUM_BUFFERS 2
|
#define NUM_BUFFERS 2
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
|
|
|
@ -43,33 +43,33 @@ static inline SDL_bool isBasicAudioConfig(const SDL_AudioSpec *spec)
|
||||||
return spec->freq == 44100;
|
return spec->freq == 44100;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PSPAUDIO_OpenDevice(_THIS, const char *devname)
|
static int PSPAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
int format, mixlen, i;
|
int format, mixlen, i;
|
||||||
|
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)
|
_this->hidden = (struct SDL_PrivateAudioData *)
|
||||||
SDL_malloc(sizeof(*this->hidden));
|
SDL_malloc(sizeof(*_this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_zerop(this->hidden);
|
SDL_zerop(_this->hidden);
|
||||||
|
|
||||||
/* device only natively supports S16LSB */
|
/* device only natively supports S16LSB */
|
||||||
this->spec.format = SDL_AUDIO_S16LSB;
|
_this->spec.format = SDL_AUDIO_S16LSB;
|
||||||
|
|
||||||
/* PSP has some limitations with the Audio. It fully supports 44.1KHz (Mono & Stereo),
|
/* PSP has some limitations with the Audio. It fully supports 44.1KHz (Mono & Stereo),
|
||||||
however with frequencies differents than 44.1KHz, it just supports Stereo,
|
however with frequencies differents than 44.1KHz, it just supports Stereo,
|
||||||
so a resampler must be done for these scenarios */
|
so a resampler must be done for these scenarios */
|
||||||
if (isBasicAudioConfig(&this->spec)) {
|
if (isBasicAudioConfig(&_this->spec)) {
|
||||||
/* The sample count must be a multiple of 64. */
|
/* The sample count must be a multiple of 64. */
|
||||||
this->spec.samples = PSP_AUDIO_SAMPLE_ALIGN(this->spec.samples);
|
_this->spec.samples = PSP_AUDIO_SAMPLE_ALIGN(_this->spec.samples);
|
||||||
/* The number of channels (1 or 2). */
|
/* The number of channels (1 or 2). */
|
||||||
this->spec.channels = this->spec.channels == 1 ? 1 : 2;
|
_this->spec.channels = _this->spec.channels == 1 ? 1 : 2;
|
||||||
format = this->spec.channels == 1 ? PSP_AUDIO_FORMAT_MONO : PSP_AUDIO_FORMAT_STEREO;
|
format = _this->spec.channels == 1 ? PSP_AUDIO_FORMAT_MONO : PSP_AUDIO_FORMAT_STEREO;
|
||||||
this->hidden->channel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, this->spec.samples, format);
|
_this->hidden->channel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, _this->spec.samples, format);
|
||||||
} else {
|
} else {
|
||||||
/* 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11050, 8000 */
|
/* 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11050, 8000 */
|
||||||
switch (this->spec.freq) {
|
switch (_this->spec.freq) {
|
||||||
case 8000:
|
case 8000:
|
||||||
case 11025:
|
case 11025:
|
||||||
case 12000:
|
case 12000:
|
||||||
|
@ -79,87 +79,87 @@ static int PSPAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
case 32000:
|
case 32000:
|
||||||
case 44100:
|
case 44100:
|
||||||
case 48000:
|
case 48000:
|
||||||
this->spec.freq = this->spec.freq;
|
_this->spec.freq = _this->spec.freq;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this->spec.freq = 48000;
|
_this->spec.freq = 48000;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* The number of samples to output in one output call (min 17, max 4111). */
|
/* The number of samples to output in one output call (min 17, max 4111). */
|
||||||
this->spec.samples = this->spec.samples < 17 ? 17 : (this->spec.samples > 4111 ? 4111 : this->spec.samples);
|
_this->spec.samples = _this->spec.samples < 17 ? 17 : (_this->spec.samples > 4111 ? 4111 : _this->spec.samples);
|
||||||
this->spec.channels = 2; /* we're forcing the hardware to stereo. */
|
_this->spec.channels = 2; /* we're forcing the hardware to stereo. */
|
||||||
this->hidden->channel = sceAudioSRCChReserve(this->spec.samples, this->spec.freq, 2);
|
_this->hidden->channel = sceAudioSRCChReserve(_this->spec.samples, _this->spec.freq, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->channel < 0) {
|
if (_this->hidden->channel < 0) {
|
||||||
free(this->hidden->rawbuf);
|
free(_this->hidden->rawbuf);
|
||||||
this->hidden->rawbuf = NULL;
|
_this->hidden->rawbuf = NULL;
|
||||||
return SDL_SetError("Couldn't reserve hardware channel");
|
return SDL_SetError("Couldn't reserve hardware channel");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the fragment size as size in bytes. */
|
/* Update the fragment size as size in bytes. */
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
/* Allocate the mixing buffer. Its size and starting address must
|
/* Allocate the mixing buffer. Its size and starting address must
|
||||||
be a multiple of 64 bytes. Our sample count is already a multiple of
|
be a multiple of 64 bytes. Our sample count is already a multiple of
|
||||||
64, so spec->size should be a multiple of 64 as well. */
|
64, so spec->size should be a multiple of 64 as well. */
|
||||||
mixlen = this->spec.size * NUM_BUFFERS;
|
mixlen = _this->spec.size * NUM_BUFFERS;
|
||||||
this->hidden->rawbuf = (Uint8 *)memalign(64, mixlen);
|
_this->hidden->rawbuf = (Uint8 *)memalign(64, mixlen);
|
||||||
if (this->hidden->rawbuf == NULL) {
|
if (_this->hidden->rawbuf == NULL) {
|
||||||
return SDL_SetError("Couldn't allocate mixing buffer");
|
return SDL_SetError("Couldn't allocate mixing buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_memset(this->hidden->rawbuf, 0, mixlen);
|
SDL_memset(_this->hidden->rawbuf, 0, mixlen);
|
||||||
for (i = 0; i < NUM_BUFFERS; i++) {
|
for (i = 0; i < NUM_BUFFERS; i++) {
|
||||||
this->hidden->mixbufs[i] = &this->hidden->rawbuf[i * this->spec.size];
|
_this->hidden->mixbufs[i] = &_this->hidden->rawbuf[i * _this->spec.size];
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->next_buffer = 0;
|
_this->hidden->next_buffer = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PSPAUDIO_PlayDevice(_THIS)
|
static void PSPAUDIO_PlayDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer];
|
Uint8 *mixbuf = _this->hidden->mixbufs[_this->hidden->next_buffer];
|
||||||
if (!isBasicAudioConfig(&this->spec)) {
|
if (!isBasicAudioConfig(&_this->spec)) {
|
||||||
SDL_assert(this->spec.channels == 2);
|
SDL_assert(_this->spec.channels == 2);
|
||||||
sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, mixbuf);
|
sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, mixbuf);
|
||||||
} else {
|
} else {
|
||||||
sceAudioOutputPannedBlocking(this->hidden->channel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, mixbuf);
|
sceAudioOutputPannedBlocking(_this->hidden->channel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, mixbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
|
_this->hidden->next_buffer = (_this->hidden->next_buffer + 1) % NUM_BUFFERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function waits until it is possible to write a full sound buffer */
|
/* This function waits until it is possible to write a full sound buffer */
|
||||||
static void PSPAUDIO_WaitDevice(_THIS)
|
static void PSPAUDIO_WaitDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
/* Because we block when sending audio, there's no need for this function to do anything. */
|
/* Because we block when sending audio, there's no need for this function to do anything. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *PSPAUDIO_GetDeviceBuf(_THIS)
|
static Uint8 *PSPAUDIO_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
return this->hidden->mixbufs[this->hidden->next_buffer];
|
return _this->hidden->mixbufs[_this->hidden->next_buffer];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PSPAUDIO_CloseDevice(_THIS)
|
static void PSPAUDIO_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (this->hidden->channel >= 0) {
|
if (_this->hidden->channel >= 0) {
|
||||||
if (!isBasicAudioConfig(&this->spec)) {
|
if (!isBasicAudioConfig(&_this->spec)) {
|
||||||
sceAudioSRCChRelease();
|
sceAudioSRCChRelease();
|
||||||
} else {
|
} else {
|
||||||
sceAudioChRelease(this->hidden->channel);
|
sceAudioChRelease(_this->hidden->channel);
|
||||||
}
|
}
|
||||||
this->hidden->channel = -1;
|
_this->hidden->channel = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->rawbuf != NULL) {
|
if (_this->hidden->rawbuf != NULL) {
|
||||||
free(this->hidden->rawbuf);
|
free(_this->hidden->rawbuf);
|
||||||
this->hidden->rawbuf = NULL;
|
_this->hidden->rawbuf = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PSPAUDIO_ThreadInit(_THIS)
|
static void PSPAUDIO_ThreadInit(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
/* Increase the priority of this audio thread by 1 to put it
|
/* Increase the priority of this audio thread by 1 to put it
|
||||||
ahead of other SDL threads. */
|
ahead of other SDL threads. */
|
||||||
|
|
|
@ -24,9 +24,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
#define NUM_BUFFERS 2
|
#define NUM_BUFFERS 2
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
|
|
|
@ -332,7 +332,7 @@ static int ConnectToPulseServer(pa_mainloop **_mainloop, pa_context **_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function waits until it is possible to write a full sound buffer */
|
/* This function waits until it is possible to write a full sound buffer */
|
||||||
static void PULSEAUDIO_WaitDevice(_THIS)
|
static void PULSEAUDIO_WaitDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
/* this is a no-op; we wait in PULSEAUDIO_PlayDevice now. */
|
/* this is a no-op; we wait in PULSEAUDIO_PlayDevice now. */
|
||||||
}
|
}
|
||||||
|
@ -344,20 +344,20 @@ static void WriteCallback(pa_stream *p, size_t nbytes, void *userdata)
|
||||||
h->bytes_requested += nbytes;
|
h->bytes_requested += nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PULSEAUDIO_PlayDevice(_THIS)
|
static void PULSEAUDIO_PlayDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *h = this->hidden;
|
struct SDL_PrivateAudioData *h = _this->hidden;
|
||||||
int available = h->mixlen;
|
int available = h->mixlen;
|
||||||
int written = 0;
|
int written = 0;
|
||||||
int cpy;
|
int cpy;
|
||||||
|
|
||||||
/*printf("PULSEAUDIO PLAYDEVICE START! mixlen=%d\n", available);*/
|
/*printf("PULSEAUDIO PLAYDEVICE START! mixlen=%d\n", available);*/
|
||||||
|
|
||||||
while (SDL_AtomicGet(&this->enabled) && (available > 0)) {
|
while (SDL_AtomicGet(&_this->enabled) && (available > 0)) {
|
||||||
cpy = SDL_min(h->bytes_requested, available);
|
cpy = SDL_min(h->bytes_requested, available);
|
||||||
if (cpy) {
|
if (cpy) {
|
||||||
if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf + written, cpy, NULL, 0LL, PA_SEEK_RELATIVE) < 0) {
|
if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf + written, cpy, NULL, 0LL, PA_SEEK_RELATIVE) < 0) {
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*printf("PULSEAUDIO FEED! nbytes=%u\n", (unsigned int) cpy);*/
|
/*printf("PULSEAUDIO FEED! nbytes=%u\n", (unsigned int) cpy);*/
|
||||||
|
@ -371,7 +371,7 @@ static void PULSEAUDIO_PlayDevice(_THIS)
|
||||||
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
|
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
|
||||||
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
|
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
|
||||||
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
|
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -379,18 +379,18 @@ static void PULSEAUDIO_PlayDevice(_THIS)
|
||||||
/*printf("PULSEAUDIO PLAYDEVICE END! written=%d\n", written);*/
|
/*printf("PULSEAUDIO PLAYDEVICE END! written=%d\n", written);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *PULSEAUDIO_GetDeviceBuf(_THIS)
|
static Uint8 *PULSEAUDIO_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
return this->hidden->mixbuf;
|
return _this->hidden->mixbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PULSEAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
static int PULSEAUDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *h = this->hidden;
|
struct SDL_PrivateAudioData *h = _this->hidden;
|
||||||
const void *data = NULL;
|
const void *data = NULL;
|
||||||
size_t nbytes = 0;
|
size_t nbytes = 0;
|
||||||
|
|
||||||
while (SDL_AtomicGet(&this->enabled)) {
|
while (SDL_AtomicGet(&_this->enabled)) {
|
||||||
if (h->capturebuf != NULL) {
|
if (h->capturebuf != NULL) {
|
||||||
const int cpy = SDL_min(buflen, h->capturelen);
|
const int cpy = SDL_min(buflen, h->capturelen);
|
||||||
SDL_memcpy(buffer, h->capturebuf, cpy);
|
SDL_memcpy(buffer, h->capturebuf, cpy);
|
||||||
|
@ -407,7 +407,7 @@ static int PULSEAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
|
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
|
||||||
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
|
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
|
||||||
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
|
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||||
return -1; /* uhoh, pulse failed! */
|
return -1; /* uhoh, pulse failed! */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,9 +432,9 @@ static int PULSEAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
return -1; /* not enabled? */
|
return -1; /* not enabled? */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PULSEAUDIO_FlushCapture(_THIS)
|
static void PULSEAUDIO_FlushCapture(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *h = this->hidden;
|
struct SDL_PrivateAudioData *h = _this->hidden;
|
||||||
const void *data = NULL;
|
const void *data = NULL;
|
||||||
size_t nbytes = 0;
|
size_t nbytes = 0;
|
||||||
|
|
||||||
|
@ -444,11 +444,11 @@ static void PULSEAUDIO_FlushCapture(_THIS)
|
||||||
h->capturelen = 0;
|
h->capturelen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (SDL_AtomicGet(&this->enabled)) {
|
while (SDL_AtomicGet(&_this->enabled)) {
|
||||||
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
|
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
|
||||||
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
|
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
|
||||||
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
|
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||||
return; /* uhoh, pulse failed! */
|
return; /* uhoh, pulse failed! */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,20 +462,20 @@ static void PULSEAUDIO_FlushCapture(_THIS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PULSEAUDIO_CloseDevice(_THIS)
|
static void PULSEAUDIO_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (this->hidden->stream) {
|
if (_this->hidden->stream) {
|
||||||
if (this->hidden->capturebuf != NULL) {
|
if (_this->hidden->capturebuf != NULL) {
|
||||||
PULSEAUDIO_pa_stream_drop(this->hidden->stream);
|
PULSEAUDIO_pa_stream_drop(_this->hidden->stream);
|
||||||
}
|
}
|
||||||
PULSEAUDIO_pa_stream_disconnect(this->hidden->stream);
|
PULSEAUDIO_pa_stream_disconnect(_this->hidden->stream);
|
||||||
PULSEAUDIO_pa_stream_unref(this->hidden->stream);
|
PULSEAUDIO_pa_stream_unref(_this->hidden->stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context);
|
DisconnectFromPulseServer(_this->hidden->mainloop, _this->hidden->context);
|
||||||
SDL_free(this->hidden->mixbuf);
|
SDL_free(_this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden->device_name);
|
SDL_free(_this->hidden->device_name);
|
||||||
SDL_free(this->hidden);
|
SDL_free(_this->hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SinkDeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
|
static void SinkDeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data)
|
||||||
|
@ -515,7 +515,7 @@ static SDL_bool FindDeviceName(struct SDL_PrivateAudioData *h, const SDL_bool is
|
||||||
return h->device_name != NULL;
|
return h->device_name != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int PULSEAUDIO_OpenDevice(_THIS, const char *devname)
|
static int PULSEAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *h = NULL;
|
struct SDL_PrivateAudioData *h = NULL;
|
||||||
SDL_AudioFormat test_format;
|
SDL_AudioFormat test_format;
|
||||||
|
@ -525,19 +525,19 @@ static int PULSEAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
pa_channel_map pacmap;
|
pa_channel_map pacmap;
|
||||||
pa_stream_flags_t flags = 0;
|
pa_stream_flags_t flags = 0;
|
||||||
const char *name = NULL;
|
const char *name = NULL;
|
||||||
SDL_bool iscapture = this->iscapture;
|
SDL_bool iscapture = _this->iscapture;
|
||||||
int state = 0, format = PA_SAMPLE_INVALID;
|
int state = 0, format = PA_SAMPLE_INVALID;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
/* Initialize all variables that we clean on shutdown */
|
/* Initialize all variables that we clean on shutdown */
|
||||||
h = this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*this->hidden));
|
h = _this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*_this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_zerop(this->hidden);
|
SDL_zerop(_this->hidden);
|
||||||
|
|
||||||
/* Try for a closest match on audio format */
|
/* Try for a closest match on audio format */
|
||||||
closefmts = SDL_ClosestAudioFormats(this->spec.format);
|
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
|
||||||
while ((test_format = *(closefmts++)) != 0) {
|
while ((test_format = *(closefmts++)) != 0) {
|
||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
|
fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
|
||||||
|
@ -572,27 +572,27 @@ static int PULSEAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
if (!test_format) {
|
if (!test_format) {
|
||||||
return SDL_SetError("%s: Unsupported audio format", "pulseaudio");
|
return SDL_SetError("%s: Unsupported audio format", "pulseaudio");
|
||||||
}
|
}
|
||||||
this->spec.format = test_format;
|
_this->spec.format = test_format;
|
||||||
paspec.format = format;
|
paspec.format = format;
|
||||||
|
|
||||||
/* Calculate the final parameters for this audio specification */
|
/* Calculate the final parameters for this audio specification */
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
if (!iscapture) {
|
if (!iscapture) {
|
||||||
h->mixlen = this->spec.size;
|
h->mixlen = _this->spec.size;
|
||||||
h->mixbuf = (Uint8 *)SDL_malloc(h->mixlen);
|
h->mixbuf = (Uint8 *)SDL_malloc(h->mixlen);
|
||||||
if (h->mixbuf == NULL) {
|
if (h->mixbuf == NULL) {
|
||||||
return SDL_OutOfMemory();
|
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.channels = _this->spec.channels;
|
||||||
paspec.rate = this->spec.freq;
|
paspec.rate = _this->spec.freq;
|
||||||
|
|
||||||
/* Reduced prebuffering compared to the defaults. */
|
/* Reduced prebuffering compared to the defaults. */
|
||||||
paattr.fragsize = this->spec.size;
|
paattr.fragsize = _this->spec.size;
|
||||||
paattr.tlength = h->mixlen;
|
paattr.tlength = h->mixlen;
|
||||||
paattr.prebuf = -1;
|
paattr.prebuf = -1;
|
||||||
paattr.maxlength = -1;
|
paattr.maxlength = -1;
|
||||||
|
@ -603,13 +603,13 @@ static int PULSEAUDIO_OpenDevice(_THIS, const char *devname)
|
||||||
return SDL_SetError("Could not connect to PulseAudio server");
|
return SDL_SetError("Could not connect to PulseAudio server");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FindDeviceName(h, iscapture, this->handle)) {
|
if (!FindDeviceName(h, iscapture, _this->handle)) {
|
||||||
return SDL_SetError("Requested PulseAudio sink/source missing?");
|
return SDL_SetError("Requested PulseAudio sink/source missing?");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The SDL ALSA output hints us that we use Windows' channel mapping */
|
/* The SDL ALSA output hints us that we use Windows' channel mapping */
|
||||||
/* http://bugzilla.libsdl.org/show_bug.cgi?id=110 */
|
/* http://bugzilla.libsdl.org/show_bug.cgi?id=110 */
|
||||||
PULSEAUDIO_pa_channel_map_init_auto(&pacmap, this->spec.channels,
|
PULSEAUDIO_pa_channel_map_init_auto(&pacmap, _this->spec.channels,
|
||||||
PA_CHANNEL_MAP_WAVEEX);
|
PA_CHANNEL_MAP_WAVEEX);
|
||||||
|
|
||||||
name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME);
|
name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME);
|
||||||
|
|
|
@ -27,9 +27,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
char *device_name;
|
char *device_name;
|
||||||
|
|
|
@ -81,7 +81,7 @@ QSA_SetError(const char *fn, int status)
|
||||||
|
|
||||||
/* !!! FIXME: does this need to be here? Does the SDL version not work? */
|
/* !!! FIXME: does this need to be here? Does the SDL version not work? */
|
||||||
static void
|
static void
|
||||||
QSA_ThreadInit(_THIS)
|
QSA_ThreadInit(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
/* Increase default 10 priority to 25 to avoid jerky sound */
|
/* Increase default 10 priority to 25 to avoid jerky sound */
|
||||||
struct sched_param param;
|
struct sched_param param;
|
||||||
|
@ -111,7 +111,7 @@ QSA_InitAudioParams(snd_pcm_channel_params_t * cpars)
|
||||||
|
|
||||||
/* This function waits until it is possible to write a full sound buffer */
|
/* This function waits until it is possible to write a full sound buffer */
|
||||||
static void
|
static void
|
||||||
QSA_WaitDevice(_THIS)
|
QSA_WaitDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
@ -119,8 +119,8 @@ QSA_WaitDevice(_THIS)
|
||||||
/* If timeout occured than something wrong with hardware or driver */
|
/* If timeout occured than something wrong with hardware or driver */
|
||||||
/* For example, Vortex 8820 audio driver stucks on second DAC because */
|
/* For example, Vortex 8820 audio driver stucks on second DAC because */
|
||||||
/* it doesn't exist ! */
|
/* it doesn't exist ! */
|
||||||
result = SDL_IOReady(this->hidden->audio_fd,
|
result = SDL_IOReady(_this->hidden->audio_fd,
|
||||||
this->hidden->iscapture ? SDL_IOR_READ : SDL_IOR_WRITE,
|
_this->hidden->iscapture ? SDL_IOR_READ : SDL_IOR_WRITE,
|
||||||
2 * 1000);
|
2 * 1000);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case -1:
|
case -1:
|
||||||
|
@ -128,16 +128,16 @@ QSA_WaitDevice(_THIS)
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
SDL_SetError("QSA: timeout on buffer waiting occured");
|
SDL_SetError("QSA: timeout on buffer waiting occured");
|
||||||
this->hidden->timeout_on_wait = 1;
|
_this->hidden->timeout_on_wait = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
this->hidden->timeout_on_wait = 0;
|
_this->hidden->timeout_on_wait = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
QSA_PlayDevice(_THIS)
|
QSA_PlayDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
snd_pcm_channel_status_t cstatus;
|
snd_pcm_channel_status_t cstatus;
|
||||||
int written;
|
int written;
|
||||||
|
@ -145,23 +145,23 @@ QSA_PlayDevice(_THIS)
|
||||||
int towrite;
|
int towrite;
|
||||||
void *pcmbuffer;
|
void *pcmbuffer;
|
||||||
|
|
||||||
if (!SDL_AtomicGet(&this->enabled) || !this->hidden) {
|
if (!SDL_AtomicGet(&_this->enabled) || !_this->hidden) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
towrite = this->spec.size;
|
towrite = _this->spec.size;
|
||||||
pcmbuffer = this->hidden->pcm_buf;
|
pcmbuffer = _this->hidden->pcm_buf;
|
||||||
|
|
||||||
/* Write the audio data, checking for EAGAIN (buffer full) and underrun */
|
/* Write the audio data, checking for EAGAIN (buffer full) and underrun */
|
||||||
do {
|
do {
|
||||||
written =
|
written =
|
||||||
snd_pcm_plugin_write(this->hidden->audio_handle, pcmbuffer,
|
snd_pcm_plugin_write(_this->hidden->audio_handle, pcmbuffer,
|
||||||
towrite);
|
towrite);
|
||||||
if (written != towrite) {
|
if (written != towrite) {
|
||||||
/* Check if samples playback got stuck somewhere in hardware or in */
|
/* Check if samples playback got stuck somewhere in hardware or in */
|
||||||
/* the audio device driver */
|
/* the audio device driver */
|
||||||
if ((errno == EAGAIN) && (written == 0)) {
|
if ((errno == EAGAIN) && (written == 0)) {
|
||||||
if (this->hidden->timeout_on_wait != 0) {
|
if (_this->hidden->timeout_on_wait != 0) {
|
||||||
SDL_SetError("QSA: buffer playback timeout");
|
SDL_SetError("QSA: buffer playback timeout");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -174,19 +174,19 @@ QSA_PlayDevice(_THIS)
|
||||||
|
|
||||||
/* if we wrote some data */
|
/* if we wrote some data */
|
||||||
towrite -= written;
|
towrite -= written;
|
||||||
pcmbuffer += written * this->spec.channels;
|
pcmbuffer += written * _this->spec.channels;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
if ((errno == EINVAL) || (errno == EIO)) {
|
if ((errno == EINVAL) || (errno == EIO)) {
|
||||||
SDL_zero(cstatus);
|
SDL_zero(cstatus);
|
||||||
if (!this->hidden->iscapture) {
|
if (!_this->hidden->iscapture) {
|
||||||
cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
|
cstatus.channel = SND_PCM_CHANNEL_PLAYBACK;
|
||||||
} else {
|
} else {
|
||||||
cstatus.channel = SND_PCM_CHANNEL_CAPTURE;
|
cstatus.channel = SND_PCM_CHANNEL_CAPTURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
status =
|
status =
|
||||||
snd_pcm_plugin_status(this->hidden->audio_handle,
|
snd_pcm_plugin_status(_this->hidden->audio_handle,
|
||||||
&cstatus);
|
&cstatus);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
QSA_SetError("snd_pcm_plugin_status", status);
|
QSA_SetError("snd_pcm_plugin_status", status);
|
||||||
|
@ -195,14 +195,14 @@ QSA_PlayDevice(_THIS)
|
||||||
|
|
||||||
if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) ||
|
if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) ||
|
||||||
(cstatus.status == SND_PCM_STATUS_READY)) {
|
(cstatus.status == SND_PCM_STATUS_READY)) {
|
||||||
if (!this->hidden->iscapture) {
|
if (!_this->hidden->iscapture) {
|
||||||
status =
|
status =
|
||||||
snd_pcm_plugin_prepare(this->hidden->
|
snd_pcm_plugin_prepare(_this->hidden->
|
||||||
audio_handle,
|
audio_handle,
|
||||||
SND_PCM_CHANNEL_PLAYBACK);
|
SND_PCM_CHANNEL_PLAYBACK);
|
||||||
} else {
|
} else {
|
||||||
status =
|
status =
|
||||||
snd_pcm_plugin_prepare(this->hidden->
|
snd_pcm_plugin_prepare(_this->hidden->
|
||||||
audio_handle,
|
audio_handle,
|
||||||
SND_PCM_CHANNEL_CAPTURE);
|
SND_PCM_CHANNEL_CAPTURE);
|
||||||
}
|
}
|
||||||
|
@ -219,46 +219,46 @@ QSA_PlayDevice(_THIS)
|
||||||
} else {
|
} else {
|
||||||
/* we wrote all remaining data */
|
/* we wrote all remaining data */
|
||||||
towrite -= written;
|
towrite -= written;
|
||||||
pcmbuffer += written * this->spec.channels;
|
pcmbuffer += written * _this->spec.channels;
|
||||||
}
|
}
|
||||||
} while ((towrite > 0) && SDL_AtomicGet(&this->enabled));
|
} while ((towrite > 0) && SDL_AtomicGet(&_this->enabled));
|
||||||
|
|
||||||
/* If we couldn't write, assume fatal error for now */
|
/* If we couldn't write, assume fatal error for now */
|
||||||
if (towrite != 0) {
|
if (towrite != 0) {
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *
|
static Uint8 *
|
||||||
QSA_GetDeviceBuf(_THIS)
|
QSA_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
return this->hidden->pcm_buf;
|
return _this->hidden->pcm_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
QSA_CloseDevice(_THIS)
|
QSA_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (this->hidden->audio_handle != NULL) {
|
if (_this->hidden->audio_handle != NULL) {
|
||||||
#if _NTO_VERSION < 710
|
#if _NTO_VERSION < 710
|
||||||
if (!this->hidden->iscapture) {
|
if (!_this->hidden->iscapture) {
|
||||||
/* Finish playing available samples */
|
/* Finish playing available samples */
|
||||||
snd_pcm_plugin_flush(this->hidden->audio_handle,
|
snd_pcm_plugin_flush(_this->hidden->audio_handle,
|
||||||
SND_PCM_CHANNEL_PLAYBACK);
|
SND_PCM_CHANNEL_PLAYBACK);
|
||||||
} else {
|
} else {
|
||||||
/* Cancel unread samples during capture */
|
/* Cancel unread samples during capture */
|
||||||
snd_pcm_plugin_flush(this->hidden->audio_handle,
|
snd_pcm_plugin_flush(_this->hidden->audio_handle,
|
||||||
SND_PCM_CHANNEL_CAPTURE);
|
SND_PCM_CHANNEL_CAPTURE);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
snd_pcm_close(this->hidden->audio_handle);
|
snd_pcm_close(_this->hidden->audio_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_free(this->hidden->pcm_buf);
|
SDL_free(_this->hidden->pcm_buf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(_this->hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
QSA_OpenDevice(_THIS, const char *devname)
|
QSA_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
/* !!! FIXME: SDL2 used to pass this handle. What's the alternative? */
|
/* !!! FIXME: SDL2 used to pass this handle. What's the alternative? */
|
||||||
|
@ -272,15 +272,15 @@ QSA_OpenDevice(_THIS, const char *devname)
|
||||||
const SDL_AudioFormat *closefmts;
|
const SDL_AudioFormat *closefmts;
|
||||||
snd_pcm_channel_setup_t csetup;
|
snd_pcm_channel_setup_t csetup;
|
||||||
snd_pcm_channel_params_t cparams;
|
snd_pcm_channel_params_t cparams;
|
||||||
SDL_bool iscapture = this->iscapture;
|
SDL_bool iscapture = _this->iscapture;
|
||||||
|
|
||||||
/* Initialize all variables that we clean on shutdown */
|
/* Initialize all variables that we clean on shutdown */
|
||||||
this->hidden =
|
_this->hidden =
|
||||||
(struct SDL_PrivateAudioData *) SDL_calloc(1,
|
(struct SDL_PrivateAudioData *) SDL_calloc(1,
|
||||||
(sizeof
|
(sizeof
|
||||||
(struct
|
(struct
|
||||||
SDL_PrivateAudioData)));
|
SDL_PrivateAudioData)));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,31 +288,31 @@ QSA_OpenDevice(_THIS, const char *devname)
|
||||||
QSA_InitAudioParams(&cparams);
|
QSA_InitAudioParams(&cparams);
|
||||||
|
|
||||||
/* Initialize channel direction: capture or playback */
|
/* Initialize channel direction: capture or playback */
|
||||||
this->hidden->iscapture = iscapture ? SDL_TRUE : SDL_FALSE;
|
_this->hidden->iscapture = iscapture ? SDL_TRUE : SDL_FALSE;
|
||||||
|
|
||||||
if (device != NULL) {
|
if (device != NULL) {
|
||||||
/* Open requested audio device */
|
/* Open requested audio device */
|
||||||
this->hidden->deviceno = device->deviceno;
|
_this->hidden->deviceno = device->deviceno;
|
||||||
this->hidden->cardno = device->cardno;
|
_this->hidden->cardno = device->cardno;
|
||||||
status = snd_pcm_open(&this->hidden->audio_handle,
|
status = snd_pcm_open(&_this->hidden->audio_handle,
|
||||||
device->cardno, device->deviceno,
|
device->cardno, device->deviceno,
|
||||||
iscapture ? SND_PCM_OPEN_CAPTURE : SND_PCM_OPEN_PLAYBACK);
|
iscapture ? SND_PCM_OPEN_CAPTURE : SND_PCM_OPEN_PLAYBACK);
|
||||||
} else {
|
} else {
|
||||||
/* Open system default audio device */
|
/* Open system default audio device */
|
||||||
status = snd_pcm_open_preferred(&this->hidden->audio_handle,
|
status = snd_pcm_open_preferred(&_this->hidden->audio_handle,
|
||||||
&this->hidden->cardno,
|
&_this->hidden->cardno,
|
||||||
&this->hidden->deviceno,
|
&_this->hidden->deviceno,
|
||||||
iscapture ? SND_PCM_OPEN_CAPTURE : SND_PCM_OPEN_PLAYBACK);
|
iscapture ? SND_PCM_OPEN_CAPTURE : SND_PCM_OPEN_PLAYBACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if requested device is opened */
|
/* Check if requested device is opened */
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
this->hidden->audio_handle = NULL;
|
_this->hidden->audio_handle = NULL;
|
||||||
return QSA_SetError("snd_pcm_open", status);
|
return QSA_SetError("snd_pcm_open", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try for a closest match on audio format */
|
/* Try for a closest match on audio format */
|
||||||
closefmts = SDL_ClosestAudioFormats(this->spec.format);
|
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
|
||||||
while ((test_format = *(closefmts++)) != 0) {
|
while ((test_format = *(closefmts++)) != 0) {
|
||||||
/* if match found set format to equivalent QSA format */
|
/* if match found set format to equivalent QSA format */
|
||||||
switch (test_format) {
|
switch (test_format) {
|
||||||
|
@ -336,44 +336,44 @@ QSA_OpenDevice(_THIS, const char *devname)
|
||||||
return SDL_SetError("QSA: Couldn't find any hardware audio formats");
|
return SDL_SetError("QSA: Couldn't find any hardware audio formats");
|
||||||
}
|
}
|
||||||
|
|
||||||
this->spec.format = test_format;
|
_this->spec.format = test_format;
|
||||||
|
|
||||||
/* Set the audio format */
|
/* Set the audio format */
|
||||||
cparams.format.format = format;
|
cparams.format.format = format;
|
||||||
|
|
||||||
/* Set mono/stereo/4ch/6ch/8ch audio */
|
/* Set mono/stereo/4ch/6ch/8ch audio */
|
||||||
cparams.format.voices = this->spec.channels;
|
cparams.format.voices = _this->spec.channels;
|
||||||
|
|
||||||
/* Set rate */
|
/* Set rate */
|
||||||
cparams.format.rate = this->spec.freq;
|
cparams.format.rate = _this->spec.freq;
|
||||||
|
|
||||||
/* Setup the transfer parameters according to cparams */
|
/* Setup the transfer parameters according to cparams */
|
||||||
status = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams);
|
status = snd_pcm_plugin_params(_this->hidden->audio_handle, &cparams);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
return QSA_SetError("snd_pcm_plugin_params", status);
|
return QSA_SetError("snd_pcm_plugin_params", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure channel is setup right one last time */
|
/* Make sure channel is setup right one last time */
|
||||||
SDL_zero(csetup);
|
SDL_zero(csetup);
|
||||||
if (!this->hidden->iscapture) {
|
if (!_this->hidden->iscapture) {
|
||||||
csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
|
csetup.channel = SND_PCM_CHANNEL_PLAYBACK;
|
||||||
} else {
|
} else {
|
||||||
csetup.channel = SND_PCM_CHANNEL_CAPTURE;
|
csetup.channel = SND_PCM_CHANNEL_CAPTURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup an audio channel */
|
/* Setup an audio channel */
|
||||||
if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) {
|
if (snd_pcm_plugin_setup(_this->hidden->audio_handle, &csetup) < 0) {
|
||||||
return SDL_SetError("QSA: Unable to setup channel");
|
return SDL_SetError("QSA: Unable to setup channel");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate the final parameters for this audio specification */
|
/* Calculate the final parameters for this audio specification */
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
this->hidden->pcm_len = this->spec.size;
|
_this->hidden->pcm_len = _this->spec.size;
|
||||||
|
|
||||||
if (this->hidden->pcm_len == 0) {
|
if (_this->hidden->pcm_len == 0) {
|
||||||
this->hidden->pcm_len =
|
_this->hidden->pcm_len =
|
||||||
csetup.buf.block.frag_size * this->spec.channels *
|
csetup.buf.block.frag_size * _this->spec.channels *
|
||||||
(snd_pcm_format_width(format) / 8);
|
(snd_pcm_format_width(format) / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,39 +382,39 @@ QSA_OpenDevice(_THIS, const char *devname)
|
||||||
* (Note that buffer size must be a multiple of fragment size, so find
|
* (Note that buffer size must be a multiple of fragment size, so find
|
||||||
* closest multiple)
|
* closest multiple)
|
||||||
*/
|
*/
|
||||||
this->hidden->pcm_buf =
|
_this->hidden->pcm_buf =
|
||||||
(Uint8 *) SDL_malloc(this->hidden->pcm_len);
|
(Uint8 *) SDL_malloc(_this->hidden->pcm_len);
|
||||||
if (this->hidden->pcm_buf == NULL) {
|
if (_this->hidden->pcm_buf == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden->pcm_buf, this->spec.silence,
|
SDL_memset(_this->hidden->pcm_buf, _this->spec.silence,
|
||||||
this->hidden->pcm_len);
|
_this->hidden->pcm_len);
|
||||||
|
|
||||||
/* get the file descriptor */
|
/* get the file descriptor */
|
||||||
if (!this->hidden->iscapture) {
|
if (!_this->hidden->iscapture) {
|
||||||
this->hidden->audio_fd =
|
_this->hidden->audio_fd =
|
||||||
snd_pcm_file_descriptor(this->hidden->audio_handle,
|
snd_pcm_file_descriptor(_this->hidden->audio_handle,
|
||||||
SND_PCM_CHANNEL_PLAYBACK);
|
SND_PCM_CHANNEL_PLAYBACK);
|
||||||
} else {
|
} else {
|
||||||
this->hidden->audio_fd =
|
_this->hidden->audio_fd =
|
||||||
snd_pcm_file_descriptor(this->hidden->audio_handle,
|
snd_pcm_file_descriptor(_this->hidden->audio_handle,
|
||||||
SND_PCM_CHANNEL_CAPTURE);
|
SND_PCM_CHANNEL_CAPTURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->audio_fd < 0) {
|
if (_this->hidden->audio_fd < 0) {
|
||||||
return QSA_SetError("snd_pcm_file_descriptor", status);
|
return QSA_SetError("snd_pcm_file_descriptor", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prepare an audio channel */
|
/* Prepare an audio channel */
|
||||||
if (!this->hidden->iscapture) {
|
if (!_this->hidden->iscapture) {
|
||||||
/* Prepare audio playback */
|
/* Prepare audio playback */
|
||||||
status =
|
status =
|
||||||
snd_pcm_plugin_prepare(this->hidden->audio_handle,
|
snd_pcm_plugin_prepare(_this->hidden->audio_handle,
|
||||||
SND_PCM_CHANNEL_PLAYBACK);
|
SND_PCM_CHANNEL_PLAYBACK);
|
||||||
} else {
|
} else {
|
||||||
/* Prepare audio capture */
|
/* Prepare audio capture */
|
||||||
status =
|
status =
|
||||||
snd_pcm_plugin_prepare(this->hidden->audio_handle,
|
snd_pcm_plugin_prepare(_this->hidden->audio_handle,
|
||||||
SND_PCM_CHANNEL_CAPTURE);
|
SND_PCM_CHANNEL_CAPTURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice* this
|
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
/* SDL capture state */
|
/* SDL capture state */
|
||||||
|
|
|
@ -149,42 +149,42 @@ static int LoadSNDIOLibrary(void)
|
||||||
|
|
||||||
#endif /* SDL_AUDIO_DRIVER_SNDIO_DYNAMIC */
|
#endif /* SDL_AUDIO_DRIVER_SNDIO_DYNAMIC */
|
||||||
|
|
||||||
static void SNDIO_WaitDevice(_THIS)
|
static void SNDIO_WaitDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
/* no-op; SNDIO_sio_write() blocks if necessary. */
|
/* no-op; SNDIO_sio_write() blocks if necessary. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SNDIO_PlayDevice(_THIS)
|
static void SNDIO_PlayDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
const int written = SNDIO_sio_write(this->hidden->dev,
|
const int written = SNDIO_sio_write(_this->hidden->dev,
|
||||||
this->hidden->mixbuf,
|
_this->hidden->mixbuf,
|
||||||
this->hidden->mixlen);
|
_this->hidden->mixlen);
|
||||||
|
|
||||||
/* If we couldn't write, assume fatal error for now */
|
/* If we couldn't write, assume fatal error for now */
|
||||||
if (written == 0) {
|
if (written == 0) {
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
|
fprintf(stderr, "Wrote %d bytes of audio data\n", written);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int SNDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
static int SNDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
size_t r;
|
size_t r;
|
||||||
int revents;
|
int revents;
|
||||||
int nfds;
|
int nfds;
|
||||||
|
|
||||||
/* Emulate a blocking read */
|
/* Emulate a blocking read */
|
||||||
r = SNDIO_sio_read(this->hidden->dev, buffer, buflen);
|
r = SNDIO_sio_read(_this->hidden->dev, buffer, buflen);
|
||||||
while (r == 0 && !SNDIO_sio_eof(this->hidden->dev)) {
|
while (r == 0 && !SNDIO_sio_eof(_this->hidden->dev)) {
|
||||||
nfds = SNDIO_sio_pollfd(this->hidden->dev, this->hidden->pfd, POLLIN);
|
nfds = SNDIO_sio_pollfd(_this->hidden->dev, _this->hidden->pfd, POLLIN);
|
||||||
if (nfds <= 0 || poll(this->hidden->pfd, nfds, INFTIM) < 0) {
|
if (nfds <= 0 || poll(_this->hidden->pfd, nfds, INFTIM) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
revents = SNDIO_sio_revents(this->hidden->dev, this->hidden->pfd);
|
revents = SNDIO_sio_revents(_this->hidden->dev, _this->hidden->pfd);
|
||||||
if (revents & POLLIN) {
|
if (revents & POLLIN) {
|
||||||
r = SNDIO_sio_read(this->hidden->dev, buffer, buflen);
|
r = SNDIO_sio_read(_this->hidden->dev, buffer, buflen);
|
||||||
}
|
}
|
||||||
if (revents & POLLHUP) {
|
if (revents & POLLHUP) {
|
||||||
break;
|
break;
|
||||||
|
@ -193,83 +193,83 @@ static int SNDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
return (int)r;
|
return (int)r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SNDIO_FlushCapture(_THIS)
|
static void SNDIO_FlushCapture(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
char buf[512];
|
char buf[512];
|
||||||
|
|
||||||
while (SNDIO_sio_read(this->hidden->dev, buf, sizeof(buf)) != 0) {
|
while (SNDIO_sio_read(_this->hidden->dev, buf, sizeof(buf)) != 0) {
|
||||||
/* do nothing */;
|
/* do nothing */;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *SNDIO_GetDeviceBuf(_THIS)
|
static Uint8 *SNDIO_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
return this->hidden->mixbuf;
|
return _this->hidden->mixbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SNDIO_CloseDevice(_THIS)
|
static void SNDIO_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (this->hidden->pfd != NULL) {
|
if (_this->hidden->pfd != NULL) {
|
||||||
SDL_free(this->hidden->pfd);
|
SDL_free(_this->hidden->pfd);
|
||||||
}
|
}
|
||||||
if (this->hidden->dev != NULL) {
|
if (_this->hidden->dev != NULL) {
|
||||||
SNDIO_sio_stop(this->hidden->dev);
|
SNDIO_sio_stop(_this->hidden->dev);
|
||||||
SNDIO_sio_close(this->hidden->dev);
|
SNDIO_sio_close(_this->hidden->dev);
|
||||||
}
|
}
|
||||||
SDL_free(this->hidden->mixbuf);
|
SDL_free(_this->hidden->mixbuf);
|
||||||
SDL_free(this->hidden);
|
SDL_free(_this->hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int SNDIO_OpenDevice(_THIS, const char *devname)
|
static int SNDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
SDL_AudioFormat test_format;
|
SDL_AudioFormat test_format;
|
||||||
const SDL_AudioFormat *closefmts;
|
const SDL_AudioFormat *closefmts;
|
||||||
struct sio_par par;
|
struct sio_par par;
|
||||||
SDL_bool iscapture = this->iscapture;
|
SDL_bool iscapture = _this->iscapture;
|
||||||
|
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)
|
_this->hidden = (struct SDL_PrivateAudioData *)
|
||||||
SDL_malloc(sizeof(*this->hidden));
|
SDL_malloc(sizeof(*_this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_zerop(this->hidden);
|
SDL_zerop(_this->hidden);
|
||||||
|
|
||||||
this->hidden->mixlen = this->spec.size;
|
_this->hidden->mixlen = _this->spec.size;
|
||||||
|
|
||||||
/* Capture devices must be non-blocking for SNDIO_FlushCapture */
|
/* Capture devices must be non-blocking for SNDIO_FlushCapture */
|
||||||
this->hidden->dev = SNDIO_sio_open(devname != NULL ? devname : SIO_DEVANY,
|
_this->hidden->dev = SNDIO_sio_open(devname != NULL ? devname : SIO_DEVANY,
|
||||||
iscapture ? SIO_REC : SIO_PLAY, iscapture);
|
iscapture ? SIO_REC : SIO_PLAY, iscapture);
|
||||||
if (this->hidden->dev == NULL) {
|
if (_this->hidden->dev == NULL) {
|
||||||
return SDL_SetError("sio_open() failed");
|
return SDL_SetError("sio_open() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate the pollfd array for capture devices */
|
/* Allocate the pollfd array for capture devices */
|
||||||
if (iscapture) {
|
if (iscapture) {
|
||||||
this->hidden->pfd = SDL_malloc(sizeof(struct pollfd) * SNDIO_sio_nfds(this->hidden->dev));
|
_this->hidden->pfd = SDL_malloc(sizeof(struct pollfd) * SNDIO_sio_nfds(_this->hidden->dev));
|
||||||
if (this->hidden->pfd == NULL) {
|
if (_this->hidden->pfd == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SNDIO_sio_initpar(&par);
|
SNDIO_sio_initpar(&par);
|
||||||
|
|
||||||
par.rate = this->spec.freq;
|
par.rate = _this->spec.freq;
|
||||||
par.pchan = this->spec.channels;
|
par.pchan = _this->spec.channels;
|
||||||
par.round = this->spec.samples;
|
par.round = _this->spec.samples;
|
||||||
par.appbufsz = par.round * 2;
|
par.appbufsz = par.round * 2;
|
||||||
|
|
||||||
/* Try for a closest match on audio format */
|
/* Try for a closest match on audio format */
|
||||||
closefmts = SDL_ClosestAudioFormats(this->spec.format);
|
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
|
||||||
while ((test_format = *(closefmts++)) != 0) {
|
while ((test_format = *(closefmts++)) != 0) {
|
||||||
if (!SDL_AUDIO_ISFLOAT(test_format)) {
|
if (!SDL_AUDIO_ISFLOAT(test_format)) {
|
||||||
par.le = SDL_AUDIO_ISLITTLEENDIAN(test_format) ? 1 : 0;
|
par.le = SDL_AUDIO_ISLITTLEENDIAN(test_format) ? 1 : 0;
|
||||||
par.sig = SDL_AUDIO_ISSIGNED(test_format) ? 1 : 0;
|
par.sig = SDL_AUDIO_ISSIGNED(test_format) ? 1 : 0;
|
||||||
par.bits = SDL_AUDIO_BITSIZE(test_format);
|
par.bits = SDL_AUDIO_BITSIZE(test_format);
|
||||||
|
|
||||||
if (SNDIO_sio_setpar(this->hidden->dev, &par) == 0) {
|
if (SNDIO_sio_setpar(_this->hidden->dev, &par) == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (SNDIO_sio_getpar(this->hidden->dev, &par) == 0) {
|
if (SNDIO_sio_getpar(_this->hidden->dev, &par) == 0) {
|
||||||
return SDL_SetError("sio_getpar() failed");
|
return SDL_SetError("sio_getpar() failed");
|
||||||
}
|
}
|
||||||
if (par.bps != SIO_BPS(par.bits)) {
|
if (par.bps != SIO_BPS(par.bits)) {
|
||||||
|
@ -286,37 +286,37 @@ static int SNDIO_OpenDevice(_THIS, const char *devname)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((par.bps == 4) && (par.sig) && (par.le)) {
|
if ((par.bps == 4) && (par.sig) && (par.le)) {
|
||||||
this->spec.format = SDL_AUDIO_S32LSB;
|
_this->spec.format = SDL_AUDIO_S32LSB;
|
||||||
} else if ((par.bps == 4) && (par.sig) && (!par.le)) {
|
} else if ((par.bps == 4) && (par.sig) && (!par.le)) {
|
||||||
this->spec.format = SDL_AUDIO_S32MSB;
|
_this->spec.format = SDL_AUDIO_S32MSB;
|
||||||
} else if ((par.bps == 2) && (par.sig) && (par.le)) {
|
} else if ((par.bps == 2) && (par.sig) && (par.le)) {
|
||||||
this->spec.format = SDL_AUDIO_S16LSB;
|
_this->spec.format = SDL_AUDIO_S16LSB;
|
||||||
} else if ((par.bps == 2) && (par.sig) && (!par.le)) {
|
} else if ((par.bps == 2) && (par.sig) && (!par.le)) {
|
||||||
this->spec.format = SDL_AUDIO_S16MSB;
|
_this->spec.format = SDL_AUDIO_S16MSB;
|
||||||
} else if ((par.bps == 1) && (par.sig)) {
|
} else if ((par.bps == 1) && (par.sig)) {
|
||||||
this->spec.format = SDL_AUDIO_S8;
|
_this->spec.format = SDL_AUDIO_S8;
|
||||||
} else if ((par.bps == 1) && (!par.sig)) {
|
} else if ((par.bps == 1) && (!par.sig)) {
|
||||||
this->spec.format = SDL_AUDIO_U8;
|
_this->spec.format = SDL_AUDIO_U8;
|
||||||
} else {
|
} else {
|
||||||
return SDL_SetError("sndio: Got unsupported hardware audio format.");
|
return SDL_SetError("sndio: Got unsupported hardware audio format.");
|
||||||
}
|
}
|
||||||
|
|
||||||
this->spec.freq = par.rate;
|
_this->spec.freq = par.rate;
|
||||||
this->spec.channels = par.pchan;
|
_this->spec.channels = par.pchan;
|
||||||
this->spec.samples = par.round;
|
_this->spec.samples = par.round;
|
||||||
|
|
||||||
/* Calculate the final parameters for this audio specification */
|
/* Calculate the final parameters for this audio specification */
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
/* Allocate mixing buffer */
|
/* Allocate mixing buffer */
|
||||||
this->hidden->mixlen = this->spec.size;
|
_this->hidden->mixlen = _this->spec.size;
|
||||||
this->hidden->mixbuf = (Uint8 *)SDL_malloc(this->hidden->mixlen);
|
_this->hidden->mixbuf = (Uint8 *)SDL_malloc(_this->hidden->mixlen);
|
||||||
if (this->hidden->mixbuf == NULL) {
|
if (_this->hidden->mixbuf == NULL) {
|
||||||
return SDL_OutOfMemory();
|
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);
|
||||||
|
|
||||||
if (!SNDIO_sio_start(this->hidden->dev)) {
|
if (!SNDIO_sio_start(_this->hidden->dev)) {
|
||||||
return SDL_SetError("sio_start() failed");
|
return SDL_SetError("sio_start() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
/* The audio device handle */
|
/* The audio device handle */
|
||||||
|
|
|
@ -39,41 +39,41 @@
|
||||||
#define SCE_AUDIO_SAMPLE_ALIGN(s) (((s) + 63) & ~63)
|
#define SCE_AUDIO_SAMPLE_ALIGN(s) (((s) + 63) & ~63)
|
||||||
#define SCE_AUDIO_MAX_VOLUME 0x8000
|
#define SCE_AUDIO_MAX_VOLUME 0x8000
|
||||||
|
|
||||||
static int VITAAUD_OpenCaptureDevice(_THIS)
|
static int VITAAUD_OpenCaptureDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
this->spec.freq = 16000;
|
_this->spec.freq = 16000;
|
||||||
this->spec.samples = 512;
|
_this->spec.samples = 512;
|
||||||
this->spec.channels = 1;
|
_this->spec.channels = 1;
|
||||||
|
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
this->hidden->port = sceAudioInOpenPort(SCE_AUDIO_IN_PORT_TYPE_VOICE, 512, 16000, SCE_AUDIO_IN_PARAM_FORMAT_S16_MONO);
|
_this->hidden->port = sceAudioInOpenPort(SCE_AUDIO_IN_PORT_TYPE_VOICE, 512, 16000, SCE_AUDIO_IN_PARAM_FORMAT_S16_MONO);
|
||||||
|
|
||||||
if (this->hidden->port < 0) {
|
if (_this->hidden->port < 0) {
|
||||||
return SDL_SetError("Couldn't open audio in port: %x", this->hidden->port);
|
return SDL_SetError("Couldn't open audio in port: %x", _this->hidden->port);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int VITAAUD_OpenDevice(_THIS, const char *devname)
|
static int VITAAUD_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
int format, mixlen, i, port = SCE_AUDIO_OUT_PORT_TYPE_MAIN;
|
int format, mixlen, i, port = SCE_AUDIO_OUT_PORT_TYPE_MAIN;
|
||||||
int vols[2] = { SCE_AUDIO_MAX_VOLUME, SCE_AUDIO_MAX_VOLUME };
|
int vols[2] = { SCE_AUDIO_MAX_VOLUME, SCE_AUDIO_MAX_VOLUME };
|
||||||
SDL_AudioFormat test_format;
|
SDL_AudioFormat test_format;
|
||||||
const SDL_AudioFormat *closefmts;
|
const SDL_AudioFormat *closefmts;
|
||||||
|
|
||||||
this->hidden = (struct SDL_PrivateAudioData *)
|
_this->hidden = (struct SDL_PrivateAudioData *)
|
||||||
SDL_malloc(sizeof(*this->hidden));
|
SDL_malloc(sizeof(*_this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_memset(this->hidden, 0, sizeof(*this->hidden));
|
SDL_memset(_this->hidden, 0, sizeof(*_this->hidden));
|
||||||
|
|
||||||
closefmts = SDL_ClosestAudioFormats(this->spec.format);
|
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
|
||||||
while ((test_format = *(closefmts++)) != 0) {
|
while ((test_format = *(closefmts++)) != 0) {
|
||||||
if (test_format == SDL_AUDIO_S16LSB) {
|
if (test_format == SDL_AUDIO_S16LSB) {
|
||||||
this->spec.format = test_format;
|
_this->spec.format = test_format;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,103 +82,103 @@ static int VITAAUD_OpenDevice(_THIS, const char *devname)
|
||||||
return SDL_SetError("Unsupported audio format");
|
return SDL_SetError("Unsupported audio format");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->iscapture) {
|
if (_this->iscapture) {
|
||||||
return VITAAUD_OpenCaptureDevice(this);
|
return VITAAUD_OpenCaptureDevice(_this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The sample count must be a multiple of 64. */
|
/* The sample count must be a multiple of 64. */
|
||||||
this->spec.samples = SCE_AUDIO_SAMPLE_ALIGN(this->spec.samples);
|
_this->spec.samples = SCE_AUDIO_SAMPLE_ALIGN(_this->spec.samples);
|
||||||
|
|
||||||
/* Update the fragment size as size in bytes. */
|
/* Update the fragment size as size in bytes. */
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
/* Allocate the mixing buffer. Its size and starting address must
|
/* Allocate the mixing buffer. Its size and starting address must
|
||||||
be a multiple of 64 bytes. Our sample count is already a multiple of
|
be a multiple of 64 bytes. Our sample count is already a multiple of
|
||||||
64, so spec->size should be a multiple of 64 as well. */
|
64, so spec->size should be a multiple of 64 as well. */
|
||||||
mixlen = this->spec.size * NUM_BUFFERS;
|
mixlen = _this->spec.size * NUM_BUFFERS;
|
||||||
this->hidden->rawbuf = (Uint8 *)memalign(64, mixlen);
|
_this->hidden->rawbuf = (Uint8 *)memalign(64, mixlen);
|
||||||
if (this->hidden->rawbuf == NULL) {
|
if (_this->hidden->rawbuf == NULL) {
|
||||||
return SDL_SetError("Couldn't allocate mixing buffer");
|
return SDL_SetError("Couldn't allocate mixing buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup the hardware channel. */
|
/* Setup the hardware channel. */
|
||||||
if (this->spec.channels == 1) {
|
if (_this->spec.channels == 1) {
|
||||||
format = SCE_AUDIO_OUT_MODE_MONO;
|
format = SCE_AUDIO_OUT_MODE_MONO;
|
||||||
} else {
|
} else {
|
||||||
format = SCE_AUDIO_OUT_MODE_STEREO;
|
format = SCE_AUDIO_OUT_MODE_STEREO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->spec.freq < 48000) {
|
if (_this->spec.freq < 48000) {
|
||||||
port = SCE_AUDIO_OUT_PORT_TYPE_BGM;
|
port = SCE_AUDIO_OUT_PORT_TYPE_BGM;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->port = sceAudioOutOpenPort(port, this->spec.samples, this->spec.freq, format);
|
_this->hidden->port = sceAudioOutOpenPort(port, _this->spec.samples, _this->spec.freq, format);
|
||||||
if (this->hidden->port < 0) {
|
if (_this->hidden->port < 0) {
|
||||||
free(this->hidden->rawbuf);
|
free(_this->hidden->rawbuf);
|
||||||
this->hidden->rawbuf = NULL;
|
_this->hidden->rawbuf = NULL;
|
||||||
return SDL_SetError("Couldn't open audio out port: %x", this->hidden->port);
|
return SDL_SetError("Couldn't open audio out port: %x", _this->hidden->port);
|
||||||
}
|
}
|
||||||
|
|
||||||
sceAudioOutSetVolume(this->hidden->port, SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH, vols);
|
sceAudioOutSetVolume(_this->hidden->port, SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH, vols);
|
||||||
|
|
||||||
SDL_memset(this->hidden->rawbuf, 0, mixlen);
|
SDL_memset(_this->hidden->rawbuf, 0, mixlen);
|
||||||
for (i = 0; i < NUM_BUFFERS; i++) {
|
for (i = 0; i < NUM_BUFFERS; i++) {
|
||||||
this->hidden->mixbufs[i] = &this->hidden->rawbuf[i * this->spec.size];
|
_this->hidden->mixbufs[i] = &_this->hidden->rawbuf[i * _this->spec.size];
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->next_buffer = 0;
|
_this->hidden->next_buffer = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void VITAAUD_PlayDevice(_THIS)
|
static void VITAAUD_PlayDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer];
|
Uint8 *mixbuf = _this->hidden->mixbufs[_this->hidden->next_buffer];
|
||||||
|
|
||||||
sceAudioOutOutput(this->hidden->port, mixbuf);
|
sceAudioOutOutput(_this->hidden->port, mixbuf);
|
||||||
|
|
||||||
this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS;
|
_this->hidden->next_buffer = (_this->hidden->next_buffer + 1) % NUM_BUFFERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function waits until it is possible to write a full sound buffer */
|
/* This function waits until it is possible to write a full sound buffer */
|
||||||
static void VITAAUD_WaitDevice(_THIS)
|
static void VITAAUD_WaitDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
/* Because we block when sending audio, there's no need for this function to do anything. */
|
/* Because we block when sending audio, there's no need for this function to do anything. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *VITAAUD_GetDeviceBuf(_THIS)
|
static Uint8 *VITAAUD_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
return this->hidden->mixbufs[this->hidden->next_buffer];
|
return _this->hidden->mixbufs[_this->hidden->next_buffer];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void VITAAUD_CloseDevice(_THIS)
|
static void VITAAUD_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (this->hidden->port >= 0) {
|
if (_this->hidden->port >= 0) {
|
||||||
if (this->iscapture) {
|
if (_this->iscapture) {
|
||||||
sceAudioInReleasePort(this->hidden->port);
|
sceAudioInReleasePort(_this->hidden->port);
|
||||||
} else {
|
} else {
|
||||||
sceAudioOutReleasePort(this->hidden->port);
|
sceAudioOutReleasePort(_this->hidden->port);
|
||||||
}
|
}
|
||||||
this->hidden->port = -1;
|
_this->hidden->port = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->iscapture && this->hidden->rawbuf != NULL) {
|
if (!_this->iscapture && _this->hidden->rawbuf != NULL) {
|
||||||
free(this->hidden->rawbuf); /* this uses memalign(), not SDL_malloc(). */
|
free(_this->hidden->rawbuf); /* this uses memalign(), not SDL_malloc(). */
|
||||||
this->hidden->rawbuf = NULL;
|
_this->hidden->rawbuf = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int VITAAUD_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
static int VITAAUD_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
SDL_assert(buflen == this->spec.size);
|
SDL_assert(buflen == _this->spec.size);
|
||||||
ret = sceAudioInInput(this->hidden->port, buffer);
|
ret = sceAudioInInput(_this->hidden->port, buffer);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return SDL_SetError("Failed to capture from device: %x", ret);
|
return SDL_SetError("Failed to capture from device: %x", ret);
|
||||||
}
|
}
|
||||||
return this->spec.size;
|
return _this->spec.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void VITAAUD_ThreadInit(_THIS)
|
static void VITAAUD_ThreadInit(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
/* Increase the priority of this audio thread by 1 to put it
|
/* Increase the priority of this audio thread by 1 to put it
|
||||||
ahead of other SDL threads. */
|
ahead of other SDL threads. */
|
||||||
|
|
|
@ -24,9 +24,6 @@
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
|
|
||||||
#define NUM_BUFFERS 2
|
#define NUM_BUFFERS 2
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
|
|
|
@ -53,83 +53,83 @@ static void WASAPI_DetectDevices(void)
|
||||||
WASAPI_EnumerateEndpoints();
|
WASAPI_EnumerateEndpoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_INLINE SDL_bool WasapiFailed(_THIS, const HRESULT err)
|
static SDL_INLINE SDL_bool WasapiFailed(SDL_AudioDevice *_this, const HRESULT err)
|
||||||
{
|
{
|
||||||
if (err == S_OK) {
|
if (err == S_OK) {
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err == AUDCLNT_E_DEVICE_INVALIDATED) {
|
if (err == AUDCLNT_E_DEVICE_INVALIDATED) {
|
||||||
this->hidden->device_lost = SDL_TRUE;
|
_this->hidden->device_lost = SDL_TRUE;
|
||||||
} else if (SDL_AtomicGet(&this->enabled)) {
|
} else if (SDL_AtomicGet(&_this->enabled)) {
|
||||||
IAudioClient_Stop(this->hidden->client);
|
IAudioClient_Stop(_this->hidden->client);
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||||
SDL_assert(!SDL_AtomicGet(&this->enabled));
|
SDL_assert(!SDL_AtomicGet(&_this->enabled));
|
||||||
}
|
}
|
||||||
|
|
||||||
return SDL_TRUE;
|
return SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int UpdateAudioStream(_THIS, const SDL_AudioSpec *oldspec)
|
static int UpdateAudioStream(SDL_AudioDevice *_this, const SDL_AudioSpec *oldspec)
|
||||||
{
|
{
|
||||||
/* Since WASAPI requires us to handle all audio conversion, and our
|
/* Since WASAPI requires us to handle all audio conversion, and our
|
||||||
device format might have changed, we might have to add/remove/change
|
device format might have changed, we might have to add/remove/change
|
||||||
the audio stream that the higher level uses to convert data, so
|
the audio stream that the higher level uses to convert data, so
|
||||||
SDL keeps firing the callback as if nothing happened here. */
|
SDL keeps firing the callback as if nothing happened here. */
|
||||||
|
|
||||||
if ((this->callbackspec.channels == this->spec.channels) &&
|
if ((_this->callbackspec.channels == _this->spec.channels) &&
|
||||||
(this->callbackspec.format == this->spec.format) &&
|
(_this->callbackspec.format == _this->spec.format) &&
|
||||||
(this->callbackspec.freq == this->spec.freq) &&
|
(_this->callbackspec.freq == _this->spec.freq) &&
|
||||||
(this->callbackspec.samples == this->spec.samples)) {
|
(_this->callbackspec.samples == _this->spec.samples)) {
|
||||||
/* no need to buffer/convert in an AudioStream! */
|
/* no need to buffer/convert in an AudioStream! */
|
||||||
SDL_DestroyAudioStream(this->stream);
|
SDL_DestroyAudioStream(_this->stream);
|
||||||
this->stream = NULL;
|
_this->stream = NULL;
|
||||||
} else if ((oldspec->channels == this->spec.channels) &&
|
} else if ((oldspec->channels == _this->spec.channels) &&
|
||||||
(oldspec->format == this->spec.format) &&
|
(oldspec->format == _this->spec.format) &&
|
||||||
(oldspec->freq == this->spec.freq)) {
|
(oldspec->freq == _this->spec.freq)) {
|
||||||
/* The existing audio stream is okay to keep using. */
|
/* The existing audio stream is okay to keep using. */
|
||||||
} else {
|
} else {
|
||||||
/* replace the audiostream for new format */
|
/* replace the audiostream for new format */
|
||||||
SDL_DestroyAudioStream(this->stream);
|
SDL_DestroyAudioStream(_this->stream);
|
||||||
if (this->iscapture) {
|
if (_this->iscapture) {
|
||||||
this->stream = SDL_CreateAudioStream(this->spec.format,
|
_this->stream = SDL_CreateAudioStream(_this->spec.format,
|
||||||
this->spec.channels, this->spec.freq,
|
_this->spec.channels, _this->spec.freq,
|
||||||
this->callbackspec.format,
|
_this->callbackspec.format,
|
||||||
this->callbackspec.channels,
|
_this->callbackspec.channels,
|
||||||
this->callbackspec.freq);
|
_this->callbackspec.freq);
|
||||||
} else {
|
} else {
|
||||||
this->stream = SDL_CreateAudioStream(this->callbackspec.format,
|
_this->stream = SDL_CreateAudioStream(_this->callbackspec.format,
|
||||||
this->callbackspec.channels,
|
_this->callbackspec.channels,
|
||||||
this->callbackspec.freq, this->spec.format,
|
_this->callbackspec.freq, _this->spec.format,
|
||||||
this->spec.channels, this->spec.freq);
|
_this->spec.channels, _this->spec.freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->stream) {
|
if (!_this->stream) {
|
||||||
return -1; /* SDL_CreateAudioStream should have called SDL_SetError. */
|
return -1; /* SDL_CreateAudioStream should have called SDL_SetError. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make sure our scratch buffer can cover the new device spec. */
|
/* make sure our scratch buffer can cover the new device spec. */
|
||||||
if (this->spec.size > this->work_buffer_len) {
|
if (_this->spec.size > _this->work_buffer_len) {
|
||||||
Uint8 *ptr = (Uint8 *)SDL_realloc(this->work_buffer, this->spec.size);
|
Uint8 *ptr = (Uint8 *)SDL_realloc(_this->work_buffer, _this->spec.size);
|
||||||
if (ptr == NULL) {
|
if (ptr == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
this->work_buffer = ptr;
|
_this->work_buffer = ptr;
|
||||||
this->work_buffer_len = this->spec.size;
|
_this->work_buffer_len = _this->spec.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReleaseWasapiDevice(_THIS);
|
static void ReleaseWasapiDevice(SDL_AudioDevice *_this);
|
||||||
|
|
||||||
static SDL_bool RecoverWasapiDevice(_THIS)
|
static SDL_bool RecoverWasapiDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
ReleaseWasapiDevice(this); /* dump the lost device's handles. */
|
ReleaseWasapiDevice(_this); /* dump the lost device's handles. */
|
||||||
|
|
||||||
if (this->hidden->default_device_generation) {
|
if (_this->hidden->default_device_generation) {
|
||||||
this->hidden->default_device_generation = SDL_AtomicGet(this->iscapture ? &SDL_IMMDevice_DefaultCaptureGeneration : &SDL_IMMDevice_DefaultPlaybackGeneration);
|
_this->hidden->default_device_generation = SDL_AtomicGet(_this->iscapture ? &SDL_IMMDevice_DefaultCaptureGeneration : &SDL_IMMDevice_DefaultPlaybackGeneration);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this can fail for lots of reasons, but the most likely is we had a
|
/* this can fail for lots of reasons, but the most likely is we had a
|
||||||
|
@ -137,46 +137,46 @@ static SDL_bool RecoverWasapiDevice(_THIS)
|
||||||
devices try to reinitialize whatever the new default is, so it's more
|
devices try to reinitialize whatever the new default is, so it's more
|
||||||
likely to carry on here, but this handles a non-default device that
|
likely to carry on here, but this handles a non-default device that
|
||||||
simply had its format changed in the Windows Control Panel. */
|
simply had its format changed in the Windows Control Panel. */
|
||||||
if (WASAPI_ActivateDevice(this, SDL_TRUE) == -1) {
|
if (WASAPI_ActivateDevice(_this, SDL_TRUE) == -1) {
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hidden->device_lost = SDL_FALSE;
|
_this->hidden->device_lost = SDL_FALSE;
|
||||||
|
|
||||||
return SDL_TRUE; /* okay, carry on with new device details! */
|
return SDL_TRUE; /* okay, carry on with new device details! */
|
||||||
}
|
}
|
||||||
|
|
||||||
static SDL_bool RecoverWasapiIfLost(_THIS)
|
static SDL_bool RecoverWasapiIfLost(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
const int generation = this->hidden->default_device_generation;
|
const int generation = _this->hidden->default_device_generation;
|
||||||
SDL_bool lost = this->hidden->device_lost;
|
SDL_bool lost = _this->hidden->device_lost;
|
||||||
|
|
||||||
if (!SDL_AtomicGet(&this->enabled)) {
|
if (!SDL_AtomicGet(&_this->enabled)) {
|
||||||
return SDL_FALSE; /* already failed. */
|
return SDL_FALSE; /* already failed. */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->hidden->client) {
|
if (!_this->hidden->client) {
|
||||||
return SDL_TRUE; /* still waiting for activation. */
|
return SDL_TRUE; /* still waiting for activation. */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lost && (generation > 0)) { /* is a default device? */
|
if (!lost && (generation > 0)) { /* is a default device? */
|
||||||
const int newgen = SDL_AtomicGet(this->iscapture ? &SDL_IMMDevice_DefaultCaptureGeneration : &SDL_IMMDevice_DefaultPlaybackGeneration);
|
const int newgen = SDL_AtomicGet(_this->iscapture ? &SDL_IMMDevice_DefaultCaptureGeneration : &SDL_IMMDevice_DefaultPlaybackGeneration);
|
||||||
if (generation != newgen) { /* the desired default device was changed, jump over to it. */
|
if (generation != newgen) { /* the desired default device was changed, jump over to it. */
|
||||||
lost = SDL_TRUE;
|
lost = SDL_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lost ? RecoverWasapiDevice(this) : SDL_TRUE;
|
return lost ? RecoverWasapiDevice(_this) : SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint8 *WASAPI_GetDeviceBuf(_THIS)
|
static Uint8 *WASAPI_GetDeviceBuf(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
/* get an endpoint buffer from WASAPI. */
|
/* get an endpoint buffer from WASAPI. */
|
||||||
BYTE *buffer = NULL;
|
BYTE *buffer = NULL;
|
||||||
|
|
||||||
while (RecoverWasapiIfLost(this) && this->hidden->render) {
|
while (RecoverWasapiIfLost(_this) && _this->hidden->render) {
|
||||||
if (!WasapiFailed(this, IAudioRenderClient_GetBuffer(this->hidden->render, this->spec.samples, &buffer))) {
|
if (!WasapiFailed(_this, IAudioRenderClient_GetBuffer(_this->hidden->render, _this->spec.samples, &buffer))) {
|
||||||
return (Uint8 *)buffer;
|
return (Uint8 *)buffer;
|
||||||
}
|
}
|
||||||
SDL_assert(buffer == NULL);
|
SDL_assert(buffer == NULL);
|
||||||
|
@ -185,24 +185,24 @@ static Uint8 *WASAPI_GetDeviceBuf(_THIS)
|
||||||
return (Uint8 *)buffer;
|
return (Uint8 *)buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WASAPI_PlayDevice(_THIS)
|
static void WASAPI_PlayDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (this->hidden->render != NULL) { /* definitely activated? */
|
if (_this->hidden->render != NULL) { /* definitely activated? */
|
||||||
/* WasapiFailed() will mark the device for reacquisition or removal elsewhere. */
|
/* WasapiFailed() will mark the device for reacquisition or removal elsewhere. */
|
||||||
WasapiFailed(this, IAudioRenderClient_ReleaseBuffer(this->hidden->render, this->spec.samples, 0));
|
WasapiFailed(_this, IAudioRenderClient_ReleaseBuffer(_this->hidden->render, _this->spec.samples, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WASAPI_WaitDevice(_THIS)
|
static void WASAPI_WaitDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
while (RecoverWasapiIfLost(this) && this->hidden->client && this->hidden->event) {
|
while (RecoverWasapiIfLost(_this) && _this->hidden->client && _this->hidden->event) {
|
||||||
DWORD waitResult = WaitForSingleObjectEx(this->hidden->event, 200, FALSE);
|
DWORD waitResult = WaitForSingleObjectEx(_this->hidden->event, 200, FALSE);
|
||||||
if (waitResult == WAIT_OBJECT_0) {
|
if (waitResult == WAIT_OBJECT_0) {
|
||||||
const UINT32 maxpadding = this->spec.samples;
|
const UINT32 maxpadding = _this->spec.samples;
|
||||||
UINT32 padding = 0;
|
UINT32 padding = 0;
|
||||||
if (!WasapiFailed(this, IAudioClient_GetCurrentPadding(this->hidden->client, &padding))) {
|
if (!WasapiFailed(_this, IAudioClient_GetCurrentPadding(_this->hidden->client, &padding))) {
|
||||||
/*SDL_Log("WASAPI EVENT! padding=%u maxpadding=%u", (unsigned int)padding, (unsigned int)maxpadding);*/
|
/*SDL_Log("WASAPI EVENT! padding=%u maxpadding=%u", (unsigned int)padding, (unsigned int)maxpadding);*/
|
||||||
if (this->iscapture) {
|
if (_this->iscapture) {
|
||||||
if (padding > 0) {
|
if (padding > 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -214,15 +214,15 @@ static void WASAPI_WaitDevice(_THIS)
|
||||||
}
|
}
|
||||||
} else if (waitResult != WAIT_TIMEOUT) {
|
} else if (waitResult != WAIT_TIMEOUT) {
|
||||||
/*SDL_Log("WASAPI FAILED EVENT!");*/
|
/*SDL_Log("WASAPI FAILED EVENT!");*/
|
||||||
IAudioClient_Stop(this->hidden->client);
|
IAudioClient_Stop(_this->hidden->client);
|
||||||
SDL_OpenedAudioDeviceDisconnected(this);
|
SDL_OpenedAudioDeviceDisconnected(_this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int WASAPI_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
static int WASAPI_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
|
||||||
{
|
{
|
||||||
SDL_AudioStream *stream = this->hidden->capturestream;
|
SDL_AudioStream *stream = _this->hidden->capturestream;
|
||||||
const int avail = SDL_GetAudioStreamAvailable(stream);
|
const int avail = SDL_GetAudioStreamAvailable(stream);
|
||||||
if (avail > 0) {
|
if (avail > 0) {
|
||||||
const int cpy = SDL_min(buflen, avail);
|
const int cpy = SDL_min(buflen, avail);
|
||||||
|
@ -230,35 +230,35 @@ static int WASAPI_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
return cpy;
|
return cpy;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (RecoverWasapiIfLost(this)) {
|
while (RecoverWasapiIfLost(_this)) {
|
||||||
HRESULT ret;
|
HRESULT ret;
|
||||||
BYTE *ptr = NULL;
|
BYTE *ptr = NULL;
|
||||||
UINT32 frames = 0;
|
UINT32 frames = 0;
|
||||||
DWORD flags = 0;
|
DWORD flags = 0;
|
||||||
|
|
||||||
/* uhoh, client isn't activated yet, just return silence. */
|
/* uhoh, client isn't activated yet, just return silence. */
|
||||||
if (!this->hidden->capture) {
|
if (!_this->hidden->capture) {
|
||||||
/* Delay so we run at about the speed that audio would be arriving. */
|
/* Delay so we run at about the speed that audio would be arriving. */
|
||||||
SDL_Delay(((this->spec.samples * 1000) / this->spec.freq));
|
SDL_Delay(((_this->spec.samples * 1000) / _this->spec.freq));
|
||||||
SDL_memset(buffer, this->spec.silence, buflen);
|
SDL_memset(buffer, _this->spec.silence, buflen);
|
||||||
return buflen;
|
return buflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = IAudioCaptureClient_GetBuffer(this->hidden->capture, &ptr, &frames, &flags, NULL, NULL);
|
ret = IAudioCaptureClient_GetBuffer(_this->hidden->capture, &ptr, &frames, &flags, NULL, NULL);
|
||||||
if (ret != AUDCLNT_S_BUFFER_EMPTY) {
|
if (ret != AUDCLNT_S_BUFFER_EMPTY) {
|
||||||
WasapiFailed(this, ret); /* mark device lost/failed if necessary. */
|
WasapiFailed(_this, ret); /* mark device lost/failed if necessary. */
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ret == AUDCLNT_S_BUFFER_EMPTY) || !frames) {
|
if ((ret == AUDCLNT_S_BUFFER_EMPTY) || !frames) {
|
||||||
WASAPI_WaitDevice(this);
|
WASAPI_WaitDevice(_this);
|
||||||
} else if (ret == S_OK) {
|
} else if (ret == S_OK) {
|
||||||
const int total = ((int)frames) * this->hidden->framesize;
|
const int total = ((int)frames) * _this->hidden->framesize;
|
||||||
const int cpy = SDL_min(buflen, total);
|
const int cpy = SDL_min(buflen, total);
|
||||||
const int leftover = total - cpy;
|
const int leftover = total - cpy;
|
||||||
const SDL_bool silent = (flags & AUDCLNT_BUFFERFLAGS_SILENT) ? SDL_TRUE : SDL_FALSE;
|
const SDL_bool silent = (flags & AUDCLNT_BUFFERFLAGS_SILENT) ? SDL_TRUE : SDL_FALSE;
|
||||||
|
|
||||||
if (silent) {
|
if (silent) {
|
||||||
SDL_memset(buffer, this->spec.silence, cpy);
|
SDL_memset(buffer, _this->spec.silence, cpy);
|
||||||
} else {
|
} else {
|
||||||
SDL_memcpy(buffer, ptr, cpy);
|
SDL_memcpy(buffer, ptr, cpy);
|
||||||
}
|
}
|
||||||
|
@ -266,7 +266,7 @@ static int WASAPI_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
if (leftover > 0) {
|
if (leftover > 0) {
|
||||||
ptr += cpy;
|
ptr += cpy;
|
||||||
if (silent) {
|
if (silent) {
|
||||||
SDL_memset(ptr, this->spec.silence, leftover); /* I guess this is safe? */
|
SDL_memset(ptr, _this->spec.silence, leftover); /* I guess this is safe? */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SDL_PutAudioStreamData(stream, ptr, leftover) == -1) {
|
if (SDL_PutAudioStreamData(stream, ptr, leftover) == -1) {
|
||||||
|
@ -274,8 +274,8 @@ static int WASAPI_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = IAudioCaptureClient_ReleaseBuffer(this->hidden->capture, frames);
|
ret = IAudioCaptureClient_ReleaseBuffer(_this->hidden->capture, frames);
|
||||||
WasapiFailed(this, ret); /* mark device lost/failed if necessary. */
|
WasapiFailed(_this, ret); /* mark device lost/failed if necessary. */
|
||||||
|
|
||||||
return cpy;
|
return cpy;
|
||||||
}
|
}
|
||||||
|
@ -284,97 +284,97 @@ static int WASAPI_CaptureFromDevice(_THIS, void *buffer, int buflen)
|
||||||
return -1; /* unrecoverable error. */
|
return -1; /* unrecoverable error. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WASAPI_FlushCapture(_THIS)
|
static void WASAPI_FlushCapture(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
BYTE *ptr = NULL;
|
BYTE *ptr = NULL;
|
||||||
UINT32 frames = 0;
|
UINT32 frames = 0;
|
||||||
DWORD flags = 0;
|
DWORD flags = 0;
|
||||||
|
|
||||||
if (!this->hidden->capture) {
|
if (!_this->hidden->capture) {
|
||||||
return; /* not activated yet? */
|
return; /* not activated yet? */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* just read until we stop getting packets, throwing them away. */
|
/* just read until we stop getting packets, throwing them away. */
|
||||||
while (SDL_TRUE) {
|
while (SDL_TRUE) {
|
||||||
const HRESULT ret = IAudioCaptureClient_GetBuffer(this->hidden->capture, &ptr, &frames, &flags, NULL, NULL);
|
const HRESULT ret = IAudioCaptureClient_GetBuffer(_this->hidden->capture, &ptr, &frames, &flags, NULL, NULL);
|
||||||
if (ret == AUDCLNT_S_BUFFER_EMPTY) {
|
if (ret == AUDCLNT_S_BUFFER_EMPTY) {
|
||||||
break; /* no more buffered data; we're done. */
|
break; /* no more buffered data; we're done. */
|
||||||
} else if (WasapiFailed(this, ret)) {
|
} else if (WasapiFailed(_this, ret)) {
|
||||||
break; /* failed for some other reason, abort. */
|
break; /* failed for some other reason, abort. */
|
||||||
} else if (WasapiFailed(this, IAudioCaptureClient_ReleaseBuffer(this->hidden->capture, frames))) {
|
} else if (WasapiFailed(_this, IAudioCaptureClient_ReleaseBuffer(_this->hidden->capture, frames))) {
|
||||||
break; /* something broke. */
|
break; /* something broke. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SDL_ClearAudioStream(this->hidden->capturestream);
|
SDL_ClearAudioStream(_this->hidden->capturestream);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReleaseWasapiDevice(_THIS)
|
static void ReleaseWasapiDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (this->hidden->client) {
|
if (_this->hidden->client) {
|
||||||
IAudioClient_Stop(this->hidden->client);
|
IAudioClient_Stop(_this->hidden->client);
|
||||||
IAudioClient_Release(this->hidden->client);
|
IAudioClient_Release(_this->hidden->client);
|
||||||
this->hidden->client = NULL;
|
_this->hidden->client = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->render) {
|
if (_this->hidden->render) {
|
||||||
IAudioRenderClient_Release(this->hidden->render);
|
IAudioRenderClient_Release(_this->hidden->render);
|
||||||
this->hidden->render = NULL;
|
_this->hidden->render = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->capture) {
|
if (_this->hidden->capture) {
|
||||||
IAudioCaptureClient_Release(this->hidden->capture);
|
IAudioCaptureClient_Release(_this->hidden->capture);
|
||||||
this->hidden->capture = NULL;
|
_this->hidden->capture = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->waveformat) {
|
if (_this->hidden->waveformat) {
|
||||||
CoTaskMemFree(this->hidden->waveformat);
|
CoTaskMemFree(_this->hidden->waveformat);
|
||||||
this->hidden->waveformat = NULL;
|
_this->hidden->waveformat = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->capturestream) {
|
if (_this->hidden->capturestream) {
|
||||||
SDL_DestroyAudioStream(this->hidden->capturestream);
|
SDL_DestroyAudioStream(_this->hidden->capturestream);
|
||||||
this->hidden->capturestream = NULL;
|
_this->hidden->capturestream = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->activation_handler) {
|
if (_this->hidden->activation_handler) {
|
||||||
WASAPI_PlatformDeleteActivationHandler(this->hidden->activation_handler);
|
WASAPI_PlatformDeleteActivationHandler(_this->hidden->activation_handler);
|
||||||
this->hidden->activation_handler = NULL;
|
_this->hidden->activation_handler = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->event) {
|
if (_this->hidden->event) {
|
||||||
CloseHandle(this->hidden->event);
|
CloseHandle(_this->hidden->event);
|
||||||
this->hidden->event = NULL;
|
_this->hidden->event = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WASAPI_CloseDevice(_THIS)
|
static void WASAPI_CloseDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
WASAPI_UnrefDevice(this);
|
WASAPI_UnrefDevice(_this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WASAPI_RefDevice(_THIS)
|
void WASAPI_RefDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
SDL_AtomicIncRef(&this->hidden->refcount);
|
SDL_AtomicIncRef(&_this->hidden->refcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WASAPI_UnrefDevice(_THIS)
|
void WASAPI_UnrefDevice(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
if (!SDL_AtomicDecRef(&this->hidden->refcount)) {
|
if (!SDL_AtomicDecRef(&_this->hidden->refcount)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* actual closing happens here. */
|
/* actual closing happens here. */
|
||||||
|
|
||||||
/* don't touch this->hidden->task in here; it has to be reverted from
|
/* don't touch _this->hidden->task in here; it has to be reverted from
|
||||||
our callback thread. We do that in WASAPI_ThreadDeinit().
|
our callback thread. We do that in WASAPI_ThreadDeinit().
|
||||||
(likewise for this->hidden->coinitialized). */
|
(likewise for _this->hidden->coinitialized). */
|
||||||
ReleaseWasapiDevice(this);
|
ReleaseWasapiDevice(_this);
|
||||||
SDL_free(this->hidden->devid);
|
SDL_free(_this->hidden->devid);
|
||||||
SDL_free(this->hidden);
|
SDL_free(_this->hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is called once a device is activated, possibly asynchronously. */
|
/* This is called once a device is activated, possibly asynchronously. */
|
||||||
int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
|
int WASAPI_PrepDevice(SDL_AudioDevice *_this, const SDL_bool updatestream)
|
||||||
{
|
{
|
||||||
/* !!! FIXME: we could request an exclusive mode stream, which is lower latency;
|
/* !!! FIXME: we could request an exclusive mode stream, which is lower latency;
|
||||||
!!! it will write into the kernel's audio buffer directly instead of
|
!!! it will write into the kernel's audio buffer directly instead of
|
||||||
|
@ -387,11 +387,11 @@ int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
|
||||||
!!! wins actually look like. Maybe add a hint to force exclusive mode at
|
!!! wins actually look like. Maybe add a hint to force exclusive mode at
|
||||||
!!! some point. To be sure, defaulting to shared mode is the right thing to
|
!!! some point. To be sure, defaulting to shared mode is the right thing to
|
||||||
!!! do in any case. */
|
!!! do in any case. */
|
||||||
const SDL_AudioSpec oldspec = this->spec;
|
const SDL_AudioSpec oldspec = _this->spec;
|
||||||
const AUDCLNT_SHAREMODE sharemode = AUDCLNT_SHAREMODE_SHARED;
|
const AUDCLNT_SHAREMODE sharemode = AUDCLNT_SHAREMODE_SHARED;
|
||||||
UINT32 bufsize = 0; /* this is in sample frames, not samples, not bytes. */
|
UINT32 bufsize = 0; /* this is in sample frames, not samples, not bytes. */
|
||||||
REFERENCE_TIME default_period = 0;
|
REFERENCE_TIME default_period = 0;
|
||||||
IAudioClient *client = this->hidden->client;
|
IAudioClient *client = _this->hidden->client;
|
||||||
IAudioRenderClient *render = NULL;
|
IAudioRenderClient *render = NULL;
|
||||||
IAudioCaptureClient *capture = NULL;
|
IAudioCaptureClient *capture = NULL;
|
||||||
WAVEFORMATEX *waveformat = NULL;
|
WAVEFORMATEX *waveformat = NULL;
|
||||||
|
@ -404,12 +404,12 @@ int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
|
||||||
SDL_assert(client != NULL);
|
SDL_assert(client != NULL);
|
||||||
|
|
||||||
#if defined(__WINRT__) || defined(__GDK__) /* CreateEventEx() arrived in Vista, so we need an #ifdef for XP. */
|
#if defined(__WINRT__) || defined(__GDK__) /* CreateEventEx() arrived in Vista, so we need an #ifdef for XP. */
|
||||||
this->hidden->event = CreateEventEx(NULL, NULL, 0, EVENT_ALL_ACCESS);
|
_this->hidden->event = CreateEventEx(NULL, NULL, 0, EVENT_ALL_ACCESS);
|
||||||
#else
|
#else
|
||||||
this->hidden->event = CreateEventW(NULL, 0, 0, NULL);
|
_this->hidden->event = CreateEventW(NULL, 0, 0, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (this->hidden->event == NULL) {
|
if (_this->hidden->event == NULL) {
|
||||||
return WIN_SetError("WASAPI can't create an event handle");
|
return WIN_SetError("WASAPI can't create an event handle");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,17 +419,17 @@ int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_assert(waveformat != NULL);
|
SDL_assert(waveformat != NULL);
|
||||||
this->hidden->waveformat = waveformat;
|
_this->hidden->waveformat = waveformat;
|
||||||
|
|
||||||
this->spec.channels = (Uint8)waveformat->nChannels;
|
_this->spec.channels = (Uint8)waveformat->nChannels;
|
||||||
|
|
||||||
/* Make sure we have a valid format that we can convert to whatever WASAPI wants. */
|
/* Make sure we have a valid format that we can convert to whatever WASAPI wants. */
|
||||||
wasapi_format = WaveFormatToSDLFormat(waveformat);
|
wasapi_format = WaveFormatToSDLFormat(waveformat);
|
||||||
|
|
||||||
closefmts = SDL_ClosestAudioFormats(this->spec.format);
|
closefmts = SDL_ClosestAudioFormats(_this->spec.format);
|
||||||
while ((test_format = *(closefmts++)) != 0) {
|
while ((test_format = *(closefmts++)) != 0) {
|
||||||
if (test_format == wasapi_format) {
|
if (test_format == wasapi_format) {
|
||||||
this->spec.format = test_format;
|
_this->spec.format = test_format;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -447,12 +447,12 @@ int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
|
||||||
it fixes some other WASAPI-specific quirks we haven't quite tracked down.
|
it fixes some other WASAPI-specific quirks we haven't quite tracked down.
|
||||||
Refer to bug #6326 for the immediate concern. */
|
Refer to bug #6326 for the immediate concern. */
|
||||||
#if 0
|
#if 0
|
||||||
this->spec.freq = waveformat->nSamplesPerSec; /* force sampling rate so our resampler kicks in, if necessary. */
|
_this->spec.freq = waveformat->nSamplesPerSec; /* force sampling rate so our resampler kicks in, if necessary. */
|
||||||
#else
|
#else
|
||||||
/* favor WASAPI's resampler over our own */
|
/* favor WASAPI's resampler over our own */
|
||||||
if ((DWORD)this->spec.freq != waveformat->nSamplesPerSec) {
|
if ((DWORD)_this->spec.freq != waveformat->nSamplesPerSec) {
|
||||||
streamflags |= (AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY);
|
streamflags |= (AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY);
|
||||||
waveformat->nSamplesPerSec = this->spec.freq;
|
waveformat->nSamplesPerSec = _this->spec.freq;
|
||||||
waveformat->nAvgBytesPerSec = waveformat->nSamplesPerSec * waveformat->nChannels * (waveformat->wBitsPerSample / 8);
|
waveformat->nAvgBytesPerSec = waveformat->nSamplesPerSec * waveformat->nChannels * (waveformat->wBitsPerSample / 8);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -463,7 +463,7 @@ int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
|
||||||
return WIN_SetErrorFromHRESULT("WASAPI can't initialize audio client", ret);
|
return WIN_SetErrorFromHRESULT("WASAPI can't initialize audio client", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = IAudioClient_SetEventHandle(client, this->hidden->event);
|
ret = IAudioClient_SetEventHandle(client, _this->hidden->event);
|
||||||
if (FAILED(ret)) {
|
if (FAILED(ret)) {
|
||||||
return WIN_SetErrorFromHRESULT("WASAPI can't set event handle", ret);
|
return WIN_SetErrorFromHRESULT("WASAPI can't set event handle", ret);
|
||||||
}
|
}
|
||||||
|
@ -477,18 +477,18 @@ int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
|
||||||
interrupts waited for in each call to WaitDevice */
|
interrupts waited for in each call to WaitDevice */
|
||||||
{
|
{
|
||||||
const float period_millis = default_period / 10000.0f;
|
const float period_millis = default_period / 10000.0f;
|
||||||
const float period_frames = period_millis * this->spec.freq / 1000.0f;
|
const float period_frames = period_millis * _this->spec.freq / 1000.0f;
|
||||||
this->spec.samples = (Uint16)SDL_ceilf(period_frames);
|
_this->spec.samples = (Uint16)SDL_ceilf(period_frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the fragment size as size in bytes */
|
/* Update the fragment size as size in bytes */
|
||||||
SDL_CalculateAudioSpec(&this->spec);
|
SDL_CalculateAudioSpec(&_this->spec);
|
||||||
|
|
||||||
this->hidden->framesize = (SDL_AUDIO_BITSIZE(this->spec.format) / 8) * this->spec.channels;
|
_this->hidden->framesize = (SDL_AUDIO_BITSIZE(_this->spec.format) / 8) * _this->spec.channels;
|
||||||
|
|
||||||
if (this->iscapture) {
|
if (_this->iscapture) {
|
||||||
this->hidden->capturestream = SDL_CreateAudioStream(this->spec.format, this->spec.channels, this->spec.freq, this->spec.format, this->spec.channels, this->spec.freq);
|
_this->hidden->capturestream = SDL_CreateAudioStream(_this->spec.format, _this->spec.channels, _this->spec.freq, _this->spec.format, _this->spec.channels, _this->spec.freq);
|
||||||
if (!this->hidden->capturestream) {
|
if (!_this->hidden->capturestream) {
|
||||||
return -1; /* already set SDL_Error */
|
return -1; /* already set SDL_Error */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,13 +498,13 @@ int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_assert(capture != NULL);
|
SDL_assert(capture != NULL);
|
||||||
this->hidden->capture = capture;
|
_this->hidden->capture = capture;
|
||||||
ret = IAudioClient_Start(client);
|
ret = IAudioClient_Start(client);
|
||||||
if (FAILED(ret)) {
|
if (FAILED(ret)) {
|
||||||
return WIN_SetErrorFromHRESULT("WASAPI can't start capture", ret);
|
return WIN_SetErrorFromHRESULT("WASAPI can't start capture", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
WASAPI_FlushCapture(this); /* MSDN says you should flush capture endpoint right after startup. */
|
WASAPI_FlushCapture(_this); /* MSDN says you should flush capture endpoint right after startup. */
|
||||||
} else {
|
} else {
|
||||||
ret = IAudioClient_GetService(client, &SDL_IID_IAudioRenderClient, (void **)&render);
|
ret = IAudioClient_GetService(client, &SDL_IID_IAudioRenderClient, (void **)&render);
|
||||||
if (FAILED(ret)) {
|
if (FAILED(ret)) {
|
||||||
|
@ -512,7 +512,7 @@ int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_assert(render != NULL);
|
SDL_assert(render != NULL);
|
||||||
this->hidden->render = render;
|
_this->hidden->render = render;
|
||||||
ret = IAudioClient_Start(client);
|
ret = IAudioClient_Start(client);
|
||||||
if (FAILED(ret)) {
|
if (FAILED(ret)) {
|
||||||
return WIN_SetErrorFromHRESULT("WASAPI can't start playback", ret);
|
return WIN_SetErrorFromHRESULT("WASAPI can't start playback", ret);
|
||||||
|
@ -520,35 +520,35 @@ int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updatestream) {
|
if (updatestream) {
|
||||||
return UpdateAudioStream(this, &oldspec);
|
return UpdateAudioStream(_this, &oldspec);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0; /* good to go. */
|
return 0; /* good to go. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int WASAPI_OpenDevice(_THIS, const char *devname)
|
static int WASAPI_OpenDevice(SDL_AudioDevice *_this, const char *devname)
|
||||||
{
|
{
|
||||||
LPCWSTR devid = (LPCWSTR)this->handle;
|
LPCWSTR devid = (LPCWSTR)_this->handle;
|
||||||
|
|
||||||
/* Initialize all variables that we clean on shutdown */
|
/* Initialize all variables that we clean on shutdown */
|
||||||
this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*this->hidden));
|
_this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*_this->hidden));
|
||||||
if (this->hidden == NULL) {
|
if (_this->hidden == NULL) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
SDL_zerop(this->hidden);
|
SDL_zerop(_this->hidden);
|
||||||
|
|
||||||
WASAPI_RefDevice(this); /* so CloseDevice() will unref to zero. */
|
WASAPI_RefDevice(_this); /* so CloseDevice() will unref to zero. */
|
||||||
|
|
||||||
if (!devid) { /* is default device? */
|
if (!devid) { /* is default device? */
|
||||||
this->hidden->default_device_generation = SDL_AtomicGet(this->iscapture ? &SDL_IMMDevice_DefaultCaptureGeneration : &SDL_IMMDevice_DefaultPlaybackGeneration);
|
_this->hidden->default_device_generation = SDL_AtomicGet(_this->iscapture ? &SDL_IMMDevice_DefaultCaptureGeneration : &SDL_IMMDevice_DefaultPlaybackGeneration);
|
||||||
} else {
|
} else {
|
||||||
this->hidden->devid = SDL_wcsdup(devid);
|
_this->hidden->devid = SDL_wcsdup(devid);
|
||||||
if (!this->hidden->devid) {
|
if (!_this->hidden->devid) {
|
||||||
return SDL_OutOfMemory();
|
return SDL_OutOfMemory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WASAPI_ActivateDevice(this, SDL_FALSE) == -1) {
|
if (WASAPI_ActivateDevice(_this, SDL_FALSE) == -1) {
|
||||||
return -1; /* already set error. */
|
return -1; /* already set error. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,14 +563,14 @@ static int WASAPI_OpenDevice(_THIS, const char *devname)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WASAPI_ThreadInit(_THIS)
|
static void WASAPI_ThreadInit(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
WASAPI_PlatformThreadInit(this);
|
WASAPI_PlatformThreadInit(_this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WASAPI_ThreadDeinit(_THIS)
|
static void WASAPI_ThreadDeinit(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
WASAPI_PlatformThreadDeinit(this);
|
WASAPI_PlatformThreadDeinit(_this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WASAPI_Deinitialize(void)
|
static void WASAPI_Deinitialize(void)
|
||||||
|
|
|
@ -29,13 +29,6 @@ extern "C" {
|
||||||
|
|
||||||
#include "../SDL_sysaudio.h"
|
#include "../SDL_sysaudio.h"
|
||||||
|
|
||||||
/* Hidden "this" pointer for the audio functions */
|
|
||||||
#ifdef __cplusplus
|
|
||||||
#define _THIS SDL_AudioDevice *_this
|
|
||||||
#else
|
|
||||||
#define _THIS SDL_AudioDevice *this
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct SDL_PrivateAudioData
|
struct SDL_PrivateAudioData
|
||||||
{
|
{
|
||||||
SDL_AtomicInt refcount;
|
SDL_AtomicInt refcount;
|
||||||
|
@ -56,18 +49,18 @@ struct SDL_PrivateAudioData
|
||||||
};
|
};
|
||||||
|
|
||||||
/* win32 and winrt implementations call into these. */
|
/* win32 and winrt implementations call into these. */
|
||||||
int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream);
|
int WASAPI_PrepDevice(SDL_AudioDevice *_this, const SDL_bool updatestream);
|
||||||
void WASAPI_RefDevice(_THIS);
|
void WASAPI_RefDevice(SDL_AudioDevice *_this);
|
||||||
void WASAPI_UnrefDevice(_THIS);
|
void WASAPI_UnrefDevice(SDL_AudioDevice *_this);
|
||||||
|
|
||||||
/* These are functions that are implemented differently for Windows vs WinRT. */
|
/* These are functions that are implemented differently for Windows vs WinRT. */
|
||||||
int WASAPI_PlatformInit(void);
|
int WASAPI_PlatformInit(void);
|
||||||
void WASAPI_PlatformDeinit(void);
|
void WASAPI_PlatformDeinit(void);
|
||||||
void WASAPI_EnumerateEndpoints(void);
|
void WASAPI_EnumerateEndpoints(void);
|
||||||
int WASAPI_GetDefaultAudioInfo(char **name, SDL_AudioSpec *spec, int iscapture);
|
int WASAPI_GetDefaultAudioInfo(char **name, SDL_AudioSpec *spec, int iscapture);
|
||||||
int WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery);
|
int WASAPI_ActivateDevice(SDL_AudioDevice *_this, const SDL_bool isrecovery);
|
||||||
void WASAPI_PlatformThreadInit(_THIS);
|
void WASAPI_PlatformThreadInit(SDL_AudioDevice *_this);
|
||||||
void WASAPI_PlatformThreadDeinit(_THIS);
|
void WASAPI_PlatformThreadDeinit(SDL_AudioDevice *_this);
|
||||||
void WASAPI_PlatformDeleteActivationHandler(void *handler);
|
void WASAPI_PlatformDeleteActivationHandler(void *handler);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -75,55 +75,55 @@ void WASAPI_PlatformDeinit(void)
|
||||||
SDL_IMMDevice_Quit();
|
SDL_IMMDevice_Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WASAPI_PlatformThreadInit(_THIS)
|
void WASAPI_PlatformThreadInit(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
/* this thread uses COM. */
|
/* this thread uses COM. */
|
||||||
if (SUCCEEDED(WIN_CoInitialize())) { /* can't report errors, hope it worked! */
|
if (SUCCEEDED(WIN_CoInitialize())) { /* can't report errors, hope it worked! */
|
||||||
this->hidden->coinitialized = SDL_TRUE;
|
_this->hidden->coinitialized = SDL_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set this thread to very high "Pro Audio" priority. */
|
/* Set this thread to very high "Pro Audio" priority. */
|
||||||
if (pAvSetMmThreadCharacteristicsW) {
|
if (pAvSetMmThreadCharacteristicsW) {
|
||||||
DWORD idx = 0;
|
DWORD idx = 0;
|
||||||
this->hidden->task = pAvSetMmThreadCharacteristicsW(L"Pro Audio", &idx);
|
_this->hidden->task = pAvSetMmThreadCharacteristicsW(L"Pro Audio", &idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WASAPI_PlatformThreadDeinit(_THIS)
|
void WASAPI_PlatformThreadDeinit(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
/* Set this thread back to normal priority. */
|
/* Set this thread back to normal priority. */
|
||||||
if (this->hidden->task && pAvRevertMmThreadCharacteristics) {
|
if (_this->hidden->task && pAvRevertMmThreadCharacteristics) {
|
||||||
pAvRevertMmThreadCharacteristics(this->hidden->task);
|
pAvRevertMmThreadCharacteristics(_this->hidden->task);
|
||||||
this->hidden->task = NULL;
|
_this->hidden->task = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->hidden->coinitialized) {
|
if (_this->hidden->coinitialized) {
|
||||||
WIN_CoUninitialize();
|
WIN_CoUninitialize();
|
||||||
this->hidden->coinitialized = SDL_FALSE;
|
_this->hidden->coinitialized = SDL_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery)
|
int WASAPI_ActivateDevice(SDL_AudioDevice *_this, const SDL_bool isrecovery)
|
||||||
{
|
{
|
||||||
IMMDevice *device = NULL;
|
IMMDevice *device = NULL;
|
||||||
HRESULT ret;
|
HRESULT ret;
|
||||||
|
|
||||||
if (SDL_IMMDevice_Get(this->hidden->devid, &device, this->iscapture) < 0) {
|
if (SDL_IMMDevice_Get(_this->hidden->devid, &device, _this->iscapture) < 0) {
|
||||||
this->hidden->client = NULL;
|
_this->hidden->client = NULL;
|
||||||
return -1; /* This is already set by SDL_IMMDevice_Get */
|
return -1; /* This is already set by SDL_IMMDevice_Get */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this is not async in standard win32, yay! */
|
/* this is not async in standard win32, yay! */
|
||||||
ret = IMMDevice_Activate(device, &SDL_IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&this->hidden->client);
|
ret = IMMDevice_Activate(device, &SDL_IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&_this->hidden->client);
|
||||||
IMMDevice_Release(device);
|
IMMDevice_Release(device);
|
||||||
|
|
||||||
if (FAILED(ret)) {
|
if (FAILED(ret)) {
|
||||||
SDL_assert(this->hidden->client == NULL);
|
SDL_assert(_this->hidden->client == NULL);
|
||||||
return WIN_SetErrorFromHRESULT("WASAPI can't activate audio endpoint", ret);
|
return WIN_SetErrorFromHRESULT("WASAPI can't activate audio endpoint", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_assert(this->hidden->client != NULL);
|
SDL_assert(_this->hidden->client != NULL);
|
||||||
if (WASAPI_PrepDevice(this, isrecovery) == -1) { /* not async, fire it right away. */
|
if (WASAPI_PrepDevice(_this, isrecovery) == -1) { /* not async, fire it right away. */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -256,7 +256,7 @@ int WASAPI_GetDefaultAudioInfo(char **name, SDL_AudioSpec *spec, int iscapture)
|
||||||
return SDL_Unsupported();
|
return SDL_Unsupported();
|
||||||
}
|
}
|
||||||
|
|
||||||
int WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery)
|
int WASAPI_ActivateDevice(SDL_AudioDevice *_this, const SDL_bool isrecovery)
|
||||||
{
|
{
|
||||||
LPCWSTR devid = _this->hidden->devid;
|
LPCWSTR devid = _this->hidden->devid;
|
||||||
Platform::String ^ defdevid;
|
Platform::String ^ defdevid;
|
||||||
|
@ -326,12 +326,12 @@ int WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WASAPI_PlatformThreadInit(_THIS)
|
void WASAPI_PlatformThreadInit(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
// !!! FIXME: set this thread to "Pro Audio" priority.
|
// !!! FIXME: set this thread to "Pro Audio" priority.
|
||||||
}
|
}
|
||||||
|
|
||||||
void WASAPI_PlatformThreadDeinit(_THIS)
|
void WASAPI_PlatformThreadDeinit(SDL_AudioDevice *_this)
|
||||||
{
|
{
|
||||||
// !!! FIXME: set this thread to "Pro Audio" priority.
|
// !!! FIXME: set this thread to "Pro Audio" priority.
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue