Remove KAudioBuffers.
[SDL.s60v3.git] / src / audio / symbian / SDL_epocaudio.cpp
blob81643a086669e5f27002e90fd04b57a80eb22c1d
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
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <signal.h>
30 #include <sys/time.h>
31 #include <sys/ioctl.h>
32 #include <sys/stat.h>
34 #include "epoc_sdl.h"
36 #include <e32hal.h>
39 extern "C" {
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 class CSimpleWait : public CTimer
67 public:
68 void Wait(TTimeIntervalMicroSeconds32 aWait);
69 static CSimpleWait* NewL();
70 private:
71 CSimpleWait();
72 void RunL();
75 CSimpleWait* CSimpleWait::NewL()
77 CSimpleWait* wait = new CSimpleWait();
78 CleanupStack::PushL(wait);
79 wait->ConstructL();
80 CleanupStack::Pop();
81 return wait;
84 void CSimpleWait::Wait(TTimeIntervalMicroSeconds32 aWait)
86 After(aWait);
87 CActiveScheduler::Start();
90 CSimpleWait::CSimpleWait() : CTimer(CActive::EPriorityStandard)
92 CActiveScheduler::Add(this);
95 void CSimpleWait::RunL()
97 CActiveScheduler::Stop();
100 class CEpocAudio : public CBase, public MStreamObs, public MStreamProvider
102 public:
103 static void* NewL(int BufferSize, int aFill);
104 inline static CEpocAudio& Current(SDL_AudioDevice* thisdevice);
106 static void Free(SDL_AudioDevice* thisdevice);
108 void Wait();
109 void Play();
110 void ThreadInitL(void* aDevice);
111 void Open(int iRate, int iChannels, TUint32 aType, int aBytes);
112 ~CEpocAudio();
113 TUint8* Buffer();
114 TBool SetPause(TBool aPause);
116 private:
117 CEpocAudio(int aBufferSize);
118 void Complete(int aState, int aError);
119 TPtrC8 Data();
120 void ConstructL(int aFill);
122 int iBufferSize;
123 CStreamPlayer* iPlayer;
124 int iBufferRate;
125 int iRate;
126 int iChannels;
127 TUint32 iType;
128 int iPosition;
129 TThreadId iTid;
130 TUint8* iAudioPtr;
131 TUint8* iBuffer;
132 TTime iStart;
133 int iTune;
134 CSimpleWait* iWait;
137 inline CEpocAudio& CEpocAudio::Current(SDL_AudioDevice* thisdevice)
139 return *static_cast<CEpocAudio*>((void*)thisdevice->hidden);
142 void CEpocAudio::Free(SDL_AudioDevice* thisdevice)
144 CEpocAudio* ea = static_cast<CEpocAudio*>((void*)thisdevice->hidden);
145 if(ea)
147 ASSERT(ea->iTid == RThread().Id());
148 delete ea;
149 thisdevice->hidden = NULL;
151 CActiveScheduler* as = CActiveScheduler::Current();
152 ASSERT(as->StackDepth() == 0);
153 delete as;
154 CActiveScheduler::Install(NULL);
156 ASSERT(thisdevice->hidden == NULL);
159 CEpocAudio::CEpocAudio(int aBufferSize)
160 : iBufferSize(aBufferSize), iPosition(-1)
164 void* CEpocAudio::NewL(int aBufferSize, int aFill)
166 CEpocAudio* eAudioLib = new CEpocAudio(aBufferSize);
167 CleanupStack::PushL(eAudioLib);
168 eAudioLib->ConstructL(aFill);
169 CleanupStack::Pop();
170 return eAudioLib;
173 void CEpocAudio::ConstructL(int aFill)
175 iBuffer = new TUint8[iBufferSize];
176 memset(iBuffer, aFill, iBufferSize);
177 iAudioPtr = iBuffer;
180 TBool CEpocAudio::SetPause(TBool aPause)
182 if(aPause && iPosition >= 0)
184 iPosition = -1;
185 if(iPlayer != NULL)
186 iPlayer->Stop();
188 if(!aPause && iPosition < 0)
190 iPosition = 0;
191 if(iPlayer != NULL)
192 iPlayer->Start();
194 return iPosition < 0;
197 void CEpocAudio::ThreadInitL(void* aDevice)
199 iTid = RThread().Id();
200 CActiveScheduler* as = new CActiveScheduler();
201 CActiveScheduler::Install(as);
203 EpocSdlEnv::AppendCleanupItem(TSdlCleanupItem((TSdlCleanupOperation)EPOC_CloseAudio, aDevice));
205 iWait = CSimpleWait::NewL();
207 iPlayer = new CStreamPlayer(*this, *this);
208 iPlayer->ConstructL();
209 iPlayer->OpenStream(iRate, iChannels, iType);
212 TUint8* CEpocAudio::Buffer()
214 iStart.UniversalTime();
215 return iAudioPtr;
218 CEpocAudio::~CEpocAudio()
220 if(iWait != NULL)
222 iWait->Cancel();
223 delete iWait;
225 if(iPlayer != NULL)
227 iPlayer->Close();
228 delete iPlayer;
230 delete iBuffer;
233 void CEpocAudio::Complete(int aState, int aError)
235 if(iPlayer->Closed())
236 return;
238 switch(aError)
240 case KErrUnderflow:
241 case KErrInUse:
242 iPlayer->Start();
243 break;
244 case KErrAbort:
245 iPlayer->Open();
249 const int KClip = 256;
251 TPtrC8 CEpocAudio::Data()
253 if(iPosition < 0)
254 return KNullDesC8();
256 TPtrC8 data(iAudioPtr + iPosition, KClip);
258 iPosition += KClip;
259 if(iPosition >= iBufferSize)
261 iAudioPtr += iBufferSize;
263 if((iAudioPtr - iBuffer) >= iBufferSize)
264 iAudioPtr = iBuffer;
266 iPosition = -1;
267 if(iWait->IsActive())
269 iWait->Cancel();
270 CActiveScheduler::Stop();
273 return data;
276 void CEpocAudio::Play()
278 iPosition = 0;
281 void CEpocAudio::Wait()
283 if(iPosition >= 0)
285 const TInt64 bufMs = TInt64(iBufferSize - KClip) * TInt64(1000000);
286 const TInt64 specTime = bufMs / TInt64(iRate * iChannels * 2);
287 iWait->After(specTime);
289 CActiveScheduler::Start();
290 TTime end;
291 end.UniversalTime();
292 const TTimeIntervalMicroSeconds delta = end.MicroSecondsFrom(iStart);
294 const int diff = specTime - delta.Int64();
296 if(diff > 0 && diff < 200000)
298 usleep(diff);
301 else
303 usleep(10000);
307 void CEpocAudio::Open(int aRate, int aChannels, TUint32 aType, int aBytes)
309 iRate = aRate;
310 iChannels = aChannels;
311 iType = aType;
312 iBufferRate = iRate * iChannels * aBytes; //1/x
315 /* Audio driver bootstrap functions */
317 AudioBootStrap EPOCAudio_bootstrap = {
318 "epoc\0\0\0",
319 "EPOC streaming audio\0\0\0",
320 Audio_Available,
321 Audio_CreateDevice
325 static SDL_AudioDevice *Audio_CreateDevice(int /*devindex*/)
327 SDL_AudioDevice *thisdevice;
329 /* Initialize all variables that we clean on shutdown */
330 thisdevice = new SDL_AudioDevice;
331 if ( thisdevice )
333 memset(thisdevice, 0, (sizeof *thisdevice));
334 thisdevice->hidden = NULL;
336 else
338 SDL_OutOfMemory();
339 return(0);
342 /* Set the function pointers */
343 thisdevice->OpenAudio = EPOC_OpenAudio;
344 thisdevice->WaitAudio = EPOC_WaitAudio;
345 thisdevice->PlayAudio = EPOC_PlayAudio;
346 thisdevice->GetAudioBuf = EPOC_GetAudioBuf;
347 thisdevice->CloseAudio = EPOC_CloseAudio;
348 thisdevice->ThreadInit = EPOC_ThreadInit;
349 thisdevice->free = Audio_DeleteDevice;
351 return thisdevice;
354 static void Audio_DeleteDevice(SDL_AudioDevice *device)
356 delete device;
359 static int Audio_Available(void)
361 return(1); // Audio stream modules should be always there!
364 static int EPOC_OpenAudio(SDL_AudioDevice *thisdevice, SDL_AudioSpec *spec)
366 TUint32 type = KMMFFourCCCodePCM16;
367 int bytes = 2;
369 switch(spec->format)
371 case AUDIO_U16LSB:
372 type = KMMFFourCCCodePCMU16;
373 break;
375 case AUDIO_S16LSB:
376 type = KMMFFourCCCodePCM16;
377 break;
379 case AUDIO_U16MSB:
380 type = KMMFFourCCCodePCMU16B;
381 break;
383 case AUDIO_S16MSB:
384 type = KMMFFourCCCodePCM16B;
385 break;
387 case AUDIO_U8:
388 type = KMMFFourCCCodePCMU8;
389 break;
391 case AUDIO_S8:
392 type = KMMFFourCCCodePCM8;
393 break;
395 default:
396 spec->format = AUDIO_S16LSB;
399 if(spec->channels > 2)
400 spec->channels = 2;
402 spec->freq = CStreamPlayer::ClosestSupportedRate(spec->freq);
404 /* Allocate mixing buffer */
405 const int buflen = spec->size;
407 TRAPD(err, thisdevice->hidden = static_cast<SDL_PrivateAudioData*>(CEpocAudio::NewL(buflen, spec->silence)));
408 if(err != KErrNone)
409 return -1;
411 CEpocAudio::Current(thisdevice).Open(spec->freq, spec->channels, type, bytes);
413 CEpocAudio::Current(thisdevice).SetPause(ETrue);
415 thisdevice->enabled = 0; // enable only after audio engine has been initialized!
417 return 0;
420 static void EPOC_CloseAudio(SDL_AudioDevice* thisdevice)
422 CEpocAudio::Free(thisdevice);
425 static void EPOC_ThreadInit(SDL_AudioDevice *thisdevice)
427 CEpocAudio::Current(thisdevice).ThreadInitL(thisdevice);
428 RThread().SetPriority(EPriorityMore);
429 thisdevice->enabled = 1;
432 /* This function waits until it is possible to write a full sound buffer */
433 static void EPOC_WaitAudio(SDL_AudioDevice* thisdevice)
435 CEpocAudio::Current(thisdevice).Wait();
438 static void EPOC_PlayAudio(SDL_AudioDevice* thisdevice)
440 if(CEpocAudio::Current(thisdevice).SetPause(SDL_GetAudioStatus() == SDL_AUDIO_PAUSED))
441 SDL_Delay(500); //hold on the busy loop
442 else
443 CEpocAudio::Current(thisdevice).Play();
446 static Uint8 *EPOC_GetAudioBuf(SDL_AudioDevice* thisdevice)
448 return CEpocAudio::Current(thisdevice).Buffer();