Disable audio callback when appropriate.
[SDL.s60v3.git] / src / audio / symbian / SDL_epocaudio.cpp
blobbf797b78f055aed78fe4d35b965cf5a70e8a453c
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"
35 #include "sdlepocapi.h"
37 #include <e32hal.h>
40 extern "C" {
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
67 public:
68 CSimpleWait();
70 private:
71 void RunL();
74 CSimpleWait::CSimpleWait()
75 : CTimer(CActive::EPriorityStandard)
77 CActiveScheduler::Add(this);
78 ConstructL();
81 void CSimpleWait::RunL()
83 CActiveScheduler::Stop();
86 class CEpocAudio : public CBase, public MStreamObs, public MStreamProvider
88 public:
89 CEpocAudio(int aBufferSize, int aFill, int aRate, int aChannels, TUint32 aType);
90 ~CEpocAudio();
92 inline static CEpocAudio& Current(SDL_AudioDevice* thisdevice);
94 static void Free(SDL_AudioDevice* thisdevice);
96 void Wait();
97 void ThreadInitL();
98 TUint8* Buffer();
100 private:
101 void Complete(int aState, int aError);
102 TPtrC8 Data();
104 CStreamPlayer* iPlayer;
105 int iRate;
106 int iChannels;
107 TUint32 iType;
108 int iBufferSize;
109 TUint8* iBuffer;
110 CSimpleWait* iWait;
113 CEpocAudio::CEpocAudio(int aBufferSize, int aFill, int aRate, int aChannels, TUint32 aType)
114 : iRate(aRate)
115 , iChannels(aChannels)
116 , iType(aType)
117 , iBufferSize(aBufferSize)
119 iBuffer = new TUint8[iBufferSize];
120 memset(iBuffer, aFill, iBufferSize);
123 CEpocAudio::~CEpocAudio()
125 if(iWait != NULL)
127 iWait->Cancel();
128 delete iWait;
130 if(iPlayer != NULL)
132 iPlayer->Close();
133 delete iPlayer;
135 delete iBuffer;
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;
146 if(ea)
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 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
167 iPlayer->Start();
170 TUint8* CEpocAudio::Buffer()
172 return iBuffer;
175 void CEpocAudio::Complete(int aState, int aError)
177 if(iPlayer->Closed())
178 return;
180 switch(aError)
182 case KErrUnderflow:
183 case KErrInUse:
184 iPlayer->Start();
185 break;
186 case KErrAbort:
187 iPlayer->Open();
191 TPtrC8 CEpocAudio::Data()
193 if(iWait->IsActive())
195 iWait->Cancel();
196 CActiveScheduler::Stop();
199 if(g_SDL->GetSoundPauseReason() != CSDL::SPR_NONE)
201 if(iPlayer->Playing())
203 iPlayer->Stop();
205 return KNullDesC8();
208 TPtrC8 data(iBuffer, iBufferSize);
210 return data;
213 void CEpocAudio::Wait()
215 int pauseReason = g_SDL->GetSoundPauseReason();
217 if(pauseReason == CSDL::SPR_NONE)
219 if(!iPlayer->Playing())
221 iPlayer->Start();
224 // This wait will be terminated by call to Data() from audio buffer callback.
225 SDL_PauseAudio(0);
226 iWait->After(10000000);
228 else
230 // This wait shouldn't be terminated.
231 if(pauseReason & CSDL::SPR_HARDSTOP)
233 // Game is paused, so don't process audio.
234 SDL_PauseAudio(1);
235 iWait->After(100000);
237 else
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.
242 SDL_PauseAudio(0);
243 iWait->After( ( (iBufferSize * 1000) / (iRate * iChannels * 2) ) * 1000 );
247 CActiveScheduler::Start();
250 /* Audio driver bootstrap functions */
252 AudioBootStrap EPOCAudio_bootstrap = {
253 "epoc\0\0\0",
254 "EPOC streaming audio\0\0\0",
255 Audio_Available,
256 Audio_CreateDevice
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;
266 if ( thisdevice )
268 memset(thisdevice, 0, (sizeof *thisdevice));
269 thisdevice->hidden = NULL;
271 else
273 SDL_OutOfMemory();
274 return(0);
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;
286 return thisdevice;
289 static void Audio_DeleteDevice(SDL_AudioDevice *device)
291 delete 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;
303 switch(spec->format)
305 case AUDIO_U16LSB:
306 type = KMMFFourCCCodePCMU16;
307 break;
309 case AUDIO_S16LSB:
310 type = KMMFFourCCCodePCM16;
311 break;
313 case AUDIO_U16MSB:
314 type = KMMFFourCCCodePCMU16B;
315 break;
317 case AUDIO_S16MSB:
318 type = KMMFFourCCCodePCM16B;
319 break;
321 case AUDIO_U8:
322 type = KMMFFourCCCodePCMU8;
323 break;
325 case AUDIO_S8:
326 type = KMMFFourCCCodePCM8;
327 break;
329 default:
330 spec->format = AUDIO_S16LSB;
333 if(spec->channels > 2)
334 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!
344 return 0;
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();