Merge pull request #1380 from shinovon/symbian-sound

Symbian: implement audio backend
This commit is contained in:
UnknownShadow200 2025-06-04 17:26:07 +10:00 committed by GitHub
commit 33d73d9f4d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 417 additions and 21 deletions

View File

@ -27,6 +27,7 @@ LIBRARY avkon.lib
LIBRARY fbscli.lib
LIBRARY ws32.lib
LIBRARY hal.lib
LIBRARY mediaclientaudiostream.lib
LIBRARY libc.lib
LIBRARY libm.lib
@ -43,7 +44,7 @@ OPTION_REPLACE ARMCC -O2 -O3
#endif
SOURCEPATH ../../src
SOURCE Animations.c Audio.c Audio_Null.c AxisLinesRenderer.c Bitmap.c Block.c BlockPhysics.c Builder.c Camera.c Chat.c Commands.c Deflate.c Drawer.c Drawer2D.c Entity.c EntityComponents.c EntityRenderers.c EnvRenderer.c Event.c ExtMath.c FancyLighting.c Formats.c Game.c GameVersion.c Generator.c Graphics_GL1.c Graphics_SoftGPU.c Gui.c HeldBlockRenderer.c Http_Web.c Http_Worker.c Input.c InputHandler.c Inventory.c IsometricDrawer.c LBackend.c LScreens.c LWeb.c LWidgets.c Launcher.c Lighting.c Logger.c MapRenderer.c MenuOptions.c Menus.c Model.c Options.c PackedCol.c Particle.c Physics.c Picking.c Platform_Posix.c Protocol.c Queue.c Resources.c SSL.c Screens.c SelOutlineRenderer.c SelectionBox.c Server.c Stream.c String.c SystemFonts.c TexturePack.c TouchUI.c Utils.c Vectors.c Widgets.c World.c _autofit.c _cff.c _ftbase.c _ftbitmap.c _ftglyph.c _ftinit.c _ftsynth.c _psaux.c _pshinter.c _psmodule.c _sfnt.c _smooth.c _truetype.c _type1.c Vorbis.c main.c Platform_Symbian.cpp Graphics_GL2.c Window_Symbian.cpp
SOURCE Animations.c Audio.c Audio_Null.c AxisLinesRenderer.c Bitmap.c Block.c BlockPhysics.c Builder.c Camera.c Chat.c Commands.c Deflate.c Drawer.c Drawer2D.c Entity.c EntityComponents.c EntityRenderers.c EnvRenderer.c Event.c ExtMath.c FancyLighting.c Formats.c Game.c GameVersion.c Generator.c Graphics_GL1.c Graphics_SoftGPU.c Gui.c HeldBlockRenderer.c Http_Web.c Http_Worker.c Input.c InputHandler.c Inventory.c IsometricDrawer.c LBackend.c LScreens.c LWeb.c LWidgets.c Launcher.c Lighting.c Logger.c MapRenderer.c MenuOptions.c Menus.c Model.c Options.c PackedCol.c Particle.c Physics.c Picking.c Platform_Posix.c Protocol.c Queue.c Resources.c SSL.c Screens.c SelOutlineRenderer.c SelectionBox.c Server.c Stream.c String.c SystemFonts.c TexturePack.c TouchUI.c Utils.c Vectors.c Widgets.c World.c _autofit.c _cff.c _ftbase.c _ftbitmap.c _ftglyph.c _ftinit.c _ftsynth.c _psaux.c _pshinter.c _psmodule.c _sfnt.c _smooth.c _truetype.c _type1.c Vorbis.c main.c Platform_Symbian.cpp Graphics_GL2.c Window_Symbian.cpp Audio_Symbian.cpp
SOURCEPATH ../../third_party/bearssl/src
SOURCE aes_big_cbcdec.c aes_big_cbcenc.c aes_big_ctr.c aes_big_ctrcbc.c aes_big_dec.c aes_big_enc.c aes_common.c aes_ct.c aes_ct64.c aes_ct64_cbcdec.c aes_ct64_cbcenc.c aes_ct64_ctr.c aes_ct64_ctrcbc.c aes_ct64_dec.c aes_ct64_enc.c aes_ct_cbcdec.c aes_ct_cbcenc.c aes_ct_ctr.c aes_ct_ctrcbc.c aes_ct_dec.c aes_ct_enc.c aes_small_cbcdec.c aes_small_cbcenc.c aes_small_ctr.c aes_small_ctrcbc.c aes_small_dec.c aes_small_enc.c aes_x86ni.c aes_x86ni_cbcdec.c aes_x86ni_cbcenc.c aes_x86ni_ctr.c aes_x86ni_ctrcbc.c aesctr_drbg.c asn1enc.c ccm.c ccopy.c chacha20_ct.c chacha20_sse2.c dec16be.c dec16le.c dec32be.c dec32le.c dec64be.c dec64le.c des_ct.c des_ct_cbcdec.c des_ct_cbcenc.c des_support.c des_tab.c des_tab_cbcdec.c des_tab_cbcenc.c dig_oid.c dig_size.c eax.c ec_all_m15.c ec_all_m31.c ec_c25519_i15.c ec_c25519_i31.c ec_c25519_m15.c ec_c25519_m31.c ec_c25519_m62.c ec_c25519_m64.c ec_curve25519.c ec_default.c ec_keygen.c ec_p256_m15.c ec_p256_m31.c ec_p256_m62.c ec_p256_m64.c ec_prime_i15.c ec_prime_i31.c ec_pubkey.c ec_secp256r1.c ec_secp384r1.c ec_secp521r1.c ecdsa_atr.c ecdsa_default_sign_asn1.c ecdsa_default_sign_raw.c ecdsa_default_vrfy_asn1.c ecdsa_default_vrfy_raw.c ecdsa_i15_bits.c ecdsa_i15_sign_asn1.c ecdsa_i15_sign_raw.c ecdsa_i15_vrfy_asn1.c ecdsa_i15_vrfy_raw.c ecdsa_i31_bits.c ecdsa_i31_sign_asn1.c ecdsa_i31_sign_raw.c ecdsa_i31_vrfy_asn1.c ecdsa_i31_vrfy_raw.c ecdsa_rta.c enc16be.c enc16le.c enc32be.c enc32le.c enc64be.c enc64le.c encode_ec_pk8der.c encode_ec_rawder.c encode_rsa_pk8der.c encode_rsa_rawder.c gcm.c ghash_ctmul.c ghash_ctmul32.c ghash_ctmul64.c ghash_pclmul.c hkdf.c hmac.c hmac_ct.c hmac_drbg.c i15_add.c i15_bitlen.c i15_decmod.c i15_decode.c i15_decred.c i15_encode.c i15_fmont.c i15_iszero.c i15_moddiv.c i15_modpow.c i15_modpow2.c i15_montmul.c i15_mulacc.c i15_muladd.c i15_ninv15.c i15_reduce.c i15_rshift.c i15_sub.c i15_tmont.c i31_add.c i31_bitlen.c i31_decmod.c i31_decode.c i31_decred.c i31_encode.c i31_fmont.c i31_iszero.c i31_moddiv.c i31_modpow.c i31_modpow2.c i31_montmul.c i31_mulacc.c i31_muladd.c i31_ninv31.c i31_reduce.c i31_rshift.c i31_sub.c i31_tmont.c i32_add.c i32_bitlen.c i32_decmod.c i32_decode.c i32_decred.c i32_div32.c i32_encode.c i32_fmont.c i32_iszero.c i32_modpow.c i32_montmul.c i32_mulacc.c i32_muladd.c i32_ninv32.c i32_reduce.c i32_sub.c i32_tmont.c i62_modpow2.c md5.c md5sha1.c mgf1.c multihash.c poly1305_ctmul.c poly1305_ctmul32.c poly1305_ctmulq.c poly1305_i15.c prf.c prf_md5sha1.c prf_sha256.c prf_sha384.c rsa_default_keygen.c rsa_default_modulus.c rsa_default_oaep_decrypt.c rsa_default_oaep_encrypt.c rsa_default_pkcs1_sign.c rsa_default_pkcs1_vrfy.c rsa_default_priv.c rsa_default_privexp.c rsa_default_pss_sign.c rsa_default_pss_vrfy.c rsa_default_pub.c rsa_default_pubexp.c rsa_i15_keygen.c rsa_i15_modulus.c rsa_i15_oaep_decrypt.c rsa_i15_oaep_encrypt.c rsa_i15_pkcs1_sign.c rsa_i15_pkcs1_vrfy.c rsa_i15_priv.c rsa_i15_privexp.c rsa_i15_pss_sign.c rsa_i15_pss_vrfy.c rsa_i15_pub.c rsa_i15_pubexp.c rsa_i31_keygen.c rsa_i31_keygen_inner.c rsa_i31_modulus.c rsa_i31_oaep_decrypt.c rsa_i31_oaep_encrypt.c rsa_i31_pkcs1_sign.c rsa_i31_pkcs1_vrfy.c rsa_i31_priv.c rsa_i31_privexp.c rsa_i31_pss_sign.c rsa_i31_pss_vrfy.c rsa_i31_pub.c rsa_i31_pubexp.c rsa_i32_oaep_decrypt.c rsa_i32_oaep_encrypt.c rsa_i32_pkcs1_sign.c rsa_i32_pkcs1_vrfy.c rsa_i32_priv.c rsa_i32_pss_sign.c rsa_i32_pss_vrfy.c rsa_i32_pub.c rsa_i62_keygen.c rsa_i62_oaep_decrypt.c rsa_i62_oaep_encrypt.c rsa_i62_pkcs1_sign.c rsa_i62_pkcs1_vrfy.c rsa_i62_priv.c rsa_i62_pss_sign.c rsa_i62_pss_vrfy.c rsa_i62_pub.c rsa_oaep_pad.c rsa_oaep_unpad.c rsa_pkcs1_sig_pad.c rsa_pkcs1_sig_unpad.c rsa_pss_sig_pad.c rsa_pss_sig_unpad.c rsa_ssl_decrypt.c settings.c sha1.c sha2big.c sha2small.c shake.c skey_decoder.c ssl_ccert_single_ec.c ssl_ccert_single_rsa.c ssl_client.c ssl_client_default_rsapub.c ssl_client_full.c ssl_engine.c ssl_engine_default_aescbc.c ssl_engine_default_aesccm.c ssl_engine_default_aesgcm.c ssl_engine_default_chapol.c ssl_engine_default_descbc.c ssl_engine_default_ec.c ssl_engine_default_ecdsa.c ssl_engine_default_rsavrfy.c ssl_hashes.c ssl_hs_client.c ssl_io.c ssl_keyexport.c ssl_lru.c ssl_rec_cbc.c ssl_rec_ccm.c ssl_rec_chapol.c ssl_rec_gcm.c ssl_scert_single_ec.c ssl_scert_single_rsa.c sysrng.c x509_decoder.c x509_knownkey.c x509_minimal.c x509_minimal_full.c

View File

@ -13,7 +13,7 @@
#include "Utils.h"
#include "Options.h"
#include "Deflate.h"
#ifdef CC_BUILD_ANDROID
#ifdef CC_BUILD_MOBILE
/* TODO: Refactor maybe to not rely on checking WinInfo.Handle != NULL */
#include "Window.h"
#endif
@ -353,27 +353,34 @@ static cc_result Music_Buffer(struct AudioChunk* chunk, int maxSamples, struct V
}
static cc_result Music_PlayOgg(struct Stream* source) {
struct OggState ogg;
struct VorbisState vorbis;
int channels, sampleRate, volume;
int chunkSize, samplesPerSecond;
struct AudioChunk chunks[AUDIO_MAX_BUFFERS] = { 0 };
int inUse, i, cur;
cc_result res;
#if CC_BUILD_MAXSTACK <= (64 * 1024)
struct VorbisState* vorbis = (struct VorbisState*)Mem_TryAllocCleared(1, sizeof(struct VorbisState));
struct OggState* ogg = (struct OggState*)Mem_TryAllocCleared(1, sizeof(struct OggState));
if (!vorbis || !ogg) return ERR_OUT_OF_MEMORY;
#else
struct OggState _ogg;
struct OggState* ogg = &ogg;
struct VorbisState _vorbis;
struct VorbisState* vorbis = &vorbis;
#endif
Ogg_Init(&ogg, source);
Vorbis_Init(&vorbis);
vorbis.source = &ogg;
if ((res = Vorbis_DecodeHeaders(&vorbis))) goto cleanup;
Ogg_Init(ogg, source);
Vorbis_Init(vorbis);
vorbis->source = ogg;
if ((res = Vorbis_DecodeHeaders(vorbis))) goto cleanup;
channels = vorbis.channels;
sampleRate = vorbis.sampleRate;
channels = vorbis->channels;
sampleRate = vorbis->sampleRate;
if ((res = Audio_SetFormat(&music_ctx, channels, sampleRate, 100))) goto cleanup;
/* largest possible vorbis frame decodes to blocksize1 * channels samples, */
/* so can end up decoding slightly over a second of audio */
chunkSize = channels * (sampleRate + vorbis.blockSizes[1]);
chunkSize = channels * (sampleRate + vorbis->blockSizes[1]);
samplesPerSecond = channels * sampleRate;
if ((res = Audio_AllocChunks(chunkSize * 2, chunks, AUDIO_MAX_BUFFERS))) goto cleanup;
@ -383,7 +390,7 @@ static cc_result Music_PlayOgg(struct Stream* source) {
/* fill up with some samples before playing */
for (i = 0; i < AUDIO_MAX_BUFFERS && !res; i++)
{
res = Music_Buffer(&chunks[i], samplesPerSecond, &vorbis);
res = Music_Buffer(&chunks[i], samplesPerSecond, vorbis);
}
if (music_stopping) goto cleanup;
@ -392,12 +399,12 @@ static cc_result Music_PlayOgg(struct Stream* source) {
cur = 0;
while (!music_stopping) {
#ifdef CC_BUILD_ANDROID
#ifdef CC_BUILD_MOBILE
/* Don't play music while in the background on Android */
/* TODO: Not use such a terrible approach */
if (!Window_Main.Handle.ptr) {
if (!Window_Main.Handle.ptr || Window_Main.Inactive) {
Audio_Pause(&music_ctx);
while (!Window_Main.Handle.ptr && !music_stopping) {
while ((!Window_Main.Handle.ptr || Window_Main.Inactive) && !music_stopping) {
Thread_Sleep(10); continue;
}
Audio_Play(&music_ctx);
@ -415,7 +422,7 @@ static cc_result Music_PlayOgg(struct Stream* source) {
Thread_Sleep(10); continue;
}
res = Music_Buffer(&chunks[cur], samplesPerSecond, &vorbis);
res = Music_Buffer(&chunks[cur], samplesPerSecond, vorbis);
cur = (cur + 1) % AUDIO_MAX_BUFFERS;
/* need to specially handle last bit of audio */
@ -437,7 +444,11 @@ static cc_result Music_PlayOgg(struct Stream* source) {
cleanup:
Audio_FreeChunks(chunks, AUDIO_MAX_BUFFERS);
Vorbis_Free(&vorbis);
Vorbis_Free(vorbis);
#if CC_BUILD_MAXSTACK <= (64 * 1024)
Mem_Free(ogg);
Mem_Free(vorbis);
#endif
return res == ERR_END_OF_STREAM ? 0 : res;
}

378
src/Audio_Symbian.cpp Normal file
View File

@ -0,0 +1,378 @@
#include "Core.h"
#if defined CC_BUILD_SYMBIAN && CC_AUD_BACKEND != CC_AUD_BACKEND_NULL
#include <e32base.h>
#include <MdaAudioOutputStream.h>
#include <mda/common/audio.h>
extern "C" {
#include "Audio.h"
#include "Platform.h"
#include "Errors.h"
#include "Funcs.h"
}
#define AUDIO_COMMON_ALLOC
struct AudioBuffer {
int available;
int size;
void* samples;
};
class CAudioStream;
struct AudioContext {
int count, bufHead, channels, sampleRate, volume;
CAudioStream* stream;
struct AudioBuffer bufs[AUDIO_MAX_BUFFERS];
};
extern "C" {
#include "_AudioBase.h"
}
enum AudioState {
STATE_INITIALIZED = 0x1,
STATE_STARTED = 0x2,
STATE_STOPPED = 0x4,
STATE_CLOSED = 0x8,
STATE_CHANGE_VOLUME = 0x10,
STATE_CHANGE_FORMAT = 0x20,
};
class CAudioStream : public CBase, public MMdaAudioOutputStreamCallback {
public:
static CAudioStream* NewL(struct AudioContext* ctx);
virtual ~CAudioStream();
void MaoscOpenComplete(TInt aError);
void MaoscBufferCopied(TInt aError, const TDesC8 &aBuffer);
void MaoscPlayComplete(TInt aError);
void Open();
void Stop();
void Close();
void Start();
void Write(struct AudioChunk* chunk);
void Request();
protected:
CAudioStream(struct AudioContext* ctx);
void ConstructL();
public:
int iState;
private:
CMdaAudioOutputStream* iOutputStream;
TMdaAudioDataSettings iAudioSettings;
struct AudioContext* iContext;
TPtrC8 iPtr;
TBuf8<256> iSilence;
};
CAudioStream::CAudioStream(struct AudioContext* ctx) :
iContext(ctx) { }
CAudioStream::~CAudioStream() {
if (iState & STATE_INITIALIZED) {
Stop();
}
User::After(100000);
delete iOutputStream;
}
CAudioStream* CAudioStream::NewL(struct AudioContext* ctx) {
CAudioStream* self = new (ELeave) CAudioStream(ctx);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop();
return self;
}
void CAudioStream::ConstructL() {
iOutputStream = CMdaAudioOutputStream::NewL(*this);
iSilence.SetMax();
iSilence.FillZ();
}
void CAudioStream::Open() {
iAudioSettings.iCaps = TMdaAudioDataSettings::ERealTime | TMdaAudioDataSettings::ESampleRateFixed;
iState &= ~STATE_STOPPED;
iOutputStream->Open(&iAudioSettings);
}
void CAudioStream::Stop() {
if (iState & (STATE_STARTED | STATE_INITIALIZED)) {
Close();
iState |= STATE_STOPPED;
}
}
void CAudioStream::Close() {
iState &= ~STATE_INITIALIZED;
iOutputStream->Stop();
iState &= ~STATE_STARTED;
}
void CAudioStream::Start() {
if (iPtr.Length() == 0) {
iState |= STATE_STARTED;
if (iState & STATE_INITIALIZED) {
Request();
} else if (iState & STATE_STOPPED) {
Open();
}
}
}
static int GetSampleRate(int sampleRate) {
switch (sampleRate) {
case 8000:
return TMdaAudioDataSettings::ESampleRate8000Hz;
case 11025:
return TMdaAudioDataSettings::ESampleRate11025Hz;
case 12000:
return TMdaAudioDataSettings::ESampleRate12000Hz;
case 16000:
return TMdaAudioDataSettings::ESampleRate16000Hz;
case 22050:
return TMdaAudioDataSettings::ESampleRate22050Hz;
case 24000:
return TMdaAudioDataSettings::ESampleRate24000Hz;
case 32000:
return TMdaAudioDataSettings::ESampleRate32000Hz;
case 44100:
return TMdaAudioDataSettings::ESampleRate44100Hz;
case 48000:
return TMdaAudioDataSettings::ESampleRate48000Hz;
case 96000:
return TMdaAudioDataSettings::ESampleRate96000Hz;
case 64000:
return TMdaAudioDataSettings::ESampleRate64000Hz;
default:
return 0;
}
}
static int GetNearestSampleRate(int sampleRate) {
if (sampleRate >= 96000) return 96000;
if (sampleRate < 8000) return 8000;
while (GetSampleRate(sampleRate) == 0) {
++sampleRate;
}
return sampleRate;
}
void CAudioStream::MaoscOpenComplete(TInt aError) {
if (aError == KErrNone) {
iOutputStream->SetPriority(EMdaPriorityNormal, EMdaPriorityPreferenceTime);
iState |= STATE_INITIALIZED | STATE_CHANGE_VOLUME | STATE_CHANGE_FORMAT;
if (iState & STATE_STARTED) {
Request();
}
} else {
Audio_Warn(aError, "Failed to open audio stream");
}
}
void CAudioStream::MaoscBufferCopied(TInt aError, const TDesC8& aBuffer) {
iPtr.Set(KNullDesC8);
if (iContext->count) {
struct AudioBuffer* buf = &iContext->bufs[iContext->bufHead];
iContext->bufHead = (iContext->bufHead + 1) % iContext->count;
buf->available = true;
}
if (aError == KErrNone) {
if (iState & STATE_INITIALIZED) {
Request();
} else {
iOutputStream->Stop();
}
}
}
void CAudioStream::MaoscPlayComplete(TInt aError) {
iPtr.Set(KNullDesC8);
iState &= ~STATE_STARTED;
if (aError != KErrNone) {
// Audio_Warn(aError, "MaoscPlayComplete");
}
}
void CAudioStream::Write(struct AudioChunk* chunk) {
iPtr.Set((const TUint8*)chunk->data, (TInt)chunk->size);
}
void CAudioStream::Request() {
if (iState & STATE_INITIALIZED) {
iPtr.Set(KNullDesC8);
if (iState & STATE_CHANGE_FORMAT) {
iState &= ~STATE_CHANGE_FORMAT;
int sampleRate = GetSampleRate(GetNearestSampleRate(iContext->sampleRate));
int channels;
switch (iContext->channels) {
case 1:
channels = TMdaAudioDataSettings::EChannelsMono;
break;
case 2:
default:
channels = TMdaAudioDataSettings::EChannelsStereo;
break;
}
iOutputStream->SetAudioPropertiesL(sampleRate, channels);
}
if (iState & STATE_CHANGE_VOLUME) {
iState &= ~STATE_CHANGE_VOLUME;
iOutputStream->SetVolume((iContext->volume * iOutputStream->MaxVolume()) / 100);
}
if (iState & STATE_STARTED) {
struct AudioBuffer* buf = &iContext->bufs[iContext->bufHead];
if (buf->size == 0 && buf->samples == NULL) {
return;
}
iPtr.Set((const TUint8*)buf->samples, (TInt)buf->size);
buf->size = 0;
buf->samples = NULL;
}
if (iPtr.Length() == 0) {
iPtr.Set(iSilence);
}
TRAPD(err, iOutputStream->WriteL(iPtr));
if (err != KErrNone) {
Audio_Warn(err, "Failed to write to audio stream");
}
}
}
cc_bool AudioBackend_Init(void) {
return true;
}
void AudioBackend_Tick(void) { }
void AudioBackend_Free(void) { }
cc_bool Audio_DescribeError(cc_result res, cc_string* dst) {
return false;
}
cc_result Audio_Init(struct AudioContext* ctx, int buffers) {
TRAPD(err, ctx->stream = CAudioStream::NewL(ctx));
if (err != KErrNone) {
return err;
}
ctx->count = buffers;
ctx->bufHead = 0;
ctx->volume = 100;
Mem_Set(ctx->bufs, 0, sizeof(ctx->bufs));
for (int i = 0; i < buffers; i++) {
ctx->bufs[i].available = true;
}
return 0;
}
void Audio_Close(struct AudioContext* ctx) {
ctx->count = 0;
if (ctx->stream) {
delete ctx->stream;
ctx->stream = NULL;
}
}
void Audio_SetVolume(struct AudioContext* ctx, int volume) {
ctx->volume = volume;
ctx->stream->iState |= STATE_CHANGE_VOLUME;
}
cc_result Audio_QueueChunk(struct AudioContext* ctx, struct AudioChunk* chunk) {
struct AudioBuffer* buf;
for (int i = 0; i < ctx->count; i++) {
buf = &ctx->bufs[i];
if (!buf->available) continue;
buf->samples = chunk->data;
buf->size = chunk->size;
buf->available = false;
return 0;
}
return ERR_INVALID_ARGUMENT;
}
cc_result Audio_Play(struct AudioContext* ctx) {
TRAPD(err, ctx->stream->Start());
return err;
}
cc_result Audio_Pause(struct AudioContext* ctx) {
ctx->stream->Stop();
return 0;
}
cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) {
struct AudioBuffer* buf;
int count = 0;
// FIXME: music thread check
if (ctx->count == AUDIO_MAX_BUFFERS) {
// Process background tasks in music thread
RThread thread;
TInt error = KErrNone;
while (thread.RequestCount()) {
CActiveScheduler::RunIfReady(error, CActive::EPriorityIdle);
User::WaitForAnyRequest();
}
}
for (int i = 0; i < ctx->count; i++) {
buf = &ctx->bufs[i];
if (!buf->available) count++;
}
*inUse = count;
return 0;
}
cc_result Audio_SetFormat(struct AudioContext* ctx, int channels, int sampleRate, int playbackRate) {
int sampleRateNew = Audio_AdjustSampleRate(sampleRate, playbackRate);
if (ctx->channels != channels || ctx->sampleRate != sampleRateNew) {
ctx->stream->Stop();
ctx->channels = channels;
ctx->sampleRate = sampleRateNew;
ctx->stream->iState |= STATE_CHANGE_FORMAT;
}
if (!(ctx->stream->iState & STATE_INITIALIZED)) {
ctx->stream->Open();
}
return 0;
}
cc_result Audio_AllocChunks(cc_uint32 size, struct AudioChunk* chunks, int numChunks) {
return AudioBase_AllocChunks(size, chunks, numChunks);
}
void Audio_FreeChunks(struct AudioChunk* chunks, int numChunks) {
AudioBase_FreeChunks(chunks, numChunks);
}
static cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) {
int channels = data->channels;
int sampleRate = Audio_AdjustSampleRate(data->sampleRate, data->rate);
return !ctx->channels || (ctx->channels == channels && ctx->sampleRate == sampleRate);
}
#endif

View File

@ -573,9 +573,6 @@ typedef cc_uint8 cc_bool;
#define CC_BUILD_EGL
#define CC_BUILD_MAXSTACK (16 * 1024)
#define CC_BUILD_LOWMEM
#define CC_BUILD_NOMUSIC
#define CC_BUILD_NOSOUNDS
#define DEFAULT_AUD_BACKEND CC_AUD_BACKEND_NULL
#define DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN
#define DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL

View File

@ -291,7 +291,16 @@ void Thread_Sleep(cc_uint32 milliseconds) {
}
static void* ExecThread(void* param) {
CTrapCleanup* cleanup = CTrapCleanup::New();
CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
CActiveScheduler::Install(scheduler);
((Thread_StartFunc)param)();
CActiveScheduler::Install(NULL);
delete scheduler;
delete cleanup;
return NULL;
}