2
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997, 1998, 1999, 2000, 2001 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();