📄 sdl_epocaudio.cpp
字号:
/* SDL - Simple DirectMedia Layer Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Sam Lantinga slouken@devolution.com*//* SDL_epocaudio.cpp Epoc based SDL audio driver implementation Markus Mertama*/#ifdef SAVE_RCSIDstatic char rcsid = "@(#) $Id: SDL_epocaudio.c,v 0.0.0.0 2001/06/19 17:19:56 hercules Exp $";#endif#include <stdlib.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <unistd.h>#include <fcntl.h>#include <signal.h>#include <sys/time.h>#include <sys/ioctl.h>#include <sys/stat.h>#include "epoc_sdl.h"#include <e32hal.h>extern "C" {#include "SDL_audio.h"#include "SDL_error.h"#include "SDL_audiomem.h"#include "SDL_audio_c.h"#include "SDL_timer.h"#include "SDL_audiodev_c.h"}#include "SDL_epocaudio.h"#include "streamplayer.h"//#define DEBUG_AUDIO/* Audio driver functions */static int EPOC_OpenAudio(SDL_AudioDevice *thisdevice, SDL_AudioSpec *spec);static void EPOC_WaitAudio(SDL_AudioDevice *thisdevice);static void EPOC_PlayAudio(SDL_AudioDevice *thisdevice);static Uint8 *EPOC_GetAudioBuf(SDL_AudioDevice *thisdevice);static void EPOC_CloseAudio(SDL_AudioDevice *thisdevice);static void EPOC_ThreadInit(SDL_AudioDevice *thisdevice);static int Audio_Available(void);static SDL_AudioDevice *Audio_CreateDevice(int devindex);static void Audio_DeleteDevice(SDL_AudioDevice *device);//void sos_adump(SDL_AudioDevice* thisdevice, void* data, int len);#ifdef __WINS__#define DODUMP#endif#ifdef DODUMPNONSHARABLE_CLASS(TDump) { public: TInt Open(); void Close(); void Dump(const TDesC8& aDes); private: RFile iFile; RFs iFs; }; TInt TDump::Open() { TInt err = iFs.Connect(); if(err == KErrNone) {#ifdef __WINS___LIT(target, "C:\\sdlau.raw");#else_LIT(target, "E:\\sdlau.raw");#endif err = iFile.Replace(iFs, target, EFileWrite); } return err; }void TDump::Close() { iFile.Close(); iFs.Close(); }void TDump::Dump(const TDesC8& aDes) { iFile.Write(aDes); }#endifNONSHARABLE_CLASS(CSimpleWait) : public CTimer { public: void Wait(TTimeIntervalMicroSeconds32 aWait); static CSimpleWait* NewL(); private: CSimpleWait(); void RunL(); };CSimpleWait* CSimpleWait::NewL() { CSimpleWait* wait = new (ELeave) CSimpleWait(); CleanupStack::PushL(wait); wait->ConstructL(); CleanupStack::Pop(); return wait; }void CSimpleWait::Wait(TTimeIntervalMicroSeconds32 aWait) { After(aWait); CActiveScheduler::Start(); } CSimpleWait::CSimpleWait() : CTimer(CActive::EPriorityStandard) { CActiveScheduler::Add(this); }void CSimpleWait::RunL() { CActiveScheduler::Stop(); }const TInt KAudioBuffers(2); NONSHARABLE_CLASS(CEpocAudio) : public CBase, public MStreamObs, public MStreamProvider { public: static void* NewL(TInt BufferSize, TInt aFill); inline static CEpocAudio& Current(SDL_AudioDevice* thisdevice); static void Free(SDL_AudioDevice* thisdevice); void Wait(); void Play(); // void SetBuffer(const TDesC8& aBuffer); void ThreadInitL(TAny* aDevice); void Open(TInt iRate, TInt iChannels, TUint32 aType, TInt aBytes); ~CEpocAudio(); TUint8* Buffer(); TBool SetPause(TBool aPause); #ifdef DODUMP void Dump(const TDesC8& aBuf) {iDump.Dump(aBuf);} #endif private: CEpocAudio(TInt aBufferSize); void Complete(TInt aState, TInt aError); TPtrC8 Data(); void ConstructL(TInt aFill); private: TInt iBufferSize; CStreamPlayer* iPlayer; TInt iBufferRate; TInt iRate; TInt iChannels; TUint32 iType; TInt iPosition; TThreadId iTid; TUint8* iAudioPtr; TUint8* iBuffer; // TTimeIntervalMicroSeconds iStart; TTime iStart; TInt iTune; CSimpleWait* iWait; #ifdef DODUMP TDump iDump; #endif };inline CEpocAudio& CEpocAudio::Current(SDL_AudioDevice* thisdevice) { return *static_cast<CEpocAudio*>((void*)thisdevice->hidden); } /*TBool EndSc(TAny*) { CActiveScheduler::Stop(); } LOCAL_C void CleanScL() { CIdle* d = CIdle::NewLC(CActive:::EPriorityIdle); d->Start(TCallBack(EndSc)); CActiveScheduler::Start(); }*/ void CEpocAudio::Free(SDL_AudioDevice* thisdevice) { CEpocAudio* ea = static_cast<CEpocAudio*>((void*)thisdevice->hidden); if(ea) { ASSERT(ea->iTid == RThread().Id()); delete ea; thisdevice->hidden = NULL; CActiveScheduler* as = CActiveScheduler::Current(); ASSERT(as->StackDepth() == 0); delete as; CActiveScheduler::Install(NULL); } ASSERT(thisdevice->hidden == NULL); } CEpocAudio::CEpocAudio(TInt aBufferSize) : iBufferSize(aBufferSize), iPosition(-1) { }void* CEpocAudio::NewL(TInt aBufferSize, TInt aFill) { CEpocAudio* eAudioLib = new (ELeave) CEpocAudio(aBufferSize); CleanupStack::PushL(eAudioLib); eAudioLib->ConstructL(aFill); CleanupStack::Pop(); return eAudioLib; } void CEpocAudio::ConstructL(TInt aFill) { iBuffer = (TUint8*) User::AllocL(KAudioBuffers * iBufferSize); memset(iBuffer, aFill, KAudioBuffers * iBufferSize); iAudioPtr = iBuffer; }TBool CEpocAudio::SetPause(TBool aPause) { if(aPause && iPosition >= 0) { iPosition = -1; if(iPlayer != NULL) iPlayer->Stop(); } if(!aPause && iPosition < 0) { iPosition = 0; if(iPlayer != NULL) iPlayer->Start(); } return iPosition < 0; } void CEpocAudio::ThreadInitL(TAny* aDevice) { iTid = RThread().Id(); CActiveScheduler* as = new (ELeave) CActiveScheduler(); CActiveScheduler::Install(as); EpocSdlEnv::AppendCleanupItem(TSdlCleanupItem((TSdlCleanupOperation)EPOC_CloseAudio, aDevice)); iWait = CSimpleWait::NewL(); iPlayer = new (ELeave) CStreamPlayer(*this, *this); iPlayer->ConstructL(); iPlayer->OpenStream(iRate, iChannels, iType); #ifdef DODUMP User::LeaveIfError(iDump.Open()); #endif } TUint8* CEpocAudio::Buffer() { iStart.UniversalTime();// iStart = iPlayer->Position(); return iAudioPtr; } CEpocAudio::~CEpocAudio() { if(iWait != NULL) iWait->Cancel(); delete iWait; if(iPlayer != NULL) iPlayer->Close(); delete iPlayer; delete iBuffer; } void CEpocAudio::Complete(TInt aState, TInt aError) { if(aState == MStreamObs::EClose) { } if(iPlayer->Closed()) return; switch(aError) { case KErrUnderflow: case KErrInUse: iPlayer->Start(); break; case KErrAbort: iPlayer->Open(); } } void sos_adump(SDL_AudioDevice* thisdevice, void* data, int len) {#ifdef DODUMP const TPtrC8 buf((TUint8*)data, len); CEpocAudio::Current(thisdevice).Dump(buf);#endif }const TInt KClip(256); TPtrC8 CEpocAudio::Data() { if(iPosition < 0) return KNullDesC8(); TPtrC8 data(iAudioPtr + iPosition, KClip); #ifdef DODUMP iDump.Dump(data);#endif iPosition += KClip; if(iPosition >= iBufferSize) { /* if(iAudioPtr == iBuffer) iAudioPtr = iBuffer + iBufferSize; else iAudioPtr = iBuffer;*/ iAudioPtr += iBufferSize; if((iAudioPtr - iBuffer) >= KAudioBuffers * iBufferSize) iAudioPtr = iBuffer; iPosition = -1; if(iWait->IsActive()) { iWait->Cancel(); CActiveScheduler::Stop(); } } return data; } void CEpocAudio::Play() { iPosition = 0; }void CEpocAudio::Wait() { if(iPosition >= 0 /*&& iPlayer->Playing()*/) { const TInt64 bufMs = TInt64(iBufferSize - KClip) * TInt64(1000000); const TInt64 specTime = bufMs / TInt64(iRate * iChannels * 2); iWait->After(specTime); CActiveScheduler::Start(); TTime end; end.UniversalTime(); const TTimeIntervalMicroSeconds delta = end.MicroSecondsFrom(iStart); // const TTimeIntervalMicroSeconds end = iPlayer->Position(); const TInt diff = specTime - delta.Int64(); if(diff > 0 && diff < 200000) { User::After(diff); } } else { User::After(10000); // iWait->Wait(10000); //just give some time... } } void CEpocAudio::Open(TInt aRate, TInt aChannels, TUint32 aType, TInt aBytes) { iRate = aRate; iChannels = aChannels; iType = aType; iBufferRate = iRate * iChannels * aBytes; //1/x } /* Audio driver bootstrap functions */AudioBootStrap EPOCAudio_bootstrap = { "epoc\0\0\0", "EPOC streaming audio\0\0\0", Audio_Available, Audio_CreateDevice};static SDL_AudioDevice *Audio_CreateDevice(int /*devindex*/){ SDL_AudioDevice *thisdevice; /* Initialize all variables that we clean on shutdown */ thisdevice = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice)); if ( thisdevice ) { memset(thisdevice, 0, (sizeof *thisdevice)); thisdevice->hidden = NULL; /*(struct SDL_PrivateAudioData *) malloc((sizeof thisdevice->hidden)); */ } if ( (thisdevice == NULL) /*|| (thisdevice->hidden == NULL) */) { SDL_OutOfMemory(); if ( thisdevice ) { free(thisdevice); } return(0); }// memset(thisdevice->hidden, 0, (sizeof *thisdevice->hidden)); /* Set the function pointers */ thisdevice->OpenAudio = EPOC_OpenAudio; thisdevice->WaitAudio = EPOC_WaitAudio; thisdevice->PlayAudio = EPOC_PlayAudio; thisdevice->GetAudioBuf = EPOC_GetAudioBuf; thisdevice->CloseAudio = EPOC_CloseAudio; thisdevice->ThreadInit = EPOC_ThreadInit; thisdevice->free = Audio_DeleteDevice; return thisdevice;}static void Audio_DeleteDevice(SDL_AudioDevice *device) { //free(device->hidden); free(device); }static int Audio_Available(void){ return(1); // Audio stream modules should be always there!}static int EPOC_OpenAudio(SDL_AudioDevice *thisdevice, SDL_AudioSpec *spec){ SDL_TRACE("SDL:EPOC_OpenAudio"); TUint32 type = KMMFFourCCCodePCM16; TInt bytes = 2; switch(spec->format) { case AUDIO_U16LSB: type = KMMFFourCCCodePCMU16; break; case AUDIO_S16LSB: type = KMMFFourCCCodePCM16; break; case AUDIO_U16MSB: type = KMMFFourCCCodePCMU16B; break; case AUDIO_S16MSB: type = KMMFFourCCCodePCM16B; break; //8 bit not supported! case AUDIO_U8: case AUDIO_S8: default: spec->format = AUDIO_S16LSB; }; if(spec->channels > 2) spec->channels = 2; spec->freq = CStreamPlayer::ClosestSupportedRate(spec->freq); /* Allocate mixing buffer */ const TInt buflen = spec->size;// * bytes * spec->channels;// audiobuf = NULL; TRAPD(err, thisdevice->hidden = static_cast<SDL_PrivateAudioData*>(CEpocAudio::NewL(buflen, spec->silence))); if(err != KErrNone) return -1; CEpocAudio::Current(thisdevice).Open(spec->freq, spec->channels, type, bytes); CEpocAudio::Current(thisdevice).SetPause(ETrue); // isSDLAudioPaused = 1; thisdevice->enabled = 0; /* enable only after audio engine has been initialized!*/ /* We're ready to rock and roll. :-) */ return(0);}static void EPOC_CloseAudio(SDL_AudioDevice* thisdevice) {#ifdef DEBUG_AUDIO SDL_TRACE("Close audio\n");#endif CEpocAudio::Free(thisdevice); }static void EPOC_ThreadInit(SDL_AudioDevice *thisdevice) { SDL_TRACE("SDL:EPOC_ThreadInit"); CEpocAudio::Current(thisdevice).ThreadInitL(thisdevice); RThread().SetPriority(EPriorityMore); thisdevice->enabled = 1; }/* This function waits until it is possible to write a full sound buffer */static void EPOC_WaitAudio(SDL_AudioDevice* thisdevice){#ifdef DEBUG_AUDIO SDL_TRACE1("wait %d audio\n", CEpocAudio::AudioLib().StreamPlayer(KSfxChannel).SyncTime()); TInt tics = User::TickCount();#endif CEpocAudio::Current(thisdevice).Wait();#ifdef DEBUG_AUDIO TInt ntics = User::TickCount() - tics; SDL_TRACE1("audio waited %d\n", ntics); SDL_TRACE1("audio at %d\n", tics);#endif} static void EPOC_PlayAudio(SDL_AudioDevice* thisdevice) { if(CEpocAudio::Current(thisdevice).SetPause(SDL_GetAudioStatus() == SDL_AUDIO_PAUSED)) SDL_Delay(500); //hold on the busy loop else CEpocAudio::Current(thisdevice).Play();#ifdef DEBUG_AUDIO SDL_TRACE("buffer has audio data\n");#endif #ifdef DEBUG_AUDIO SDL_TRACE1("Wrote %d bytes of audio data\n", buflen);#endif}static Uint8 *EPOC_GetAudioBuf(SDL_AudioDevice* thisdevice) { return CEpocAudio::Current(thisdevice).Buffer(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -