From 0b102ee2c105320efe25b54ac55cdd176af32017 Mon Sep 17 00:00:00 2001 From: Shinovon Date: Tue, 3 Jun 2025 17:22:33 +0500 Subject: [PATCH] Symbian: Implement audio backend --- misc/symbian/ClassiCube_common.mmh | 3 +- src/Audio.c | 45 ++-- src/Audio_Symbian.cpp | 378 +++++++++++++++++++++++++++++ src/Core.h | 3 - src/Platform_Symbian.cpp | 9 + 5 files changed, 417 insertions(+), 21 deletions(-) create mode 100644 src/Audio_Symbian.cpp diff --git a/misc/symbian/ClassiCube_common.mmh b/misc/symbian/ClassiCube_common.mmh index db9ba410d..ee807829e 100644 --- a/misc/symbian/ClassiCube_common.mmh +++ b/misc/symbian/ClassiCube_common.mmh @@ -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 diff --git a/src/Audio.c b/src/Audio.c index 9b791d66b..77ba07dd6 100644 --- a/src/Audio.c +++ b/src/Audio.c @@ -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; } diff --git a/src/Audio_Symbian.cpp b/src/Audio_Symbian.cpp new file mode 100644 index 000000000..cddc643f1 --- /dev/null +++ b/src/Audio_Symbian.cpp @@ -0,0 +1,378 @@ +#include "Core.h" +#if defined CC_BUILD_SYMBIAN && CC_AUD_BACKEND != CC_AUD_BACKEND_NULL + +#include +#include +#include +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 diff --git a/src/Core.h b/src/Core.h index 9e77f8813..b4e6d6bdf 100644 --- a/src/Core.h +++ b/src/Core.h @@ -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 diff --git a/src/Platform_Symbian.cpp b/src/Platform_Symbian.cpp index c26c1f676..62db0f8aa 100644 --- a/src/Platform_Symbian.cpp +++ b/src/Platform_Symbian.cpp @@ -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; }