mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-08 14:56:12 -04:00
Merge pull request #1380 from shinovon/symbian-sound
Symbian: implement audio backend
This commit is contained in:
commit
33d73d9f4d
@ -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
|
||||
|
45
src/Audio.c
45
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;
|
||||
}
|
||||
|
||||
|
378
src/Audio_Symbian.cpp
Normal file
378
src/Audio_Symbian.cpp
Normal 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
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user