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.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
31 #include "backends/base.h"
33 #include <portaudio.h>
36 static const ALCchar pa_device
[] = "PortAudio Default";
40 static void *pa_handle
;
41 #define MAKE_FUNC(x) static __typeof(x) * p##x
42 MAKE_FUNC(Pa_Initialize
);
43 MAKE_FUNC(Pa_Terminate
);
44 MAKE_FUNC(Pa_GetErrorText
);
45 MAKE_FUNC(Pa_StartStream
);
46 MAKE_FUNC(Pa_StopStream
);
47 MAKE_FUNC(Pa_OpenStream
);
48 MAKE_FUNC(Pa_CloseStream
);
49 MAKE_FUNC(Pa_GetDefaultOutputDevice
);
50 MAKE_FUNC(Pa_GetDefaultInputDevice
);
51 MAKE_FUNC(Pa_GetStreamInfo
);
54 #define Pa_Initialize pPa_Initialize
55 #define Pa_Terminate pPa_Terminate
56 #define Pa_GetErrorText pPa_GetErrorText
57 #define Pa_StartStream pPa_StartStream
58 #define Pa_StopStream pPa_StopStream
59 #define Pa_OpenStream pPa_OpenStream
60 #define Pa_CloseStream pPa_CloseStream
61 #define Pa_GetDefaultOutputDevice pPa_GetDefaultOutputDevice
62 #define Pa_GetDefaultInputDevice pPa_GetDefaultInputDevice
63 #define Pa_GetStreamInfo pPa_GetStreamInfo
66 static ALCboolean
pa_load(void)
74 # define PALIB "portaudio.dll"
75 #elif defined(__APPLE__) && defined(__MACH__)
76 # define PALIB "libportaudio.2.dylib"
77 #elif defined(__OpenBSD__)
78 # define PALIB "libportaudio.so"
80 # define PALIB "libportaudio.so.2"
83 pa_handle
= LoadLib(PALIB
);
87 #define LOAD_FUNC(f) do { \
88 p##f = GetSymbol(pa_handle, #f); \
91 CloseLib(pa_handle); \
96 LOAD_FUNC(Pa_Initialize
);
97 LOAD_FUNC(Pa_Terminate
);
98 LOAD_FUNC(Pa_GetErrorText
);
99 LOAD_FUNC(Pa_StartStream
);
100 LOAD_FUNC(Pa_StopStream
);
101 LOAD_FUNC(Pa_OpenStream
);
102 LOAD_FUNC(Pa_CloseStream
);
103 LOAD_FUNC(Pa_GetDefaultOutputDevice
);
104 LOAD_FUNC(Pa_GetDefaultInputDevice
);
105 LOAD_FUNC(Pa_GetStreamInfo
);
108 if((err
=Pa_Initialize()) != paNoError
)
110 ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err
));
117 if((err
=Pa_Initialize()) != paNoError
)
119 ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err
));
127 typedef struct ALCportPlayback
{
128 DERIVE_FROM_TYPE(ALCbackend
);
131 PaStreamParameters params
;
135 static int ALCportPlayback_WriteCallback(const void *inputBuffer
, void *outputBuffer
,
136 unsigned long framesPerBuffer
, const PaStreamCallbackTimeInfo
*timeInfo
,
137 const PaStreamCallbackFlags statusFlags
, void *userData
);
139 static void ALCportPlayback_Construct(ALCportPlayback
*self
, ALCdevice
*device
);
140 static void ALCportPlayback_Destruct(ALCportPlayback
*self
);
141 static ALCenum
ALCportPlayback_open(ALCportPlayback
*self
, const ALCchar
*name
);
142 static void ALCportPlayback_close(ALCportPlayback
*self
);
143 static ALCboolean
ALCportPlayback_reset(ALCportPlayback
*self
);
144 static ALCboolean
ALCportPlayback_start(ALCportPlayback
*self
);
145 static void ALCportPlayback_stop(ALCportPlayback
*self
);
146 static DECLARE_FORWARD2(ALCportPlayback
, ALCbackend
, ALCenum
, captureSamples
, ALCvoid
*, ALCuint
)
147 static DECLARE_FORWARD(ALCportPlayback
, ALCbackend
, ALCuint
, availableSamples
)
148 static DECLARE_FORWARD(ALCportPlayback
, ALCbackend
, ClockLatency
, getClockLatency
)
149 static DECLARE_FORWARD(ALCportPlayback
, ALCbackend
, void, lock
)
150 static DECLARE_FORWARD(ALCportPlayback
, ALCbackend
, void, unlock
)
151 DECLARE_DEFAULT_ALLOCATORS(ALCportPlayback
)
153 DEFINE_ALCBACKEND_VTABLE(ALCportPlayback
);
156 static void ALCportPlayback_Construct(ALCportPlayback
*self
, ALCdevice
*device
)
158 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
159 SET_VTABLE2(ALCportPlayback
, ALCbackend
, self
);
164 static void ALCportPlayback_Destruct(ALCportPlayback
*self
)
167 Pa_CloseStream(self
->stream
);
170 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
174 static int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer
), void *outputBuffer
,
175 unsigned long framesPerBuffer
, const PaStreamCallbackTimeInfo
*UNUSED(timeInfo
),
176 const PaStreamCallbackFlags
UNUSED(statusFlags
), void *userData
)
178 ALCportPlayback
*self
= userData
;
180 aluMixData(STATIC_CAST(ALCbackend
, self
)->mDevice
, outputBuffer
, framesPerBuffer
);
185 static ALCenum
ALCportPlayback_open(ALCportPlayback
*self
, const ALCchar
*name
)
187 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
192 else if(strcmp(name
, pa_device
) != 0)
193 return ALC_INVALID_VALUE
;
195 self
->update_size
= device
->UpdateSize
;
197 self
->params
.device
= -1;
198 if(!ConfigValueInt(NULL
, "port", "device", &self
->params
.device
) ||
199 self
->params
.device
< 0)
200 self
->params
.device
= Pa_GetDefaultOutputDevice();
201 self
->params
.suggestedLatency
= (device
->UpdateSize
*device
->NumUpdates
) /
202 (float)device
->Frequency
;
203 self
->params
.hostApiSpecificStreamInfo
= NULL
;
205 self
->params
.channelCount
= ((device
->FmtChans
== DevFmtMono
) ? 1 : 2);
207 switch(device
->FmtType
)
210 self
->params
.sampleFormat
= paInt8
;
213 self
->params
.sampleFormat
= paUInt8
;
218 self
->params
.sampleFormat
= paInt16
;
223 self
->params
.sampleFormat
= paInt32
;
226 self
->params
.sampleFormat
= paFloat32
;
231 err
= Pa_OpenStream(&self
->stream
, NULL
, &self
->params
,
232 device
->Frequency
, device
->UpdateSize
, paNoFlag
,
233 ALCportPlayback_WriteCallback
, self
237 if(self
->params
.sampleFormat
== paFloat32
)
239 self
->params
.sampleFormat
= paInt16
;
242 ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err
));
243 return ALC_INVALID_VALUE
;
246 al_string_copy_cstr(&device
->DeviceName
, name
);
252 static void ALCportPlayback_close(ALCportPlayback
*self
)
254 PaError err
= Pa_CloseStream(self
->stream
);
256 ERR("Error closing stream: %s\n", Pa_GetErrorText(err
));
260 static ALCboolean
ALCportPlayback_reset(ALCportPlayback
*self
)
262 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
263 const PaStreamInfo
*streamInfo
;
265 streamInfo
= Pa_GetStreamInfo(self
->stream
);
266 device
->Frequency
= streamInfo
->sampleRate
;
267 device
->UpdateSize
= self
->update_size
;
269 if(self
->params
.sampleFormat
== paInt8
)
270 device
->FmtType
= DevFmtByte
;
271 else if(self
->params
.sampleFormat
== paUInt8
)
272 device
->FmtType
= DevFmtUByte
;
273 else if(self
->params
.sampleFormat
== paInt16
)
274 device
->FmtType
= DevFmtShort
;
275 else if(self
->params
.sampleFormat
== paInt32
)
276 device
->FmtType
= DevFmtInt
;
277 else if(self
->params
.sampleFormat
== paFloat32
)
278 device
->FmtType
= DevFmtFloat
;
281 ERR("Unexpected sample format: 0x%lx\n", self
->params
.sampleFormat
);
285 if(self
->params
.channelCount
== 2)
286 device
->FmtChans
= DevFmtStereo
;
287 else if(self
->params
.channelCount
== 1)
288 device
->FmtChans
= DevFmtMono
;
291 ERR("Unexpected channel count: %u\n", self
->params
.channelCount
);
294 SetDefaultChannelOrder(device
);
299 static ALCboolean
ALCportPlayback_start(ALCportPlayback
*self
)
303 err
= Pa_StartStream(self
->stream
);
306 ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err
));
313 static void ALCportPlayback_stop(ALCportPlayback
*self
)
315 PaError err
= Pa_StopStream(self
->stream
);
317 ERR("Error stopping stream: %s\n", Pa_GetErrorText(err
));
321 typedef struct ALCportCapture
{
322 DERIVE_FROM_TYPE(ALCbackend
);
325 PaStreamParameters params
;
327 ll_ringbuffer_t
*ring
;
330 static int ALCportCapture_ReadCallback(const void *inputBuffer
, void *outputBuffer
,
331 unsigned long framesPerBuffer
, const PaStreamCallbackTimeInfo
*timeInfo
,
332 const PaStreamCallbackFlags statusFlags
, void *userData
);
334 static void ALCportCapture_Construct(ALCportCapture
*self
, ALCdevice
*device
);
335 static void ALCportCapture_Destruct(ALCportCapture
*self
);
336 static ALCenum
ALCportCapture_open(ALCportCapture
*self
, const ALCchar
*name
);
337 static void ALCportCapture_close(ALCportCapture
*self
);
338 static DECLARE_FORWARD(ALCportCapture
, ALCbackend
, ALCboolean
, reset
)
339 static ALCboolean
ALCportCapture_start(ALCportCapture
*self
);
340 static void ALCportCapture_stop(ALCportCapture
*self
);
341 static ALCenum
ALCportCapture_captureSamples(ALCportCapture
*self
, ALCvoid
*buffer
, ALCuint samples
);
342 static ALCuint
ALCportCapture_availableSamples(ALCportCapture
*self
);
343 static DECLARE_FORWARD(ALCportCapture
, ALCbackend
, ClockLatency
, getClockLatency
)
344 static DECLARE_FORWARD(ALCportCapture
, ALCbackend
, void, lock
)
345 static DECLARE_FORWARD(ALCportCapture
, ALCbackend
, void, unlock
)
346 DECLARE_DEFAULT_ALLOCATORS(ALCportCapture
)
348 DEFINE_ALCBACKEND_VTABLE(ALCportCapture
);
351 static void ALCportCapture_Construct(ALCportCapture
*self
, ALCdevice
*device
)
353 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
354 SET_VTABLE2(ALCportCapture
, ALCbackend
, self
);
359 static void ALCportCapture_Destruct(ALCportCapture
*self
)
362 Pa_CloseStream(self
->stream
);
366 ll_ringbuffer_free(self
->ring
);
369 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
373 static int ALCportCapture_ReadCallback(const void *inputBuffer
, void *UNUSED(outputBuffer
),
374 unsigned long framesPerBuffer
, const PaStreamCallbackTimeInfo
*UNUSED(timeInfo
),
375 const PaStreamCallbackFlags
UNUSED(statusFlags
), void *userData
)
377 ALCportCapture
*self
= userData
;
378 size_t writable
= ll_ringbuffer_write_space(self
->ring
);
380 if(framesPerBuffer
> writable
)
381 framesPerBuffer
= writable
;
382 ll_ringbuffer_write(self
->ring
, inputBuffer
, framesPerBuffer
);
387 static ALCenum
ALCportCapture_open(ALCportCapture
*self
, const ALCchar
*name
)
389 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
390 ALuint samples
, frame_size
;
395 else if(strcmp(name
, pa_device
) != 0)
396 return ALC_INVALID_VALUE
;
398 samples
= device
->UpdateSize
* device
->NumUpdates
;
399 samples
= maxu(samples
, 100 * device
->Frequency
/ 1000);
400 frame_size
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
);
402 self
->ring
= ll_ringbuffer_create(samples
, frame_size
);
403 if(self
->ring
== NULL
) return ALC_INVALID_VALUE
;
405 self
->params
.device
= -1;
406 if(!ConfigValueInt(NULL
, "port", "capture", &self
->params
.device
) ||
407 self
->params
.device
< 0)
408 self
->params
.device
= Pa_GetDefaultInputDevice();
409 self
->params
.suggestedLatency
= 0.0f
;
410 self
->params
.hostApiSpecificStreamInfo
= NULL
;
412 switch(device
->FmtType
)
415 self
->params
.sampleFormat
= paInt8
;
418 self
->params
.sampleFormat
= paUInt8
;
421 self
->params
.sampleFormat
= paInt16
;
424 self
->params
.sampleFormat
= paInt32
;
427 self
->params
.sampleFormat
= paFloat32
;
431 ERR("%s samples not supported\n", DevFmtTypeString(device
->FmtType
));
432 return ALC_INVALID_VALUE
;
434 self
->params
.channelCount
= ChannelsFromDevFmt(device
->FmtChans
);
436 err
= Pa_OpenStream(&self
->stream
, &self
->params
, NULL
,
437 device
->Frequency
, paFramesPerBufferUnspecified
, paNoFlag
,
438 ALCportCapture_ReadCallback
, self
442 ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err
));
443 return ALC_INVALID_VALUE
;
446 al_string_copy_cstr(&device
->DeviceName
, name
);
451 static void ALCportCapture_close(ALCportCapture
*self
)
453 PaError err
= Pa_CloseStream(self
->stream
);
455 ERR("Error closing stream: %s\n", Pa_GetErrorText(err
));
458 ll_ringbuffer_free(self
->ring
);
463 static ALCboolean
ALCportCapture_start(ALCportCapture
*self
)
465 PaError err
= Pa_StartStream(self
->stream
);
468 ERR("Error starting stream: %s\n", Pa_GetErrorText(err
));
474 static void ALCportCapture_stop(ALCportCapture
*self
)
476 PaError err
= Pa_StopStream(self
->stream
);
478 ERR("Error stopping stream: %s\n", Pa_GetErrorText(err
));
482 static ALCuint
ALCportCapture_availableSamples(ALCportCapture
*self
)
484 return ll_ringbuffer_read_space(self
->ring
);
487 static ALCenum
ALCportCapture_captureSamples(ALCportCapture
*self
, ALCvoid
*buffer
, ALCuint samples
)
489 ll_ringbuffer_read(self
->ring
, buffer
, samples
);
494 typedef struct ALCportBackendFactory
{
495 DERIVE_FROM_TYPE(ALCbackendFactory
);
496 } ALCportBackendFactory
;
497 #define ALCPORTBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCportBackendFactory, ALCbackendFactory) } }
499 static ALCboolean
ALCportBackendFactory_init(ALCportBackendFactory
*self
);
500 static void ALCportBackendFactory_deinit(ALCportBackendFactory
*self
);
501 static ALCboolean
ALCportBackendFactory_querySupport(ALCportBackendFactory
*self
, ALCbackend_Type type
);
502 static void ALCportBackendFactory_probe(ALCportBackendFactory
*self
, enum DevProbe type
);
503 static ALCbackend
* ALCportBackendFactory_createBackend(ALCportBackendFactory
*self
, ALCdevice
*device
, ALCbackend_Type type
);
505 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCportBackendFactory
);
508 static ALCboolean
ALCportBackendFactory_init(ALCportBackendFactory
* UNUSED(self
))
515 static void ALCportBackendFactory_deinit(ALCportBackendFactory
* UNUSED(self
))
529 static ALCboolean
ALCportBackendFactory_querySupport(ALCportBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
531 if(type
== ALCbackend_Playback
|| type
== ALCbackend_Capture
)
536 static void ALCportBackendFactory_probe(ALCportBackendFactory
* UNUSED(self
), enum DevProbe type
)
540 case ALL_DEVICE_PROBE
:
541 AppendAllDevicesList(pa_device
);
543 case CAPTURE_DEVICE_PROBE
:
544 AppendCaptureDeviceList(pa_device
);
549 static ALCbackend
* ALCportBackendFactory_createBackend(ALCportBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
551 if(type
== ALCbackend_Playback
)
553 ALCportPlayback
*backend
;
554 NEW_OBJ(backend
, ALCportPlayback
)(device
);
555 if(!backend
) return NULL
;
556 return STATIC_CAST(ALCbackend
, backend
);
558 if(type
== ALCbackend_Capture
)
560 ALCportCapture
*backend
;
561 NEW_OBJ(backend
, ALCportCapture
)(device
);
562 if(!backend
) return NULL
;
563 return STATIC_CAST(ALCbackend
, backend
);
569 ALCbackendFactory
*ALCportBackendFactory_getFactory(void)
571 static ALCportBackendFactory factory
= ALCPORTBACKENDFACTORY_INITIALIZER
;
572 return STATIC_CAST(ALCbackendFactory
, &factory
);