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
31 #include <sys/ioctl.h>
40 #include "SDL_audio.h"
41 #include "SDL_error.h"
42 #include "SDL_audiomem.h"
43 #include "SDL_audio_c.h"
44 #include "SDL_timer.h"
45 #include "SDL_audiodev_c.h"
48 #include "SDL_epocaudio.h"
50 #include "streamplayer.h"
52 /* Audio driver functions */
54 static int EPOC_OpenAudio(SDL_AudioDevice
*thisdevice
, SDL_AudioSpec
*spec
);
55 static void EPOC_WaitAudio(SDL_AudioDevice
*thisdevice
);
56 static void EPOC_PlayAudio(SDL_AudioDevice
*thisdevice
);
57 static Uint8
*EPOC_GetAudioBuf(SDL_AudioDevice
*thisdevice
);
58 static void EPOC_CloseAudio(SDL_AudioDevice
*thisdevice
);
59 static void EPOC_ThreadInit(SDL_AudioDevice
*thisdevice
);
61 static int Audio_Available(void);
62 static SDL_AudioDevice
*Audio_CreateDevice(int devindex
);
63 static void Audio_DeleteDevice(SDL_AudioDevice
*device
);
65 const int KAudioBuffers
= 2;
67 NONSHARABLE_CLASS(CSimpleWait
) : public CTimer
70 void Wait(TTimeIntervalMicroSeconds32 aWait
);
71 static CSimpleWait
* NewL();
77 CSimpleWait
* CSimpleWait::NewL()
79 CSimpleWait
* wait
= new (ELeave
) CSimpleWait();
80 CleanupStack::PushL(wait
);
86 void CSimpleWait::Wait(TTimeIntervalMicroSeconds32 aWait
)
89 CActiveScheduler::Start();
92 CSimpleWait::CSimpleWait() : CTimer(CActive::EPriorityStandard
)
94 CActiveScheduler::Add(this);
97 void CSimpleWait::RunL()
99 CActiveScheduler::Stop();
102 NONSHARABLE_CLASS(CEpocAudio
) : public CBase
, public MStreamObs
, public MStreamProvider
105 static void* NewL(int BufferSize
, int aFill
);
106 inline static CEpocAudio
& Current(SDL_AudioDevice
* thisdevice
);
108 static void Free(SDL_AudioDevice
* thisdevice
);
112 void ThreadInitL(TAny
* aDevice
);
113 void Open(int iRate
, int iChannels
, TUint32 aType
, int aBytes
);
116 TBool
SetPause(TBool aPause
);
119 CEpocAudio(int aBufferSize
);
120 void Complete(int aState
, int aError
);
122 void ConstructL(int aFill
);
124 CStreamPlayer
* iPlayer
;
138 inline CEpocAudio
& CEpocAudio::Current(SDL_AudioDevice
* thisdevice
)
140 return *static_cast<CEpocAudio
*>((void*)thisdevice
->hidden
);
143 void CEpocAudio::Free(SDL_AudioDevice
* thisdevice
)
145 CEpocAudio
* ea
= static_cast<CEpocAudio
*>((void*)thisdevice
->hidden
);
148 ASSERT(ea
->iTid
== RThread().Id());
150 thisdevice
->hidden
= NULL
;
152 CActiveScheduler
* as
= CActiveScheduler::Current();
153 ASSERT(as
->StackDepth() == 0);
155 CActiveScheduler::Install(NULL
);
157 ASSERT(thisdevice
->hidden
== NULL
);
160 CEpocAudio::CEpocAudio(int aBufferSize
)
161 : iBufferSize(aBufferSize
), iPosition(-1)
165 void* CEpocAudio::NewL(int aBufferSize
, int aFill
)
167 CEpocAudio
* eAudioLib
= new (ELeave
) CEpocAudio(aBufferSize
);
168 CleanupStack::PushL(eAudioLib
);
169 eAudioLib
->ConstructL(aFill
);
174 void CEpocAudio::ConstructL(int aFill
)
176 iBuffer
= new TUint8
[KAudioBuffers
* iBufferSize
];
177 memset(iBuffer
, aFill
, KAudioBuffers
* iBufferSize
);
181 TBool
CEpocAudio::SetPause(TBool aPause
)
183 if(aPause
&& iPosition
>= 0)
189 if(!aPause
&& iPosition
< 0)
195 return iPosition
< 0;
198 void CEpocAudio::ThreadInitL(TAny
* aDevice
)
200 iTid
= RThread().Id();
201 CActiveScheduler
* as
= new (ELeave
) CActiveScheduler();
202 CActiveScheduler::Install(as
);
204 EpocSdlEnv::AppendCleanupItem(TSdlCleanupItem((TSdlCleanupOperation
)EPOC_CloseAudio
, aDevice
));
206 iWait
= CSimpleWait::NewL();
208 iPlayer
= new (ELeave
) CStreamPlayer(*this, *this);
209 iPlayer
->ConstructL();
210 iPlayer
->OpenStream(iRate
, iChannels
, iType
);
213 TUint8
* CEpocAudio::Buffer()
215 iStart
.UniversalTime();
219 CEpocAudio::~CEpocAudio()
234 void CEpocAudio::Complete(int aState
, int aError
)
236 if(iPlayer
->Closed())
250 const int KClip
= 256;
252 TPtrC8
CEpocAudio::Data()
257 TPtrC8
data(iAudioPtr
+ iPosition
, KClip
);
260 if(iPosition
>= iBufferSize
)
262 iAudioPtr
+= iBufferSize
;
264 if((iAudioPtr
- iBuffer
) >= KAudioBuffers
* iBufferSize
)
268 if(iWait
->IsActive())
271 CActiveScheduler::Stop();
277 void CEpocAudio::Play()
282 void CEpocAudio::Wait()
286 const TInt64 bufMs
= TInt64(iBufferSize
- KClip
) * TInt64(1000000);
287 const TInt64 specTime
= bufMs
/ TInt64(iRate
* iChannels
* 2);
288 iWait
->After(specTime
);
290 CActiveScheduler::Start();
293 const TTimeIntervalMicroSeconds delta
= end
.MicroSecondsFrom(iStart
);
295 const int diff
= specTime
- delta
.Int64();
297 if(diff
> 0 && diff
< 200000)
308 void CEpocAudio::Open(int aRate
, int aChannels
, TUint32 aType
, int aBytes
)
311 iChannels
= aChannels
;
313 iBufferRate
= iRate
* iChannels
* aBytes
; //1/x
316 /* Audio driver bootstrap functions */
318 AudioBootStrap EPOCAudio_bootstrap
= {
320 "EPOC streaming audio\0\0\0",
326 static SDL_AudioDevice
*Audio_CreateDevice(int /*devindex*/)
328 SDL_AudioDevice
*thisdevice
;
330 /* Initialize all variables that we clean on shutdown */
331 thisdevice
= new SDL_AudioDevice
;
334 memset(thisdevice
, 0, (sizeof *thisdevice
));
335 thisdevice
->hidden
= NULL
;
343 /* Set the function pointers */
344 thisdevice
->OpenAudio
= EPOC_OpenAudio
;
345 thisdevice
->WaitAudio
= EPOC_WaitAudio
;
346 thisdevice
->PlayAudio
= EPOC_PlayAudio
;
347 thisdevice
->GetAudioBuf
= EPOC_GetAudioBuf
;
348 thisdevice
->CloseAudio
= EPOC_CloseAudio
;
349 thisdevice
->ThreadInit
= EPOC_ThreadInit
;
350 thisdevice
->free
= Audio_DeleteDevice
;
355 static void Audio_DeleteDevice(SDL_AudioDevice
*device
)
360 static int Audio_Available(void)
362 return(1); // Audio stream modules should be always there!
365 static int EPOC_OpenAudio(SDL_AudioDevice
*thisdevice
, SDL_AudioSpec
*spec
)
367 TUint32 type
= KMMFFourCCCodePCM16
;
373 type
= KMMFFourCCCodePCMU16
;
377 type
= KMMFFourCCCodePCM16
;
381 type
= KMMFFourCCCodePCMU16B
;
385 type
= KMMFFourCCCodePCM16B
;
389 type
= KMMFFourCCCodePCMU8
;
393 type
= KMMFFourCCCodePCM8
;
397 spec
->format
= AUDIO_S16LSB
;
400 if(spec
->channels
> 2)
403 spec
->freq
= CStreamPlayer::ClosestSupportedRate(spec
->freq
);
405 /* Allocate mixing buffer */
406 const int buflen
= spec
->size
;
408 TRAPD(err
, thisdevice
->hidden
= static_cast<SDL_PrivateAudioData
*>(CEpocAudio::NewL(buflen
, spec
->silence
)));
412 CEpocAudio::Current(thisdevice
).Open(spec
->freq
, spec
->channels
, type
, bytes
);
414 CEpocAudio::Current(thisdevice
).SetPause(ETrue
);
416 thisdevice
->enabled
= 0; // enable only after audio engine has been initialized!
421 static void EPOC_CloseAudio(SDL_AudioDevice
* thisdevice
)
423 CEpocAudio::Free(thisdevice
);
426 static void EPOC_ThreadInit(SDL_AudioDevice
*thisdevice
)
428 CEpocAudio::Current(thisdevice
).ThreadInitL(thisdevice
);
429 RThread().SetPriority(EPriorityMore
);
430 thisdevice
->enabled
= 1;
433 /* This function waits until it is possible to write a full sound buffer */
434 static void EPOC_WaitAudio(SDL_AudioDevice
* thisdevice
)
436 CEpocAudio::Current(thisdevice
).Wait();
439 static void EPOC_PlayAudio(SDL_AudioDevice
* thisdevice
)
441 if(CEpocAudio::Current(thisdevice
).SetPause(SDL_GetAudioStatus() == SDL_AUDIO_PAUSED
))
442 SDL_Delay(500); //hold on the busy loop
444 CEpocAudio::Current(thisdevice
).Play();
447 static Uint8
*EPOC_GetAudioBuf(SDL_AudioDevice
* thisdevice
)
449 return CEpocAudio::Current(thisdevice
).Buffer();