Big cleanup part 1.
[SDL.s60v3.git] / src / audio / symbian / SDL_epocaudio.cpp
blob80c790cbed7f6599f932ca1a8e9a208359438b4a
1 /*
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
19 Sam Lantinga
20 slouken@devolution.com
24 SDL_epocaudio.cpp
25 Epoc based SDL audio driver implementation
27 Markus Mertama
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <signal.h>
37 #include <sys/time.h>
38 #include <sys/ioctl.h>
39 #include <sys/stat.h>
41 #include "epoc_sdl.h"
43 #include <e32hal.h>
46 extern "C" {
47 #include "SDL_audio.h"
48 #include "SDL_error.h"
49 #include "SDL_audiomem.h"
50 #include "SDL_audio_c.h"
51 #include "SDL_timer.h"
52 #include "SDL_audiodev_c.h"
55 #include "SDL_epocaudio.h"
57 #include "streamplayer.h"
59 /* Audio driver functions */
61 static int EPOC_OpenAudio(SDL_AudioDevice *thisdevice, SDL_AudioSpec *spec);
62 static void EPOC_WaitAudio(SDL_AudioDevice *thisdevice);
63 static void EPOC_PlayAudio(SDL_AudioDevice *thisdevice);
64 static Uint8 *EPOC_GetAudioBuf(SDL_AudioDevice *thisdevice);
65 static void EPOC_CloseAudio(SDL_AudioDevice *thisdevice);
66 static void EPOC_ThreadInit(SDL_AudioDevice *thisdevice);
68 static int Audio_Available(void);
69 static SDL_AudioDevice *Audio_CreateDevice(int devindex);
70 static void Audio_DeleteDevice(SDL_AudioDevice *device);
72 NONSHARABLE_CLASS(CSimpleWait) : public CTimer
74 public:
75 void Wait(TTimeIntervalMicroSeconds32 aWait);
76 static CSimpleWait* NewL();
77 private:
78 CSimpleWait();
79 void RunL();
82 CSimpleWait* CSimpleWait::NewL()
84 CSimpleWait* wait = new (ELeave) CSimpleWait();
85 CleanupStack::PushL(wait);
86 wait->ConstructL();
87 CleanupStack::Pop();
88 return wait;
91 void CSimpleWait::Wait(TTimeIntervalMicroSeconds32 aWait)
93 After(aWait);
94 CActiveScheduler::Start();
97 CSimpleWait::CSimpleWait() : CTimer(CActive::EPriorityStandard)
99 CActiveScheduler::Add(this);
102 void CSimpleWait::RunL()
104 CActiveScheduler::Stop();
107 const TInt KAudioBuffers(2);
110 NONSHARABLE_CLASS(CEpocAudio) : public CBase, public MStreamObs, public MStreamProvider
112 public:
113 static void* NewL(TInt BufferSize, TInt aFill);
114 inline static CEpocAudio& Current(SDL_AudioDevice* thisdevice);
116 static void Free(SDL_AudioDevice* thisdevice);
118 void Wait();
119 void Play();
120 void ThreadInitL(TAny* aDevice);
121 void Open(TInt iRate, TInt iChannels, TUint32 aType, TInt aBytes);
122 ~CEpocAudio();
123 TUint8* Buffer();
124 TBool SetPause(TBool aPause);
126 private:
127 CEpocAudio(TInt aBufferSize);
128 void Complete(TInt aState, TInt aError);
129 TPtrC8 Data();
130 void ConstructL(TInt aFill);
131 TInt iBufferSize;
132 CStreamPlayer* iPlayer;
133 TInt iBufferRate;
134 TInt iRate;
135 TInt iChannels;
136 TUint32 iType;
137 TInt iPosition;
138 TThreadId iTid;
139 TUint8* iAudioPtr;
140 TUint8* iBuffer;
141 TTime iStart;
142 TInt iTune;
143 CSimpleWait* iWait;
146 inline CEpocAudio& CEpocAudio::Current(SDL_AudioDevice* thisdevice)
148 return *static_cast<CEpocAudio*>((void*)thisdevice->hidden);
151 void CEpocAudio::Free(SDL_AudioDevice* thisdevice)
153 CEpocAudio* ea = static_cast<CEpocAudio*>((void*)thisdevice->hidden);
154 if(ea)
156 ASSERT(ea->iTid == RThread().Id());
157 delete ea;
158 thisdevice->hidden = NULL;
160 CActiveScheduler* as = CActiveScheduler::Current();
161 ASSERT(as->StackDepth() == 0);
162 delete as;
163 CActiveScheduler::Install(NULL);
165 ASSERT(thisdevice->hidden == NULL);
168 CEpocAudio::CEpocAudio(TInt aBufferSize) : iBufferSize(aBufferSize), iPosition(-1)
172 void* CEpocAudio::NewL(TInt aBufferSize, TInt aFill)
174 CEpocAudio* eAudioLib = new (ELeave) CEpocAudio(aBufferSize);
175 CleanupStack::PushL(eAudioLib);
176 eAudioLib->ConstructL(aFill);
177 CleanupStack::Pop();
178 return eAudioLib;
181 void CEpocAudio::ConstructL(TInt aFill)
183 iBuffer = (TUint8*) User::AllocL(KAudioBuffers * iBufferSize);
184 memset(iBuffer, aFill, KAudioBuffers * iBufferSize);
185 iAudioPtr = iBuffer;
189 TBool CEpocAudio::SetPause(TBool aPause)
191 if(aPause && iPosition >= 0)
193 iPosition = -1;
194 if(iPlayer != NULL)
195 iPlayer->Stop();
197 if(!aPause && iPosition < 0)
199 iPosition = 0;
200 if(iPlayer != NULL)
201 iPlayer->Start();
203 return iPosition < 0;
206 void CEpocAudio::ThreadInitL(TAny* aDevice)
208 iTid = RThread().Id();
209 CActiveScheduler* as = new (ELeave) CActiveScheduler();
210 CActiveScheduler::Install(as);
212 EpocSdlEnv::AppendCleanupItem(TSdlCleanupItem((TSdlCleanupOperation)EPOC_CloseAudio, aDevice));
214 iWait = CSimpleWait::NewL();
216 iPlayer = new (ELeave) CStreamPlayer(*this, *this);
217 iPlayer->ConstructL();
218 iPlayer->OpenStream(iRate, iChannels, iType);
221 TUint8* CEpocAudio::Buffer()
223 iStart.UniversalTime();
224 return iAudioPtr;
227 CEpocAudio::~CEpocAudio()
229 if(iWait != NULL)
230 iWait->Cancel();
231 delete iWait;
232 if(iPlayer != NULL)
233 iPlayer->Close();
234 delete iPlayer;
235 delete iBuffer;
238 void CEpocAudio::Complete(TInt aState, TInt aError)
240 if(aState == MStreamObs::EClose)
243 if(iPlayer->Closed())
244 return;
245 switch(aError)
247 case KErrUnderflow:
248 case KErrInUse:
249 iPlayer->Start();
250 break;
251 case KErrAbort:
252 iPlayer->Open();
257 const TInt KClip(256);
259 TPtrC8 CEpocAudio::Data()
261 if(iPosition < 0)
262 return KNullDesC8();
264 TPtrC8 data(iAudioPtr + iPosition, KClip);
266 iPosition += KClip;
267 if(iPosition >= iBufferSize)
269 iAudioPtr += iBufferSize;
271 if((iAudioPtr - iBuffer) >= KAudioBuffers * iBufferSize)
272 iAudioPtr = iBuffer;
274 iPosition = -1;
275 if(iWait->IsActive())
277 iWait->Cancel();
278 CActiveScheduler::Stop();
281 return data;
284 void CEpocAudio::Play()
286 iPosition = 0;
289 void CEpocAudio::Wait()
291 if(iPosition >= 0)
293 const TInt64 bufMs = TInt64(iBufferSize - KClip) * TInt64(1000000);
294 const TInt64 specTime = bufMs / TInt64(iRate * iChannels * 2);
295 iWait->After(specTime);
297 CActiveScheduler::Start();
298 TTime end;
299 end.UniversalTime();
300 const TTimeIntervalMicroSeconds delta = end.MicroSecondsFrom(iStart);
302 const TInt diff = specTime - delta.Int64();
304 if(diff > 0 && diff < 200000)
306 User::After(diff);
310 else
312 User::After(10000);
316 void CEpocAudio::Open(TInt aRate, TInt aChannels, TUint32 aType, TInt aBytes)
318 iRate = aRate;
319 iChannels = aChannels;
320 iType = aType;
321 iBufferRate = iRate * iChannels * aBytes; //1/x
324 /* Audio driver bootstrap functions */
326 AudioBootStrap EPOCAudio_bootstrap = {
327 "epoc\0\0\0",
328 "EPOC streaming audio\0\0\0",
329 Audio_Available,
330 Audio_CreateDevice
334 static SDL_AudioDevice *Audio_CreateDevice(int /*devindex*/)
336 SDL_AudioDevice *thisdevice;
338 /* Initialize all variables that we clean on shutdown */
339 thisdevice = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
340 if ( thisdevice ) {
341 memset(thisdevice, 0, (sizeof *thisdevice));
342 thisdevice->hidden = NULL;
344 if ( (thisdevice == NULL) ) {
345 SDL_OutOfMemory();
346 if ( thisdevice ) {
347 free(thisdevice);
349 return(0);
352 /* Set the function pointers */
353 thisdevice->OpenAudio = EPOC_OpenAudio;
354 thisdevice->WaitAudio = EPOC_WaitAudio;
355 thisdevice->PlayAudio = EPOC_PlayAudio;
356 thisdevice->GetAudioBuf = EPOC_GetAudioBuf;
357 thisdevice->CloseAudio = EPOC_CloseAudio;
358 thisdevice->ThreadInit = EPOC_ThreadInit;
359 thisdevice->free = Audio_DeleteDevice;
361 return thisdevice;
365 static void Audio_DeleteDevice(SDL_AudioDevice *device)
367 free(device);
370 static int Audio_Available(void)
372 return(1); // Audio stream modules should be always there!
376 static int EPOC_OpenAudio(SDL_AudioDevice *thisdevice, SDL_AudioSpec *spec)
378 TUint32 type = KMMFFourCCCodePCM16;
379 TInt bytes = 2;
381 switch(spec->format)
383 case AUDIO_U16LSB:
384 type = KMMFFourCCCodePCMU16;
385 break;
386 case AUDIO_S16LSB:
387 type = KMMFFourCCCodePCM16;
388 break;
389 case AUDIO_U16MSB:
390 type = KMMFFourCCCodePCMU16B;
391 break;
392 case AUDIO_S16MSB:
393 type = KMMFFourCCCodePCM16B;
394 break;
395 //8 bit not supported!
396 case AUDIO_U8:
397 case AUDIO_S8:
398 default:
399 spec->format = AUDIO_S16LSB;
402 if(spec->channels > 2)
403 spec->channels = 2;
405 spec->freq = CStreamPlayer::ClosestSupportedRate(spec->freq);
407 /* Allocate mixing buffer */
408 const TInt buflen = spec->size;// * bytes * spec->channels;
410 TRAPD(err, thisdevice->hidden = static_cast<SDL_PrivateAudioData*>(CEpocAudio::NewL(buflen, spec->silence)));
411 if(err != KErrNone)
412 return -1;
414 CEpocAudio::Current(thisdevice).Open(spec->freq, spec->channels, type, bytes);
416 CEpocAudio::Current(thisdevice).SetPause(ETrue);
418 thisdevice->enabled = 0; /* enable only after audio engine has been initialized!*/
420 /* We're ready to rock and roll. :-) */
421 return(0);
424 static void EPOC_CloseAudio(SDL_AudioDevice* thisdevice)
426 CEpocAudio::Free(thisdevice);
429 static void EPOC_ThreadInit(SDL_AudioDevice *thisdevice)
431 CEpocAudio::Current(thisdevice).ThreadInitL(thisdevice);
432 RThread().SetPriority(EPriorityMore);
433 thisdevice->enabled = 1;
436 /* This function waits until it is possible to write a full sound buffer */
437 static void EPOC_WaitAudio(SDL_AudioDevice* thisdevice)
439 CEpocAudio::Current(thisdevice).Wait();
442 static void EPOC_PlayAudio(SDL_AudioDevice* thisdevice)
444 if(CEpocAudio::Current(thisdevice).SetPause(SDL_GetAudioStatus() == SDL_AUDIO_PAUSED))
445 SDL_Delay(500); //hold on the busy loop
446 else
447 CEpocAudio::Current(thisdevice).Play();
450 static Uint8 *EPOC_GetAudioBuf(SDL_AudioDevice* thisdevice)
452 return CEpocAudio::Current(thisdevice).Buffer();