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>
35 #include "sdlepocapi.h"
41 #include "SDL_audio.h"
42 #include "SDL_error.h"
43 #include "SDL_audiomem.h"
44 #include "SDL_audio_c.h"
45 #include "SDL_timer.h"
46 #include "SDL_audiodev_c.h"
47 #include "SDL_sysaudio.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 class CSimpleWait
: public CTimer
74 CSimpleWait::CSimpleWait()
75 : CTimer(CActive::EPriorityStandard
)
77 CActiveScheduler::Add(this);
81 void CSimpleWait::RunL()
83 CActiveScheduler::Stop();
86 class CEpocAudio
: public CBase
, public MStreamObs
, public MStreamProvider
89 CEpocAudio(int aBufferSize
, int aFill
, int aRate
, int aChannels
, TUint32 aType
);
92 inline static CEpocAudio
& Current(SDL_AudioDevice
* thisdevice
);
94 static void Free(SDL_AudioDevice
* thisdevice
);
101 void Complete(int aState
, int aError
);
104 CStreamPlayer
* iPlayer
;
113 CEpocAudio::CEpocAudio(int aBufferSize
, int aFill
, int aRate
, int aChannels
, TUint32 aType
)
115 , iChannels(aChannels
)
117 , iBufferSize(aBufferSize
)
119 iBuffer
= new TUint8
[iBufferSize
];
120 memset(iBuffer
, aFill
, iBufferSize
);
123 CEpocAudio::~CEpocAudio()
138 inline CEpocAudio
& CEpocAudio::Current(SDL_AudioDevice
* thisdevice
)
140 return *(CEpocAudio
*)thisdevice
->hidden
;
143 void CEpocAudio::Free(SDL_AudioDevice
* thisdevice
)
145 CEpocAudio
* ea
= (CEpocAudio
*)thisdevice
->hidden
;
149 thisdevice
->hidden
= NULL
;
151 CActiveScheduler
* as
= CActiveScheduler::Current();
152 ASSERT(as
->StackDepth() == 0);
154 CActiveScheduler::Install(NULL
);
156 ASSERT(thisdevice
->hidden
== NULL
);
159 void CEpocAudio::ThreadInitL()
161 iWait
= new CSimpleWait
;
163 iPlayer
= new CStreamPlayer(*this, *this);
164 iPlayer
->OpenStream(iRate
, iChannels
, iType
);
166 /// \todo Implement proper start/pause conditions
170 TUint8
* CEpocAudio::Buffer()
175 void CEpocAudio::Complete(int aState
, int aError
)
177 if(iPlayer
->Closed())
191 TPtrC8
CEpocAudio::Data()
193 if(iWait
->IsActive())
196 CActiveScheduler::Stop();
199 if(g_SDL
->GetSoundPauseReason() != CSDL::SPR_NONE
)
201 if(iPlayer
->Playing())
208 TPtrC8
data(iBuffer
, iBufferSize
);
213 void CEpocAudio::Wait()
215 int pauseReason
= g_SDL
->GetSoundPauseReason();
217 if(pauseReason
== CSDL::SPR_NONE
)
219 if(!iPlayer
->Playing())
224 // This wait will be terminated by call to Data() from audio buffer callback.
226 iWait
->After(10000000);
230 // This wait shouldn't be terminated.
231 if(pauseReason
& CSDL::SPR_HARDSTOP
)
233 // Game is paused, so don't process audio.
235 iWait
->After(100000);
239 // Game is running with audio disabled.
240 // Audio should be mixed in case application expects audio to timer synchronization.
241 // Approximate time needed for mixing.
243 iWait
->After( ( (iBufferSize
* 1000) / (iRate
* iChannels
* 2) ) * 1000 );
247 CActiveScheduler::Start();
250 /* Audio driver bootstrap functions */
252 AudioBootStrap EPOCAudio_bootstrap
= {
254 "EPOC streaming audio\0\0\0",
260 static SDL_AudioDevice
*Audio_CreateDevice(int /*devindex*/)
262 SDL_AudioDevice
*thisdevice
;
264 /* Initialize all variables that we clean on shutdown */
265 thisdevice
= new SDL_AudioDevice
;
268 memset(thisdevice
, 0, (sizeof *thisdevice
));
269 thisdevice
->hidden
= NULL
;
277 /* Set the function pointers */
278 thisdevice
->OpenAudio
= EPOC_OpenAudio
;
279 thisdevice
->WaitAudio
= EPOC_WaitAudio
;
280 thisdevice
->PlayAudio
= EPOC_PlayAudio
;
281 thisdevice
->GetAudioBuf
= EPOC_GetAudioBuf
;
282 thisdevice
->CloseAudio
= EPOC_CloseAudio
;
283 thisdevice
->ThreadInit
= EPOC_ThreadInit
;
284 thisdevice
->free
= Audio_DeleteDevice
;
289 static void Audio_DeleteDevice(SDL_AudioDevice
*device
)
294 static int Audio_Available(void)
296 return(1); // Audio stream modules should be always there!
299 static int EPOC_OpenAudio(SDL_AudioDevice
*thisdevice
, SDL_AudioSpec
*spec
)
301 TUint32 type
= KMMFFourCCCodePCM16
;
306 type
= KMMFFourCCCodePCMU16
;
310 type
= KMMFFourCCCodePCM16
;
314 type
= KMMFFourCCCodePCMU16B
;
318 type
= KMMFFourCCCodePCM16B
;
322 type
= KMMFFourCCCodePCMU8
;
326 type
= KMMFFourCCCodePCM8
;
330 spec
->format
= AUDIO_S16LSB
;
333 if(spec
->channels
> 2)
336 spec
->freq
= CStreamPlayer::ClosestSupportedRate(spec
->freq
);
338 /* Allocate mixing buffer */
339 const int buflen
= spec
->size
;
341 thisdevice
->hidden
= (SDL_PrivateAudioData
*)new CEpocAudio(buflen
, spec
->silence
, spec
->freq
, spec
->channels
, type
);
342 thisdevice
->enabled
= 0; // enable only after audio engine has been initialized!
347 static void EPOC_CloseAudio(SDL_AudioDevice
* thisdevice
)
349 CEpocAudio::Free(thisdevice
);
352 static void EPOC_ThreadInit(SDL_AudioDevice
*thisdevice
)
354 CActiveScheduler
* as
= new CActiveScheduler();
355 CActiveScheduler::Install(as
);
357 EpocSdlEnv::AppendCleanupItem(TSdlCleanupItem((TSdlCleanupOperation
)EPOC_CloseAudio
, thisdevice
));
359 CEpocAudio::Current(thisdevice
).ThreadInitL();
360 RThread().SetPriority(EPriorityMore
);
361 thisdevice
->enabled
= 1;
364 /* This function waits until it is possible to write a full sound buffer */
365 static void EPOC_WaitAudio(SDL_AudioDevice
* thisdevice
)
367 CEpocAudio::Current(thisdevice
).Wait();
370 static void EPOC_PlayAudio(SDL_AudioDevice
* thisdevice
)
374 static Uint8
*EPOC_GetAudioBuf(SDL_AudioDevice
* thisdevice
)
376 return CEpocAudio::Current(thisdevice
).Buffer();