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
33 #include <portaudio.h>
35 static void *pa_handle
;
36 #define MAKE_FUNC(x) static typeof(x) * p##x
37 MAKE_FUNC(Pa_Initialize
);
38 MAKE_FUNC(Pa_Terminate
);
39 MAKE_FUNC(Pa_GetErrorText
);
40 MAKE_FUNC(Pa_StartStream
);
41 MAKE_FUNC(Pa_StopStream
);
42 MAKE_FUNC(Pa_OpenStream
);
43 MAKE_FUNC(Pa_CloseStream
);
44 MAKE_FUNC(Pa_GetDefaultOutputDevice
);
45 MAKE_FUNC(Pa_GetStreamInfo
);
49 static const ALCchar pa_device
[] = "PortAudio Software";
50 static const ALCchar pa_capture
[] = "PortAudio Capture";
51 static volatile ALuint load_count
;
61 pa_handle
= LoadLibrary("portaudio.dll");
62 #define LOAD_FUNC(x) do { \
63 p##x = (typeof(p##x))GetProcAddress(pa_handle, #x); \
65 AL_PRINT("Could not load %s from portaudio.dll\n", #x); \
66 FreeLibrary(pa_handle); \
72 #elif defined(HAVE_DLFCN_H)
75 #if defined(__APPLE__) && defined(__MACH__)
76 # define PALIB "libportaudio.2.dylib"
78 # define PALIB "libportaudio.so.2"
80 pa_handle
= dlopen(PALIB
, RTLD_NOW
);
83 #define LOAD_FUNC(f) do { \
84 p##f = (typeof(f)*)dlsym(pa_handle, #f); \
85 if((str=dlerror()) != NULL) \
89 AL_PRINT("Could not load %s from "PALIB": %s\n", #f, str); \
96 pa_handle
= (void*)0xDEADBEEF;
97 #define LOAD_FUNC(f) p##f = f
103 LOAD_FUNC(Pa_Initialize
);
104 LOAD_FUNC(Pa_Terminate
);
105 LOAD_FUNC(Pa_GetErrorText
);
106 LOAD_FUNC(Pa_StartStream
);
107 LOAD_FUNC(Pa_StopStream
);
108 LOAD_FUNC(Pa_OpenStream
);
109 LOAD_FUNC(Pa_CloseStream
);
110 LOAD_FUNC(Pa_GetDefaultOutputDevice
);
111 LOAD_FUNC(Pa_GetStreamInfo
);
115 if((err
=pPa_Initialize()) != paNoError
)
117 AL_PRINT("Pa_Initialize() returned an error: %s\n", pPa_GetErrorText(err
));
119 FreeLibrary(pa_handle
);
120 #elif defined(HAVE_DLFCN_H)
134 if(load_count
== 0 || --load_count
> 0)
139 FreeLibrary(pa_handle
);
140 #elif defined(HAVE_DLFCN_H)
155 static int pa_callback(const void *inputBuffer
, void *outputBuffer
,
156 unsigned long framesPerBuffer
, const PaStreamCallbackTimeInfo
*timeInfo
,
157 const PaStreamCallbackFlags statusFlags
, void *userData
)
159 ALCdevice
*device
= (ALCdevice
*)userData
;
165 aluMixData(device
, outputBuffer
, framesPerBuffer
);
169 static int pa_capture_cb(const void *inputBuffer
, void *outputBuffer
,
170 unsigned long framesPerBuffer
, const PaStreamCallbackTimeInfo
*timeInfo
,
171 const PaStreamCallbackFlags statusFlags
, void *userData
)
173 ALCdevice
*device
= (ALCdevice
*)userData
;
174 pa_data
*data
= (pa_data
*)device
->ExtraData
;
180 WriteRingBuffer(data
->ring
, inputBuffer
, framesPerBuffer
);
185 static ALCboolean
pa_open_playback(ALCdevice
*device
, const ALCchar
*deviceName
)
187 const PaStreamInfo
*streamInfo
;
188 PaStreamParameters outParams
;
193 deviceName
= pa_device
;
194 else if(strcmp(deviceName
, pa_device
) != 0)
200 data
= (pa_data
*)calloc(1, sizeof(pa_data
));
201 data
->update_size
= device
->UpdateSize
;
203 device
->ExtraData
= data
;
205 outParams
.device
= GetConfigValueInt("port", "device", -1);
206 if(outParams
.device
< 0)
207 outParams
.device
= pPa_GetDefaultOutputDevice();
208 outParams
.suggestedLatency
= (device
->UpdateSize
*device
->NumUpdates
) /
209 (float)device
->Frequency
;
210 outParams
.hostApiSpecificStreamInfo
= NULL
;
212 switch(aluBytesFromFormat(device
->Format
))
215 outParams
.sampleFormat
= paUInt8
;
218 outParams
.sampleFormat
= paInt16
;
221 outParams
.sampleFormat
= paFloat32
;
224 AL_PRINT("Unknown format: 0x%x\n", device
->Format
);
225 device
->ExtraData
= NULL
;
230 outParams
.channelCount
= aluChannelsFromFormat(device
->Format
);
232 SetDefaultChannelOrder(device
);
234 err
= pPa_OpenStream(&data
->stream
, NULL
, &outParams
, device
->Frequency
,
235 device
->UpdateSize
, paNoFlag
, pa_callback
, device
);
238 AL_PRINT("Pa_OpenStream() returned an error: %s\n", pPa_GetErrorText(err
));
239 device
->ExtraData
= NULL
;
244 streamInfo
= pPa_GetStreamInfo(data
->stream
);
246 device
->szDeviceName
= strdup(deviceName
);
247 device
->Frequency
= streamInfo
->sampleRate
;
252 static void pa_close_playback(ALCdevice
*device
)
254 pa_data
*data
= (pa_data
*)device
->ExtraData
;
257 err
= pPa_CloseStream(data
->stream
);
259 AL_PRINT("Error closing stream: %s\n", pPa_GetErrorText(err
));
262 device
->ExtraData
= NULL
;
267 static ALCboolean
pa_reset_playback(ALCdevice
*device
)
269 pa_data
*data
= (pa_data
*)device
->ExtraData
;
270 const PaStreamInfo
*streamInfo
;
273 streamInfo
= pPa_GetStreamInfo(data
->stream
);
274 device
->Frequency
= streamInfo
->sampleRate
;
275 device
->UpdateSize
= data
->update_size
;
277 err
= pPa_StartStream(data
->stream
);
280 AL_PRINT("Pa_StartStream() returned an error: %s\n", pPa_GetErrorText(err
));
287 static void pa_stop_playback(ALCdevice
*device
)
289 pa_data
*data
= (pa_data
*)device
->ExtraData
;
292 err
= pPa_StopStream(data
->stream
);
294 AL_PRINT("Error stopping stream: %s\n", pPa_GetErrorText(err
));
298 static ALCboolean
pa_open_capture(ALCdevice
*device
, const ALCchar
*deviceName
)
300 PaStreamParameters inParams
;
306 deviceName
= pa_capture
;
307 else if(strcmp(deviceName
, pa_capture
) != 0)
313 data
= (pa_data
*)calloc(1, sizeof(pa_data
));
316 alcSetError(device
, ALC_OUT_OF_MEMORY
);
320 frame_size
= aluChannelsFromFormat(device
->Format
) *
321 aluBytesFromFormat(device
->Format
);
322 data
->ring
= CreateRingBuffer(frame_size
, device
->UpdateSize
*device
->NumUpdates
);
323 if(data
->ring
== NULL
)
325 alcSetError(device
, ALC_OUT_OF_MEMORY
);
329 inParams
.device
= GetConfigValueInt("port", "capture", -1);
330 if(inParams
.device
< 0)
331 inParams
.device
= pPa_GetDefaultOutputDevice();
332 inParams
.suggestedLatency
= 0.0f
;
333 inParams
.hostApiSpecificStreamInfo
= NULL
;
335 switch(aluBytesFromFormat(device
->Format
))
338 inParams
.sampleFormat
= paUInt8
;
341 inParams
.sampleFormat
= paInt16
;
344 inParams
.sampleFormat
= paFloat32
;
347 AL_PRINT("Unknown format: 0x%x\n", device
->Format
);
350 inParams
.channelCount
= aluChannelsFromFormat(device
->Format
);
352 err
= pPa_OpenStream(&data
->stream
, &inParams
, NULL
, device
->Frequency
,
353 paFramesPerBufferUnspecified
, paNoFlag
, pa_capture_cb
, device
);
356 AL_PRINT("Pa_OpenStream() returned an error: %s\n", pPa_GetErrorText(err
));
360 device
->szDeviceName
= strdup(deviceName
);
362 device
->ExtraData
= data
;
366 DestroyRingBuffer(data
->ring
);
372 static void pa_close_capture(ALCdevice
*device
)
374 pa_data
*data
= (pa_data
*)device
->ExtraData
;
377 err
= pPa_CloseStream(data
->stream
);
379 AL_PRINT("Error closing stream: %s\n", pPa_GetErrorText(err
));
382 device
->ExtraData
= NULL
;
387 static void pa_start_capture(ALCdevice
*device
)
389 pa_data
*data
= device
->ExtraData
;
392 err
= pPa_StartStream(data
->stream
);
394 AL_PRINT("Error starting stream: %s\n", pPa_GetErrorText(err
));
397 static void pa_stop_capture(ALCdevice
*device
)
399 pa_data
*data
= (pa_data
*)device
->ExtraData
;
402 err
= pPa_StopStream(data
->stream
);
404 AL_PRINT("Error stopping stream: %s\n", pPa_GetErrorText(err
));
407 static void pa_capture_samples(ALCdevice
*device
, ALCvoid
*buffer
, ALCuint samples
)
409 pa_data
*data
= device
->ExtraData
;
410 if(samples
<= (ALCuint
)RingBufferSize(data
->ring
))
411 ReadRingBuffer(data
->ring
, buffer
, samples
);
413 alcSetError(device
, ALC_INVALID_VALUE
);
416 static ALCuint
pa_available_samples(ALCdevice
*device
)
418 pa_data
*data
= device
->ExtraData
;
419 return RingBufferSize(data
->ring
);
423 static const BackendFuncs pa_funcs
= {
436 void alc_pa_init(BackendFuncs
*func_list
)
438 *func_list
= pa_funcs
;
441 void alc_pa_deinit(void)
445 void alc_pa_probe(int type
)
447 if(!pa_load()) return;
449 if(type
== DEVICE_PROBE
)
450 AppendDeviceList(pa_device
);
451 else if(type
== ALL_DEVICE_PROBE
)
452 AppendAllDeviceList(pa_device
);
453 else if(type
== CAPTURE_DEVICE_PROBE
)
454 AppendCaptureDeviceList(pa_capture
);