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"
46 #include "SDL_sysaudio.h"
49 #include "streamplayer.h"
51 /* Audio driver functions */
53 static int EPOC_OpenAudio(SDL_AudioDevice
*thisdevice
, SDL_AudioSpec
*spec
);
54 static void EPOC_WaitAudio(SDL_AudioDevice
*thisdevice
);
55 static void EPOC_PlayAudio(SDL_AudioDevice
*thisdevice
);
56 static Uint8
*EPOC_GetAudioBuf(SDL_AudioDevice
*thisdevice
);
57 static void EPOC_CloseAudio(SDL_AudioDevice
*thisdevice
);
58 static void EPOC_ThreadInit(SDL_AudioDevice
*thisdevice
);
60 static int Audio_Available(void);
61 static SDL_AudioDevice
*Audio_CreateDevice(int devindex
);
62 static void Audio_DeleteDevice(SDL_AudioDevice
*device
);
64 class CSimpleWait
: public CTimer
68 void Wait(TTimeIntervalMicroSeconds32 aWait
);
74 CSimpleWait::CSimpleWait()
75 : CTimer(CActive::EPriorityStandard
)
77 CActiveScheduler::Add(this);
81 void CSimpleWait::Wait(TTimeIntervalMicroSeconds32 aWait
)
84 CActiveScheduler::Start();
87 void CSimpleWait::RunL()
89 CActiveScheduler::Stop();
92 class CEpocAudio
: public CBase
, public MStreamObs
, public MStreamProvider
95 CEpocAudio(int aBufferSize
, int aFill
);
98 inline static CEpocAudio
& Current(SDL_AudioDevice
* thisdevice
);
100 static void Free(SDL_AudioDevice
* thisdevice
);
104 void ThreadInitL(void* aDevice
);
105 void Open(int iRate
, int iChannels
, TUint32 aType
, int aBytes
);
107 bool SetPause(bool aPause
);
110 void Complete(int aState
, int aError
);
113 CStreamPlayer
* iPlayer
;
126 CEpocAudio::CEpocAudio(int aBufferSize
, int aFill
)
127 : iBufferSize(aBufferSize
)
130 iBuffer
= new TUint8
[iBufferSize
];
131 memset(iBuffer
, aFill
, iBufferSize
);
134 CEpocAudio::~CEpocAudio()
149 inline CEpocAudio
& CEpocAudio::Current(SDL_AudioDevice
* thisdevice
)
151 return *(CEpocAudio
*)thisdevice
->hidden
;
154 void CEpocAudio::Free(SDL_AudioDevice
* thisdevice
)
156 CEpocAudio
* ea
= (CEpocAudio
*)thisdevice
->hidden
;
159 ASSERT(ea
->iTid
== RThread().Id());
161 thisdevice
->hidden
= NULL
;
163 CActiveScheduler
* as
= CActiveScheduler::Current();
164 ASSERT(as
->StackDepth() == 0);
166 CActiveScheduler::Install(NULL
);
168 ASSERT(thisdevice
->hidden
== NULL
);
171 bool CEpocAudio::SetPause(bool aPause
)
173 if(iPlayer
!= NULL
&& aPause
!= iPause
)
186 void CEpocAudio::ThreadInitL(void* aDevice
)
188 iTid
= RThread().Id();
189 CActiveScheduler
* as
= new CActiveScheduler();
190 CActiveScheduler::Install(as
);
192 EpocSdlEnv::AppendCleanupItem(TSdlCleanupItem((TSdlCleanupOperation
)EPOC_CloseAudio
, aDevice
));
194 iWait
= new CSimpleWait
;
196 iPlayer
= new CStreamPlayer(*this, *this);
197 iPlayer
->OpenStream(iRate
, iChannels
, iType
);
200 TUint8
* CEpocAudio::Buffer()
202 iStart
.UniversalTime();
206 void CEpocAudio::Complete(int aState
, int aError
)
208 if(iPlayer
->Closed())
222 TPtrC8
CEpocAudio::Data()
227 TPtrC8
data(iBuffer
, iBufferSize
);
230 if(iWait
->IsActive())
233 CActiveScheduler::Stop();
239 void CEpocAudio::Play()
244 void CEpocAudio::Wait()
248 const TInt64 bufMs
= TInt64(iBufferSize
) * TInt64(1000000);
249 const TInt64 specTime
= bufMs
/ TInt64(iRate
* iChannels
* 2);
250 iWait
->After(specTime
);
252 CActiveScheduler::Start();
255 const TTimeIntervalMicroSeconds delta
= end
.MicroSecondsFrom(iStart
);
257 const int diff
= specTime
- delta
.Int64();
270 void CEpocAudio::Open(int aRate
, int aChannels
, TUint32 aType
, int aBytes
)
273 iChannels
= aChannels
;
277 /* Audio driver bootstrap functions */
279 AudioBootStrap EPOCAudio_bootstrap
= {
281 "EPOC streaming audio\0\0\0",
287 static SDL_AudioDevice
*Audio_CreateDevice(int /*devindex*/)
289 SDL_AudioDevice
*thisdevice
;
291 /* Initialize all variables that we clean on shutdown */
292 thisdevice
= new SDL_AudioDevice
;
295 memset(thisdevice
, 0, (sizeof *thisdevice
));
296 thisdevice
->hidden
= NULL
;
304 /* Set the function pointers */
305 thisdevice
->OpenAudio
= EPOC_OpenAudio
;
306 thisdevice
->WaitAudio
= EPOC_WaitAudio
;
307 thisdevice
->PlayAudio
= EPOC_PlayAudio
;
308 thisdevice
->GetAudioBuf
= EPOC_GetAudioBuf
;
309 thisdevice
->CloseAudio
= EPOC_CloseAudio
;
310 thisdevice
->ThreadInit
= EPOC_ThreadInit
;
311 thisdevice
->free
= Audio_DeleteDevice
;
316 static void Audio_DeleteDevice(SDL_AudioDevice
*device
)
321 static int Audio_Available(void)
323 return(1); // Audio stream modules should be always there!
326 static int EPOC_OpenAudio(SDL_AudioDevice
*thisdevice
, SDL_AudioSpec
*spec
)
328 TUint32 type
= KMMFFourCCCodePCM16
;
334 type
= KMMFFourCCCodePCMU16
;
338 type
= KMMFFourCCCodePCM16
;
342 type
= KMMFFourCCCodePCMU16B
;
346 type
= KMMFFourCCCodePCM16B
;
350 type
= KMMFFourCCCodePCMU8
;
354 type
= KMMFFourCCCodePCM8
;
358 spec
->format
= AUDIO_S16LSB
;
361 if(spec
->channels
> 2)
364 spec
->freq
= CStreamPlayer::ClosestSupportedRate(spec
->freq
);
366 /* Allocate mixing buffer */
367 const int buflen
= spec
->size
;
369 thisdevice
->hidden
= (SDL_PrivateAudioData
*)new CEpocAudio(buflen
, spec
->silence
);
371 CEpocAudio::Current(thisdevice
).Open(spec
->freq
, spec
->channels
, type
, bytes
);
373 CEpocAudio::Current(thisdevice
).SetPause(true);
375 thisdevice
->enabled
= 0; // enable only after audio engine has been initialized!
380 static void EPOC_CloseAudio(SDL_AudioDevice
* thisdevice
)
382 CEpocAudio::Free(thisdevice
);
385 static void EPOC_ThreadInit(SDL_AudioDevice
*thisdevice
)
387 CEpocAudio::Current(thisdevice
).ThreadInitL(thisdevice
);
388 RThread().SetPriority(EPriorityMore
);
389 thisdevice
->enabled
= 1;
392 /* This function waits until it is possible to write a full sound buffer */
393 static void EPOC_WaitAudio(SDL_AudioDevice
* thisdevice
)
395 CEpocAudio::Current(thisdevice
).Wait();
398 static void EPOC_PlayAudio(SDL_AudioDevice
* thisdevice
)
400 if(CEpocAudio::Current(thisdevice
).SetPause(SDL_GetAudioStatus() == SDL_AUDIO_PAUSED
))
401 SDL_Delay(500); //hold on the busy loop
403 CEpocAudio::Current(thisdevice
).Play();
406 static Uint8
*EPOC_GetAudioBuf(SDL_AudioDevice
* thisdevice
)
408 return CEpocAudio::Current(thisdevice
).Buffer();