2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 slouken@devolution.com
25 Epoc based SDL audio driver implementation
32 "@(#) $Id: SDL_epocaudio.c,v 0.0.0.0 2001/06/19 17:19:56 hercules Exp $";
44 #include <sys/ioctl.h>
53 #include "SDL_audio.h"
54 #include "SDL_error.h"
55 #include "SDL_audiomem.h"
56 #include "SDL_audio_c.h"
57 #include "SDL_timer.h"
58 #include "SDL_audiodev_c.h"
61 #include "SDL_epocaudio.h"
63 #include "streamplayer.h"
69 /* Audio driver functions */
71 static int EPOC_OpenAudio(SDL_AudioDevice *thisdevice, SDL_AudioSpec *spec);
72 static void EPOC_WaitAudio(SDL_AudioDevice *thisdevice);
73 static void EPOC_PlayAudio(SDL_AudioDevice *thisdevice);
74 static Uint8 *EPOC_GetAudioBuf(SDL_AudioDevice *thisdevice);
75 static void EPOC_CloseAudio(SDL_AudioDevice *thisdevice);
76 static void EPOC_ThreadInit(SDL_AudioDevice *thisdevice);
78 static int Audio_Available(void);
79 static SDL_AudioDevice *Audio_CreateDevice(int devindex);
80 static void Audio_DeleteDevice(SDL_AudioDevice *device);
83 //void sos_adump(SDL_AudioDevice* thisdevice, void* data, int len);
90 NONSHARABLE_CLASS(TDump)
95 void Dump(const TDesC8& aDes);
103 TInt err = iFs.Connect();
107 _LIT(target, "C:\\sdlau.raw");
109 _LIT(target, "E:\\sdlau.raw");
111 err = iFile.Replace(iFs, target, EFileWrite);
120 void TDump::Dump(const TDesC8& aDes)
127 NONSHARABLE_CLASS(CSimpleWait) : public CTimer
130 void Wait(TTimeIntervalMicroSeconds32 aWait);
131 static CSimpleWait* NewL();
138 CSimpleWait* CSimpleWait::NewL()
140 CSimpleWait* wait = new (ELeave) CSimpleWait();
141 CleanupStack::PushL(wait);
147 void CSimpleWait::Wait(TTimeIntervalMicroSeconds32 aWait)
150 CActiveScheduler::Start();
153 CSimpleWait::CSimpleWait() : CTimer(CActive::EPriorityStandard)
155 CActiveScheduler::Add(this);
158 void CSimpleWait::RunL()
160 CActiveScheduler::Stop();
163 const TInt KAudioBuffers(2);
166 NONSHARABLE_CLASS(CEpocAudio) : public CBase, public MStreamObs, public MStreamProvider
169 static void* NewL(TInt BufferSize, TInt aFill);
170 inline static CEpocAudio& Current(SDL_AudioDevice* thisdevice);
172 static void Free(SDL_AudioDevice* thisdevice);
176 // void SetBuffer(const TDesC8& aBuffer);
177 void ThreadInitL(TAny* aDevice);
178 void Open(TInt iRate, TInt iChannels, TUint32 aType, TInt aBytes);
181 TBool SetPause(TBool aPause);
183 void Dump(const TDesC8& aBuf) {iDump.Dump(aBuf);}
186 CEpocAudio(TInt aBufferSize);
187 void Complete(TInt aState, TInt aError);
189 void ConstructL(TInt aFill);
192 CStreamPlayer* iPlayer;
201 // TTimeIntervalMicroSeconds iStart;
210 inline CEpocAudio& CEpocAudio::Current(SDL_AudioDevice* thisdevice)
212 return *static_cast<CEpocAudio*>((void*)thisdevice->hidden);
219 CActiveScheduler::Stop();
222 LOCAL_C void CleanScL()
224 CIdle* d = CIdle::NewLC(CActive:::EPriorityIdle);
225 d->Start(TCallBack(EndSc));
226 CActiveScheduler::Start();
231 void CEpocAudio::Free(SDL_AudioDevice* thisdevice)
233 CEpocAudio* ea = static_cast<CEpocAudio*>((void*)thisdevice->hidden);
236 ASSERT(ea->iTid == RThread().Id());
238 thisdevice->hidden = NULL;
240 CActiveScheduler* as = CActiveScheduler::Current();
241 ASSERT(as->StackDepth() == 0);
243 CActiveScheduler::Install(NULL);
245 ASSERT(thisdevice->hidden == NULL);
248 CEpocAudio::CEpocAudio(TInt aBufferSize) : iBufferSize(aBufferSize), iPosition(-1)
252 void* CEpocAudio::NewL(TInt aBufferSize, TInt aFill)
254 CEpocAudio* eAudioLib = new (ELeave) CEpocAudio(aBufferSize);
255 CleanupStack::PushL(eAudioLib);
256 eAudioLib->ConstructL(aFill);
261 void CEpocAudio::ConstructL(TInt aFill)
263 iBuffer = (TUint8*) User::AllocL(KAudioBuffers * iBufferSize);
264 memset(iBuffer, aFill, KAudioBuffers * iBufferSize);
269 TBool CEpocAudio::SetPause(TBool aPause)
271 if(aPause && iPosition >= 0)
277 if(!aPause && iPosition < 0)
283 return iPosition < 0;
286 void CEpocAudio::ThreadInitL(TAny* aDevice)
288 iTid = RThread().Id();
289 CActiveScheduler* as = new (ELeave) CActiveScheduler();
290 CActiveScheduler::Install(as);
292 EpocSdlEnv::AppendCleanupItem(TSdlCleanupItem((TSdlCleanupOperation)EPOC_CloseAudio, aDevice));
294 iWait = CSimpleWait::NewL();
296 iPlayer = new (ELeave) CStreamPlayer(*this, *this);
297 iPlayer->ConstructL();
298 iPlayer->OpenStream(iRate, iChannels, iType);
301 User::LeaveIfError(iDump.Open());
307 TUint8* CEpocAudio::Buffer()
309 iStart.UniversalTime();
310 // iStart = iPlayer->Position();
315 CEpocAudio::~CEpocAudio()
326 void CEpocAudio::Complete(TInt aState, TInt aError)
328 if(aState == MStreamObs::EClose)
331 if(iPlayer->Closed())
345 void sos_adump(SDL_AudioDevice* thisdevice, void* data, int len)
348 const TPtrC8 buf((TUint8*)data, len);
349 CEpocAudio::Current(thisdevice).Dump(buf);
353 const TInt KClip(256);
355 TPtrC8 CEpocAudio::Data()
360 TPtrC8 data(iAudioPtr + iPosition, KClip);
367 if(iPosition >= iBufferSize)
370 /* if(iAudioPtr == iBuffer)
371 iAudioPtr = iBuffer + iBufferSize;
375 iAudioPtr += iBufferSize;
377 if((iAudioPtr - iBuffer) >= KAudioBuffers * iBufferSize)
381 if(iWait->IsActive())
384 CActiveScheduler::Stop();
393 void CEpocAudio::Play()
398 void CEpocAudio::Wait()
400 if(iPosition >= 0 /*&& iPlayer->Playing()*/)
402 const TInt64 bufMs = TInt64(iBufferSize - KClip) * TInt64(1000000);
403 const TInt64 specTime = bufMs / TInt64(iRate * iChannels * 2);
404 iWait->After(specTime);
406 CActiveScheduler::Start();
409 const TTimeIntervalMicroSeconds delta = end.MicroSecondsFrom(iStart);
412 // const TTimeIntervalMicroSeconds end = iPlayer->Position();
417 const TInt diff = specTime - delta.Int64();
419 if(diff > 0 && diff < 200000)
428 // iWait->Wait(10000); //just give some time...
432 void CEpocAudio::Open(TInt aRate, TInt aChannels, TUint32 aType, TInt aBytes)
435 iChannels = aChannels;
437 iBufferRate = iRate * iChannels * aBytes; //1/x
441 /* Audio driver bootstrap functions */
443 AudioBootStrap EPOCAudio_bootstrap = {
445 "EPOC streaming audio\0\0\0",
451 static SDL_AudioDevice *Audio_CreateDevice(int /*devindex*/)
453 SDL_AudioDevice *thisdevice;
455 /* Initialize all variables that we clean on shutdown */
456 thisdevice = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
458 memset(thisdevice, 0, (sizeof *thisdevice));
459 thisdevice->hidden = NULL; /*(struct SDL_PrivateAudioData *)
460 malloc((sizeof thisdevice->hidden)); */
462 if ( (thisdevice == NULL) /*|| (thisdevice->hidden == NULL) */) {
469 // memset(thisdevice->hidden, 0, (sizeof *thisdevice->hidden));
471 /* Set the function pointers */
472 thisdevice->OpenAudio = EPOC_OpenAudio;
473 thisdevice->WaitAudio = EPOC_WaitAudio;
474 thisdevice->PlayAudio = EPOC_PlayAudio;
475 thisdevice->GetAudioBuf = EPOC_GetAudioBuf;
476 thisdevice->CloseAudio = EPOC_CloseAudio;
477 thisdevice->ThreadInit = EPOC_ThreadInit;
478 thisdevice->free = Audio_DeleteDevice;
484 static void Audio_DeleteDevice(SDL_AudioDevice *device)
486 //free(device->hidden);
490 static int Audio_Available(void)
492 return(1); // Audio stream modules should be always there!
496 static int EPOC_OpenAudio(SDL_AudioDevice *thisdevice, SDL_AudioSpec *spec)
498 SDL_TRACE("SDL:EPOC_OpenAudio");
501 TUint32 type = KMMFFourCCCodePCM16;
507 type = KMMFFourCCCodePCMU16;
510 type = KMMFFourCCCodePCM16;
513 type = KMMFFourCCCodePCMU16B;
516 type = KMMFFourCCCodePCM16B;
518 //8 bit not supported!
522 spec->format = AUDIO_S16LSB;
527 if(spec->channels > 2)
530 spec->freq = CStreamPlayer::ClosestSupportedRate(spec->freq);
533 /* Allocate mixing buffer */
534 const TInt buflen = spec->size;// * bytes * spec->channels;
537 TRAPD(err, thisdevice->hidden = static_cast<SDL_PrivateAudioData*>(CEpocAudio::NewL(buflen, spec->silence)));
541 CEpocAudio::Current(thisdevice).Open(spec->freq, spec->channels, type, bytes);
543 CEpocAudio::Current(thisdevice).SetPause(ETrue);
545 // isSDLAudioPaused = 1;
547 thisdevice->enabled = 0; /* enable only after audio engine has been initialized!*/
549 /* We're ready to rock and roll. :-) */
554 static void EPOC_CloseAudio(SDL_AudioDevice* thisdevice)
557 SDL_TRACE("Close audio\n");
560 CEpocAudio::Free(thisdevice);
564 static void EPOC_ThreadInit(SDL_AudioDevice *thisdevice)
566 SDL_TRACE("SDL:EPOC_ThreadInit");
567 CEpocAudio::Current(thisdevice).ThreadInitL(thisdevice);
568 RThread().SetPriority(EPriorityMore);
569 thisdevice->enabled = 1;
572 /* This function waits until it is possible to write a full sound buffer */
573 static void EPOC_WaitAudio(SDL_AudioDevice* thisdevice)
576 SDL_TRACE1("wait %d audio\n", CEpocAudio::AudioLib().StreamPlayer(KSfxChannel).SyncTime());
577 TInt tics = User::TickCount();
580 CEpocAudio::Current(thisdevice).Wait();
583 TInt ntics = User::TickCount() - tics;
584 SDL_TRACE1("audio waited %d\n", ntics);
585 SDL_TRACE1("audio at %d\n", tics);
591 static void EPOC_PlayAudio(SDL_AudioDevice* thisdevice)
593 if(CEpocAudio::Current(thisdevice).SetPause(SDL_GetAudioStatus() == SDL_AUDIO_PAUSED))
594 SDL_Delay(500); //hold on the busy loop
596 CEpocAudio::Current(thisdevice).Play();
599 SDL_TRACE("buffer has audio data\n");
604 SDL_TRACE1("Wrote %d bytes of audio data\n", buflen);
608 static Uint8 *EPOC_GetAudioBuf(SDL_AudioDevice* thisdevice)
610 return CEpocAudio::Current(thisdevice).Buffer();