2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
35 #elif defined(HAVE_SDL_H)
39 static void *sdl_handle
;
40 #define MAKE_FUNC(x) static typeof(x) * p##x
41 MAKE_FUNC(SDL_PauseAudio
);
42 MAKE_FUNC(SDL_CloseAudio
);
43 MAKE_FUNC(SDL_OpenAudio
);
44 MAKE_FUNC(SDL_InitSubSystem
);
45 MAKE_FUNC(SDL_GetError
);
46 MAKE_FUNC(SDL_LockAudio
);
47 MAKE_FUNC(SDL_UnlockAudio
);
50 static char *sdl_device
;
51 /* SDL audio can only be initialized once per process */
52 static int initialized
;
55 SDL_AudioSpec audioSpec
;
66 static void SDLCALL
fillAudio(void *userdata
, Uint8
*stream
, int len
)
68 sdl_data
*data
= (sdl_data
*)userdata
;
69 int rem
= data
->data_size
-data
->data_read
;
72 memcpy(stream
, data
->mix_data
+ data
->data_read
, rem
);
79 memcpy(stream
, data
->mix_data
+ data
->data_read
, len
);
80 data
->data_read
+= len
;
84 static ALuint
SDLProc(ALvoid
*ptr
)
86 ALCdevice
*pDevice
= (ALCdevice
*)ptr
;
87 sdl_data
*data
= (sdl_data
*)pDevice
->ExtraData
;
95 len
= (data
->data_read
-data
->data_write
+data
->data_size
)%data
->data_size
;
104 rem
= data
->data_size
- data
->data_write
;
106 SuspendContext(NULL
);
109 aluMixData(pDevice
->Context
, data
->mix_data
+data
->data_write
, rem
, pDevice
->Format
);
110 aluMixData(pDevice
->Context
, data
->mix_data
, len
-rem
, pDevice
->Format
);
113 aluMixData(pDevice
->Context
, data
->mix_data
+data
->data_write
, len
, pDevice
->Format
);
114 ProcessContext(NULL
);
116 data
->data_write
= data
->data_read
;
125 static ALCboolean
sdl_open_playback(ALCdevice
*device
, const ALCchar
*deviceName
)
127 SDL_AudioSpec sdlSpec
;
131 if(initialized
|| !sdl_device
)
136 if(strcmp(deviceName
, sdl_device
))
138 device
->szDeviceName
= sdl_device
;
141 device
->szDeviceName
= sdl_device
;
143 data
= (sdl_data
*)calloc(1, sizeof(sdl_data
));
146 frameSize
= aluBytesFromFormat(device
->Format
) *
147 aluChannelsFromFormat(device
->Format
);
149 sdlSpec
.freq
= device
->Frequency
;
150 sdlSpec
.channels
= aluChannelsFromFormat(device
->Format
);
151 switch(aluBytesFromFormat(device
->Format
))
154 sdlSpec
.format
= AUDIO_U8
;
157 sdlSpec
.format
= AUDIO_S16SYS
;
160 AL_PRINT("Unknown format?! %x\n", device
->Format
);
165 while(sdlSpec
.samples
< device
->UpdateSize
)
166 sdlSpec
.samples
<<= 1;
167 sdlSpec
.samples
>>= 1;
169 sdlSpec
.callback
= fillAudio
;
170 sdlSpec
.userdata
= data
;
172 if(pSDL_OpenAudio(&sdlSpec
, &data
->audioSpec
) < 0)
174 AL_PRINT("Audio init failed: %s\n", pSDL_GetError());
179 if(!((data
->audioSpec
.format
== AUDIO_U8
&& aluBytesFromFormat(device
->Format
) == 1) ||
180 (data
->audioSpec
.format
== AUDIO_S16SYS
&& aluBytesFromFormat(device
->Format
) == 2)))
182 AL_PRINT("Could not set %d-bit, got format %#x instead\n", aluBytesFromFormat(device
->Format
), data
->audioSpec
.format
);
187 if(aluChannelsFromFormat(device
->Format
) != data
->audioSpec
.channels
)
189 AL_PRINT("Could not set %d channels, got %d instead\n", aluChannelsFromFormat(device
->Format
), data
->audioSpec
.channels
);
195 device
->Frequency
= data
->audioSpec
.freq
;
196 device
->UpdateSize
= data
->audioSpec
.size
/ frameSize
;
198 data
->data_size
= device
->UpdateSize
* frameSize
* 2;
199 data
->mix_data
= malloc(data
->data_size
);
200 if(data
->mix_data
== NULL
)
202 AL_PRINT("Could not allocate %d bytes\n", data
->data_size
);
207 memset(data
->mix_data
, data
->audioSpec
.silence
, data
->data_size
);
209 device
->ExtraData
= data
;
210 data
->thread
= StartThread(SDLProc
, device
);
211 if(data
->thread
== NULL
)
214 device
->ExtraData
= NULL
;
215 free(data
->mix_data
);
225 static void sdl_close_playback(ALCdevice
*device
)
227 sdl_data
*data
= (sdl_data
*)device
->ExtraData
;
229 StopThread(data
->thread
);
234 free(data
->mix_data
);
236 device
->ExtraData
= NULL
;
240 static ALCboolean
sdl_open_capture(ALCdevice
*device
, const ALCchar
*deviceName
, ALCuint frequency
, ALCenum format
, ALCsizei SampleSize
)
251 BackendFuncs sdl_funcs
= {
262 void alc_sdl_init(BackendFuncs
*func_list
)
266 *func_list
= sdl_funcs
;
269 #if defined(__APPLE__) && defined(__MACH__)
270 # define SDLLIB "SDL.framework/SDL"
272 # define SDLLIB "libSDL.so"
274 sdl_handle
= dlopen(SDLLIB
, RTLD_NOW
);
279 #define LOAD_FUNC(f) do { \
280 p##f = (typeof(f)*)dlsym(sdl_handle, #f); \
281 if((str=dlerror()) != NULL) \
283 dlclose(sdl_handle); \
285 AL_PRINT("Could not load %s from "SDLLIB": %s\n", #f, str); \
291 sdl_handle
= 0xDEADBEEF;
292 #define LOAD_FUNC(f) p##f = f
295 LOAD_FUNC(SDL_PauseAudio
);
296 LOAD_FUNC(SDL_CloseAudio
);
297 LOAD_FUNC(SDL_OpenAudio
);
298 LOAD_FUNC(SDL_InitSubSystem
);
299 LOAD_FUNC(SDL_GetError
);
300 LOAD_FUNC(SDL_LockAudio
);
301 LOAD_FUNC(SDL_UnlockAudio
);
305 if(pSDL_InitSubSystem(SDL_INIT_AUDIO
) < 0)
308 sdl_device
= AppendDeviceList("SDL Software");
309 AppendAllDeviceList(sdl_device
);