From d43d931ed8366f60f083deca54da752c9f0907b5 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Tue, 10 Aug 2021 23:13:58 +1000 Subject: [PATCH 1/7] Move 'fast context detection' code into dedicated Audio_FastPlay This only benefits OpenAL backend --- src/Audio.c | 47 ++++++++++++++++++++++++++--------------------- src/Audio.h | 8 ++++---- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/Audio.c b/src/Audio.c index f2054bcc2..6201ca70c 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -272,6 +272,11 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { } *inUse = ctx->count - ctx->free; return 0; } + +cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) { + /* Channels/Sample rate is per buffer, not a per source property */ + return true; +} #elif defined CC_BUILD_WINMM /*########################################################################################################################* *------------------------------------------------------WinMM backend------------------------------------------------------* @@ -414,6 +419,10 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { *inUse = count; return res; } + +cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) { + return !ctx->channels || (ctx->channels == channels && ctx->sampleRate == sampleRate); +} #elif defined CC_BUILD_OPENSLES /*########################################################################################################################* *----------------------------------------------------OpenSL ES backend----------------------------------------------------* @@ -587,6 +596,10 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { *inUse = state.count; return res; } + +cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) { + return !ctx->channels || (ctx->channels == channels && ctx->sampleRate == sampleRate); +} #endif /*########################################################################################################################* @@ -595,9 +608,6 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { #ifndef AUDIO_HAS_BACKEND static void AudioBackend_Free(void) { } #else -int Audio_GetChannels(struct AudioContext* ctx) { return ctx->channels; } -int Audio_GetSampleRate(struct AudioContext* ctx) { return ctx->sampleRate; } - cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { if (ctx->channels == channels && ctx->sampleRate == sampleRate) return 0; @@ -811,7 +821,6 @@ static void Sounds_Play(cc_uint8 type, struct Soundboard* board) { const struct Sound* snd_; struct Sound snd; struct AudioContext* ctx; - int chans, freq; int inUse, i, volume; cc_result res; @@ -836,26 +845,18 @@ static void Sounds_Play(cc_uint8 type, struct Soundboard* board) { if (type == SOUND_METAL) snd.sampleRate = (snd.sampleRate * 7) / 5; } - /* Try to play on fresh device, or device with same data format */ + /* Try to play on a context that doesn't need to be recreated */ for (i = 0; i < SOUND_MAX_CONTEXTS; i++) { ctx = &sound_contexts[i]; - if (!ctx->count) { - Audio_Init(ctx, 1); - } else { - res = Audio_Poll(ctx, &inUse); + res = Audio_Poll(ctx, &inUse); - if (res) { Sounds_Fail(res); return; } - if (inUse > 0) continue; - } - - chans = Audio_GetChannels(ctx); - freq = Audio_GetSampleRate(ctx); - if (!chans || (chans == snd.channels && freq == snd.sampleRate)) { + if (res) { Sounds_Fail(res); return; } + if (inUse > 0) continue; + if (!Audio_FastPlay(ctx, snd.channels, snd.sampleRate)) continue; - res = Audio_PlaySound(ctx, &snd, volume); - if (res) Sounds_Fail(res); - return; - } + res = Audio_PlaySound(ctx, &snd, volume); + if (res) Sounds_Fail(res); + return; } /* Try again with all contexts, even if need to recreate one (expensive) */ @@ -891,6 +892,11 @@ static void Sounds_LoadFile(const cc_string* path, void* obj) { static cc_bool sounds_loaded; static void Sounds_Start(void) { + int i; + for (i = 0; i < SOUND_MAX_CONTEXTS; i++) { + Audio_Init(&sound_contexts[i], 1); + } + if (sounds_loaded) return; sounds_loaded = true; Directory_Enum(&audio_dir, NULL, Sounds_LoadFile); @@ -899,7 +905,6 @@ static void Sounds_Start(void) { static void Sounds_Stop(void) { int i; for (i = 0; i < SOUND_MAX_CONTEXTS; i++) { - if (!sound_contexts[i].count) continue; Audio_Close(&sound_contexts[i]); } } diff --git a/src/Audio.h b/src/Audio.h index eaa2cb45c..455e96d13 100644 --- a/src/Audio.h +++ b/src/Audio.h @@ -30,10 +30,6 @@ void Audio_PlayStepSound(cc_uint8 type); void Audio_Init(struct AudioContext* ctx, int buffers); /* Stops any playing audio and then frees the audio context. */ void Audio_Close(struct AudioContext* ctx); -/* Returns number of channels of the format audio is played in. */ -int Audio_GetChannels(struct AudioContext* ctx); -/* Returns number of channels of the format audio is played in. */ -int Audio_GetSampleRate(struct AudioContext* ctx); /* Sets the format of the audio data to be played. */ /* NOTE: Changing the format can be expensive, depending on the backend. */ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate); @@ -48,5 +44,9 @@ cc_result Audio_Play(struct AudioContext* ctx); /* (e.g. if inUse is 0, no audio buffers are being played or queued) */ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse); +/* Plays the given audio data at the given volume */ cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume); +/* Whether the given audio context can play audio data in the given format */ +/* without recreating the underlying audio device */ +cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate); #endif From 7055bd1fa36eb7b6860a2c651e3af20877acdb84 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Tue, 10 Aug 2021 23:31:26 +1000 Subject: [PATCH 2/7] Move Audio_SetFormat into backend, fix backends not working at all --- src/Audio.c | 84 ++++++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/src/Audio.c b/src/Audio.c index 6201ca70c..2d51d1ad2 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -101,8 +101,8 @@ struct AudioContext { ALuint source; ALuint buffers[AUDIO_MAX_BUFFERS]; ALuint freeIDs[AUDIO_MAX_BUFFERS]; - int count, free, channels, sampleRate; - ALenum dataFormat; + int count, free, sampleRate; + ALenum channels; cc_uint32 _tmpSize; void* _tmpData; }; static void* audio_device; @@ -190,30 +190,17 @@ void Audio_Init(struct AudioContext* ctx, int buffers) { ctx->count = buffers; } -static cc_result AudioBackend_Reset(struct AudioContext* ctx) { - ALenum err; +static void AudioBackend_Reset(struct AudioContext* ctx) { ClearFree(ctx); - if (!ctx->source) return 0; + if (!ctx->source) return; _alDeleteSources(1, &ctx->source); - ctx->source = 0; - if ((err = _alGetError())) return err; - _alDeleteBuffers(ctx->count, ctx->buffers); - if ((err = _alGetError())) return err; - return 0; + ctx->source = 0; } -static ALenum GetALFormat(int channels) { - if (channels == 1) return AL_FORMAT_MONO16; - if (channels == 2) return AL_FORMAT_STEREO16; - Logger_Abort("Unsupported audio format"); return 0; -} - -static cc_result AudioBackend_UpdateFormat(struct AudioContext* ctx) { +cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { ALenum i, err; - ctx->dataFormat = GetALFormat(ctx->channels); - if (!ctx->source) { _alGenSources(1, &ctx->source); if ((err = _alGetError())) return err; @@ -226,6 +213,15 @@ static cc_result AudioBackend_UpdateFormat(struct AudioContext* ctx) { } ctx->free = ctx->count; } + ctx->sampleRate = sampleRate; + + if (channels == 1) { + ctx->channels = AL_FORMAT_MONO16; + } else if (channels == 2) { + ctx->channels = AL_FORMAT_STEREO16; + } else { + return ERR_INVALID_ARGUMENT; + } return 0; } @@ -236,7 +232,7 @@ cc_result Audio_QueueData(struct AudioContext* ctx, void* data, cc_uint32 size) if (!ctx->free) return ERR_INVALID_ARGUMENT; buffer = ctx->freeIDs[--ctx->free]; - _alBufferData(buffer, ctx->dataFormat, data, size, ctx->sampleRate); + _alBufferData(buffer, ctx->channels, data, size, ctx->sampleRate); if ((err = _alGetError())) return err; _alSourceQueueBuffers(ctx->source, 1, &buffer); if ((err = _alGetError())) return err; @@ -261,6 +257,8 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { ALenum err; *inUse = 0; + if (!ctx->source) return 0; + _alGetSourcei(ctx->source, AL_BUFFERS_PROCESSED, &processed); if ((err = _alGetError())) return err; @@ -358,16 +356,22 @@ static cc_result AudioBackend_Reset(struct AudioContext* ctx) { return res; } -static cc_result AudioBackend_UpdateFormat(struct AudioContext* ctx) { +cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { WAVEFORMATEX fmt; cc_result res; - int sampleSize = ctx->channels * 2; /* 16 bits per sample / 8 */ + int sampleSize; + + if (ctx->channels == channels && ctx->sampleRate == sampleRate) return 0; + ctx->channels = channels; + ctx->sampleRate = sampleRate; + + sampleSize = channels * 2; /* 16 bits per sample / 8 */ if ((res = AudioBackend_Reset(ctx))) return res; fmt.wFormatTag = WAVE_FORMAT_PCM; - fmt.nChannels = ctx->channels; - fmt.nSamplesPerSec = ctx->sampleRate; - fmt.nAvgBytesPerSec = ctx->sampleRate * sampleSize; + fmt.nChannels = channels; + fmt.nSamplesPerSec = sampleRate; + fmt.nAvgBytesPerSec = sampleRate * sampleSize; fmt.nBlockAlign = sampleSize; fmt.wBitsPerSample = 16; fmt.cbSize = 0; @@ -524,7 +528,7 @@ static void AudioBackend_Reset(struct AudioContext* ctx) { ctx->bqPlayerQueue = NULL; } -static cc_result AudioBackend_UpdateFormat(struct AudioContext* ctx) { +cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { SLDataLocator_AndroidSimpleBufferQueue input; SLDataLocator_OutputMix output; SLObjectItf bqPlayerObject; @@ -534,11 +538,15 @@ static cc_result AudioBackend_UpdateFormat(struct AudioContext* ctx) { SLDataSource src; SLDataSink dst; cc_result res; + + if (ctx->channels == channels && ctx->sampleRate == sampleRate) return 0; + ctx->channels = channels; + ctx->sampleRate = sampleRate; AudioBackend_Reset(ctx); fmt.formatType = SL_DATAFORMAT_PCM; - fmt.numChannels = ctx->channels; - fmt.samplesPerSec = ctx->sampleRate * 1000; + fmt.numChannels = channels; + fmt.samplesPerSec = sampleRate * 1000; fmt.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; fmt.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16; fmt.channelMask = 0; @@ -608,14 +616,6 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) { #ifndef AUDIO_HAS_BACKEND static void AudioBackend_Free(void) { } #else -cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { - if (ctx->channels == channels && ctx->sampleRate == sampleRate) return 0; - - ctx->channels = channels; - ctx->sampleRate = sampleRate; - return AudioBackend_UpdateFormat(ctx); -} - void Audio_Close(struct AudioContext* ctx) { int inUse; AudioBackend_Stop(ctx); @@ -828,12 +828,6 @@ static void Sounds_Play(cc_uint8 type, struct Soundboard* board) { snd_ = Soundboard_PickRandom(board, type); if (!snd_) return; - if (!AudioBackend_Init()) { - AudioBackend_Free(); - Audio_SoundsVolume = 0; - return; - } - snd = *snd_; volume = Audio_SoundsVolume; @@ -893,6 +887,12 @@ static void Sounds_LoadFile(const cc_string* path, void* obj) { static cc_bool sounds_loaded; static void Sounds_Start(void) { int i; + if (!AudioBackend_Init()) { + AudioBackend_Free(); + Audio_SoundsVolume = 0; + return; + } + for (i = 0; i < SOUND_MAX_CONTEXTS; i++) { Audio_Init(&sound_contexts[i], 1); } From dc692eefaa92c0cea45dc3c6a4d7b417d1c7450e Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 11 Aug 2021 19:20:41 +1000 Subject: [PATCH 3/7] Add error messages for audio --- src/Audio.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++----- src/Audio.h | 4 ++- 2 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/Audio.c b/src/Audio.c index 2d51d1ad2..20b54aeca 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -49,6 +49,10 @@ static int GetVolume(const char* volKey, const char* boolKey) { return volume; } +static void AudioWarn(cc_result res, const char* action) { + Logger_Warn(res, action, Audio_DescribeError); +} + #if defined CC_BUILD_OPENAL /*########################################################################################################################* @@ -69,6 +73,12 @@ static int GetVolume(const char* volKey, const char* boolKey) { #define AL_FORMAT_MONO16 0x1101 #define AL_FORMAT_STEREO16 0x1103 +#define AL_INVALID_NAME 0xA001 +#define AL_INVALID_ENUM 0xA002 +#define AL_INVALID_VALUE 0xA003 +#define AL_INVALID_OPERATION 0xA004 +#define AL_OUT_OF_MEMORY 0xA005 + typedef char ALboolean; typedef int ALint; typedef unsigned int ALuint; @@ -159,7 +169,7 @@ static cc_bool AudioBackend_Init(void) { if (!LoadALFuncs()) { Logger_WarnFunc(&msg); return false; } res = CreateALContext(); - if (res) { Logger_SimpleWarn(res, "initing OpenAL"); return false; } + if (res) { AudioWarn(res, "initing OpenAL"); return false; } return true; } @@ -275,6 +285,25 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) { /* Channels/Sample rate is per buffer, not a per source property */ return true; } + +static const char* GetError(cc_result res) { + switch (res) { + case AL_ERR_INIT_CONTEXT: return "Failed to init OpenAL context"; + case AL_ERR_INIT_DEVICE: return "Failed to init OpenAL device"; + case AL_INVALID_NAME: return "Invalid parameter name"; + case AL_INVALID_ENUM: return "Invalid parameter"; + case AL_INVALID_VALUE: return "Invalid parameter value"; + case AL_INVALID_OPERATION: return "Invalid operation"; + case AL_OUT_OF_MEMORY: return "OpenAL out of memory"; + } + return NULL; +} + +cc_bool Audio_DescribeError(cc_result res, cc_string* dst) { + const char* err = GetError(res); + if (err) String_AppendConst(dst, err); + return err != NULL; +} #elif defined CC_BUILD_WINMM /*########################################################################################################################* *------------------------------------------------------WinMM backend------------------------------------------------------* @@ -327,6 +356,7 @@ WINMMAPI MMRESULT WINAPI waveOutPrepareHeader(HWAVEOUT hwo, WAVEHDR* hdr, UINT h WINMMAPI MMRESULT WINAPI waveOutUnprepareHeader(HWAVEOUT hwo, WAVEHDR* hdr, UINT hdrSize); WINMMAPI MMRESULT WINAPI waveOutWrite(HWAVEOUT hwo, WAVEHDR* hdr, UINT hdrSize); WINMMAPI MMRESULT WINAPI waveOutReset(HWAVEOUT hwo); +WINMMAPI MMRESULT WINAPI waveOutGetErrorTextA(MMRESULT err, LPSTR text, UINT textLen); /* === END mmeapi.h === */ struct AudioContext { @@ -427,6 +457,15 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) { return !ctx->channels || (ctx->channels == channels && ctx->sampleRate == sampleRate); } + +cc_bool Audio_DescribeError(cc_result res, cc_string* dst) { + char buffer[NATIVE_STR_LEN] = { 0 }; + waveOutGetErrorTextA(res, buffer, NATIVE_STR_LEN); + + if (!buffer[0]) return false; + String_AppendConst(dst, buffer); + return true; +} #elif defined CC_BUILD_OPENSLES /*########################################################################################################################* *----------------------------------------------------OpenSL ES backend----------------------------------------------------* @@ -485,19 +524,19 @@ static cc_bool AudioBackend_Init(void) { ids[0] = *_SL_IID_NULL; req[0] = SL_BOOLEAN_FALSE; res = _slCreateEngine(&slEngineObject, 0, NULL, 0, NULL, NULL); - if (res) { Logger_SimpleWarn(res, "creating OpenSL ES engine"); return false; } + if (res) { AudioWarn(res, "creating OpenSL ES engine"); return false; } res = (*slEngineObject)->Realize(slEngineObject, SL_BOOLEAN_FALSE); - if (res) { Logger_SimpleWarn(res, "realising OpenSL ES engine"); return false; } + if (res) { AudioWarn(res, "realising OpenSL ES engine"); return false; } res = (*slEngineObject)->GetInterface(slEngineObject, *_SL_IID_ENGINE, &slEngineEngine); - if (res) { Logger_SimpleWarn(res, "initing OpenSL ES engine"); return false; } + if (res) { AudioWarn(res, "initing OpenSL ES engine"); return false; } res = (*slEngineEngine)->CreateOutputMix(slEngineEngine, &slOutputObject, 1, ids, req); - if (res) { Logger_SimpleWarn(res, "creating OpenSL ES mixer"); return false; } + if (res) { AudioWarn(res, "creating OpenSL ES mixer"); return false; } res = (*slOutputObject)->Realize(slOutputObject, SL_BOOLEAN_FALSE); - if (res) { Logger_SimpleWarn(res, "realising OpenSL ES mixer"); return false; } + if (res) { AudioWarn(res, "realising OpenSL ES mixer"); return false; } return true; } @@ -608,6 +647,34 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) { return !ctx->channels || (ctx->channels == channels && ctx->sampleRate == sampleRate); } + +static const char* GetError(cc_result res) { + switch (res) { + case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated"; + case SL_RESULT_PARAMETER_INVALID: return "Invalid parameter"; + case SL_RESULT_MEMORY_FAILURE: return "Memory failure"; + case SL_RESULT_RESOURCE_ERROR: return "Resource error"; + case SL_RESULT_RESOURCE_LOST: return "Resource lost"; + case SL_RESULT_IO_ERROR: return "I/O error"; + case SL_RESULT_BUFFER_INSUFFICIENT: return "Insufficient buffer"; + case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted"; + case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported"; + case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found"; + case SL_RESULT_PERMISSION_DENIED: return "Permission denied"; + case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported"; + case SL_RESULT_INTERNAL_ERROR: return "Internal error"; + case SL_RESULT_UNKNOWN_ERROR: return "Unknown error"; + case SL_RESULT_OPERATION_ABORTED: return "Operation aborted"; + case SL_RESULT_CONTROL_LOST: return "Control lost"; + } + return NULL; +} + +cc_bool Audio_DescribeError(cc_result res, cc_string* dst) { + const char* err = GetError(res); + if (err) String_AppendConst(dst, err); + return err != NULL; +} #endif /*########################################################################################################################* @@ -812,7 +879,7 @@ static const struct Sound* Soundboard_PickRandom(struct Soundboard* board, cc_ui CC_NOINLINE static void Sounds_Fail(cc_result res) { - Logger_SimpleWarn(res, "playing sounds"); + AudioWarn(res, "playing sounds"); Chat_AddRaw("&cDisabling sounds"); Audio_SetSounds(0); } diff --git a/src/Audio.h b/src/Audio.h index 455e96d13..1aee4f26d 100644 --- a/src/Audio.h +++ b/src/Audio.h @@ -46,7 +46,9 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse); /* Plays the given audio data at the given volume */ cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume); -/* Whether the given audio context can play audio data in the given format */ +/* Whether the given audio context can play audio data in the given format, */ /* without recreating the underlying audio device */ cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate); +/* Outputs more detailed information about errors with audio. */ +cc_bool Audio_DescribeError(cc_result res, cc_string* dst); #endif From a3e81f3f5741799f6e37b6dc4fdd86b201cbfb11 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Thu, 12 Aug 2021 11:54:24 +1000 Subject: [PATCH 4/7] Fix OpenAL backend crashing when sounds is initially 0 due to my mistakes --- src/Audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Audio.c b/src/Audio.c index 20b54aeca..b9dc13a82 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -255,7 +255,7 @@ cc_result Audio_Play(struct AudioContext* ctx) { } static void AudioBackend_Stop(struct AudioContext* ctx) { - if (ctx->source == -1) return; + if (!ctx->source) return; _alSourceStop(ctx->source); _alGetError(); From 37dfbcfefd2d48a49a35a04ec30d39ae679809bf Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Thu, 12 Aug 2021 17:16:18 +1000 Subject: [PATCH 5/7] Split up Audio_Close and mostly move into backend --- src/Audio.c | 80 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/src/Audio.c b/src/Audio.c index b9dc13a82..b830e19e1 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -52,6 +52,7 @@ static int GetVolume(const char* volKey, const char* boolKey) { static void AudioWarn(cc_result res, const char* action) { Logger_Warn(res, action, Audio_DescribeError); } +static void AudioContext_Clear(struct AudioContext* ctx); #if defined CC_BUILD_OPENAL @@ -200,15 +201,26 @@ void Audio_Init(struct AudioContext* ctx, int buffers) { ctx->count = buffers; } -static void AudioBackend_Reset(struct AudioContext* ctx) { - ClearFree(ctx); - if (!ctx->source) return; +static void Audio_Stop(struct AudioContext* ctx) { + _alSourceStop(ctx->source); +} - _alDeleteSources(1, &ctx->source); +static void Audio_Reset(struct AudioContext* ctx) { + _alDeleteSources(1, &ctx->source); _alDeleteBuffers(ctx->count, ctx->buffers); ctx->source = 0; } +void Audio_Close(struct AudioContext* ctx) { + if (ctx->source) { + Audio_Stop(ctx); + Audio_Reset(ctx); + _alGetError(); + } + ClearFree(ctx->source); + AudioContext_Clear(ctx); +} + cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { ALenum i, err; if (!ctx->source) { @@ -254,13 +266,6 @@ cc_result Audio_Play(struct AudioContext* ctx) { return _alGetError(); } -static void AudioBackend_Stop(struct AudioContext* ctx) { - if (!ctx->source) return; - - _alSourceStop(ctx->source); - _alGetError(); -} - cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { ALint processed = 0; ALuint buffer; @@ -377,7 +382,11 @@ void Audio_Init(struct AudioContext* ctx, int buffers) { ctx->count = buffers; } -static cc_result AudioBackend_Reset(struct AudioContext* ctx) { +static void Audio_Stop(struct AudioContext* ctx) { + waveOutReset(ctx->handle); +} + +static cc_result Audio_Reset(struct AudioContext* ctx) { cc_result res; if (!ctx->handle) return 0; @@ -386,6 +395,16 @@ static cc_result AudioBackend_Reset(struct AudioContext* ctx) { return res; } +void Audio_Close(struct AudioContext* ctx) { + int inUse; + if (ctx->handle) { + Audio_Stop(ctx); + Audio_Poll(ctx, &inUse); /* unprepare buffers */ + Audio_Reset(ctx); + } + AudioContext_Clear(ctx); +} + cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { WAVEFORMATEX fmt; cc_result res; @@ -396,7 +415,7 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate ctx->sampleRate = sampleRate; sampleSize = channels * 2; /* 16 bits per sample / 8 */ - if ((res = AudioBackend_Reset(ctx))) return res; + if ((res = Audio_Reset(ctx))) return res; fmt.wFormatTag = WAVE_FORMAT_PCM; fmt.nChannels = channels; @@ -432,10 +451,6 @@ cc_result Audio_QueueData(struct AudioContext* ctx, void* data, cc_uint32 dataSi cc_result Audio_Play(struct AudioContext* ctx) { return 0; } -static void AudioBackend_Stop(struct AudioContext* ctx) { - if (ctx->handle) waveOutReset(ctx->handle); -} - cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { cc_result res = 0; WAVEHDR* hdr; @@ -557,7 +572,14 @@ void Audio_Init(struct AudioContext* ctx, int buffers) { ctx->count = buffers; } -static void AudioBackend_Reset(struct AudioContext* ctx) { +static void Audio_Stop(struct AudioContext* ctx) { + if (!ctx->bqPlayerPlayer) return; + + (*ctx->bqPlayerQueue)->Clear(ctx->bqPlayerQueue); + (*ctx->bqPlayerPlayer)->SetPlayState(ctx->bqPlayerPlayer, SL_PLAYSTATE_STOPPED); +} + +static void Audio_Reset(struct AudioContext* ctx) { SLObjectItf bqPlayerObject = ctx->bqPlayerObject; if (!bqPlayerObject) return; @@ -567,6 +589,12 @@ static void AudioBackend_Reset(struct AudioContext* ctx) { ctx->bqPlayerQueue = NULL; } +void Audio_Close(struct AudioContext* ctx) { + Audio_Stop(ctx); + Audio_Reset(ctx); + AudioContext_Clear(ctx); +} + cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { SLDataLocator_AndroidSimpleBufferQueue input; SLDataLocator_OutputMix output; @@ -581,7 +609,7 @@ cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate if (ctx->channels == channels && ctx->sampleRate == sampleRate) return 0; ctx->channels = channels; ctx->sampleRate = sampleRate; - AudioBackend_Reset(ctx); + Audio_Reset(ctx); fmt.formatType = SL_DATAFORMAT_PCM; fmt.numChannels = channels; @@ -626,13 +654,6 @@ cc_result Audio_Play(struct AudioContext* ctx) { return (*ctx->bqPlayerPlayer)->SetPlayState(ctx->bqPlayerPlayer, SL_PLAYSTATE_PLAYING); } -static void AudioBackend_Stop(struct AudioContext* ctx) { - if (!ctx->bqPlayerPlayer) return; - - (*ctx->bqPlayerQueue)->Clear(ctx->bqPlayerQueue); - (*ctx->bqPlayerPlayer)->SetPlayState(ctx->bqPlayerPlayer, SL_PLAYSTATE_STOPPED); -} - cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) { SLBufferQueueState state = { 0 }; cc_result res = 0; @@ -683,11 +704,7 @@ cc_bool Audio_DescribeError(cc_result res, cc_string* dst) { #ifndef AUDIO_HAS_BACKEND static void AudioBackend_Free(void) { } #else -void Audio_Close(struct AudioContext* ctx) { - int inUse; - AudioBackend_Stop(ctx); - Audio_Poll(ctx, &inUse); /* unqueue buffers */ - +static void AudioContext_Clear(struct AudioContext* ctx) { ctx->count = 0; ctx->channels = 0; ctx->sampleRate = 0; @@ -695,7 +712,6 @@ void Audio_Close(struct AudioContext* ctx) { Mem_Free(ctx->_tmpData); ctx->_tmpData = NULL; ctx->_tmpSize = 0; - AudioBackend_Reset(ctx); } cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume) { From ad79a63b058cf86742142357e52a728e48f26718 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Thu, 12 Aug 2021 19:15:32 +1000 Subject: [PATCH 6/7] Split up Audio_PlaySound and partially move into backend --- src/Audio.c | 72 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/src/Audio.c b/src/Audio.c index b830e19e1..1add4d47d 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -49,10 +49,13 @@ static int GetVolume(const char* volKey, const char* boolKey) { return volume; } +/* Common/Base methods */ static void AudioWarn(cc_result res, const char* action) { Logger_Warn(res, action, Audio_DescribeError); } -static void AudioContext_Clear(struct AudioContext* ctx); +static void AudioBase_Clear(struct AudioContext* ctx); +static void* AudioBase_AdjustSound(struct AudioContext* ctx, struct Sound* snd, int volume); +static cc_result AudioBase_PlaySound(struct AudioContext* ctx, struct Sound* snd, void* data); #if defined CC_BUILD_OPENAL @@ -218,7 +221,7 @@ void Audio_Close(struct AudioContext* ctx) { _alGetError(); } ClearFree(ctx->source); - AudioContext_Clear(ctx); + AudioBase_Clear(ctx); } cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { @@ -291,6 +294,12 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) { return true; } +cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume) { + void* data = AudioBase_AdjustSound(ctx, snd, volume); + if (data) return AudioBase_PlaySound(ctx, snd, data); + return ERR_OUT_OF_MEMORY; +} + static const char* GetError(cc_result res) { switch (res) { case AL_ERR_INIT_CONTEXT: return "Failed to init OpenAL context"; @@ -402,7 +411,7 @@ void Audio_Close(struct AudioContext* ctx) { Audio_Poll(ctx, &inUse); /* unprepare buffers */ Audio_Reset(ctx); } - AudioContext_Clear(ctx); + AudioBase_Clear(ctx); } cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { @@ -473,6 +482,12 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) { return !ctx->channels || (ctx->channels == channels && ctx->sampleRate == sampleRate); } +cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume) { + void* data = AudioBase_AdjustSound(ctx, snd, volume); + if (data) return AudioBase_PlaySound(ctx, snd, data); + return ERR_OUT_OF_MEMORY; +} + cc_bool Audio_DescribeError(cc_result res, cc_string* dst) { char buffer[NATIVE_STR_LEN] = { 0 }; waveOutGetErrorTextA(res, buffer, NATIVE_STR_LEN); @@ -592,7 +607,7 @@ static void Audio_Reset(struct AudioContext* ctx) { void Audio_Close(struct AudioContext* ctx) { Audio_Stop(ctx); Audio_Reset(ctx); - AudioContext_Clear(ctx); + AudioBase_Clear(ctx); } cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate) { @@ -669,6 +684,12 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) { return !ctx->channels || (ctx->channels == channels && ctx->sampleRate == sampleRate); } +cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume) { + void* data = AudioBase_AdjustSound(ctx, snd, volume); + if (data) return AudioBase_PlaySound(ctx, snd, data); + return ERR_OUT_OF_MEMORY; +} + static const char* GetError(cc_result res) { switch (res) { case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated"; @@ -704,7 +725,7 @@ cc_bool Audio_DescribeError(cc_result res, cc_string* dst) { #ifndef AUDIO_HAS_BACKEND static void AudioBackend_Free(void) { } #else -static void AudioContext_Clear(struct AudioContext* ctx) { +static void AudioBase_Clear(struct AudioContext* ctx) { ctx->count = 0; ctx->channels = 0; ctx->sampleRate = 0; @@ -714,31 +735,32 @@ static void AudioContext_Clear(struct AudioContext* ctx) { ctx->_tmpSize = 0; } -cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume) { - cc_result res; - void* data = snd->data; - void* tmp; - - /* copy to temp buffer to apply volume */ - if (volume < 100) { - if (ctx->_tmpSize < snd->size) { - /* TODO: check if we can realloc NULL without a problem */ - if (ctx->_tmpData) { - tmp = Mem_TryRealloc(ctx->_tmpData, snd->size, 1); - } else { - tmp = Mem_TryAlloc(snd->size, 1); - } +static void* AudioBase_AdjustSound(struct AudioContext* ctx, struct Sound* snd, int volume) { + void* data; + if (volume >= 100) return snd->data; - if (!tmp) return ERR_OUT_OF_MEMORY; - ctx->_tmpData = tmp; - ctx->_tmpSize = snd->size; + /* copy to temp buffer to apply volume */ + if (ctx->_tmpSize < snd->size) { + /* TODO: check if we can realloc NULL without a problem */ + if (ctx->_tmpData) { + data = Mem_TryRealloc(ctx->_tmpData, snd->size, 1); + } else { + data = Mem_TryAlloc(snd->size, 1); } - data = ctx->_tmpData; - Mem_Copy(data, snd->data, snd->size); - ApplyVolume((cc_int16*)data, snd->size / 2, volume); + if (!data) return NULL; + ctx->_tmpData = data; + ctx->_tmpSize = snd->size; } + data = ctx->_tmpData; + Mem_Copy(data, snd->data, snd->size); + ApplyVolume((cc_int16*)data, snd->size / 2, volume); + return data; +} + +static cc_result AudioBase_PlaySound(struct AudioContext* ctx, struct Sound* snd, void* data) { + cc_result res; if ((res = Audio_SetFormat(ctx, snd->channels, snd->sampleRate))) return res; if ((res = Audio_QueueData(ctx, data, snd->size))) return res; if ((res = Audio_Play(ctx))) return res; From 399bc9210a9d005e9f3e8f668f657b53e6890d59 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Thu, 12 Aug 2021 20:13:10 +1000 Subject: [PATCH 7/7] How many times will I break OpenAL backend? --- src/Audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Audio.c b/src/Audio.c index 1add4d47d..bc486ef03 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -220,7 +220,7 @@ void Audio_Close(struct AudioContext* ctx) { Audio_Reset(ctx); _alGetError(); } - ClearFree(ctx->source); + ClearFree(ctx); AudioBase_Clear(ctx); }