mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-12 15:14:35 +00:00
* Adjustment: Update libsdl to address a bug in compilation on MacOS devices.
This commit is contained in:
parent
516163fd5d
commit
eab544c8f3
270 changed files with 9531 additions and 3704 deletions
|
|
@ -1649,8 +1649,6 @@ SDL_AudioQuit(void)
|
|||
#ifdef HAVE_LIBSAMPLERATE_H
|
||||
UnloadLibSampleRate();
|
||||
#endif
|
||||
|
||||
SDL_FreeResampleFilter();
|
||||
}
|
||||
|
||||
#define NUM_FORMATS 10
|
||||
|
|
|
|||
|
|
@ -70,11 +70,6 @@ extern SDL_AudioFilter SDL_Convert_F32_to_S16;
|
|||
extern SDL_AudioFilter SDL_Convert_F32_to_U16;
|
||||
extern SDL_AudioFilter SDL_Convert_F32_to_S32;
|
||||
|
||||
/* You need to call SDL_PrepareResampleFilter() before using the internal resampler.
|
||||
SDL_AudioQuit() calls SDL_FreeResamplerFilter(), you should never call it yourself. */
|
||||
extern int SDL_PrepareResampleFilter(void);
|
||||
extern void SDL_FreeResampleFilter(void);
|
||||
|
||||
#endif /* SDL_audio_c_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
|||
1062
Engine/lib/sdl/src/audio/SDL_audio_resampler_filter.h
Normal file
1062
Engine/lib/sdl/src/audio/SDL_audio_resampler_filter.h
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -704,97 +704,7 @@ SDL_Convert51To71(SDL_AudioCVT * cvt, SDL_AudioFormat format)
|
|||
/* SDL's resampler uses a "bandlimited interpolation" algorithm:
|
||||
https://ccrma.stanford.edu/~jos/resample/ */
|
||||
|
||||
#define RESAMPLER_ZERO_CROSSINGS 5
|
||||
#define RESAMPLER_BITS_PER_SAMPLE 16
|
||||
#define RESAMPLER_SAMPLES_PER_ZERO_CROSSING (1 << ((RESAMPLER_BITS_PER_SAMPLE / 2) + 1))
|
||||
#define RESAMPLER_FILTER_SIZE ((RESAMPLER_SAMPLES_PER_ZERO_CROSSING * RESAMPLER_ZERO_CROSSINGS) + 1)
|
||||
|
||||
/* This is a "modified" bessel function, so you can't use POSIX j0() */
|
||||
static double
|
||||
bessel(const double x)
|
||||
{
|
||||
const double xdiv2 = x / 2.0;
|
||||
double i0 = 1.0f;
|
||||
double f = 1.0f;
|
||||
int i = 1;
|
||||
|
||||
while (SDL_TRUE) {
|
||||
const double diff = SDL_pow(xdiv2, i * 2) / SDL_pow(f, 2);
|
||||
if (diff < 1.0e-21f) {
|
||||
break;
|
||||
}
|
||||
i0 += diff;
|
||||
i++;
|
||||
f *= (double) i;
|
||||
}
|
||||
|
||||
return i0;
|
||||
}
|
||||
|
||||
/* build kaiser table with cardinal sine applied to it, and array of differences between elements. */
|
||||
static void
|
||||
kaiser_and_sinc(float *table, float *diffs, const int tablelen, const double beta)
|
||||
{
|
||||
const int lenm1 = tablelen - 1;
|
||||
const int lenm1div2 = lenm1 / 2;
|
||||
int i;
|
||||
|
||||
table[0] = 1.0f;
|
||||
for (i = 1; i < tablelen; i++) {
|
||||
const double kaiser = bessel(beta * SDL_sqrt(1.0 - SDL_pow(((i - lenm1) / 2.0) / lenm1div2, 2.0))) / bessel(beta);
|
||||
table[tablelen - i] = (float) kaiser;
|
||||
}
|
||||
|
||||
for (i = 1; i < tablelen; i++) {
|
||||
const float x = (((float) i) / ((float) RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) * ((float) M_PI);
|
||||
table[i] *= SDL_sinf(x) / x;
|
||||
diffs[i - 1] = table[i] - table[i - 1];
|
||||
}
|
||||
diffs[lenm1] = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
static SDL_SpinLock ResampleFilterSpinlock = 0;
|
||||
static float *ResamplerFilter = NULL;
|
||||
static float *ResamplerFilterDifference = NULL;
|
||||
|
||||
int
|
||||
SDL_PrepareResampleFilter(void)
|
||||
{
|
||||
SDL_AtomicLock(&ResampleFilterSpinlock);
|
||||
if (!ResamplerFilter) {
|
||||
/* if dB > 50, beta=(0.1102 * (dB - 8.7)), according to Matlab. */
|
||||
const double dB = 80.0;
|
||||
const double beta = 0.1102 * (dB - 8.7);
|
||||
const size_t alloclen = RESAMPLER_FILTER_SIZE * sizeof (float);
|
||||
|
||||
ResamplerFilter = (float *) SDL_malloc(alloclen);
|
||||
if (!ResamplerFilter) {
|
||||
SDL_AtomicUnlock(&ResampleFilterSpinlock);
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
ResamplerFilterDifference = (float *) SDL_malloc(alloclen);
|
||||
if (!ResamplerFilterDifference) {
|
||||
SDL_free(ResamplerFilter);
|
||||
ResamplerFilter = NULL;
|
||||
SDL_AtomicUnlock(&ResampleFilterSpinlock);
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
kaiser_and_sinc(ResamplerFilter, ResamplerFilterDifference, RESAMPLER_FILTER_SIZE, beta);
|
||||
}
|
||||
SDL_AtomicUnlock(&ResampleFilterSpinlock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_FreeResampleFilter(void)
|
||||
{
|
||||
SDL_free(ResamplerFilter);
|
||||
SDL_free(ResamplerFilterDifference);
|
||||
ResamplerFilter = NULL;
|
||||
ResamplerFilterDifference = NULL;
|
||||
}
|
||||
#include "SDL_audio_resampler_filter.h"
|
||||
|
||||
static int
|
||||
ResamplerPadding(const int inrate, const int outrate)
|
||||
|
|
@ -803,7 +713,7 @@ ResamplerPadding(const int inrate, const int outrate)
|
|||
return 0;
|
||||
}
|
||||
if (inrate > outrate) {
|
||||
return (int) SDL_ceil(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate)));
|
||||
return (int) SDL_ceilf(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate)));
|
||||
}
|
||||
return RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
|
||||
}
|
||||
|
|
@ -815,33 +725,38 @@ SDL_ResampleAudio(const int chans, const int inrate, const int outrate,
|
|||
const float *inbuf, const int inbuflen,
|
||||
float *outbuf, const int outbuflen)
|
||||
{
|
||||
const double finrate = (double) inrate;
|
||||
const double outtimeincr = 1.0 / ((float) outrate);
|
||||
const double ratio = ((float) outrate) / ((float) inrate);
|
||||
/* Note that this used to be double, but it looks like we can get by with float in most cases at
|
||||
almost twice the speed on Intel processors, and orders of magnitude more
|
||||
on CPUs that need a software fallback for double calculations. */
|
||||
typedef float ResampleFloatType;
|
||||
|
||||
const ResampleFloatType finrate = (ResampleFloatType) inrate;
|
||||
const ResampleFloatType outtimeincr = ((ResampleFloatType) 1.0f) / ((ResampleFloatType) outrate);
|
||||
const ResampleFloatType ratio = ((float) outrate) / ((float) inrate);
|
||||
const int paddinglen = ResamplerPadding(inrate, outrate);
|
||||
const int framelen = chans * (int)sizeof (float);
|
||||
const int inframes = inbuflen / framelen;
|
||||
const int wantedoutframes = (int) ((inbuflen / framelen) * ratio); /* outbuflen isn't total to write, it's total available. */
|
||||
const int maxoutframes = outbuflen / framelen;
|
||||
const int outframes = SDL_min(wantedoutframes, maxoutframes);
|
||||
ResampleFloatType outtime = 0.0f;
|
||||
float *dst = outbuf;
|
||||
double outtime = 0.0;
|
||||
int i, j, chan;
|
||||
|
||||
for (i = 0; i < outframes; i++) {
|
||||
const int srcindex = (int) (outtime * inrate);
|
||||
const double intime = ((double) srcindex) / finrate;
|
||||
const double innexttime = ((double) (srcindex + 1)) / finrate;
|
||||
const double interpolation1 = 1.0 - ((innexttime - outtime) / (innexttime - intime));
|
||||
const ResampleFloatType intime = ((ResampleFloatType) srcindex) / finrate;
|
||||
const ResampleFloatType innexttime = ((ResampleFloatType) (srcindex + 1)) / finrate;
|
||||
const ResampleFloatType indeltatime = innexttime - intime;
|
||||
const ResampleFloatType interpolation1 = (indeltatime == 0.0f) ? 1.0f : (1.0f - ((innexttime - outtime) / indeltatime));
|
||||
const int filterindex1 = (int) (interpolation1 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
|
||||
const double interpolation2 = 1.0 - interpolation1;
|
||||
const ResampleFloatType interpolation2 = 1.0f - interpolation1;
|
||||
const int filterindex2 = (int) (interpolation2 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
|
||||
|
||||
for (chan = 0; chan < chans; chan++) {
|
||||
float outsample = 0.0f;
|
||||
|
||||
/* do this twice to calculate the sample, once for the "left wing" and then same for the right. */
|
||||
/* !!! FIXME: do both wings in one loop */
|
||||
for (j = 0; (filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
|
||||
const int srcframe = srcindex - j;
|
||||
/* !!! FIXME: we can bubble this conditional out of here by doing a pre loop. */
|
||||
|
|
@ -849,12 +764,15 @@ SDL_ResampleAudio(const int chans, const int inrate, const int outrate,
|
|||
outsample += (float)(insample * (ResamplerFilter[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation1 * ResamplerFilterDifference[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
|
||||
}
|
||||
|
||||
/* Do the right wing! */
|
||||
for (j = 0; (filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
|
||||
const int jsamples = j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
|
||||
const int srcframe = srcindex + 1 + j;
|
||||
/* !!! FIXME: we can bubble this conditional out of here by doing a post loop. */
|
||||
const float insample = (srcframe >= inframes) ? rpadding[((srcframe - inframes) * chans) + chan] : inbuf[(srcframe * chans) + chan];
|
||||
outsample += (float)(insample * (ResamplerFilter[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation2 * ResamplerFilterDifference[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
|
||||
outsample += (float)(insample * (ResamplerFilter[filterindex2 + jsamples] + (interpolation2 * ResamplerFilterDifference[filterindex2 + jsamples])));
|
||||
}
|
||||
|
||||
*(dst++) = outsample;
|
||||
}
|
||||
|
||||
|
|
@ -1119,10 +1037,6 @@ SDL_BuildAudioResampleCVT(SDL_AudioCVT * cvt, const int dst_channels,
|
|||
return SDL_SetError("No conversion available for these rates");
|
||||
}
|
||||
|
||||
if (SDL_PrepareResampleFilter() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Update (cvt) with filter details... */
|
||||
if (SDL_AddAudioCVTFilter(cvt, filter) < 0) {
|
||||
return -1;
|
||||
|
|
@ -1743,13 +1657,6 @@ SDL_NewAudioStream(const SDL_AudioFormat src_format,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (SDL_PrepareResampleFilter() < 0) {
|
||||
SDL_free(retval->resampler_state);
|
||||
retval->resampler_state = NULL;
|
||||
SDL_FreeAudioStream(retval);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
retval->resampler_func = SDL_ResampleAudioStream;
|
||||
retval->reset_resampler_func = SDL_ResetAudioStreamResampler;
|
||||
retval->cleanup_resampler_func = SDL_CleanupAudioStreamResampler;
|
||||
|
|
|
|||
|
|
@ -522,8 +522,12 @@ static void
|
|||
outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
|
||||
{
|
||||
SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData;
|
||||
|
||||
SDL_LockMutex(this->mixer_lock);
|
||||
|
||||
if (SDL_AtomicGet(&this->hidden->shutdown)) {
|
||||
return; /* don't do anything. */
|
||||
SDL_UnlockMutex(this->mixer_lock);
|
||||
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)) {
|
||||
|
|
@ -536,10 +540,8 @@ outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffe
|
|||
while (remaining > 0) {
|
||||
if (SDL_AudioStreamAvailable(this->stream) == 0) {
|
||||
/* Generate the data */
|
||||
SDL_LockMutex(this->mixer_lock);
|
||||
(*this->callbackspec.callback)(this->callbackspec.userdata,
|
||||
this->hidden->buffer, this->hidden->bufferSize);
|
||||
SDL_UnlockMutex(this->mixer_lock);
|
||||
this->hidden->bufferOffset = 0;
|
||||
SDL_AudioStreamPut(this->stream, this->hidden->buffer, this->hidden->bufferSize);
|
||||
}
|
||||
|
|
@ -565,10 +567,8 @@ outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffe
|
|||
UInt32 len;
|
||||
if (this->hidden->bufferOffset >= this->hidden->bufferSize) {
|
||||
/* Generate the data */
|
||||
SDL_LockMutex(this->mixer_lock);
|
||||
(*this->callbackspec.callback)(this->callbackspec.userdata,
|
||||
this->hidden->buffer, this->hidden->bufferSize);
|
||||
SDL_UnlockMutex(this->mixer_lock);
|
||||
this->hidden->bufferOffset = 0;
|
||||
}
|
||||
|
||||
|
|
@ -587,6 +587,8 @@ outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffe
|
|||
AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL);
|
||||
|
||||
inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity;
|
||||
|
||||
SDL_UnlockMutex(this->mixer_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -28,6 +28,11 @@
|
|||
|
||||
#include <emscripten/emscripten.h>
|
||||
|
||||
/* !!! FIXME: this currently expects that the audio callback runs in the main thread,
|
||||
!!! FIXME: in intervals when the application isn't running, but that may not be
|
||||
!!! FIXME: true always once pthread support becomes widespread. Revisit this code
|
||||
!!! FIXME: at some point and see what needs to be done for that! */
|
||||
|
||||
static void
|
||||
FeedAudioDevice(_THIS, const void *buf, const int buflen)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -49,39 +49,40 @@ FillSound(void *device, void *stream, size_t len,
|
|||
SDL_AudioDevice *audio = (SDL_AudioDevice *) device;
|
||||
SDL_AudioCallback callback = audio->callbackspec.callback;
|
||||
|
||||
SDL_LockMutex(audio->mixer_lock);
|
||||
|
||||
/* Only do something if audio is enabled */
|
||||
if (!SDL_AtomicGet(&audio->enabled) || SDL_AtomicGet(&audio->paused)) {
|
||||
if (audio->stream) {
|
||||
SDL_AudioStreamClear(audio->stream);
|
||||
}
|
||||
SDL_memset(stream, audio->spec.silence, len);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
SDL_assert(audio->spec.size == len);
|
||||
|
||||
SDL_assert(audio->spec.size == len);
|
||||
if (audio->stream == NULL) { /* no conversion necessary. */
|
||||
callback(audio->callbackspec.userdata, (Uint8 *) stream, len);
|
||||
} else { /* streaming/converting */
|
||||
const int stream_len = audio->callbackspec.size;
|
||||
const int ilen = (int) len;
|
||||
while (SDL_AudioStreamAvailable(audio->stream) < ilen) {
|
||||
callback(audio->callbackspec.userdata, audio->work_buffer, stream_len);
|
||||
if (SDL_AudioStreamPut(audio->stream, audio->work_buffer, stream_len) == -1) {
|
||||
SDL_AudioStreamClear(audio->stream);
|
||||
SDL_AtomicSet(&audio->enabled, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (audio->stream == NULL) { /* no conversion necessary. */
|
||||
SDL_LockMutex(audio->mixer_lock);
|
||||
callback(audio->callbackspec.userdata, (Uint8 *) stream, len);
|
||||
SDL_UnlockMutex(audio->mixer_lock);
|
||||
} else { /* streaming/converting */
|
||||
const int stream_len = audio->callbackspec.size;
|
||||
const int ilen = (int) len;
|
||||
while (SDL_AudioStreamAvailable(audio->stream) < ilen) {
|
||||
callback(audio->callbackspec.userdata, audio->work_buffer, stream_len);
|
||||
if (SDL_AudioStreamPut(audio->stream, audio->work_buffer, stream_len) == -1) {
|
||||
SDL_AudioStreamClear(audio->stream);
|
||||
SDL_AtomicSet(&audio->enabled, 0);
|
||||
break;
|
||||
const int got = SDL_AudioStreamGet(audio->stream, stream, ilen);
|
||||
SDL_assert((got < 0) || (got == ilen));
|
||||
if (got != ilen) {
|
||||
SDL_memset(stream, audio->spec.silence, len);
|
||||
}
|
||||
}
|
||||
|
||||
const int got = SDL_AudioStreamGet(audio->stream, stream, ilen);
|
||||
SDL_assert((got < 0) || (got == ilen));
|
||||
if (got != ilen) {
|
||||
SDL_memset(stream, audio->spec.silence, len);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(audio->mixer_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ static void nacl_audio_callback(void* stream, uint32_t buffer_size, PP_TimeDelta
|
|||
const int len = (int) buffer_size;
|
||||
SDL_AudioDevice* _this = (SDL_AudioDevice*) data;
|
||||
SDL_AudioCallback callback = _this->callbackspec.callback;
|
||||
|
||||
SDL_LockMutex(private->mutex); /* !!! FIXME: is this mutex necessary? */
|
||||
|
||||
SDL_LockMutex(_this->mixer_lock);
|
||||
|
||||
/* Only do something if audio is enabled */
|
||||
if (!SDL_AtomicGet(&_this->enabled) || SDL_AtomicGet(&_this->paused)) {
|
||||
|
|
@ -58,34 +58,31 @@ static void nacl_audio_callback(void* stream, uint32_t buffer_size, PP_TimeDelta
|
|||
SDL_AudioStreamClear(_this->stream);
|
||||
}
|
||||
SDL_memset(stream, _this->spec.silence, len);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
SDL_assert(_this->spec.size == len);
|
||||
|
||||
SDL_assert(_this->spec.size == len);
|
||||
if (_this->stream == NULL) { /* no conversion necessary. */
|
||||
callback(_this->callbackspec.userdata, stream, len);
|
||||
} else { /* streaming/converting */
|
||||
const int stream_len = _this->callbackspec.size;
|
||||
while (SDL_AudioStreamAvailable(_this->stream) < len) {
|
||||
callback(_this->callbackspec.userdata, _this->work_buffer, stream_len);
|
||||
if (SDL_AudioStreamPut(_this->stream, _this->work_buffer, stream_len) == -1) {
|
||||
SDL_AudioStreamClear(_this->stream);
|
||||
SDL_AtomicSet(&_this->enabled, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_this->stream == NULL) { /* no conversion necessary. */
|
||||
SDL_LockMutex(_this->mixer_lock);
|
||||
callback(_this->callbackspec.userdata, stream, len);
|
||||
SDL_UnlockMutex(_this->mixer_lock);
|
||||
} else { /* streaming/converting */
|
||||
const int stream_len = _this->callbackspec.size;
|
||||
while (SDL_AudioStreamAvailable(_this->stream) < len) {
|
||||
callback(_this->callbackspec.userdata, _this->work_buffer, stream_len);
|
||||
if (SDL_AudioStreamPut(_this->stream, _this->work_buffer, stream_len) == -1) {
|
||||
SDL_AudioStreamClear(_this->stream);
|
||||
SDL_AtomicSet(&_this->enabled, 0);
|
||||
break;
|
||||
const int got = SDL_AudioStreamGet(_this->stream, stream, len);
|
||||
SDL_assert((got < 0) || (got == len));
|
||||
if (got != len) {
|
||||
SDL_memset(stream, _this->spec.silence, len);
|
||||
}
|
||||
}
|
||||
|
||||
const int got = SDL_AudioStreamGet(_this->stream, stream, len);
|
||||
SDL_assert((got < 0) || (got == len));
|
||||
if (got != len) {
|
||||
SDL_memset(stream, _this->spec.silence, len);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(private->mutex);
|
||||
SDL_UnlockMutex(_this->mixer_lock);
|
||||
}
|
||||
|
||||
static void NACLAUDIO_CloseDevice(SDL_AudioDevice *device) {
|
||||
|
|
@ -94,7 +91,6 @@ static void NACLAUDIO_CloseDevice(SDL_AudioDevice *device) {
|
|||
SDL_PrivateAudioData *hidden = (SDL_PrivateAudioData *) device->hidden;
|
||||
|
||||
ppb_audio->StopPlayback(hidden->audio);
|
||||
SDL_DestroyMutex(hidden->mutex);
|
||||
core->ReleaseResource(hidden->audio);
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +105,6 @@ NACLAUDIO_OpenDevice(_THIS, const char *devname) {
|
|||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
private->mutex = SDL_CreateMutex();
|
||||
_this->spec.freq = 44100;
|
||||
_this->spec.format = AUDIO_S16LSB;
|
||||
_this->spec.channels = 2;
|
||||
|
|
|
|||
|
|
@ -34,8 +34,7 @@
|
|||
#define private _this->hidden
|
||||
|
||||
typedef struct SDL_PrivateAudioData {
|
||||
SDL_mutex* mutex;
|
||||
PP_Resource audio;
|
||||
PP_Resource audio;
|
||||
} SDL_PrivateAudioData;
|
||||
|
||||
#endif /* SDL_naclaudio_h_ */
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ static void
|
|||
NETBSDAUDIO_Status(_THIS)
|
||||
{
|
||||
#ifdef DEBUG_AUDIO
|
||||
/* *INDENT-OFF* */
|
||||
/* *INDENT-OFF* */ /* clang-format off */
|
||||
audio_info_t info;
|
||||
const struct audio_prinfo *prinfo;
|
||||
|
||||
|
|
@ -118,7 +118,7 @@ NETBSDAUDIO_Status(_THIS)
|
|||
"",
|
||||
this->spec.format,
|
||||
this->spec.size);
|
||||
/* *INDENT-ON* */
|
||||
/* *INDENT-ON* */ /* clang-format on */
|
||||
#endif /* DEBUG_AUDIO */
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -910,6 +910,7 @@ output_callback(void *data)
|
|||
* and run the callback with the work buffer to keep the callback
|
||||
* firing regularly in case the audio is being used as a timer.
|
||||
*/
|
||||
SDL_LockMutex(this->mixer_lock);
|
||||
if (!SDL_AtomicGet(&this->paused)) {
|
||||
if (SDL_AtomicGet(&this->enabled)) {
|
||||
dst = spa_buf->datas[0].data;
|
||||
|
|
@ -919,18 +920,13 @@ output_callback(void *data)
|
|||
}
|
||||
|
||||
if (!this->stream) {
|
||||
SDL_LockMutex(this->mixer_lock);
|
||||
this->callbackspec.callback(this->callbackspec.userdata, dst, this->callbackspec.size);
|
||||
SDL_UnlockMutex(this->mixer_lock);
|
||||
} else {
|
||||
int got;
|
||||
|
||||
/* Fire the callback until we have enough to fill a buffer */
|
||||
while (SDL_AudioStreamAvailable(this->stream) < this->spec.size) {
|
||||
SDL_LockMutex(this->mixer_lock);
|
||||
this->callbackspec.callback(this->callbackspec.userdata, this->work_buffer, this->callbackspec.size);
|
||||
SDL_UnlockMutex(this->mixer_lock);
|
||||
|
||||
SDL_AudioStreamPut(this->stream, this->work_buffer, this->callbackspec.size);
|
||||
}
|
||||
|
||||
|
|
@ -940,6 +936,7 @@ output_callback(void *data)
|
|||
} else {
|
||||
SDL_memset(spa_buf->datas[0].data, this->spec.silence, this->spec.size);
|
||||
}
|
||||
SDL_UnlockMutex(this->mixer_lock);
|
||||
|
||||
spa_buf->datas[0].chunk->offset = 0;
|
||||
spa_buf->datas[0].chunk->stride = this->hidden->stride;
|
||||
|
|
|
|||
|
|
@ -107,8 +107,6 @@ static int (*PULSEAUDIO_pa_stream_connect_record) (pa_stream *, const char *,
|
|||
static pa_stream_state_t (*PULSEAUDIO_pa_stream_get_state) (const pa_stream *);
|
||||
static size_t (*PULSEAUDIO_pa_stream_writable_size) (const pa_stream *);
|
||||
static size_t (*PULSEAUDIO_pa_stream_readable_size) (const pa_stream *);
|
||||
static int (*PULSEAUDIO_pa_stream_begin_write) (pa_stream *, void **, size_t*);
|
||||
static int (*PULSEAUDIO_pa_stream_cancel_write) (pa_stream *);
|
||||
static int (*PULSEAUDIO_pa_stream_write) (pa_stream *, const void *, size_t,
|
||||
pa_free_cb_t, int64_t, pa_seek_mode_t);
|
||||
static pa_operation * (*PULSEAUDIO_pa_stream_drain) (pa_stream *,
|
||||
|
|
@ -119,6 +117,7 @@ static pa_operation * (*PULSEAUDIO_pa_stream_flush) (pa_stream *,
|
|||
pa_stream_success_cb_t, void *);
|
||||
static int (*PULSEAUDIO_pa_stream_disconnect) (pa_stream *);
|
||||
static void (*PULSEAUDIO_pa_stream_unref) (pa_stream *);
|
||||
static void (*PULSEAUDIO_pa_stream_set_write_callback)(pa_stream *, pa_stream_request_cb_t, void *);
|
||||
|
||||
static int load_pulseaudio_syms(void);
|
||||
|
||||
|
|
@ -222,8 +221,6 @@ load_pulseaudio_syms(void)
|
|||
SDL_PULSEAUDIO_SYM(pa_stream_writable_size);
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_readable_size);
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_write);
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_begin_write);
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_cancel_write);
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_drain);
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_disconnect);
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_peek);
|
||||
|
|
@ -232,6 +229,7 @@ load_pulseaudio_syms(void)
|
|||
SDL_PULSEAUDIO_SYM(pa_stream_unref);
|
||||
SDL_PULSEAUDIO_SYM(pa_channel_map_init_auto);
|
||||
SDL_PULSEAUDIO_SYM(pa_strerror);
|
||||
SDL_PULSEAUDIO_SYM(pa_stream_set_write_callback);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -359,51 +357,56 @@ ConnectToPulseServer(pa_mainloop **_mainloop, pa_context **_context)
|
|||
static void
|
||||
PULSEAUDIO_WaitDevice(_THIS)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = this->hidden;
|
||||
/* this is a no-op; we wait in PULSEAUDIO_PlayDevice now. */
|
||||
}
|
||||
|
||||
while (SDL_AtomicGet(&this->enabled)) {
|
||||
static void WriteCallback(pa_stream *p, size_t nbytes, void *userdata)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = (struct SDL_PrivateAudioData *) userdata;
|
||||
/*printf("PULSEAUDIO WRITE CALLBACK! nbytes=%u\n", (unsigned int) nbytes);*/
|
||||
h->bytes_requested += nbytes;
|
||||
}
|
||||
|
||||
static void
|
||||
PULSEAUDIO_PlayDevice(_THIS)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = this->hidden;
|
||||
int available = h->mixlen;
|
||||
int written = 0;
|
||||
int cpy;
|
||||
|
||||
/*printf("PULSEAUDIO PLAYDEVICE START! mixlen=%d\n", available);*/
|
||||
|
||||
while (SDL_AtomicGet(&this->enabled) && (available > 0)) {
|
||||
cpy = SDL_min(h->bytes_requested, available);
|
||||
if (cpy) {
|
||||
if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf + written, cpy, NULL, 0LL, PA_SEEK_RELATIVE) < 0) {
|
||||
SDL_OpenedAudioDeviceDisconnected(this);
|
||||
return;
|
||||
}
|
||||
/*printf("PULSEAUDIO FEED! nbytes=%u\n", (unsigned int) cpy);*/
|
||||
h->bytes_requested -= cpy;
|
||||
written += cpy;
|
||||
available -= cpy;
|
||||
}
|
||||
|
||||
/* let WriteCallback fire if necessary. */
|
||||
/*printf("PULSEAUDIO ITERATE!\n");*/
|
||||
if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
|
||||
PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
|
||||
PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
|
||||
SDL_OpenedAudioDeviceDisconnected(this);
|
||||
return;
|
||||
}
|
||||
if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= (h->mixlen/8)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
PULSEAUDIO_PlayDevice(_THIS)
|
||||
{
|
||||
/* Write the audio data */
|
||||
struct SDL_PrivateAudioData *h = this->hidden;
|
||||
if (SDL_AtomicGet(&this->enabled)) {
|
||||
if (PULSEAUDIO_pa_stream_write(h->stream, h->pabuf, h->mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0) {
|
||||
SDL_OpenedAudioDeviceDisconnected(this);
|
||||
}
|
||||
}
|
||||
/*printf("PULSEAUDIO PLAYDEVICE END! written=%d\n", written);*/
|
||||
}
|
||||
|
||||
static Uint8 *
|
||||
PULSEAUDIO_GetDeviceBuf(_THIS)
|
||||
{
|
||||
struct SDL_PrivateAudioData *h = this->hidden;
|
||||
size_t nbytes = h->mixlen;
|
||||
int ret;
|
||||
|
||||
ret = PULSEAUDIO_pa_stream_begin_write(h->stream, &h->pabuf, &nbytes);
|
||||
|
||||
if (ret != 0) {
|
||||
/* fall back it intermediate buffer */
|
||||
h->pabuf = h->mixbuf;
|
||||
} else if (nbytes < h->mixlen) {
|
||||
PULSEAUDIO_pa_stream_cancel_write(h->stream);
|
||||
h->pabuf = h->mixbuf;
|
||||
}
|
||||
|
||||
return (Uint8 *)h->pabuf;
|
||||
return this->hidden->mixbuf;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -604,9 +607,6 @@ PULSEAUDIO_OpenDevice(_THIS, const char *devname)
|
|||
paspec.format = format;
|
||||
|
||||
/* Calculate the final parameters for this audio specification */
|
||||
#ifdef PA_STREAM_ADJUST_LATENCY
|
||||
this->spec.samples /= 2; /* Mix in smaller chunck to avoid underruns */
|
||||
#endif
|
||||
SDL_CalculateAudioSpec(&this->spec);
|
||||
|
||||
/* Allocate mixing buffer */
|
||||
|
|
@ -623,22 +623,12 @@ PULSEAUDIO_OpenDevice(_THIS, const char *devname)
|
|||
paspec.rate = this->spec.freq;
|
||||
|
||||
/* Reduced prebuffering compared to the defaults. */
|
||||
#ifdef PA_STREAM_ADJUST_LATENCY
|
||||
paattr.fragsize = this->spec.size;
|
||||
/* 2x original requested bufsize */
|
||||
paattr.tlength = h->mixlen * 4;
|
||||
paattr.tlength = h->mixlen;
|
||||
paattr.prebuf = -1;
|
||||
paattr.maxlength = -1;
|
||||
/* -1 can lead to pa_stream_writable_size() >= mixlen never being true */
|
||||
paattr.minreq = h->mixlen;
|
||||
flags = PA_STREAM_ADJUST_LATENCY;
|
||||
#else
|
||||
paattr.fragsize = this->spec.size;
|
||||
paattr.tlength = h->mixlen*2;
|
||||
paattr.prebuf = h->mixlen*2;
|
||||
paattr.maxlength = h->mixlen*2;
|
||||
paattr.minreq = h->mixlen;
|
||||
#endif
|
||||
paattr.minreq = -1;
|
||||
flags |= PA_STREAM_ADJUST_LATENCY;
|
||||
|
||||
if (ConnectToPulseServer(&h->mainloop, &h->context) < 0) {
|
||||
return SDL_SetError("Could not connect to PulseAudio server");
|
||||
|
|
@ -675,6 +665,7 @@ PULSEAUDIO_OpenDevice(_THIS, const char *devname)
|
|||
if (iscapture) {
|
||||
rc = PULSEAUDIO_pa_stream_connect_record(h->stream, h->device_name, &paattr, flags);
|
||||
} else {
|
||||
PULSEAUDIO_pa_stream_set_write_callback(h->stream, WriteCallback, h);
|
||||
rc = PULSEAUDIO_pa_stream_connect_playback(h->stream, h->device_name, &paattr, flags, NULL, NULL);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,11 +43,7 @@ struct SDL_PrivateAudioData
|
|||
Uint8 *mixbuf;
|
||||
int mixlen;
|
||||
|
||||
/* Pointer to the actual buffer in use in the current
|
||||
GetDeviceBuf() -> PlayDevice() iteration.
|
||||
Can be either the pointer returned by pa_stream_begin_write()
|
||||
or mixbuf */
|
||||
void *pabuf;
|
||||
int bytes_requested; /* bytes of data the hardware wants _now_. */
|
||||
|
||||
const Uint8 *capturebuf;
|
||||
int capturelen;
|
||||
|
|
|
|||
|
|
@ -362,7 +362,7 @@ typedef struct
|
|||
WAVEFORMATEXTENSIBLE fmt;
|
||||
} EndpointItem;
|
||||
|
||||
static int sort_endpoints(const void *_a, const void *_b)
|
||||
static int SDLCALL sort_endpoints(const void *_a, const void *_b)
|
||||
{
|
||||
LPWSTR a = ((const EndpointItem *) _a)->devid;
|
||||
LPWSTR b = ((const EndpointItem *) _b)->devid;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue