change streaming to use OnBufferEnded callback

pull/1/head
cosmonaut 2021-10-27 21:18:59 -07:00
parent 9983fa3275
commit 23eab952c1
1 changed files with 36 additions and 113 deletions

View File

@ -142,52 +142,6 @@ static inline uint32_t IdStack_Pop(IdStack* stack)
return stack->array[stack->count]; return stack->array[stack->count];
} }
typedef struct BufferQueue
{
uint32_t head;
uint32_t tail;
uint32_t size; /* DO NOT MUTATE */
uint32_t count; /* number of currently enqueued elements */
uint8_t** buffers;
} BufferQueue;
static inline void BufferQueue_Init(BufferQueue* queue, uint32_t size)
{
queue->head = 0;
queue->tail = 0;
queue->size = size;
queue->count = 0;
queue->buffers = SDL_malloc(size * sizeof(uint8_t*));
}
static inline uint8_t* BufferQueue_Dequeue(BufferQueue *queue)
{
if (queue->tail == queue->head)
{
return NULL;
}
uint8_t* buffer = queue->buffers[queue->tail];
queue->buffers[queue->tail] = NULL;
queue->tail = (queue->tail + 1) % queue->size;
queue->count -= 1;
return buffer;
}
static inline void BufferQueue_Enqueue(BufferQueue *queue, uint8_t* buffer)
{
if (((queue->head + 1) % queue->size) == queue->tail)
{
return;
}
queue->buffers[queue->head] = buffer;
queue->head = (queue->head + 1) % queue->size;
queue->count += 1;
}
typedef enum FAudioGMS_SoundState typedef enum FAudioGMS_SoundState
{ {
SoundState_Playing, SoundState_Playing,
@ -210,7 +164,6 @@ typedef struct FAudioGMS_StreamingSound
{ {
stb_vorbis* fileHandle; stb_vorbis* fileHandle;
stb_vorbis_info info; stb_vorbis_info info;
BufferQueue bufferQueue;
} FAudioGMS_StreamingSound; } FAudioGMS_StreamingSound;
typedef struct FAudioGMS_SoundInstance typedef struct FAudioGMS_SoundInstance
@ -272,10 +225,8 @@ typedef struct FAudioGMS_EffectChain
static const float SPEED_OF_SOUND = 343.5f; static const float SPEED_OF_SOUND = 343.5f;
static const float DOPPLER_SCALE = 1.0f; static const float DOPPLER_SCALE = 1.0f;
static const uint32_t MINIMUM_BUFFER_CHECK = 3;
#define MAX_BUFFER_QUEUE_COUNT 16 #define STREAMING_BUFFER_SIZE 1024 * 16 * sizeof(float) /* FIXME: what should this value be? */
#define STREAMING_BUFFER_SIZE 1024 * 8 * sizeof(float) /* FIXME: what should this value be? */
typedef struct FAudioGMS_Device typedef struct FAudioGMS_Device
{ {
@ -288,6 +239,8 @@ typedef struct FAudioGMS_Device
F3DAUDIO_LISTENER listener; F3DAUDIO_LISTENER listener;
float spatialDistanceScale; float spatialDistanceScale;
FAudioVoiceCallback voiceCallbacks;
FAudioGMS_StaticSound **staticSounds; FAudioGMS_StaticSound **staticSounds;
uint32_t staticSoundCount; uint32_t staticSoundCount;
IdStack staticSoundIndexStack; IdStack staticSoundIndexStack;
@ -348,6 +301,17 @@ static inline FAudioGMS_EffectChain* FAudioGMS_INTERNAL_LookupEffectChain(uint32
} }
} }
/* Forward declare this to avoid annoying BS */
static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance* instance);
static void FAudioGMS_INTERNAL_StreamingBufferEndCallback(FAudioVoiceCallback* callback, FAudioGMS_SoundInstance *instance)
{
if (instance->soundState == SoundState_Playing)
{
FAudioGMS_INTERNAL_SoundInstance_AddBuffer(instance);
}
}
void FAudioGMS_Init(double spatialDistanceScale, double timestep) void FAudioGMS_Init(double spatialDistanceScale, double timestep)
{ {
device = SDL_malloc(sizeof(FAudioGMS_Device)); device = SDL_malloc(sizeof(FAudioGMS_Device));
@ -443,6 +407,14 @@ void FAudioGMS_Init(double spatialDistanceScale, double timestep)
device->listener.Velocity.z = 0; device->listener.Velocity.z = 0;
device->listener.pCone = NULL; device->listener.pCone = NULL;
device->voiceCallbacks.OnBufferEnd = FAudioGMS_INTERNAL_StreamingBufferEndCallback;
device->voiceCallbacks.OnBufferStart = NULL;
device->voiceCallbacks.OnLoopEnd = NULL;
device->voiceCallbacks.OnStreamEnd = NULL;
device->voiceCallbacks.OnVoiceError = NULL;
device->voiceCallbacks.OnVoiceProcessingPassEnd = NULL;
device->voiceCallbacks.OnVoiceProcessingPassStart = NULL;
device->staticSounds = NULL; device->staticSounds = NULL;
device->staticSoundCount = 0; device->staticSoundCount = 0;
IdStack_Init(&device->staticSoundIndexStack); IdStack_Init(&device->staticSoundIndexStack);
@ -458,7 +430,7 @@ void FAudioGMS_Init(double spatialDistanceScale, double timestep)
device->timestep = timestep; device->timestep = timestep;
Log("FAudio initialized successfully!"); Log("FAudio initialized successfully!");
printf("Device: %ls", device->deviceDetails.DisplayName); printf("Device: %ls\n", device->deviceDetails.DisplayName);
fflush(stdout); fflush(stdout);
} }
@ -716,12 +688,14 @@ static void FAudioGMS_INTERNAL_Apply3D(FAudioGMS_SoundInstance* instance)
static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_Init( static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_Init(
uint32_t channelCount, uint32_t channelCount,
uint32_t samplesPerSecond uint32_t samplesPerSecond,
uint8_t isStatic
) { ) {
FAudioGMS_SoundInstance* instance = SDL_malloc(sizeof(FAudioGMS_SoundInstance)); FAudioGMS_SoundInstance* instance = SDL_malloc(sizeof(FAudioGMS_SoundInstance));
instance->handle = NULL; instance->handle = NULL;
instance->isStatic = isStatic;
instance->loop = 0; instance->loop = 0;
instance->destroyOnFinish = 0; instance->destroyOnFinish = 0;
@ -738,7 +712,7 @@ static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_Init(
&instance->format, &instance->format,
FAUDIO_VOICE_USEFILTER, FAUDIO_VOICE_USEFILTER,
FAUDIO_DEFAULT_FREQ_RATIO, FAUDIO_DEFAULT_FREQ_RATIO,
NULL, isStatic ? NULL : &device->voiceCallbacks,
NULL, NULL,
NULL); NULL);
@ -802,7 +776,8 @@ static FAudioGMS_SoundInstance* FAudioGMS_INTERNAL_SoundInstance_CreateFromStati
) { ) {
FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_Init( FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_Init(
staticSound->channels, staticSound->channels,
staticSound->samplesPerSecond staticSound->samplesPerSecond,
1
); );
instance->isStatic = 1; instance->isStatic = 1;
@ -827,8 +802,6 @@ static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance*
uint8_t* nextBuffer = SDL_malloc(bufferLength); uint8_t* nextBuffer = SDL_malloc(bufferLength);
SDL_memcpy(nextBuffer, device->streamStagingBuffer, bufferLength); SDL_memcpy(nextBuffer, device->streamStagingBuffer, bufferLength);
BufferQueue_Enqueue(&instance->soundData.streamingSound.bufferQueue, nextBuffer);
FAudioBuffer buffer; FAudioBuffer buffer;
buffer.AudioBytes = bufferLength; buffer.AudioBytes = bufferLength;
buffer.pAudioData = nextBuffer; buffer.pAudioData = nextBuffer;
@ -842,7 +815,7 @@ static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance*
buffer.LoopBegin = 0; buffer.LoopBegin = 0;
buffer.LoopCount = 0; buffer.LoopCount = 0;
buffer.LoopLength = 0; buffer.LoopLength = 0;
buffer.pContext = NULL; buffer.pContext = instance; /* context for OnBufferEnd callback */
FAudioSourceVoice_SubmitSourceBuffer(instance->handle, &buffer, NULL); FAudioSourceVoice_SubmitSourceBuffer(instance->handle, &buffer, NULL);
@ -860,31 +833,6 @@ static void FAudioGMS_INTERNAL_SoundInstance_AddBuffer(FAudioGMS_SoundInstance*
} }
} }
static void FAudioGMS_INTERNAL_SoundInstance_StreamingUpdate(FAudioGMS_SoundInstance* instance)
{
uint32_t i;
FAudioVoiceState voiceState;
if (instance->isStatic) { return; }
FAudioSourceVoice_GetState(
instance->handle,
&voiceState,
FAUDIO_VOICE_NOSAMPLESPLAYED
);
while (instance->soundData.streamingSound.bufferQueue.count > voiceState.BuffersQueued)
{
uint8_t* buffer = BufferQueue_Dequeue(&instance->soundData.streamingSound.bufferQueue);
SDL_free(buffer);
}
for (i = MINIMUM_BUFFER_CHECK - instance->soundData.streamingSound.bufferQueue.count; i > 0; i -= 1)
{
FAudioGMS_INTERNAL_SoundInstance_AddBuffer(instance);
}
}
double FAudioGMS_StreamingSound_LoadOGG(char* filePath) double FAudioGMS_StreamingSound_LoadOGG(char* filePath)
{ {
RETURN_ON_NULL_DEVICE(-1.0) RETURN_ON_NULL_DEVICE(-1.0)
@ -902,15 +850,14 @@ double FAudioGMS_StreamingSound_LoadOGG(char* filePath)
FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_Init( FAudioGMS_SoundInstance* instance = FAudioGMS_INTERNAL_SoundInstance_Init(
info.channels, info.channels,
info.sample_rate info.sample_rate,
0
); );
instance->isStatic = 0;
instance->soundData.streamingSound.fileHandle = fileHandle; instance->soundData.streamingSound.fileHandle = fileHandle;
instance->soundData.streamingSound.info = info; instance->soundData.streamingSound.info = info;
BufferQueue_Init(&instance->soundData.streamingSound.bufferQueue, MAX_BUFFER_QUEUE_COUNT);
FAudioGMS_INTERNAL_SoundInstance_StreamingUpdate(instance); FAudioGMS_INTERNAL_SoundInstance_AddBuffer(instance);
return instance->id; return instance->id;
} }
@ -956,18 +903,6 @@ static void FAudioGMS_INTERNAL_StaticSound_AddEmitter(FAudioGMS_SoundInstance* i
FAudioGMS_INTERNAL_Apply3D(instance); FAudioGMS_INTERNAL_Apply3D(instance);
} }
static void FAudioGMS_INTERNAL_SoundInstance_ClearBuffers(FAudioGMS_SoundInstance* instance)
{
uint32_t i;
uint32_t bufferCount = instance->soundData.streamingSound.bufferQueue.count;
for (i = 0; i < bufferCount; i += 1)
{
uint8_t* buffer = BufferQueue_Dequeue(&instance->soundData.streamingSound.bufferQueue);
SDL_free(buffer);
}
}
static void FAudioGMS_INTERNAL_SoundInstance_Play(FAudioGMS_SoundInstance* instance) static void FAudioGMS_INTERNAL_SoundInstance_Play(FAudioGMS_SoundInstance* instance)
{ {
if (instance->soundState == SoundState_Playing) if (instance->soundState == SoundState_Playing)
@ -992,10 +927,6 @@ static void FAudioGMS_INTERNAL_SoundInstance_Play(FAudioGMS_SoundInstance* insta
FAudioSourceVoice_SubmitSourceBuffer(instance->handle, &instance->soundData.staticSound->buffer, NULL); FAudioSourceVoice_SubmitSourceBuffer(instance->handle, &instance->soundData.staticSound->buffer, NULL);
} }
else
{
FAudioGMS_INTERNAL_SoundInstance_StreamingUpdate(instance);
}
FAudioSourceVoice_Start(instance->handle, 0, 0); FAudioSourceVoice_Start(instance->handle, 0, 0);
instance->soundState = SoundState_Playing; instance->soundState = SoundState_Playing;
@ -1114,17 +1045,16 @@ static void FAudioGMS_INTERNAL_SoundInstance_Stop(FAudioGMS_SoundInstance* insta
{ {
if (instance != NULL) if (instance != NULL)
{ {
instance->soundState = SoundState_Stopped; /* set this before so flush buffers doesn't trigger buffer add callback */
FAudioSourceVoice_Stop(instance->handle, 0, 0); FAudioSourceVoice_Stop(instance->handle, 0, 0);
FAudioSourceVoice_FlushSourceBuffers(instance->handle); FAudioSourceVoice_FlushSourceBuffers(instance->handle);
if (!instance->isStatic) if (!instance->isStatic)
{ {
FAudioGMS_INTERNAL_SoundInstance_ClearBuffers(instance);
stb_vorbis_seek_start(instance->soundData.streamingSound.fileHandle); /* back to the start */ stb_vorbis_seek_start(instance->soundData.streamingSound.fileHandle); /* back to the start */
FAudioGMS_INTERNAL_SoundInstance_StreamingUpdate(instance); /* preload so we dont stutter on play */ FAudioGMS_INTERNAL_SoundInstance_AddBuffer(instance); /* preload so we dont stutter on play */
} }
instance->soundState = SoundState_Stopped;
} }
else else
{ {
@ -1317,7 +1247,6 @@ static void FAudioGMS_INTERNAL_SoundInstance_Destroy(FAudioGMS_SoundInstance* in
FAudioVoice_DestroyVoice(instance->handle); FAudioVoice_DestroyVoice(instance->handle);
if (!instance->isStatic) if (!instance->isStatic)
{ {
SDL_free(instance->soundData.streamingSound.bufferQueue.buffers);
stb_vorbis_close(instance->soundData.streamingSound.fileHandle); stb_vorbis_close(instance->soundData.streamingSound.fileHandle);
} }
if (instance->is3D) if (instance->is3D)
@ -1667,12 +1596,6 @@ void FAudioGMS_Update()
FAudioGMS_INTERNAL_SoundInstance_SetVolume(instance, volume); FAudioGMS_INTERNAL_SoundInstance_SetVolume(instance, volume);
} }
/* Update streaming instance */
if (!instance->isStatic && instance->soundState == SoundState_Playing)
{
FAudioGMS_INTERNAL_SoundInstance_StreamingUpdate(instance);
}
if (instance->destroyOnFinish) if (instance->destroyOnFinish)
{ {
FAudioVoiceState state; FAudioVoiceState state;